{"id":18652483,"url":"https://github.com/boostercloud/rocket-file-uploads","last_synced_at":"2026-04-16T05:01:19.842Z","repository":{"id":57100574,"uuid":"443339037","full_name":"boostercloud/rocket-file-uploads","owner":"boostercloud","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-14T20:40:59.000Z","size":3099,"stargazers_count":3,"open_issues_count":4,"forks_count":3,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-10-19T14:19:36.235Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boostercloud.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-12-31T12:18:36.000Z","updated_at":"2025-04-14T20:41:02.000Z","dependencies_parsed_at":"2022-08-20T17:30:49.508Z","dependency_job_id":"cd6f3730-c9b7-4e20-be0b-390de42351d8","html_url":"https://github.com/boostercloud/rocket-file-uploads","commit_stats":null,"previous_names":["boostercloud/rocket-files"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/boostercloud/rocket-file-uploads","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boostercloud%2Frocket-file-uploads","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boostercloud%2Frocket-file-uploads/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boostercloud%2Frocket-file-uploads/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boostercloud%2Frocket-file-uploads/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boostercloud","download_url":"https://codeload.github.com/boostercloud/rocket-file-uploads/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boostercloud%2Frocket-file-uploads/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31872036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"online","status_checked_at":"2026-04-16T02:00:06.042Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T07:06:55.448Z","updated_at":"2026-04-16T05:01:19.806Z","avatar_url":"https://github.com/boostercloud.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Files Rocket\n\nThis package is a configurable rocket to add a storage API to your Booster applications.\n\n## Supported Providers\n\n- Azure Provider\n- Local Provider\n\n## Overview\n\nThis rocket provides some methods to access files stores in your cloud provider:\n\n- `presignedPut`: Returns a presigned put url and the necessary form params. With this url files can be uploaded directly to your provider.\n- `presignedGet`: Returns a presigned get url to download a file. With this url files can be downloaded directly from your provider.\n- `list`: Returns a list of files stored in the provider.\n\nThese methods may be used from a Command in your project secured via JWT Token.\n\nThis rocket also provides a Booster Event each time a file is uploaded.\n\n## Usage\n\nInstall needed **dependency** packages:\n\n```bash\nnpm install --save @boostercloud/rocket-file-uploads-core @boostercloud/rocket-file-uploads-types\n```\n\nDepending on your provider you could need some of the following **dependency** packages:\n\n_Azure Provider:_\n\n```bash\nnpm install --save @boostercloud/rocket-file-uploads-azure\n```\n\n_Local Provider:_\n\n```bash\nnpm install --save @boostercloud/rocket-file-uploads-local\n```\n\nAlso, you will need a **devDependency** in your project, depending on your provider:\n\n_Azure Provider_\n\n```bash\nnpm install --save-dev @boostercloud/rocket-file-uploads-azure-infrastructure\n```\n\n_Local Provider:_\n\n```bash\nnpm install --save-dev @boostercloud/rocket-file-uploads-local-infrastructure\n```\n\nIn your Booster config file, configure your `BoosterRocketFiles`:\n\n```typescript\nimport { Booster } from '@boostercloud/framework-core'\nimport { BoosterConfig } from '@boostercloud/framework-types'\nimport { BoosterRocketFiles } from '@boostercloud/rocket-file-uploads-core'\nimport { RocketFilesUserConfiguration } from '@boostercloud/rocket-file-uploads-types'\n\nconst rocketFilesConfigurationDefault: RocketFilesUserConfiguration = {\n  storageName: 'clientst',\n  containerName: 'rocketfiles',\n  directories: ['client1', 'client2'],\n}\n\nconst rocketFilesConfigurationCms: RocketFilesUserConfiguration = {\n  storageName: 'cmsst',\n  containerName: 'rocketfiles',\n  directories: ['cms1', 'cms2'],\n}\n\nconst APP_NAME = 'test'\n\n// Azure Config:\nBooster.configure('production', (config: BoosterConfig): void =\u003e {\n  config.appName = APP_NAME\n  config.providerPackage = '@boostercloud/framework-provider-azure'\n  config.rockets = [\n    new BoosterRocketFiles(config, [rocketFilesConfigurationDefault, rocketFilesConfigurationCms]).rocketForAzure(),\n  ]\n})\n\n// Local Config:\nBooster.configure('local', (config: BoosterConfig): void =\u003e {\n  config.appName = APP_NAME\n  config.providerPackage = '@boostercloud/framework-provider-local'\n  config.rockets = [\n    new BoosterRocketFiles(config, [rocketFilesConfigurationDefault, rocketFilesConfigurationCms]).rocketForLocal(),\n  ]\n})\n\n```\n\nAvailable parameters are:\n\n- `storageName`: Name of the storage repository.\n- `containerName`: Directories container.\n- `directories` A list of dirs to be watched, or [glob patterns](https://en.wikipedia.org/wiki/Glob_(programming))\n\n\u003e [!NOTE] Azure Provider will use `storageName` as the **Storage Account Name**. \n\u003e Local Provider will use it as the **root folder name**\n\nThe structure created for Azure and the Local Provider will be:\n\u003e    * storage\n\u003e        * container\n\u003e            * directory\n\n\u003e [!NOTE] Azure and Local provider urls are not equals. For Local you will need to use:\n\u003e http://localhost:3000/storageName/containerName/filename.ext but for Azure:\n\u003e http://storageAccountUrl:3000/containerName/filename.ext\n\n\n### PresignedPut Usage\n\n#### Azure \u0026  Local\n\nCreate a command in your application and call the `presignedPut` method on the FileHandler class with the `directory` and `filename` you want to upload on the storage.\n\nThe `storageName` parameter is optional. It will use the first storage if undefined.\n\n```typescript\nimport { Booster, Command } from '@boostercloud/framework-core'\nimport { Register } from '@boostercloud/framework-types'\nimport { FileHandler } from '@boostercloud/rocket-file-uploads-core'\n\n@Command({\n  authorize: 'all',\n})\nexport class FileUploadPut {\n  public constructor(readonly directory: string, readonly fileName: string, readonly storageName?: string) {}\n\n  public static async handle(command: FileUploadPut, register: Register): Promise\u003cstring\u003e {\n    const boosterConfig = Booster.config\n    const fileHandler = new FileHandler(boosterConfig, command.storageName)\n    return await fileHandler.presignedPut(command.directory, command.fileName)\n  }\n}\n```\n\nMutation example:\n\n```graphql\nmutation {\n  FileUploadPut(input: {\n    storageName: \"clientst\",\n    directory: \"client1\",\n    fileName: \"myfile.txt\"\n  }\n  )\n}\n```\n\nThis returns the following payload:\n\n```json\n{\n  \"data\": {\n    \"FileUploadPut\": \"https://clientst.blob.core.windows.net/rocketfiles/client1/myfile.txt?\u003cSAS\u003e\"\n  }\n}\n```\n\nNote: For Local Provider, the url will be simpler:\n\n```json\n{\n  \"data\": {\n    \"FileUploadPut\": \"http://localhost:3000/clientst/rocketfiles/client1/myfile.txt\"\n  }\n}\n```\n\nThat can be used in a new PUT rest call replacing the `AZ_URL` with the `FileUploadPut` field from the previous response:\n\n```shell\n#!/bin/bash\n\nDATE_NOW=$(date -Ru | sed 's/\\+0000/GMT/')\nAZ_VERSION=\"2020-02-10\"\nFILE_PATH=\"~/myfile.txt\"\nAZ_URL=\"\u003cFileUploadPut\u003e\"\n\ncurl -v -X PUT \\\n-H \"Content-Type: application/octet-stream\" \\\n-H \"x-ms-date: ${DATE_NOW}\" \\\n-H \"x-ms-version: ${AZ_VERSION}\" \\\n-H \"x-ms-blob-type: BlockBlob\" \\\n--data-binary @\"${FILE_PATH}\" \\\n\"${AZ_URL}\"\n```\n\nFor Local Provider, the request could be:\n\n```shell\n#!/bin/bash\n\nDATE_NOW=$(date -Ru | sed 's/\\+0000/GMT/')\nAZ_VERSION=\"2020-02-10\"\nFILE_PATH=\"~/myfile.txt\"\nAZ_URL=\"http://localhost:3000/rocketfiles/folder02/myfile.txt\"\n\ncurl -v -X PUT \\\n-H \"Content-Type: application/octet-stream\" \\\n-H \"x-ms-date: ${DATE_NOW}\" \\\n-H \"x-ms-version: ${AZ_VERSION}\" \\\n-H \"x-ms-blob-type: BlockBlob\" \\\n--data-binary @\"${FILE_PATH}\" \\\n\"${AZ_URL}\"\n```\n\nLocal Provider will write files on `.\u003cstorageName\u003e/rocketfiles` folder\n\n**Note**: Azure will return a 201 status but Local will return a 200\n\n### PresignedGet Usage\n\nCreate a command in your application and call the `presignedGet` method on the FileHandler class with the `directory` and `filename` you want to get on the storage.\n\nThe `storageName` parameter is optional. It will use the first storage if undefined.\n\n```typescript\nimport { Booster, Command } from '@boostercloud/framework-core'\nimport { Register } from '@boostercloud/framework-types'\nimport { FileHandler } from '@boostercloud/rocket-file-uploads-core'\n\n@Command({\n  authorize: 'all',\n})\nexport class FileUploadGet {\n  public constructor(readonly directory: string, readonly fileName: string, readonly storageName?: string) {}\n\n  public static async handle(command: FileUploadGet, register: Register): Promise\u003cstring\u003e {\n    const boosterConfig = Booster.config\n    const fileHandler = new FileHandler(boosterConfig, command.storageName)\n    return await fileHandler.presignedGet(command.directory, command.fileName)\n  }\n}\n```\n\nMutation example:\n\n```graphql\nmutation {\n  FileUploadGet(input: {\n    storageName: \"clientst\",\n    directory: \"client1\",\n    fileName: \"myfile.txt\"\n  }\n  )\n}\n```\n\nThis returns the following payload:\n\n```json\n{\n  \"data\": {\n    \"FileUploadGet\": \"https://clientst.blob.core.windows.net/rocketfiles/folder01%2Fmyfile.txt?\u003cSAS\u003e\"\n  }\n}\n```\n\nNOTE: For Local Provider, the url will be simpler:\n\n```json\n{\n  \"data\": {\n    \"FileUploadGet\": \"http://localhost:3000/clientst/rocketfiles/client1/myfile.txt\"\n  }\n}\n```\n\nThat can be used in a new GET rest call with the `FileUploadGet` field from the previous response:\n\n```shell\ncurl --request GET '\u003cFileUploadGet\u003e'\n```\n\n### List Usage\n\nCreate a command in your application and call the `list` method on the FileHandler class with the `directory` you want to get the info and return the formatted results.\n\nThe `storageName` parameter is optional. It will use the first storage if undefined.\n\n```typescript\nimport { Booster, Command } from '@boostercloud/framework-core'\nimport { Register } from '@boostercloud/framework-types'\nimport { FileHandler } from '@boostercloud/rocket-file-uploads-core'\nimport { ListItem } from '@boostercloud/rocket-file-uploads-types'\n\n@Command({\n  authorize: 'all',\n})\nexport class FileUploadList {\n  public constructor(readonly directory: string, readonly storageName?: string) {}\n\n  public static async handle(command: FileUploadList, register: Register): Promise\u003cArray\u003cListItem\u003e\u003e {\n    const boosterConfig = Booster.config\n    const fileHandler = new FileHandler(boosterConfig, command.storageName)\n    return await fileHandler.list(command.directory)\n  }\n}\n\n```\n\nMutation example:\n\n```graphql\nmutation {\n  FileUploadList(input: {\n    storageName: \"clientst\",\n    directory: \"client1\"\n  }\n  )\n}\n```\n\nThis returns the following payload in Azure:\n\n```json\n{\n  \"data\": {\n    \"FileUploadList\": [\n      {\n        \"name\": \"client1/myfile.txt\",\n        \"properties\": {\n          \"createdOn\": \"2022-10-26T05:40:47.000Z\",\n          \"lastModified\": \"2022-10-26T05:40:47.000Z\",\n          \"contentLength\": 6,\n          \"contentType\": \"text/plain\"\n        }\n      }\n    ]\n  }\n}\n```\n\nLocal Provider payload:\n\n```json\n{\n  \"data\": {\n    \"FileUploadList\": [\n      {\n        \"name\": \"client1/myfile.txt\",\n        \"properties\": {\n          \"lastModified\": \"2022-10-26T10:35:18.905Z\"\n        }\n      }\n    ]\n  }\n}\n```\n\n### Uploaded files event Usage\n\nCreate a Booster ReadModel to provide a view of the files uploaded to a directory\n\n```typescript\nimport { Projects, ReadModel } from '@boostercloud/framework-core'\nimport { ProjectionResult } from '@boostercloud/framework-types'\nimport { UploadedFileEntity } from '@boostercloud/rocket-file-uploads-types'\n\n@ReadModel({\n  authorize: 'all',\n})\nexport class UploadedFileEntityReadModel {\n  public constructor(public id: string, readonly metadata: unknown) {\n  }\n\n  @Projects(UploadedFileEntity, 'id')\n  public static projectUploadedFileEntity(\n    entity: UploadedFileEntity,\n    currentUploadedFileEntityReadModel?: UploadedFileEntityReadModel\n  ): ProjectionResult\u003cUploadedFileEntity\u003e {\n    return new UploadedFileEntityReadModel(entity.id, entity.metadata)\n  }\n}\n```\n\nMutation example:\n\n```graphql\nquery {\n  ListUploadedFileReadModels(filter: {}) {\n    items {\n      id\n      metadata\n    }\n  }\n}\n```\n\nThis returns the following payload:\n\n```json\n{\n  \"data\": {\n    \"ListUploadedFileReadModels\": {\n      \"items\": [\n        {\n          \"id\": \"f119ef635226888dd1bacd734f8955db\",\n      \"metadata\": {\n      \t\t// A bunch of fields (depending on Azure) \n        }\n      ],\n      \"count\": 1,\n      \"cursor\": {\n        \"id\": \"1\"\n      }\n    }\n  }\n}\n```\n\nFor Local\n\n```json\n{\n  \"data\": {\n    \"ListUploadedFileEntityReadModels\": {\n      \"items\": [\n        {\n          \"id\": \"xxx\",\n          \"metadata\": {\n            \"uri\": \"http://localhost:3000/clientst/rocketfiles/client1/myfile.txt\",\n            \"name\": \"client1/myfile.txt\"\n          }\n        }\n      ],\n      \"count\": 1,\n      \"cursor\": {\n        \"id\": \"1\"\n      }\n    }\n  }\n}\n```\n\n## Events\n\nFor each upload file a new event will be generated.\n\nOn Azure, the event will be like this:\n\n```json\n{\n  \"version\": 1,\n  \"kind\": \"snapshot\",\n  \"superKind\": \"domain\",\n  \"requestID\": \"xxx\",\n  \"entityID\": \"xxxx\",\n  \"entityTypeName\": \"UploadedFileEntity\",\n  \"typeName\": \"UploadedFileEntity\",\n  \"value\": {\n    \"id\": \"xxx\",\n    \"metadata\": {\n      // A bunch of fields (depending on Azure)\n    }\n  },\n  \"createdAt\": \"2022-10-26T10:23:36.562Z\",\n  \"snapshottedEventCreatedAt\": \"2022-10-26T10:23:32.34Z\",\n  \"entityTypeName_entityID_kind\": \"UploadedFileEntity-xxx-b842-x-8975-xx-snapshot\",\n  \"id\": \"x-x-x-x-x\",\n  \"_rid\": \"x==\",\n  \"_self\": \"dbs/x==/colls/x=/docs/x==/\",\n  \"_etag\": \"\\\"x-x-0500-0000-x\\\"\",\n  \"_attachments\": \"attachments/\",\n  \"_ts\": 123456\n}\n```\n\nOn Local, the event will be:\n\n```json\n{\n  \"version\": 1,\n  \"kind\": \"snapshot\",\n  \"superKind\": \"domain\",\n  \"requestID\": \"x\",\n  \"entityID\": \"x\",\n  \"entityTypeName\": \"UploadedFileEntity\",\n  \"typeName\": \"UploadedFileEntity\",\n  \"value\": {\n    \"id\": \"x\",\n    \"metadata\": {\n      \"uri\": \"http://localhost:3000/clientst/rocketfiles/client1/myfile.txt\",\n      \"name\": \"client1/myfile.txt\"\n    }\n  },\n  \"createdAt\": \"2022-10-26T10:35:18.967Z\",\n  \"snapshottedEventCreatedAt\": \"2022-10-26T10:35:18.958Z\",\n  \"_id\": \"lMolccTNJVojXiLz\"\n}\n```\n\n## Azure Roles\n\n\u003e [!NOTE] Starting at version 0.31.0 this Rocket use **Managed Identities** instead of **Connection Strings**. Please, \n\u003e check that you have the required permissions to assign roles https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal-managed-identity#prerequisites\n\nFor uploading files to Azure you need the `Storage Blob Data Contributor` role. This can be assigned to a user using the portal or with the next scripts:\n\nFirst, check if you have the correct permissions:\n\n```shell\nACCOUNT_NAME=\"\u003cSTORAGE ACCOUNT NAME\u003e\"\nCONTAINER_NAME=\"\u003cCONTAINER NAME\u003e\"\n\n# use this to test if you have the correct permissions\naz storage blob exists --account-name $ACCOUNT_NAME `\n                        --container-name $CONTAINER_NAME `\n                        --name blob1.txt --auth-mode login\n```\n\nIf you don't have it, then run this script as admin:\n\n```shell\nACCOUNT_NAME=\"\u003cSTORAGE ACCOUNT NAME\u003e\"\nCONTAINER_NAME=\"\u003cCONTAINER NAME\u003e\"\n\nOBJECT_ID=$(az ad user list --query \"[?mailNickname=='\u003cYOUR MAIL NICK NAME\u003e'].objectId\" -o tsv)\nSTORAGE_ID=$(az storage account show -n $ACCOUNT_NAME --query id -o tsv)\n\naz role assignment create \\\n    --role \"Storage Blob Data Contributor\" \\\n    --assignee $OBJECT_ID \\\n    --scope \"$STORAGE_ID/blobServices/default/containers/$CONTAINER_NAME\"\n```\n\n## Security\n\nLocal Provider doesn't check `paths`. You should check that the `directory` and `files` passed as paratemers are valid.\n\n### TODOs:\n- Optional storage deletion when unmounting the stack. \n- Optional events, in case you don't want to store that information in the events-store.\n- When deleting a file, save a deletion event in the events-store. Only uploads are stored at the moment.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboostercloud%2Frocket-file-uploads","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboostercloud%2Frocket-file-uploads","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboostercloud%2Frocket-file-uploads/lists"}