npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cap-attachments-plus

v1.0.29

Published

CAP cds-plugin providing image and attachment storing out-of-the-box.

Readme

REUSE status

Attachments Plugin

The cap-attachments-plus package is a CDS plugin that provides out-of-the box asset storage and handling by using an aspect called Attachments.

Why use this package

Any CAP application that lets users upload files (documents, images, PDFs, etc.) needs to solve the same set of problems repeatedly: where to store the binary content, how to keep a database reference in sync with it, how to render an upload/download UI facet, how to scan uploads for malware before they're accessible, and how to enforce size/MIME-type limits. Building all of this by hand for every application is repetitive and error-prone.

This plugin solves that once, and gives you:

  • A single CDS aspect (Attachments) that, when composed into an entity, automatically generates the OData actions, DB entity, and Fiori Elements UI facet for uploading, listing, downloading and deleting files — no handler code required.
  • Pluggable storage backends — store attachment content directly in the database (for local development), or offload it to AWS S3, Azure Blob Storage, or Google Cloud Storage, all configured directly against your own cloud account via a BTP destination. You choose the target per environment; the application code and CDS model never change.
  • Built-in malware scanning via the SAP Malware Scanning Service (or a mocked scanner for local development), with per-attachment scan status tracking so infected files are automatically removed and never made downloadable.
  • File size and MIME type validation out of the box, configurable per entity via standard CDS annotations (@Validation.Maximum, @Core.AcceptableMediaTypes).
  • Multitenancy support, including tenant-scoped storage isolation.
  • Consistent, actionable error handling and logging throughout, so failures during upload/download/scan surface a clear reason and remediation hint rather than an opaque stack trace.

In short: add the plugin, add one line to your CDS model, and you have production-ready attachment handling — you only configure where the files should live.

Table of Contents

Usage

Quick Start

For a quick local development setup with in-memory storage:

  • The plugin is self-configuring as described, see the following details section. To enable attachments, simply add the plugin package to your project:

    npm add cap-attachments-plus
    "devDependencies": { 
      "cap-attachments-plus": "<latest-version>", 
      // (...)
    }

    In addition, different profiles can be found in package.json as well, such as:

    "cds": {  
      "requires": {  
        // (...)
        "[hybrid]": {  
          "attachments": {  
            "kind": "attachments-standard"  
            // (...)
          }  
        }  
      }  
    }  
  • To use Attachments, extend a CDS model by adding an element that refers to the pre-defined Attachments type (see Changes in the CDS Models for more details):

    using { Attachments } from 'cap-attachments-plus';
    
    entity Incidents {  
        // (...)
        attachments: Composition of many Attachments;  
    }

In this guide, we use the Incidents Management reference sample app as the base application to provide a demonstration how to use this plugin. A miniature version of this app can be found within the tests directory for local testing.

For productive use, a valid object store binding is required, see Object Stores and Storage Targets.

Local Walk-Through

With the steps above, we have successfully set up asset handling for our reference application. To test the application locally, use the following steps.

[!NOTE] For local testing, the attachment objects are stored in a local database.

  1. Start the server:
  • Default scenario (In memory database):
    cds watch
  1. Navigate to the object page of the incident Solar panel broken: Go to object page for incident Solar panel broken

  2. The Attachments type has generated an out-of-the-box Attachments table (see 1) at the bottom of the Object page:

  1. Upload a file by going into Edit mode and either using the Upload button on the Attachments table or by drag/drop. Then click the Save button to have that file stored that file in the dedicated resource (database, S3 bucket, etc.). We demonstrate this by uploading the PDF file from tests/integration/content/sample.pdf:
  1. Delete a file by going into Edit mode, selecting the file, and pressing the Delete button above the Attachments table. Clicking the Save button will then delete that file from the resource (database, S3 bucket, etc.).

Changes in the CDS Models

To use the aspect Attachments on an existing entity, the corresponding entity needs to either include attachments as an element in the model definition or be extended in a CDS file in the srv module. In the quick start, the former was done, adding an element to the model definition:

using { Attachments } from 'cap-attachments-plus';  

entity Incidents {  
  // ...  
  attachments: Composition of many Attachments;  
} 

The entity Incidents can also be extended in the srv module, as seen in the following example:

using { Attachments } from 'cap-attachments-plus'; 

extend my.Incidents with { 
  attachments: Composition of many Attachments; 
} 
  
service ProcessorService { 
  entity Incidents as projection on my.Incidents 
}

Both methods directly add the respective UI Facet. To use the plugin with an SAP Fiori elements UI, be sure that draft is enabled for the entity using @odata.draft.enabled. For example:

annotate service.Incidents with @odata.draft.enabled;

Storage Targets

The plugin supports two categories of storage target, selected via kind:

  • Local database (kind: "attachments-db", the development profile default) — attachments are stored directly in the application's own database. No cloud account or binding of any kind is required.
  • Cloud storage (kind: "attachments-s3" / "attachments-azure" / "attachments-gcp" / "attachments-standard") — the attachment content is saved in your own AWS S3 bucket, Azure Blob Storage container, or GCP Cloud Storage bucket, and only a reference plus metadata is kept in the database, as defined in the CDS model. Credentials come from a BTP destination you create yourself (see step 4) — there is no SAP Object Store service instance to provision for this.

To test a cloud storage target in a hybrid setup, bind the Destination service instance (which the plugin uses to look up your BTP destination at runtime) using cds bind, as described in the CAP documentation for hybrid testing:

  1. Log in to Cloud Foundry:
cf login -a <CF-API> -o <ORG-NAME> -s <SPACE-NAME> --sso
  1. Bind the Destination service instance, which generates/updates a .cdsrc-private.json file in the project directory:
cds bind <HybridDestinationServiceName> --to <RemoteDestinationServiceName>

Where HybridDestinationServiceName can be any name you choose, and RemoteDestinationServiceName is the name of your Destination service instance in SAP BTP.

  1. Run the application in hybrid mode:
cds watch --profile hybrid

See Object Stores for background on when an SAP Object Store binding is still relevant (multitenancy provisioning only, not attachment storage).

Malware Scanner

The BTP malware scanning service is used in the AttachmentService to scan attachments for vulnerabilities.

For using SAP Malware Scanning Service, you must already have a service instance which you can access. To bind it, run the following command:

cds bind <HybridMalwareScannerName> --to <RemoteMalwareScannerName>

By default, malware scanning is enabled for all profiles if a storage provider has been specified. You can configure malware scanning by setting:

{  
  "cds": {  
     // (...)  
     "attachments": {  
       "scan": true  
     }  
  }  
} 

If there is no malware scanner available and the scanner is not disabled, then the upload will fail.

Disabling malware scanning

If you don't need scanning at all, set scan: false in your application's own package.json:

{
  "cds": {
    "requires": {
      "attachments": {
        "scan": false
      }
    }
  }
}

With scanning disabled, no Malware Scanning Service binding is required, and uploaded files become downloadable immediately — the scan step (and the status gating in validateAttachment, which otherwise blocks download until status is Clean) is skipped entirely.

This can also be scoped to a single environment profile, e.g. to disable scanning only in development:

{
  "cds": {
    "requires": {
      "[development]": {
        "attachments": { "scan": false }
      }
    }
  }
}

[!Note] The plugin's own [development] profile default already wires up a mocked scanner (kind: "malwareScanner-mocked") that always reports Clean without calling any real service. So for local development you typically don't need scan: false or real malware scanning credentials at all — scan: false is for skipping the scan step altogether, including in production.

Scan status codes:

  • Unscanned: Attachment is still unscanned.
  • Scanning: Immediately after upload, the attachment is marked as Scanning. Depending on processing speed, it may already appear as Clean when the page is reloaded.
  • Clean: Only attachments with the status Clean are accessible.
  • Infected: The attachment is infected.
  • Failed: Scanning failed.

[!Note] The malware scanner supports mTLS authentication which requires an annual renewal of the certificate. Previously, basic authentication was used which has now been deprecated.

[!Note] If the malware scanner reports a file size larger than the limit specified via @Validation.Maximum it removes the file and sets the status of the attachment metadata to failed.

Visibility Control for Attachments UI Facet Generation

By setting the @UI.Hidden property to true, developers can hide the visibility of the plugin in the UI. This feature is particularly useful in scenarios where the visibility of the plugin needs to be dynamically controlled based on certain conditions.

Example Usage

entity Incidents {
  // ...
  @UI.Hidden
  attachments: Composition of many Attachments;
}

In this example, the @UI.Hidden is set to true, which means the plugin will be hidden by default. You can also use dynamic expressions which are then added to the facet.

entity Incidents {
  // ...
  status : Integer enum {
    submitted =  1;
    fulfilled =  2;
    shipped   =  3;
    canceled  = -1;
  };
  @UI.Hidden : (status = #canceled ? true : false)
  attachments: Composition of many Attachments;
}

Non-Draft Upload

For scenarios where the entity is not draft-enabled, for example tests/non-draft-request.http, separate HTTP requests for metadata creation and asset uploading need to be performed manually.

The typical sequence includes:

  1. POST -> create attachment metadata, returns ID
  2. PUT -> upload file content using the ID

Specify the maximum file size

You can specify the maximum file size by annotating the attachments content property with @Validation.Maximum

entity Incidents {
  ...
  attachments: Composition of many Attachments;
}

annotate Incidents.attachments with {
  content @Validation.Maximum : '20MB';
}

The default is 400MB

Restrict allowed MIME types

You can restrict which MIME types are allowed for attachments by annotating the content property with @Core.AcceptableMediaTypes. This validation is performed during file upload.

entity Incidents {
  ...
  attachments: Composition of many Attachments;
}

annotate Incidents.attachments with {
  content @Core.AcceptableMediaTypes : ['image/jpeg', 'image/png', 'application/pdf'];
}

Wildcard patterns are supported:

annotate Incidents.attachments with {
  content @Core.AcceptableMediaTypes : ['image/*', 'application/pdf'];
}

To allow all MIME types (default behavior), either omit the annotation or use:

annotate Incidents.attachments with {
  content @Core.AcceptableMediaTypes : ['*/*'];
}

When a file with a disallowed MIME type is uploaded, the request will be rejected with a 400 error.

Configuration Reference

This section lists every configuration step, in order, needed to go from "no attachments" to a fully working, production-ready setup.

1. Install the plugin

npm add cap-attachments-plus

2. Reference it in your CDS model

Add the Attachments composition to the entity that should support file uploads (see Changes in the CDS Models):

using { Attachments } from 'cap-attachments-plus';

entity Incidents {
  // ...
  attachments: Composition of many Attachments;
}

If the entity is exposed via a Fiori Elements UI, ensure draft is enabled:

annotate service.Incidents with @odata.draft.enabled;

3. Choose where files are stored (kind)

The plugin acts as a middleware in front of whichever storage backend you choose — your CDS model and application code stay identical no matter which one is active. You select the backend entirely through configuration, in your own application's package.json, using the standard CAP cds.requires.<service>.kind convention (the same mechanism CAP itself uses to pick a database kind like "sqlite" or "hana"). Nothing Azure/AWS/GCP-specific needs to be written in your code or CDS model — just this one string:

"cds": {
  "requires": {
    "attachments": {
      "kind": "attachments-azure"
    }
  }
}

| kind value | Storage backend | What it needs | | --- | --- | --- | | attachments-db | The application's own database (SQLite/HANA) | Nothing — this is the default for the development profile | | attachments-standard | Auto-detects AWS S3, Azure Blob Storage or GCP Cloud Storage from the shape of the bound destination's configuration | A BTP destination (any provider's fields) | | attachments-s3 | AWS S3 | A BTP destination with AWS credentials | | attachments-azure | Azure Blob Storage | A BTP destination with Azure credentials | | attachments-gcp | GCP Cloud Storage | A BTP destination with GCP credentials |

The kind you set is the only thing that tells the plugin which client code to run (srv/aws-s3.js, srv/azure-blob-storage.js, srv/gcp.js or srv/basic.js, mapped once via cds.requires.kinds inside this plugin — consuming apps never need to know these file paths). Which cloud account those credentials actually point at is entirely up to what you put in the destination in step 4 below — the plugin itself is cloud-agnostic.

For local development, kind defaults to attachments-db and files are stored directly in the application's own database — no cloud account, destination, or further setup required (see Local Walk-Through).

4. For a cloud backend: create and bind a BTP destination with your storage credentials

Each cloud provider (attachments-s3/attachments-azure/attachments-gcp/attachments-standard) reads its credentials from a BTP destination that you create in BTP Cockpit, pointing at your own AWS, Azure, or GCP account. This means attachments are stored directly in your own cloud infrastructure — no SAP Object Store service instance is required.

  1. In BTP Cockpit, create a destination (default expected name: attachments) with Authentication: BasicAuthentication, and put the credential in User/Password and the non-secret identifiers as additional properties, per the table below.
  2. Ensure a Destination service instance is bound to your application (required to look up the destination at runtime).
  3. If you want to use a destination name other than attachments, set it explicitly. destination can be overridden globally, or per environment profile (e.g. "[production]").

[!IMPORTANT] Use Authentication: BasicAuthentication and put the actual secret in the destination's User/Password fields — not as a plain additional property. The Destination service encrypts and access-controls User/Password (and masks Password in BTP Cockpit); a custom additional property does not get that protection. Non-secret identifiers (bucket name, region, container URI, project ID, etc.) can stay as plain additional properties.

Destination configuration per provider — User/Password hold the actual secret, everything else is a plain additional property:

| Provider | User | Password | Additional properties (non-secret) | | --- | --- | --- | --- | | AWS S3 | access_key_id | secret_access_key | bucket, region (optionally endpoint for S3-compatible storage) | | Azure Blob Storage | container_name | sas_token | container_uri | | GCP Cloud Storage | projectId | base64EncodedPrivateKeyData (the full service account key, base64-encoded) | bucket |

For backwards compatibility, the plugin also still accepts these values as plain additional properties named access_key_id/secret_access_key, container_name/sas_token, and projectId/base64EncodedPrivateKeyData if User/Password aren't set — but that path is not recommended, since those properties aren't encrypted/masked the way User/Password are.

Full, ready-to-use examples

Azure Blob Storage

"cds": {
  "requires": {
    "attachments": {
      "kind": "attachments-azure",
      "destination": "myAzureDestination"
    }
  }
}

AWS S3

"cds": {
  "requires": {
    "attachments": {
      "kind": "attachments-s3",
      "destination": "myAwsDestination"
    }
  }
}

GCP Cloud Storage

"cds": {
  "requires": {
    "attachments": {
      "kind": "attachments-gcp",
      "destination": "myGcpDestination"
    }
  }
}

Auto-detect (let the destination's contents decide the provider)

"cds": {
  "requires": {
    "attachments": {
      "kind": "attachments-standard",
      "destination": "myStorageDestination"
    }
  }
}

Only one of these blocks needs to be in your package.json at a time — kind and destination are the complete, end-to-end configuration surface needed to target a specific provider. Nothing else in your application (model, handlers, UI) changes between providers.

5. Configure malware scanning

Malware scanning is enabled by default whenever a storage provider is configured. See Malware Scanner for how to bind the SAP Malware Scanning Service, or disable it explicitly:

"cds": {
  "requires": {
    "attachments": {
      "scan": false
    }
  }
}

[!WARNING] If scanning is enabled but no malware scanner is bound, uploads will fail. If disabled, uploaded files are made available for download immediately without being scanned.

6. (Optional) Restrict file size and MIME types

Add @Validation.Maximum and/or @Core.AcceptableMediaTypes annotations on the content property — see Specify the maximum file size and Restrict allowed MIME types.

7. (Optional) Configure multitenancy

See Multitenancy for shared vs. tenant-scoped storage.

8. (Optional) Configure logging

See Monitoring & Logging to raise the log level for troubleshooting.

Configuration checklist

| Step | Config key | Required? | | --- | --- | --- | | Storage backend | cds.requires.attachments.kind | Optional (defaults to attachments-db in development, attachments-standard otherwise) | | Destination name | cds.requires.attachments.destination | Optional (defaults to "attachments") | | Destination service binding | (VCAP binding) | Required for any storage backend other than the local database | | Malware scanning toggle | cds.requires.attachments.scan | Optional (defaults to true) | | Malware scanner binding | (VCAP binding) | Required if scanning is enabled | | Max file size | @Validation.Maximum on content | Optional (defaults to 400 MB) | | Allowed MIME types | @Core.AcceptableMediaTypes on content | Optional (defaults to all types) | | Multitenancy object store mode | cds.requires.attachments.objectStore.kind | Optional (defaults to separate) | | Log level | cds.log.levels.attachments | Optional (defaults to CAP's default log level) |

Error Reference

The plugin surfaces two categories of errors: OData request errors, returned to the client with an HTTP status and a message code (translatable via _i18n/messages.properties), and configuration errors, thrown during service initialization or client creation and written to the attachments log with a suggested remediation.

OData request errors

| HTTP Status | Message code | Meaning | Remediation | | --- | --- | --- | --- | | 400 | ContentLengthHeaderMissing | The Content-Length header is missing or invalid on an upload request. | Ensure the HTTP client sends a valid Content-Length header. | | 400 | InvalidContentLengthHeader | The Content-Length header value could not be parsed as a number. | Check the client is not sending a malformed header. | | 413 | AttachmentSizeExceeded | The uploaded file exceeds the configured (or default 400MB) size limit. | Increase @Validation.Maximum on the content property, or reduce the file size. | | 400 | AttachmentMimeTypeDisallowed | The uploaded file's MIME type isn't in the entity's @Core.AcceptableMediaTypes allow-list. | Adjust the allow-list annotation, or upload a supported file type. | | 403 | UnableToDownloadAttachmentScanStatusNotClean | A download was attempted before the malware scan completed (or the file was flagged). | Wait for the scan to complete; check the attachment's status field. | | 404 | (none) | The attachment, or its parent record, could not be found. | Verify the entity/parent record exists before uploading or downloading. | | 501 | MultiUpdateNotSupported | A PUT/UPDATE targeted more than one attachment record at once. | Update attachments one at a time. |

Configuration / connectivity errors

These are thrown (and logged with a suggestion) when the plugin cannot reach or validate a storage or scanning backend. They typically surface on the first upload/download after a deployment or configuration change.

| Error | Cause | Remediation | | --- | --- | --- | | Destination service Instance Binding is needed | No Destination service instance is bound to the application. | Bind a Destination service instance. | | Destination "<name>" not found in BTP Cockpit | The configured/default destination name doesn't exist. | Create the destination, or set cds.requires.attachments.destination to the correct name. | | Missing AWS S3 configuration in destination "<name>": ... | The bound destination is missing one or more required S3 properties (User/Password or bucket/region). | Add the missing properties (see step 4). | | Missing Azure Blob Storage configuration in destination "<name>": ... | The bound destination is missing one or more required Azure properties (User/Password or container_uri). | Add the missing properties. | | Missing Google Cloud Platform configuration in destination "<name>": ... | The bound destination is missing one or more required GCP properties (User/Password or bucket). | Add the missing properties. | | <Provider> configuration found where <OtherProvider> configuration expected | kind doesn't match the credentials shape in the bound destination. | Fix cds.requires.attachments.kind, or point destination at the correct BTP destination. | | Unable to determine storage provider from the destination configuration | Using kind: "attachments-standard" but the destination's fields don't match any known provider shape. | Select a provider explicitly via kind. | | cds.env.requires.malwareScanner.credentials is empty! | Malware scanning is enabled but no Malware Scanning Service is bound. | Bind the service, or set cds.requires.attachments.scan to false. | | Missing Malware Scanner credentials: mTLS [...], Basic Auth [...] | The malware scanner binding is missing required credential fields. | Check the service binding/service key. | | Malware scanner certificate expired | The mTLS certificate used for the malware scanner has expired. | Renew the certificate (annual renewal required). | | SAP Object Store instance credentials not found (multitenancy shared mode) | No shared Object Store instance bound to the mtx module. | Bind a shared Object Store instance to the mtx/sidecar application module. | | Service Manager Instance is not bound (multitenancy separate mode) | No Service Manager instance bound, needed to provision per-tenant object stores. | Bind a Service Manager instance. |

Releases

Minimum UI5 and CAP NodeJS Version

| Component | Minimum Version | |-----------|-----------------| | CAP Node | 8.0.0 | | UI5 | 1.136.0 |

Architecture Overview

Multitenancy

The plugin supports multi-tenancy scenarios, allowing both shared and tenant-specific object store instances.

[!Note] Starting from version 2.1.0, separate mode for object store instances is the default setting for multi-tenancy.

For multi-tenant applications, cap-attachments-plus must be included in the dependencies of both the application-level and mtx/sidecar/package.json files.

Separate object store instances

By default the plugin creates for each tenant its own object store instance during the tenants subscription.

When the tenant unsubscribes the object store instance is deleted.

[!WARNING] When you remove the plugin from an application after separate object stores already have been created, the object stores are not automatically removed!

Shared Object Store Instance

To configure a shared object store instance, modify both the package.json files as follows:

"cds": {
  "requires": {
    "attachments": {
      "objectStore": {
        "kind": "shared"
      }
    }
  }
}

To ensure tenant identification when using a shared object store instance, the plugin prefixes attachment URLs with the tenant ID. Be sure the shared object store instance is bound to the mtx application module before deployment.

Object Stores

[!Note] The attachment content (AWS S3 / Azure Blob Storage / GCP Cloud Storage) is configured via a BTP destination pointing directly at your own cloud account — see Storage Targets and step 4 of the Configuration Reference. The SAP Object Store service binding described below is only relevant for multi-tenant deployments that use the plugin's automatic per-tenant Object Store provisioning (see Multitenancy); it is not required to store attachment files themselves.

A valid object store service binding is required, typically one provisioned through SAP BTP. See Storage Targets and Deployment to Cloud Foundry on how to use this object store service binding.

Deployment to Cloud Foundry

The corresponding entry in the mta-file possibly looks like:

_schema-version: '0.1'
ID: consuming-app
version: 1.0.0
description: "App consuming the attachments plugin with an object store"
parameters:
  ...
modules:
  - name: consuming-app-srv
# ------------------------------------------------------------
    type: nodejs
    path: srv
    parameters:
      ...
    properties:
      ...
    build-parameters:
      ...
    requires:
      - name: consuming-app-hdi-container
      - name: consuming-app-uaa
      - name: cf-logging
      - name: **object-store-service**
...
resources:
  ...
  - name: **object-store-service**
    type: org.cloudfoundry.managed-service
    parameters:
      service: objectstore
      service-plan: standard
Tests

The unit tests in this module do not need a binding to the respective object stores, run them with npm install. To achieve a clean install, the command rm -rf node_modules should be used before installation.

The integration tests need a binding to a real object store. Run them with npm run test. To set the binding, please see the section Storage Targets.

Supported Storage Provider

Each cloud provider reads its configuration directly from a BTP destination, pointing at your own AWS, Azure or GCP account rather than an SAP Object Store service instance. attachments-db stores content in the application's own database instead, with no cloud dependency at all.

See step 3: Choose where files are stored and step 4: Create and bind a BTP destination in the Configuration Reference for the full list of kind values, required destination properties per provider, and ready-to-use package.json examples.

Model Texts

In the model, several fields are annotated with the @title annotation. Default texts are provided in 2 languages. If these defaults are not sufficient for an application, they can be overwritten by applications with custom texts or translations.

The following table gives an overview of the fields and the i18n codes:

| Field Name | i18n Code | |------------|--------------| | mimeType | MediaType | | fileName | FileName | | status | ScanStatus | | note | note |

In addition to the field names, header information (@UI.HeaderInfo) are also annotated:

| Header Info | i18n Code |
|------------------|---------------| | TypeName | Attachment | | TypeNamePlural | Attachments |

Monitoring & Logging

To configure logging for the attachments plugin, add the following configuration to the package.json of the consuming application:

{
  "cds": {
    "log": {
      "levels": {
         // (...)
         "attachments": "debug"
      }
    }
  }
}
...

Support, Feedback, and Contributing

This project is open to feature requests/suggestions, bug reports etc. via GitHub issues. Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, the local development setup, as well as additional contribution information, see our Contribution Guidelines.

Code of Conduct

We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. By participating in this project, you agree to abide by its Code of Conduct at all times.

Licensing

Copyright 2024 SAP SE or an SAP affiliate company and contributors. Please see our LICENSE for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available via the REUSE tool.