@fragno-dev/upload 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +16 -0
- package/README.md +43 -0
- package/bin/run.js +5 -0
- package/dist/browser/client/clients.js +49 -0
- package/dist/browser/client/clients.js.map +1 -0
- package/dist/browser/client/helpers.d.ts +51 -0
- package/dist/browser/client/helpers.d.ts.map +1 -0
- package/dist/browser/client/helpers.js +242 -0
- package/dist/browser/client/helpers.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/@nanostores_query@0.3.4_nanostores@1.1.0/node_modules/@nanostores/query/dist/nanoquery.js +354 -0
- package/dist/browser/client/node_modules/.pnpm/@nanostores_query@0.3.4_nanostores@1.1.0/node_modules/@nanostores/query/dist/nanoquery.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/@nanostores_solid@1.1.1_nanostores@1.1.0_solid-js@1.9.10/node_modules/@nanostores/solid/dist/index.js +14 -0
- package/dist/browser/client/node_modules/.pnpm/@nanostores_solid@1.1.1_nanostores@1.1.0_solid-js@1.9.10/node_modules/@nanostores/solid/dist/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanoevents@9.1.0/node_modules/nanoevents/index.js +17 -0
- package/dist/browser/client/node_modules/.pnpm/nanoevents@9.1.0/node_modules/nanoevents/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/atom/index.js +62 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/atom/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/clean-stores/index.js +6 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/clean-stores/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/computed/index.js +50 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/computed/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/lifecycle/index.js +99 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/lifecycle/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/listen-keys/index.js +11 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/listen-keys/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/map/index.js +25 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/map/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/task/index.js +24 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/task/index.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/definition.js +49 -0
- package/dist/browser/client/packages/fragment-upload/src/definition.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/keys.d.ts +7 -0
- package/dist/browser/client/packages/fragment-upload/src/keys.d.ts.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/keys.js +28 -0
- package/dist/browser/client/packages/fragment-upload/src/keys.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/files.js +98 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/files.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/index.js +9 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/index.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/shared.js +41 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/shared.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/uploads.js +186 -0
- package/dist/browser/client/packages/fragment-upload/src/routes/uploads.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/schema.js +8 -0
- package/dist/browser/client/packages/fragment-upload/src/schema.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/storage/types.d.ts +9 -0
- package/dist/browser/client/packages/fragment-upload/src/storage/types.d.ts.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/types.d.ts +31 -0
- package/dist/browser/client/packages/fragment-upload/src/types.d.ts.map +1 -0
- package/dist/browser/client/packages/fragno/dist/api/error.js +48 -0
- package/dist/browser/client/packages/fragno/dist/api/error.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/api/internal/path.js +76 -0
- package/dist/browser/client/packages/fragno/dist/api/internal/path.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/api/internal/response-stream.js +81 -0
- package/dist/browser/client/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/api/internal/route.js +10 -0
- package/dist/browser/client/packages/fragno/dist/api/internal/route.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/api/request-input-context.js +185 -0
- package/dist/browser/client/packages/fragno/dist/api/request-input-context.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/api/request-output-context.js +119 -0
- package/dist/browser/client/packages/fragno/dist/api/request-output-context.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/api/route.js +17 -0
- package/dist/browser/client/packages/fragno/dist/api/route.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/client-error.js +92 -0
- package/dist/browser/client/packages/fragno/dist/client/client-error.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/client.js +495 -0
- package/dist/browser/client/packages/fragno/dist/client/client.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/client.svelte.js +120 -0
- package/dist/browser/client/packages/fragno/dist/client/client.svelte.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/internal/fetcher-merge.js +36 -0
- package/dist/browser/client/packages/fragno/dist/client/internal/fetcher-merge.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/internal/ndjson-streaming.js +139 -0
- package/dist/browser/client/packages/fragno/dist/client/internal/ndjson-streaming.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/react.js +70 -0
- package/dist/browser/client/packages/fragno/dist/client/react.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/solid.js +108 -0
- package/dist/browser/client/packages/fragno/dist/client/solid.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/vanilla.js +96 -0
- package/dist/browser/client/packages/fragno/dist/client/vanilla.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/client/vue.js +120 -0
- package/dist/browser/client/packages/fragno/dist/client/vue.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/util/async.js +40 -0
- package/dist/browser/client/packages/fragno/dist/util/async.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/util/content-type.js +49 -0
- package/dist/browser/client/packages/fragno/dist/util/content-type.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/util/nanostores.js +31 -0
- package/dist/browser/client/packages/fragno/dist/util/nanostores.js.map +1 -0
- package/dist/browser/client/packages/fragno/dist/util/ssr.js +18 -0
- package/dist/browser/client/packages/fragno/dist/util/ssr.js.map +1 -0
- package/dist/browser/client/react.d.ts +295 -0
- package/dist/browser/client/react.d.ts.map +1 -0
- package/dist/browser/client/react.js +11 -0
- package/dist/browser/client/react.js.map +1 -0
- package/dist/browser/client/solid.d.ts +303 -0
- package/dist/browser/client/solid.d.ts.map +1 -0
- package/dist/browser/client/solid.js +11 -0
- package/dist/browser/client/solid.js.map +1 -0
- package/dist/browser/client/svelte.d.ts +295 -0
- package/dist/browser/client/svelte.d.ts.map +1 -0
- package/dist/browser/client/svelte.js +11 -0
- package/dist/browser/client/svelte.js.map +1 -0
- package/dist/browser/client/vanilla.d.ts +296 -0
- package/dist/browser/client/vanilla.d.ts.map +1 -0
- package/dist/browser/client/vanilla.js +11 -0
- package/dist/browser/client/vanilla.js.map +1 -0
- package/dist/browser/client/vue.d.ts +295 -0
- package/dist/browser/client/vue.d.ts.map +1 -0
- package/dist/browser/client/vue.js +11 -0
- package/dist/browser/client/vue.js.map +1 -0
- package/dist/browser/index-BdjKPO4J.d.ts +177 -0
- package/dist/browser/index-BdjKPO4J.d.ts.map +1 -0
- package/dist/browser/index.js +3 -0
- package/dist/browser/src-vdNJUbjT.js +1982 -0
- package/dist/browser/src-vdNJUbjT.js.map +1 -0
- package/dist/cli/commands/files/delete.d.ts +40 -0
- package/dist/cli/commands/files/delete.d.ts.map +1 -0
- package/dist/cli/commands/files/delete.js +31 -0
- package/dist/cli/commands/files/delete.js.map +1 -0
- package/dist/cli/commands/files/download-url.d.ts +40 -0
- package/dist/cli/commands/files/download-url.d.ts.map +1 -0
- package/dist/cli/commands/files/download-url.js +31 -0
- package/dist/cli/commands/files/download-url.js.map +1 -0
- package/dist/cli/commands/files/download.d.ts +49 -0
- package/dist/cli/commands/files/download.d.ts.map +1 -0
- package/dist/cli/commands/files/download.js +65 -0
- package/dist/cli/commands/files/download.js.map +1 -0
- package/dist/cli/commands/files/get.d.ts +40 -0
- package/dist/cli/commands/files/get.d.ts.map +1 -0
- package/dist/cli/commands/files/get.js +31 -0
- package/dist/cli/commands/files/get.js.map +1 -0
- package/dist/cli/commands/files/list.d.ts +56 -0
- package/dist/cli/commands/files/list.d.ts.map +1 -0
- package/dist/cli/commands/files/list.js +53 -0
- package/dist/cli/commands/files/list.js.map +1 -0
- package/dist/cli/commands/files/update.d.ts +56 -0
- package/dist/cli/commands/files/update.d.ts.map +1 -0
- package/dist/cli/commands/files/update.js +53 -0
- package/dist/cli/commands/files/update.js.map +1 -0
- package/dist/cli/commands/files/upload.d.ts +73 -0
- package/dist/cli/commands/files/upload.d.ts.map +1 -0
- package/dist/cli/commands/files/upload.js +87 -0
- package/dist/cli/commands/files/upload.js.map +1 -0
- package/dist/cli/commands/uploads/abort.d.ts +37 -0
- package/dist/cli/commands/uploads/abort.d.ts.map +1 -0
- package/dist/cli/commands/uploads/abort.js +26 -0
- package/dist/cli/commands/uploads/abort.js.map +1 -0
- package/dist/cli/commands/uploads/complete.d.ts +41 -0
- package/dist/cli/commands/uploads/complete.d.ts.map +1 -0
- package/dist/cli/commands/uploads/complete.js +45 -0
- package/dist/cli/commands/uploads/complete.js.map +1 -0
- package/dist/cli/commands/uploads/content.d.ts +46 -0
- package/dist/cli/commands/uploads/content.d.ts.map +1 -0
- package/dist/cli/commands/uploads/content.js +43 -0
- package/dist/cli/commands/uploads/content.js.map +1 -0
- package/dist/cli/commands/uploads/create.d.ts +72 -0
- package/dist/cli/commands/uploads/create.d.ts.map +1 -0
- package/dist/cli/commands/uploads/create.js +84 -0
- package/dist/cli/commands/uploads/create.js.map +1 -0
- package/dist/cli/commands/uploads/get.d.ts +37 -0
- package/dist/cli/commands/uploads/get.d.ts.map +1 -0
- package/dist/cli/commands/uploads/get.js +26 -0
- package/dist/cli/commands/uploads/get.js.map +1 -0
- package/dist/cli/commands/uploads/parts-complete.d.ts +41 -0
- package/dist/cli/commands/uploads/parts-complete.d.ts.map +1 -0
- package/dist/cli/commands/uploads/parts-complete.js +44 -0
- package/dist/cli/commands/uploads/parts-complete.js.map +1 -0
- package/dist/cli/commands/uploads/parts-list.d.ts +37 -0
- package/dist/cli/commands/uploads/parts-list.d.ts.map +1 -0
- package/dist/cli/commands/uploads/parts-list.js +26 -0
- package/dist/cli/commands/uploads/parts-list.js.map +1 -0
- package/dist/cli/commands/uploads/parts-urls.d.ts +46 -0
- package/dist/cli/commands/uploads/parts-urls.d.ts.map +1 -0
- package/dist/cli/commands/uploads/parts-urls.js +57 -0
- package/dist/cli/commands/uploads/parts-urls.js.map +1 -0
- package/dist/cli/commands/uploads/progress.d.ts +45 -0
- package/dist/cli/commands/uploads/progress.d.ts.map +1 -0
- package/dist/cli/commands/uploads/progress.js +40 -0
- package/dist/cli/commands/uploads/progress.js.map +1 -0
- package/dist/cli/commands/uploads/transfer.d.ts +73 -0
- package/dist/cli/commands/uploads/transfer.d.ts.map +1 -0
- package/dist/cli/commands/uploads/transfer.js +170 -0
- package/dist/cli/commands/uploads/transfer.js.map +1 -0
- package/dist/cli/index.d.ts +27 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +198 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/keys.js +32 -0
- package/dist/cli/keys.js.map +1 -0
- package/dist/cli/utils/client.js +174 -0
- package/dist/cli/utils/client.js.map +1 -0
- package/dist/cli/utils/options.js +135 -0
- package/dist/cli/utils/options.js.map +1 -0
- package/dist/node/cli/commands/files/delete.d.ts +40 -0
- package/dist/node/cli/commands/files/delete.d.ts.map +1 -0
- package/dist/node/cli/commands/files/delete.js +31 -0
- package/dist/node/cli/commands/files/delete.js.map +1 -0
- package/dist/node/cli/commands/files/download-url.d.ts +40 -0
- package/dist/node/cli/commands/files/download-url.d.ts.map +1 -0
- package/dist/node/cli/commands/files/download-url.js +31 -0
- package/dist/node/cli/commands/files/download-url.js.map +1 -0
- package/dist/node/cli/commands/files/download.d.ts +49 -0
- package/dist/node/cli/commands/files/download.d.ts.map +1 -0
- package/dist/node/cli/commands/files/download.js +65 -0
- package/dist/node/cli/commands/files/download.js.map +1 -0
- package/dist/node/cli/commands/files/get.d.ts +40 -0
- package/dist/node/cli/commands/files/get.d.ts.map +1 -0
- package/dist/node/cli/commands/files/get.js +31 -0
- package/dist/node/cli/commands/files/get.js.map +1 -0
- package/dist/node/cli/commands/files/list.d.ts +56 -0
- package/dist/node/cli/commands/files/list.d.ts.map +1 -0
- package/dist/node/cli/commands/files/list.js +53 -0
- package/dist/node/cli/commands/files/list.js.map +1 -0
- package/dist/node/cli/commands/files/update.d.ts +56 -0
- package/dist/node/cli/commands/files/update.d.ts.map +1 -0
- package/dist/node/cli/commands/files/update.js +53 -0
- package/dist/node/cli/commands/files/update.js.map +1 -0
- package/dist/node/cli/commands/files/upload.d.ts +73 -0
- package/dist/node/cli/commands/files/upload.d.ts.map +1 -0
- package/dist/node/cli/commands/files/upload.js +87 -0
- package/dist/node/cli/commands/files/upload.js.map +1 -0
- package/dist/node/cli/commands/uploads/abort.d.ts +37 -0
- package/dist/node/cli/commands/uploads/abort.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/abort.js +26 -0
- package/dist/node/cli/commands/uploads/abort.js.map +1 -0
- package/dist/node/cli/commands/uploads/complete.d.ts +41 -0
- package/dist/node/cli/commands/uploads/complete.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/complete.js +45 -0
- package/dist/node/cli/commands/uploads/complete.js.map +1 -0
- package/dist/node/cli/commands/uploads/content.d.ts +46 -0
- package/dist/node/cli/commands/uploads/content.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/content.js +43 -0
- package/dist/node/cli/commands/uploads/content.js.map +1 -0
- package/dist/node/cli/commands/uploads/create.d.ts +72 -0
- package/dist/node/cli/commands/uploads/create.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/create.js +84 -0
- package/dist/node/cli/commands/uploads/create.js.map +1 -0
- package/dist/node/cli/commands/uploads/get.d.ts +37 -0
- package/dist/node/cli/commands/uploads/get.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/get.js +26 -0
- package/dist/node/cli/commands/uploads/get.js.map +1 -0
- package/dist/node/cli/commands/uploads/parts-complete.d.ts +41 -0
- package/dist/node/cli/commands/uploads/parts-complete.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/parts-complete.js +44 -0
- package/dist/node/cli/commands/uploads/parts-complete.js.map +1 -0
- package/dist/node/cli/commands/uploads/parts-list.d.ts +37 -0
- package/dist/node/cli/commands/uploads/parts-list.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/parts-list.js +26 -0
- package/dist/node/cli/commands/uploads/parts-list.js.map +1 -0
- package/dist/node/cli/commands/uploads/parts-urls.d.ts +46 -0
- package/dist/node/cli/commands/uploads/parts-urls.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/parts-urls.js +57 -0
- package/dist/node/cli/commands/uploads/parts-urls.js.map +1 -0
- package/dist/node/cli/commands/uploads/progress.d.ts +45 -0
- package/dist/node/cli/commands/uploads/progress.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/progress.js +40 -0
- package/dist/node/cli/commands/uploads/progress.js.map +1 -0
- package/dist/node/cli/commands/uploads/transfer.d.ts +73 -0
- package/dist/node/cli/commands/uploads/transfer.d.ts.map +1 -0
- package/dist/node/cli/commands/uploads/transfer.js +170 -0
- package/dist/node/cli/commands/uploads/transfer.js.map +1 -0
- package/dist/node/cli/index.d.ts +27 -0
- package/dist/node/cli/index.d.ts.map +1 -0
- package/dist/node/cli/index.js +198 -0
- package/dist/node/cli/index.js.map +1 -0
- package/dist/node/cli/utils/client.js +174 -0
- package/dist/node/cli/utils/client.js.map +1 -0
- package/dist/node/cli/utils/options.js +135 -0
- package/dist/node/cli/utils/options.js.map +1 -0
- package/dist/node/client/clients.d.ts +295 -0
- package/dist/node/client/clients.d.ts.map +1 -0
- package/dist/node/client/clients.js +49 -0
- package/dist/node/client/clients.js.map +1 -0
- package/dist/node/client/helpers.d.ts +51 -0
- package/dist/node/client/helpers.d.ts.map +1 -0
- package/dist/node/client/helpers.js +242 -0
- package/dist/node/client/helpers.js.map +1 -0
- package/dist/node/client/react.d.ts +295 -0
- package/dist/node/client/react.d.ts.map +1 -0
- package/dist/node/client/react.js +11 -0
- package/dist/node/client/react.js.map +1 -0
- package/dist/node/client/solid.d.ts +303 -0
- package/dist/node/client/solid.d.ts.map +1 -0
- package/dist/node/client/solid.js +11 -0
- package/dist/node/client/solid.js.map +1 -0
- package/dist/node/client/svelte.d.ts +295 -0
- package/dist/node/client/svelte.d.ts.map +1 -0
- package/dist/node/client/svelte.js +11 -0
- package/dist/node/client/svelte.js.map +1 -0
- package/dist/node/client/vanilla.d.ts +296 -0
- package/dist/node/client/vanilla.d.ts.map +1 -0
- package/dist/node/client/vanilla.js +11 -0
- package/dist/node/client/vanilla.js.map +1 -0
- package/dist/node/client/vue.d.ts +295 -0
- package/dist/node/client/vue.d.ts.map +1 -0
- package/dist/node/client/vue.js +11 -0
- package/dist/node/client/vue.js.map +1 -0
- package/dist/node/config.d.ts +41 -0
- package/dist/node/config.d.ts.map +1 -0
- package/dist/node/config.js +26 -0
- package/dist/node/config.js.map +1 -0
- package/dist/node/definition.d.ts +829 -0
- package/dist/node/definition.d.ts.map +1 -0
- package/dist/node/definition.js +59 -0
- package/dist/node/definition.js.map +1 -0
- package/dist/node/index.d.ts +1246 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +19 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/keys.d.ts +12 -0
- package/dist/node/keys.d.ts.map +1 -0
- package/dist/node/keys.js +63 -0
- package/dist/node/keys.js.map +1 -0
- package/dist/node/routes/files.js +450 -0
- package/dist/node/routes/files.js.map +1 -0
- package/dist/node/routes/index.d.ts +2023 -0
- package/dist/node/routes/index.d.ts.map +1 -0
- package/dist/node/routes/index.js +9 -0
- package/dist/node/routes/index.js.map +1 -0
- package/dist/node/routes/shared.js +66 -0
- package/dist/node/routes/shared.js.map +1 -0
- package/dist/node/routes/uploads.js +454 -0
- package/dist/node/routes/uploads.js.map +1 -0
- package/dist/node/schema.d.ts +14 -0
- package/dist/node/schema.d.ts.map +1 -0
- package/dist/node/schema.js +30 -0
- package/dist/node/schema.js.map +1 -0
- package/dist/node/services/files.d.ts +20 -0
- package/dist/node/services/files.d.ts.map +1 -0
- package/dist/node/services/files.js +93 -0
- package/dist/node/services/files.js.map +1 -0
- package/dist/node/services/helpers.js +36 -0
- package/dist/node/services/helpers.js.map +1 -0
- package/dist/node/services/index.js +4 -0
- package/dist/node/services/uploads.d.ts +50 -0
- package/dist/node/services/uploads.d.ts.map +1 -0
- package/dist/node/services/uploads.js +358 -0
- package/dist/node/services/uploads.js.map +1 -0
- package/dist/node/storage/fs.d.ts +16 -0
- package/dist/node/storage/fs.d.ts.map +1 -0
- package/dist/node/storage/fs.js +94 -0
- package/dist/node/storage/fs.js.map +1 -0
- package/dist/node/storage/r2.d.ts +103 -0
- package/dist/node/storage/r2.d.ts.map +1 -0
- package/dist/node/storage/r2.js +23 -0
- package/dist/node/storage/r2.js.map +1 -0
- package/dist/node/storage/s3.d.ts +44 -0
- package/dist/node/storage/s3.d.ts.map +1 -0
- package/dist/node/storage/s3.js +398 -0
- package/dist/node/storage/s3.js.map +1 -0
- package/dist/node/storage/types.d.ts +118 -0
- package/dist/node/storage/types.d.ts.map +1 -0
- package/dist/node/types.d.ts +32 -0
- package/dist/node/types.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +105 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;iBA0CgB,oBAAA,SACN,+BACC,mDAA8B,uDAAA,2CAAA;mEAAA,IAAA,CAAA,SAAA;;;;;;;;;IAFzB,CAAA,CAAA;IAAoB,KAAA,gBAAA;yBAC1B,CAAA,CAAA,CAAA;MACC,kBAAA,cAAA,gBAAA,CAAA;YAA8B,kBAAA,aAAA,CAAA;;;;;;;;YAAA,IAAA,CAAA;;;;;;;;;;;;;;;;;;;;;aAAA,kBAAA,gBAAA;IAAA,aAAA,kBAAA,eAAA,gCAAA,CAAA;;;;;;;;;;;;sEAAA,sBAAA,CAAA;;;;;;;;;;;;;;;;;;;iCAAA,gBAAA;WAAA,cAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAH;;;;;;;;sBAW/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAX+B,QAAA,EAAA,MAAA;;IAW/B,WAAA,EAAA,MAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { resolveUploadFragmentConfig } from "./config.js";
|
|
2
|
+
import { uploadSchema } from "./schema.js";
|
|
3
|
+
import { decodeFileKey, encodeFileKey, encodeFileKeyPrefix } from "./keys.js";
|
|
4
|
+
import { uploadFragmentDefinition } from "./definition.js";
|
|
5
|
+
import { uploadRoutes } from "./routes/index.js";
|
|
6
|
+
import { createUploadFragmentClients } from "./client/clients.js";
|
|
7
|
+
import { createFilesystemStorageAdapter } from "./storage/fs.js";
|
|
8
|
+
import { createS3CompatibleStorageAdapter } from "./storage/s3.js";
|
|
9
|
+
import { createR2StorageAdapter } from "./storage/r2.js";
|
|
10
|
+
import { instantiate } from "@fragno-dev/core";
|
|
11
|
+
|
|
12
|
+
//#region src/index.ts
|
|
13
|
+
function createUploadFragment(config, options) {
|
|
14
|
+
return instantiate(uploadFragmentDefinition).withConfig(config).withRoutes(uploadRoutes).withOptions(options).build();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { createFilesystemStorageAdapter, createR2StorageAdapter, createS3CompatibleStorageAdapter, createUploadFragment, createUploadFragmentClients, decodeFileKey, encodeFileKey, encodeFileKeyPrefix, resolveUploadFragmentConfig, uploadFragmentDefinition, uploadRoutes, uploadSchema };
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import type { FragnoPublicConfigWithDatabase } from \"@fragno-dev/db\";\nimport { instantiate } from \"@fragno-dev/core\";\nimport { uploadFragmentDefinition } from \"./definition\";\nimport type { UploadFragmentConfig } from \"./config\";\nimport { uploadRoutes } from \"./routes\";\nimport { createUploadFragmentClients } from \"./client/clients\";\n\nexport type {\n FileHookPayload,\n UploadFragmentConfig,\n UploadFragmentResolvedConfig,\n UploadTimeoutPayload,\n} from \"./config\";\nexport { resolveUploadFragmentConfig } from \"./config\";\nexport { uploadSchema } from \"./schema\";\nexport type { FileKeyEncoded, FileKeyPart, FileKeyParts } from \"./keys\";\nexport { decodeFileKey, encodeFileKey, encodeFileKeyPrefix } from \"./keys\";\nexport type {\n StorageAdapter,\n StorageAdapterCapabilities,\n StorageAdapterLimits,\n StorageAdapterRecommendations,\n UploadChecksum,\n UploadMode,\n UploadTransport,\n} from \"./storage/types\";\nexport { createFilesystemStorageAdapter, type FilesystemStorageAdapterOptions } from \"./storage/fs\";\nexport {\n createS3CompatibleStorageAdapter,\n type S3CompatibleStorageAdapterOptions,\n type S3Signer,\n type S3SignerInput,\n} from \"./storage/s3\";\nexport { createR2StorageAdapter, type R2StorageAdapterOptions } from \"./storage/r2\";\nexport type {\n CreateUploadAndTransferOptions,\n UploadHelpers,\n UploadProgress,\n} from \"./client/helpers\";\n\nexport { uploadRoutes };\n\nexport function createUploadFragment(\n config: UploadFragmentConfig,\n options: FragnoPublicConfigWithDatabase,\n) {\n return instantiate(uploadFragmentDefinition)\n .withConfig(config)\n .withRoutes(uploadRoutes)\n .withOptions(options)\n .build();\n}\nexport { createUploadFragmentClients };\n\nexport { uploadFragmentDefinition } from \"./definition\";\n"],"mappings":";;;;;;;;;;;;AA0CA,SAAgB,qBACd,QACA,SACA;AACA,QAAO,YAAY,yBAAyB,CACzC,WAAW,OAAO,CAClB,WAAW,aAAa,CACxB,YAAY,QAAQ,CACpB,OAAO"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/keys.d.ts
|
|
2
|
+
type FileKeyPart = string | number;
|
|
3
|
+
type FileKeyParts = readonly FileKeyPart[];
|
|
4
|
+
type FileKeyEncoded = string;
|
|
5
|
+
declare function encodeFileKey(parts: FileKeyParts): FileKeyEncoded;
|
|
6
|
+
declare function decodeFileKey(key: FileKeyEncoded): FileKeyParts;
|
|
7
|
+
declare function encodeFileKeyPrefix(parts: FileKeyParts): string;
|
|
8
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { FileKeyEncoded, FileKeyPart, FileKeyParts, decodeFileKey, encodeFileKey, encodeFileKeyPrefix };
|
|
12
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","names":[],"sources":["../../src/keys.ts"],"sourcesContent":[],"mappings":";KAAY,WAAA;AAAA,KACA,YAAA,GADW,SACa,WADb,EAAA;AACX,KACA,cAAA,GADY,MAAY;AACxB,iBAgGI,aAAA,CAhGU,KAAA,EAgGW,YAhGX,CAAA,EAgG0B,cAhG1B;AAgGV,iBAQA,aAAA,CARa,GAAA,EAQM,cARN,CAAA,EAQuB,YARvB;AAAA,iBA+Bb,mBAAA,CA/Ba,KAAA,EA+Bc,YA/Bd,CAAA,EAAA,MAAA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region src/keys.ts
|
|
2
|
+
const base64UrlPattern = /^[A-Za-z0-9_-]*$/;
|
|
3
|
+
function base64UrlEncode(value) {
|
|
4
|
+
const bytes = new TextEncoder().encode(value);
|
|
5
|
+
if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
6
|
+
const encoder = globalThis.btoa;
|
|
7
|
+
if (!encoder) throw new Error("Base64 encoding is not available");
|
|
8
|
+
let binary = "";
|
|
9
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
10
|
+
return encoder(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
11
|
+
}
|
|
12
|
+
function base64UrlDecode(value) {
|
|
13
|
+
if (!base64UrlPattern.test(value)) throw new Error("Invalid base64url value");
|
|
14
|
+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
15
|
+
const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
|
|
16
|
+
if (typeof Buffer !== "undefined") return new TextDecoder().decode(Buffer.from(padded, "base64"));
|
|
17
|
+
const decoder = globalThis.atob;
|
|
18
|
+
if (!decoder) throw new Error("Base64 decoding is not available");
|
|
19
|
+
const binary = decoder(padded);
|
|
20
|
+
const bytes = new Uint8Array(binary.length);
|
|
21
|
+
for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);
|
|
22
|
+
return new TextDecoder().decode(bytes);
|
|
23
|
+
}
|
|
24
|
+
function encodePart(part) {
|
|
25
|
+
if (typeof part === "string") return `s~${base64UrlEncode(part)}`;
|
|
26
|
+
if (typeof part === "number") {
|
|
27
|
+
if (!Number.isFinite(part)) throw new Error("File key number parts must be finite");
|
|
28
|
+
const serialized = String(part);
|
|
29
|
+
if (serialized.includes(".") || serialized.includes("e") || serialized.includes("E")) throw new Error("File key number parts must be integers");
|
|
30
|
+
return `n~${serialized}`;
|
|
31
|
+
}
|
|
32
|
+
throw new Error("File key parts must be strings or numbers");
|
|
33
|
+
}
|
|
34
|
+
function decodeNumberPart(raw) {
|
|
35
|
+
if (raw.length === 0) throw new Error("Invalid number part");
|
|
36
|
+
if (raw.includes(".") || raw.includes("e") || raw.includes("E")) throw new Error("Invalid number part");
|
|
37
|
+
const value = Number(raw);
|
|
38
|
+
if (!Number.isFinite(value)) throw new Error("Invalid number part");
|
|
39
|
+
if (String(value) !== raw) throw new Error("Invalid number part");
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
function encodeFileKey(parts) {
|
|
43
|
+
if (parts.length === 0) return "";
|
|
44
|
+
return parts.map((part) => encodePart(part)).join(".");
|
|
45
|
+
}
|
|
46
|
+
function decodeFileKey(key) {
|
|
47
|
+
if (key.length === 0) return [];
|
|
48
|
+
return key.split(".").map((segment) => {
|
|
49
|
+
const prefix = segment.slice(0, 2);
|
|
50
|
+
const payload = segment.slice(2);
|
|
51
|
+
if (prefix === "s~") return base64UrlDecode(payload);
|
|
52
|
+
if (prefix === "n~") return decodeNumberPart(payload);
|
|
53
|
+
throw new Error("Invalid file key segment");
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function encodeFileKeyPrefix(parts) {
|
|
57
|
+
if (parts.length === 0) return "";
|
|
58
|
+
return `${encodeFileKey(parts)}.`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { decodeFileKey, encodeFileKey, encodeFileKeyPrefix };
|
|
63
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","names":[],"sources":["../../src/keys.ts"],"sourcesContent":["export type FileKeyPart = string | number;\nexport type FileKeyParts = readonly FileKeyPart[];\nexport type FileKeyEncoded = string;\n\nconst base64UrlPattern = /^[A-Za-z0-9_-]*$/;\n\nfunction base64UrlEncode(value: string): string {\n const bytes = new TextEncoder().encode(value);\n\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes)\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n }\n\n const encoder = (globalThis as { btoa?: (value: string) => string }).btoa;\n if (!encoder) {\n throw new Error(\"Base64 encoding is not available\");\n }\n\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return encoder(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n}\n\nfunction base64UrlDecode(value: string): string {\n if (!base64UrlPattern.test(value)) {\n throw new Error(\"Invalid base64url value\");\n }\n\n const base64 = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = base64 + \"=\".repeat((4 - (base64.length % 4)) % 4);\n\n if (typeof Buffer !== \"undefined\") {\n return new TextDecoder().decode(Buffer.from(padded, \"base64\"));\n }\n\n const decoder = (globalThis as { atob?: (value: string) => string }).atob;\n if (!decoder) {\n throw new Error(\"Base64 decoding is not available\");\n }\n\n const binary = decoder(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) {\n bytes[i] = binary.charCodeAt(i);\n }\n\n return new TextDecoder().decode(bytes);\n}\n\nfunction encodePart(part: FileKeyPart): string {\n if (typeof part === \"string\") {\n return `s~${base64UrlEncode(part)}`;\n }\n\n if (typeof part === \"number\") {\n if (!Number.isFinite(part)) {\n throw new Error(\"File key number parts must be finite\");\n }\n\n const serialized = String(part);\n if (serialized.includes(\".\") || serialized.includes(\"e\") || serialized.includes(\"E\")) {\n throw new Error(\"File key number parts must be integers\");\n }\n\n return `n~${serialized}`;\n }\n\n throw new Error(\"File key parts must be strings or numbers\");\n}\n\nfunction decodeNumberPart(raw: string): number {\n if (raw.length === 0) {\n throw new Error(\"Invalid number part\");\n }\n\n if (raw.includes(\".\") || raw.includes(\"e\") || raw.includes(\"E\")) {\n throw new Error(\"Invalid number part\");\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n throw new Error(\"Invalid number part\");\n }\n\n if (String(value) !== raw) {\n throw new Error(\"Invalid number part\");\n }\n\n return value;\n}\n\nexport function encodeFileKey(parts: FileKeyParts): FileKeyEncoded {\n if (parts.length === 0) {\n return \"\";\n }\n\n return parts.map((part) => encodePart(part)).join(\".\");\n}\n\nexport function decodeFileKey(key: FileKeyEncoded): FileKeyParts {\n if (key.length === 0) {\n return [];\n }\n\n const segments = key.split(\".\");\n\n return segments.map((segment) => {\n const prefix = segment.slice(0, 2);\n const payload = segment.slice(2);\n\n if (prefix === \"s~\") {\n return base64UrlDecode(payload);\n }\n\n if (prefix === \"n~\") {\n return decodeNumberPart(payload);\n }\n\n throw new Error(\"Invalid file key segment\");\n });\n}\n\nexport function encodeFileKeyPrefix(parts: FileKeyParts): string {\n if (parts.length === 0) {\n return \"\";\n }\n\n return `${encodeFileKey(parts)}.`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { resolveUploadFragmentConfig } from "../config.js";
|
|
2
|
+
import { resolveFileKeyInput } from "../services/helpers.js";
|
|
3
|
+
import { uploadFragmentDefinition } from "../definition.js";
|
|
4
|
+
import { checksumSchema, fileKeyPartsSchema, fileMetadataSchema, toFileMetadata, visibilitySchema } from "./shared.js";
|
|
5
|
+
import { defineRoutes } from "@fragno-dev/core";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
//#region src/routes/files.ts
|
|
9
|
+
const listQuerySchema = z.object({
|
|
10
|
+
prefix: z.string().optional(),
|
|
11
|
+
cursor: z.string().optional(),
|
|
12
|
+
pageSize: z.coerce.number().min(1).max(100).catch(25),
|
|
13
|
+
status: z.enum(["ready", "deleted"]).optional(),
|
|
14
|
+
uploaderId: z.string().optional()
|
|
15
|
+
});
|
|
16
|
+
const updateFileSchema = z.object({
|
|
17
|
+
filename: z.string().min(1).optional(),
|
|
18
|
+
visibility: visibilitySchema.optional(),
|
|
19
|
+
tags: z.array(z.string()).nullable().optional(),
|
|
20
|
+
metadata: z.record(z.string(), z.unknown()).nullable().optional()
|
|
21
|
+
});
|
|
22
|
+
const errorCodes = [
|
|
23
|
+
"UPLOAD_NOT_FOUND",
|
|
24
|
+
"UPLOAD_ALREADY_ACTIVE",
|
|
25
|
+
"FILE_ALREADY_EXISTS",
|
|
26
|
+
"FILE_NOT_FOUND",
|
|
27
|
+
"UPLOAD_EXPIRED",
|
|
28
|
+
"UPLOAD_INVALID_STATE",
|
|
29
|
+
"SIGNED_URL_UNSUPPORTED",
|
|
30
|
+
"STORAGE_ERROR",
|
|
31
|
+
"INVALID_FILE_KEY",
|
|
32
|
+
"INVALID_CHECKSUM",
|
|
33
|
+
"INVALID_REQUEST"
|
|
34
|
+
];
|
|
35
|
+
const handleServiceError = (err, error) => {
|
|
36
|
+
if (!(err instanceof Error)) throw err;
|
|
37
|
+
switch (err.message) {
|
|
38
|
+
case "FILE_NOT_FOUND": return error({
|
|
39
|
+
message: "File not found",
|
|
40
|
+
code: "FILE_NOT_FOUND"
|
|
41
|
+
}, 404);
|
|
42
|
+
case "UPLOAD_NOT_FOUND": return error({
|
|
43
|
+
message: "Upload not found",
|
|
44
|
+
code: "UPLOAD_NOT_FOUND"
|
|
45
|
+
}, 404);
|
|
46
|
+
case "FILE_ALREADY_EXISTS": return error({
|
|
47
|
+
message: "File already exists",
|
|
48
|
+
code: "FILE_ALREADY_EXISTS"
|
|
49
|
+
}, 409);
|
|
50
|
+
case "UPLOAD_ALREADY_ACTIVE": return error({
|
|
51
|
+
message: "Upload already active",
|
|
52
|
+
code: "UPLOAD_ALREADY_ACTIVE"
|
|
53
|
+
}, 409);
|
|
54
|
+
case "UPLOAD_EXPIRED": return error({
|
|
55
|
+
message: "Upload expired",
|
|
56
|
+
code: "UPLOAD_EXPIRED"
|
|
57
|
+
}, 410);
|
|
58
|
+
case "UPLOAD_INVALID_STATE": return error({
|
|
59
|
+
message: "Upload invalid state",
|
|
60
|
+
code: "UPLOAD_INVALID_STATE"
|
|
61
|
+
}, 409);
|
|
62
|
+
case "INVALID_FILE_KEY": return error({
|
|
63
|
+
message: "Invalid file key",
|
|
64
|
+
code: "INVALID_FILE_KEY"
|
|
65
|
+
}, 400);
|
|
66
|
+
case "INVALID_CHECKSUM": return error({
|
|
67
|
+
message: "Invalid checksum",
|
|
68
|
+
code: "INVALID_CHECKSUM"
|
|
69
|
+
}, 400);
|
|
70
|
+
case "INVALID_REQUEST": return error({
|
|
71
|
+
message: "Invalid request",
|
|
72
|
+
code: "INVALID_REQUEST"
|
|
73
|
+
}, 400);
|
|
74
|
+
default: throw err;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const parseJson = (value) => {
|
|
78
|
+
if (value === null || typeof value !== "string" || value.length === 0) return;
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(value);
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const parseTags = (value) => {
|
|
86
|
+
if (value === null) return;
|
|
87
|
+
if (typeof value !== "string") return;
|
|
88
|
+
const parsed = parseJson(value);
|
|
89
|
+
if (Array.isArray(parsed)) return parsed.filter((tag) => typeof tag === "string");
|
|
90
|
+
if (typeof value === "string" && value.length > 0) return [value];
|
|
91
|
+
};
|
|
92
|
+
const parseMetadata = (value) => {
|
|
93
|
+
const parsed = parseJson(value);
|
|
94
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
95
|
+
};
|
|
96
|
+
const fileRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ services, defineRoute, config }) => {
|
|
97
|
+
const getResolvedConfig = () => resolveUploadFragmentConfig(config);
|
|
98
|
+
const parseListQuery = (query) => {
|
|
99
|
+
const result = listQuerySchema.safeParse({
|
|
100
|
+
prefix: query.get("prefix") || void 0,
|
|
101
|
+
cursor: query.get("cursor") || void 0,
|
|
102
|
+
pageSize: query.get("pageSize"),
|
|
103
|
+
status: query.get("status") || void 0,
|
|
104
|
+
uploaderId: query.get("uploaderId") || void 0
|
|
105
|
+
});
|
|
106
|
+
if (!result.success) throw new Error("INVALID_REQUEST");
|
|
107
|
+
const params = result.data;
|
|
108
|
+
if (params.prefix && !params.prefix.endsWith(".")) throw new Error("INVALID_FILE_KEY");
|
|
109
|
+
return params;
|
|
110
|
+
};
|
|
111
|
+
return [
|
|
112
|
+
defineRoute({
|
|
113
|
+
method: "POST",
|
|
114
|
+
path: "/files",
|
|
115
|
+
contentType: "multipart/form-data",
|
|
116
|
+
outputSchema: fileMetadataSchema,
|
|
117
|
+
errorCodes,
|
|
118
|
+
handler: async function(context, { json, error }) {
|
|
119
|
+
const resolvedConfig = getResolvedConfig();
|
|
120
|
+
const form = context.formData();
|
|
121
|
+
const file = form.get("file");
|
|
122
|
+
if (!(file instanceof Blob)) return error({
|
|
123
|
+
message: "File is required",
|
|
124
|
+
code: "INVALID_REQUEST"
|
|
125
|
+
}, 400);
|
|
126
|
+
let keyParts;
|
|
127
|
+
if (form.has("keyParts")) {
|
|
128
|
+
const parsed = parseJson(form.get("keyParts"));
|
|
129
|
+
const result = fileKeyPartsSchema.safeParse(parsed);
|
|
130
|
+
if (!result.success) return error({
|
|
131
|
+
message: "Invalid file key",
|
|
132
|
+
code: "INVALID_FILE_KEY"
|
|
133
|
+
}, 400);
|
|
134
|
+
keyParts = result.data;
|
|
135
|
+
}
|
|
136
|
+
const fileKeyValue = form.get("fileKey");
|
|
137
|
+
const fileKey = typeof fileKeyValue === "string" ? fileKeyValue : void 0;
|
|
138
|
+
const parsedChecksum = parseJson(form.get("checksum"));
|
|
139
|
+
const checksumResult = checksumSchema.safeParse(parsedChecksum);
|
|
140
|
+
if (!checksumResult.success) return error({
|
|
141
|
+
message: "Invalid checksum",
|
|
142
|
+
code: "INVALID_CHECKSUM"
|
|
143
|
+
}, 400);
|
|
144
|
+
const tags = parseTags(form.get("tags"));
|
|
145
|
+
const metadata = parseMetadata(form.get("metadata"));
|
|
146
|
+
let resolvedKey;
|
|
147
|
+
try {
|
|
148
|
+
resolvedKey = resolveFileKeyInput({
|
|
149
|
+
keyParts,
|
|
150
|
+
fileKey: fileKey ?? void 0
|
|
151
|
+
});
|
|
152
|
+
} catch (err) {
|
|
153
|
+
return handleServiceError(err, error);
|
|
154
|
+
}
|
|
155
|
+
const checksumForStorage = checksumResult.data ?? null;
|
|
156
|
+
const checksumForRecord = checksumResult.data ?? void 0;
|
|
157
|
+
let storageInit;
|
|
158
|
+
const uploaderIdValue = form.get("uploaderId");
|
|
159
|
+
const uploaderId = typeof uploaderIdValue === "string" ? uploaderIdValue : void 0;
|
|
160
|
+
const visibilityValue = form.get("visibility");
|
|
161
|
+
const parsedVisibility = typeof visibilityValue === "string" ? visibilityValue : void 0;
|
|
162
|
+
const visibilityResult = visibilitySchema.optional().safeParse(parsedVisibility);
|
|
163
|
+
if (!visibilityResult.success) return error({
|
|
164
|
+
message: "Invalid request",
|
|
165
|
+
code: "INVALID_REQUEST"
|
|
166
|
+
}, 400);
|
|
167
|
+
const visibility = visibilityResult.data;
|
|
168
|
+
const filenameValue = form.get("filename");
|
|
169
|
+
const filename = typeof filenameValue === "string" && filenameValue ? filenameValue : file instanceof File && file.name ? file.name : "upload";
|
|
170
|
+
const contentType = file.type || "application/octet-stream";
|
|
171
|
+
const createInput = {
|
|
172
|
+
fileKey: resolvedKey.fileKey,
|
|
173
|
+
keyParts: resolvedKey.fileKeyParts,
|
|
174
|
+
filename,
|
|
175
|
+
sizeBytes: file.size,
|
|
176
|
+
contentType,
|
|
177
|
+
checksum: checksumForRecord,
|
|
178
|
+
tags,
|
|
179
|
+
visibility,
|
|
180
|
+
uploaderId,
|
|
181
|
+
metadata
|
|
182
|
+
};
|
|
183
|
+
try {
|
|
184
|
+
await this.handlerTx().withServiceCalls(() => [services.checkUploadAvailability(createInput, { allowIdempotentReuse: false })]).execute();
|
|
185
|
+
} catch (err) {
|
|
186
|
+
return handleServiceError(err, error);
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
storageInit = await resolvedConfig.storage.initUpload({
|
|
190
|
+
fileKey: resolvedKey.fileKey,
|
|
191
|
+
fileKeyParts: resolvedKey.fileKeyParts,
|
|
192
|
+
sizeBytes: BigInt(file.size),
|
|
193
|
+
contentType,
|
|
194
|
+
checksum: checksumForStorage,
|
|
195
|
+
metadata: metadata ?? null
|
|
196
|
+
});
|
|
197
|
+
} catch {
|
|
198
|
+
return error({
|
|
199
|
+
message: "Storage error",
|
|
200
|
+
code: "STORAGE_ERROR"
|
|
201
|
+
}, 502);
|
|
202
|
+
}
|
|
203
|
+
if (storageInit.strategy === "direct-multipart") {
|
|
204
|
+
if (resolvedConfig.storage.abortMultipartUpload && storageInit.storageUploadId) try {
|
|
205
|
+
await resolvedConfig.storage.abortMultipartUpload({
|
|
206
|
+
storageKey: storageInit.storageKey,
|
|
207
|
+
storageUploadId: storageInit.storageUploadId
|
|
208
|
+
});
|
|
209
|
+
} catch {}
|
|
210
|
+
return error({
|
|
211
|
+
message: "Upload invalid state",
|
|
212
|
+
code: "UPLOAD_INVALID_STATE"
|
|
213
|
+
}, 409);
|
|
214
|
+
}
|
|
215
|
+
let created;
|
|
216
|
+
try {
|
|
217
|
+
created = await this.handlerTx().withServiceCalls(() => [services.createUploadRecord({
|
|
218
|
+
...createInput,
|
|
219
|
+
storageInit,
|
|
220
|
+
allowIdempotentReuse: false
|
|
221
|
+
})]).transform(({ serviceResult: [result] }) => result).execute();
|
|
222
|
+
} catch (err) {
|
|
223
|
+
return handleServiceError(err, error);
|
|
224
|
+
}
|
|
225
|
+
const createdUpload = created.result;
|
|
226
|
+
try {
|
|
227
|
+
if (createdUpload.strategy === "proxy") {
|
|
228
|
+
if (!resolvedConfig.storage.writeStream) throw new Error("STORAGE_ERROR");
|
|
229
|
+
await resolvedConfig.storage.writeStream({
|
|
230
|
+
storageKey: storageInit.storageKey,
|
|
231
|
+
body: file.stream(),
|
|
232
|
+
contentType,
|
|
233
|
+
sizeBytes: BigInt(file.size)
|
|
234
|
+
});
|
|
235
|
+
} else if (createdUpload.strategy === "direct-single") {
|
|
236
|
+
if (!storageInit.uploadUrl) throw new Error("STORAGE_ERROR");
|
|
237
|
+
if (!(await fetch(storageInit.uploadUrl, {
|
|
238
|
+
method: "PUT",
|
|
239
|
+
headers: storageInit.uploadHeaders,
|
|
240
|
+
body: file
|
|
241
|
+
})).ok) throw new Error("STORAGE_ERROR");
|
|
242
|
+
} else return error({
|
|
243
|
+
message: "Upload invalid state",
|
|
244
|
+
code: "UPLOAD_INVALID_STATE"
|
|
245
|
+
}, 409);
|
|
246
|
+
if (resolvedConfig.storage.finalizeUpload) await resolvedConfig.storage.finalizeUpload({
|
|
247
|
+
storageKey: storageInit.storageKey,
|
|
248
|
+
expectedSizeBytes: BigInt(file.size),
|
|
249
|
+
checksum: checksumResult.data ?? null
|
|
250
|
+
});
|
|
251
|
+
} catch {
|
|
252
|
+
await this.handlerTx().withServiceCalls(() => [services.markUploadFailed(createdUpload.uploadId, "STORAGE_ERROR", "Storage upload failed")]).execute();
|
|
253
|
+
return error({
|
|
254
|
+
message: "Storage error",
|
|
255
|
+
code: "STORAGE_ERROR"
|
|
256
|
+
}, 502);
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
return json(toFileMetadata((await this.handlerTx().withServiceCalls(() => [services.markUploadComplete(createdUpload.uploadId, createdUpload.fileKey, { sizeBytes: BigInt(file.size) })]).transform(({ serviceResult: [result] }) => result).execute()).file));
|
|
260
|
+
} catch (err) {
|
|
261
|
+
return handleServiceError(err, error);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}),
|
|
265
|
+
defineRoute({
|
|
266
|
+
method: "GET",
|
|
267
|
+
path: "/files",
|
|
268
|
+
queryParameters: [
|
|
269
|
+
"prefix",
|
|
270
|
+
"cursor",
|
|
271
|
+
"pageSize",
|
|
272
|
+
"status",
|
|
273
|
+
"uploaderId"
|
|
274
|
+
],
|
|
275
|
+
outputSchema: z.object({
|
|
276
|
+
files: z.array(fileMetadataSchema),
|
|
277
|
+
cursor: z.string().optional(),
|
|
278
|
+
hasNextPage: z.boolean()
|
|
279
|
+
}),
|
|
280
|
+
errorCodes,
|
|
281
|
+
handler: async function({ query }, { json, error }) {
|
|
282
|
+
let params;
|
|
283
|
+
try {
|
|
284
|
+
params = parseListQuery(query);
|
|
285
|
+
} catch (err) {
|
|
286
|
+
return handleServiceError(err, error);
|
|
287
|
+
}
|
|
288
|
+
const result = await this.handlerTx().withServiceCalls(() => [services.listFiles({
|
|
289
|
+
prefix: params.prefix,
|
|
290
|
+
pageSize: params.pageSize,
|
|
291
|
+
cursor: params.cursor,
|
|
292
|
+
status: params.status,
|
|
293
|
+
uploaderId: params.uploaderId
|
|
294
|
+
})]).transform(({ serviceResult: [files] }) => files).execute();
|
|
295
|
+
return json({
|
|
296
|
+
files: result.items.map(toFileMetadata),
|
|
297
|
+
cursor: result.cursor?.encode(),
|
|
298
|
+
hasNextPage: result.hasNextPage
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}),
|
|
302
|
+
defineRoute({
|
|
303
|
+
method: "GET",
|
|
304
|
+
path: "/files/:fileKey",
|
|
305
|
+
outputSchema: fileMetadataSchema,
|
|
306
|
+
errorCodes,
|
|
307
|
+
handler: async function({ pathParams }, { json, error }) {
|
|
308
|
+
let resolvedKey;
|
|
309
|
+
try {
|
|
310
|
+
resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });
|
|
311
|
+
} catch (err) {
|
|
312
|
+
return handleServiceError(err, error);
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
return json(toFileMetadata(await this.handlerTx().withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)]).transform(({ serviceResult: [result] }) => result).execute()));
|
|
316
|
+
} catch (err) {
|
|
317
|
+
return handleServiceError(err, error);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}),
|
|
321
|
+
defineRoute({
|
|
322
|
+
method: "PATCH",
|
|
323
|
+
path: "/files/:fileKey",
|
|
324
|
+
inputSchema: updateFileSchema,
|
|
325
|
+
outputSchema: fileMetadataSchema,
|
|
326
|
+
errorCodes,
|
|
327
|
+
handler: async function({ pathParams, input }, { json, error }) {
|
|
328
|
+
const payload = await input.valid();
|
|
329
|
+
let resolvedKey;
|
|
330
|
+
try {
|
|
331
|
+
resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });
|
|
332
|
+
} catch (err) {
|
|
333
|
+
return handleServiceError(err, error);
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
return json(toFileMetadata(await this.handlerTx().withServiceCalls(() => [services.updateFile(resolvedKey.fileKey, payload)]).transform(({ serviceResult: [result] }) => result).execute()));
|
|
337
|
+
} catch (err) {
|
|
338
|
+
return handleServiceError(err, error);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}),
|
|
342
|
+
defineRoute({
|
|
343
|
+
method: "DELETE",
|
|
344
|
+
path: "/files/:fileKey",
|
|
345
|
+
outputSchema: z.object({ ok: z.literal(true) }),
|
|
346
|
+
errorCodes,
|
|
347
|
+
handler: async function({ pathParams }, { json, error }) {
|
|
348
|
+
const resolvedConfig = getResolvedConfig();
|
|
349
|
+
let resolvedKey;
|
|
350
|
+
try {
|
|
351
|
+
resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });
|
|
352
|
+
} catch (err) {
|
|
353
|
+
return handleServiceError(err, error);
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
const file = await this.handlerTx().withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)]).transform(({ serviceResult: [result] }) => result).execute();
|
|
357
|
+
try {
|
|
358
|
+
await resolvedConfig.storage.deleteObject({ storageKey: file.storageKey });
|
|
359
|
+
} catch {
|
|
360
|
+
return error({
|
|
361
|
+
message: "Storage error",
|
|
362
|
+
code: "STORAGE_ERROR"
|
|
363
|
+
}, 502);
|
|
364
|
+
}
|
|
365
|
+
await this.handlerTx().withServiceCalls(() => [services.markFileDeleted(resolvedKey.fileKey, resolvedKey.fileKeyParts)]).execute();
|
|
366
|
+
return json({ ok: true });
|
|
367
|
+
} catch (err) {
|
|
368
|
+
return handleServiceError(err, error);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}),
|
|
372
|
+
defineRoute({
|
|
373
|
+
method: "GET",
|
|
374
|
+
path: "/files/:fileKey/download-url",
|
|
375
|
+
outputSchema: z.object({
|
|
376
|
+
url: z.string(),
|
|
377
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
378
|
+
expiresAt: z.date()
|
|
379
|
+
}),
|
|
380
|
+
errorCodes,
|
|
381
|
+
handler: async function({ pathParams }, { json, error }) {
|
|
382
|
+
const resolvedConfig = getResolvedConfig();
|
|
383
|
+
let resolvedKey;
|
|
384
|
+
try {
|
|
385
|
+
resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });
|
|
386
|
+
} catch (err) {
|
|
387
|
+
return handleServiceError(err, error);
|
|
388
|
+
}
|
|
389
|
+
if (!resolvedConfig.storage.getDownloadUrl) return error({
|
|
390
|
+
message: "Signed URLs are not supported",
|
|
391
|
+
code: "SIGNED_URL_UNSUPPORTED"
|
|
392
|
+
}, 400);
|
|
393
|
+
try {
|
|
394
|
+
const file = await this.handlerTx().withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)]).transform(({ serviceResult: [result$1] }) => result$1).execute();
|
|
395
|
+
let result;
|
|
396
|
+
try {
|
|
397
|
+
result = await resolvedConfig.storage.getDownloadUrl({
|
|
398
|
+
storageKey: file.storageKey,
|
|
399
|
+
expiresInSeconds: resolvedConfig.signedUrlExpiresInSeconds,
|
|
400
|
+
contentType: file.contentType ?? void 0
|
|
401
|
+
});
|
|
402
|
+
} catch {
|
|
403
|
+
return error({
|
|
404
|
+
message: "Storage error",
|
|
405
|
+
code: "STORAGE_ERROR"
|
|
406
|
+
}, 502);
|
|
407
|
+
}
|
|
408
|
+
return json(result);
|
|
409
|
+
} catch (err) {
|
|
410
|
+
return handleServiceError(err, error);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}),
|
|
414
|
+
defineRoute({
|
|
415
|
+
method: "GET",
|
|
416
|
+
path: "/files/:fileKey/content",
|
|
417
|
+
errorCodes,
|
|
418
|
+
handler: async function({ pathParams }, { error }) {
|
|
419
|
+
const resolvedConfig = getResolvedConfig();
|
|
420
|
+
let resolvedKey;
|
|
421
|
+
try {
|
|
422
|
+
resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });
|
|
423
|
+
} catch (err) {
|
|
424
|
+
return handleServiceError(err, error);
|
|
425
|
+
}
|
|
426
|
+
if (!resolvedConfig.storage.getDownloadStream) return error({
|
|
427
|
+
message: "Download streaming unsupported",
|
|
428
|
+
code: "SIGNED_URL_UNSUPPORTED"
|
|
429
|
+
}, 400);
|
|
430
|
+
try {
|
|
431
|
+
const file = await this.handlerTx().withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)]).transform(({ serviceResult: [result] }) => result).execute();
|
|
432
|
+
try {
|
|
433
|
+
return await resolvedConfig.storage.getDownloadStream({ storageKey: file.storageKey });
|
|
434
|
+
} catch {
|
|
435
|
+
return error({
|
|
436
|
+
message: "Storage error",
|
|
437
|
+
code: "STORAGE_ERROR"
|
|
438
|
+
}, 502);
|
|
439
|
+
}
|
|
440
|
+
} catch (err) {
|
|
441
|
+
return handleServiceError(err, error);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
})
|
|
445
|
+
];
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
//#endregion
|
|
449
|
+
export { fileRoutesFactory };
|
|
450
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","names":["keyParts: z.infer<typeof fileKeyPartsSchema> | undefined","result"],"sources":["../../../src/routes/files.ts"],"sourcesContent":["import { defineRoutes } from \"@fragno-dev/core\";\nimport type { FragnoRouteConfig } from \"@fragno-dev/core\";\nimport { z } from \"zod\";\nimport { uploadFragmentDefinition } from \"../definition\";\nimport { resolveUploadFragmentConfig } from \"../config\";\nimport { resolveFileKeyInput } from \"../services/helpers\";\nimport {\n checksumSchema,\n fileKeyPartsSchema,\n fileMetadataSchema,\n toFileMetadata,\n visibilitySchema,\n} from \"./shared\";\n\nconst listQuerySchema = z.object({\n prefix: z.string().optional(),\n cursor: z.string().optional(),\n pageSize: z.coerce.number().min(1).max(100).catch(25),\n status: z.enum([\"ready\", \"deleted\"]).optional(),\n uploaderId: z.string().optional(),\n});\n\nconst updateFileSchema = z.object({\n filename: z.string().min(1).optional(),\n visibility: visibilitySchema.optional(),\n tags: z.array(z.string()).nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n});\n\nconst errorCodes = [\n \"UPLOAD_NOT_FOUND\",\n \"UPLOAD_ALREADY_ACTIVE\",\n \"FILE_ALREADY_EXISTS\",\n \"FILE_NOT_FOUND\",\n \"UPLOAD_EXPIRED\",\n \"UPLOAD_INVALID_STATE\",\n \"SIGNED_URL_UNSUPPORTED\",\n \"STORAGE_ERROR\",\n \"INVALID_FILE_KEY\",\n \"INVALID_CHECKSUM\",\n \"INVALID_REQUEST\",\n] as const;\n\ntype FileErrorCode = (typeof errorCodes)[number];\n\ntype ErrorFn<Code extends string> = Parameters<\n FragnoRouteConfig<\"GET\", \"/__error\", undefined, undefined, Code>[\"handler\"]\n>[1][\"error\"];\n\nconst handleServiceError = <Code extends FileErrorCode>(\n err: unknown,\n error: ErrorFn<Code>,\n): Response => {\n if (!(err instanceof Error)) {\n throw err;\n }\n\n switch (err.message) {\n case \"FILE_NOT_FOUND\":\n return error({ message: \"File not found\", code: \"FILE_NOT_FOUND\" as Code }, 404);\n case \"UPLOAD_NOT_FOUND\":\n return error({ message: \"Upload not found\", code: \"UPLOAD_NOT_FOUND\" as Code }, 404);\n case \"FILE_ALREADY_EXISTS\":\n return error({ message: \"File already exists\", code: \"FILE_ALREADY_EXISTS\" as Code }, 409);\n case \"UPLOAD_ALREADY_ACTIVE\":\n return error(\n { message: \"Upload already active\", code: \"UPLOAD_ALREADY_ACTIVE\" as Code },\n 409,\n );\n case \"UPLOAD_EXPIRED\":\n return error({ message: \"Upload expired\", code: \"UPLOAD_EXPIRED\" as Code }, 410);\n case \"UPLOAD_INVALID_STATE\":\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" as Code }, 409);\n case \"INVALID_FILE_KEY\":\n return error({ message: \"Invalid file key\", code: \"INVALID_FILE_KEY\" as Code }, 400);\n case \"INVALID_CHECKSUM\":\n return error({ message: \"Invalid checksum\", code: \"INVALID_CHECKSUM\" as Code }, 400);\n case \"INVALID_REQUEST\":\n return error({ message: \"Invalid request\", code: \"INVALID_REQUEST\" as Code }, 400);\n default:\n throw err;\n }\n};\n\nconst parseJson = <T>(value: FormDataEntryValue | null): T | undefined => {\n if (value === null || typeof value !== \"string\" || value.length === 0) {\n return undefined;\n }\n try {\n return JSON.parse(value) as T;\n } catch {\n return undefined;\n }\n};\n\nconst parseTags = (value: FormDataEntryValue | null): string[] | undefined => {\n if (value === null) {\n return undefined;\n }\n if (typeof value !== \"string\") {\n return undefined;\n }\n const parsed = parseJson<unknown>(value);\n if (Array.isArray(parsed)) {\n return parsed.filter((tag) => typeof tag === \"string\") as string[];\n }\n if (typeof value === \"string\" && value.length > 0) {\n return [value];\n }\n return undefined;\n};\n\nconst parseMetadata = (value: FormDataEntryValue | null): Record<string, unknown> | undefined => {\n const parsed = parseJson<unknown>(value);\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return undefined;\n};\n\nexport const fileRoutesFactory = defineRoutes(uploadFragmentDefinition).create(\n ({ services, defineRoute, config }) => {\n const getResolvedConfig = () => resolveUploadFragmentConfig(config);\n\n const parseListQuery = (query: URLSearchParams) => {\n const result = listQuerySchema.safeParse({\n prefix: query.get(\"prefix\") || undefined,\n cursor: query.get(\"cursor\") || undefined,\n pageSize: query.get(\"pageSize\"),\n status: query.get(\"status\") || undefined,\n uploaderId: query.get(\"uploaderId\") || undefined,\n });\n if (!result.success) {\n throw new Error(\"INVALID_REQUEST\");\n }\n const params = result.data;\n\n if (params.prefix && !params.prefix.endsWith(\".\")) {\n throw new Error(\"INVALID_FILE_KEY\");\n }\n\n return params;\n };\n\n return [\n defineRoute({\n method: \"POST\",\n path: \"/files\",\n contentType: \"multipart/form-data\",\n outputSchema: fileMetadataSchema,\n errorCodes,\n handler: async function (context, { json, error }) {\n const resolvedConfig = getResolvedConfig();\n const form = context.formData();\n const file = form.get(\"file\");\n if (!(file instanceof Blob)) {\n return error({ message: \"File is required\", code: \"INVALID_REQUEST\" }, 400);\n }\n\n let keyParts: z.infer<typeof fileKeyPartsSchema> | undefined;\n if (form.has(\"keyParts\")) {\n const parsed = parseJson<unknown>(form.get(\"keyParts\"));\n const result = fileKeyPartsSchema.safeParse(parsed);\n if (!result.success) {\n return error({ message: \"Invalid file key\", code: \"INVALID_FILE_KEY\" }, 400);\n }\n keyParts = result.data;\n }\n\n const fileKeyValue = form.get(\"fileKey\");\n const fileKey = typeof fileKeyValue === \"string\" ? fileKeyValue : undefined;\n\n const checksumValue = form.get(\"checksum\");\n const parsedChecksum = parseJson<unknown>(checksumValue);\n const checksumResult = checksumSchema.safeParse(parsedChecksum);\n if (!checksumResult.success) {\n return error({ message: \"Invalid checksum\", code: \"INVALID_CHECKSUM\" }, 400);\n }\n\n const tags = parseTags(form.get(\"tags\"));\n const metadata = parseMetadata(form.get(\"metadata\"));\n\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({ keyParts, fileKey: fileKey ?? undefined });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n const checksumForStorage = checksumResult.data ?? null;\n const checksumForRecord = checksumResult.data ?? undefined;\n\n let storageInit;\n\n const uploaderIdValue = form.get(\"uploaderId\");\n const uploaderId = typeof uploaderIdValue === \"string\" ? uploaderIdValue : undefined;\n const visibilityValue = form.get(\"visibility\");\n const parsedVisibility =\n typeof visibilityValue === \"string\" ? visibilityValue : undefined;\n const visibilityResult = visibilitySchema.optional().safeParse(parsedVisibility);\n if (!visibilityResult.success) {\n return error({ message: \"Invalid request\", code: \"INVALID_REQUEST\" }, 400);\n }\n const visibility = visibilityResult.data;\n const filenameValue = form.get(\"filename\");\n const filename =\n typeof filenameValue === \"string\" && filenameValue\n ? filenameValue\n : file instanceof File && file.name\n ? file.name\n : \"upload\";\n const contentType = file.type || \"application/octet-stream\";\n\n const createInput = {\n fileKey: resolvedKey.fileKey,\n keyParts: resolvedKey.fileKeyParts,\n filename,\n sizeBytes: file.size,\n contentType,\n checksum: checksumForRecord,\n tags,\n visibility,\n uploaderId,\n metadata,\n };\n\n try {\n await this.handlerTx()\n .withServiceCalls(() => [\n services.checkUploadAvailability(createInput, { allowIdempotentReuse: false }),\n ])\n .execute();\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n try {\n storageInit = await resolvedConfig.storage.initUpload({\n fileKey: resolvedKey.fileKey,\n fileKeyParts: resolvedKey.fileKeyParts,\n sizeBytes: BigInt(file.size),\n contentType,\n checksum: checksumForStorage,\n metadata: metadata ?? null,\n });\n } catch {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n if (storageInit.strategy === \"direct-multipart\") {\n if (resolvedConfig.storage.abortMultipartUpload && storageInit.storageUploadId) {\n try {\n await resolvedConfig.storage.abortMultipartUpload({\n storageKey: storageInit.storageKey,\n storageUploadId: storageInit.storageUploadId,\n });\n } catch {\n // Ignore abort failures; the request is still invalid for this endpoint.\n }\n }\n\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" }, 409);\n }\n\n let created;\n try {\n created = await this.handlerTx()\n .withServiceCalls(() => [\n services.createUploadRecord({\n ...createInput,\n storageInit,\n allowIdempotentReuse: false,\n }),\n ])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n const createdUpload = created.result;\n\n try {\n if (createdUpload.strategy === \"proxy\") {\n if (!resolvedConfig.storage.writeStream) {\n throw new Error(\"STORAGE_ERROR\");\n }\n await resolvedConfig.storage.writeStream({\n storageKey: storageInit.storageKey,\n body: file.stream(),\n contentType,\n sizeBytes: BigInt(file.size),\n });\n } else if (createdUpload.strategy === \"direct-single\") {\n if (!storageInit.uploadUrl) {\n throw new Error(\"STORAGE_ERROR\");\n }\n const response = await fetch(storageInit.uploadUrl, {\n method: \"PUT\",\n headers: storageInit.uploadHeaders,\n body: file,\n });\n if (!response.ok) {\n throw new Error(\"STORAGE_ERROR\");\n }\n } else {\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" }, 409);\n }\n\n if (resolvedConfig.storage.finalizeUpload) {\n await resolvedConfig.storage.finalizeUpload({\n storageKey: storageInit.storageKey,\n expectedSizeBytes: BigInt(file.size),\n checksum: checksumResult.data ?? null,\n });\n }\n } catch {\n await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadFailed(\n createdUpload.uploadId,\n \"STORAGE_ERROR\",\n \"Storage upload failed\",\n ),\n ])\n .execute();\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n try {\n const completed = await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadComplete(createdUpload.uploadId, createdUpload.fileKey, {\n sizeBytes: BigInt(file.size),\n }),\n ])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json(toFileMetadata(completed.file));\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/files\",\n queryParameters: [\"prefix\", \"cursor\", \"pageSize\", \"status\", \"uploaderId\"],\n outputSchema: z.object({\n files: z.array(fileMetadataSchema),\n cursor: z.string().optional(),\n hasNextPage: z.boolean(),\n }),\n errorCodes,\n handler: async function ({ query }, { json, error }) {\n let params;\n try {\n params = parseListQuery(query);\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n const result = await this.handlerTx()\n .withServiceCalls(() => [\n services.listFiles({\n prefix: params.prefix,\n pageSize: params.pageSize,\n cursor: params.cursor,\n status: params.status,\n uploaderId: params.uploaderId,\n }),\n ])\n .transform(({ serviceResult: [files] }) => files)\n .execute();\n\n return json({\n files: result.items.map(toFileMetadata),\n cursor: result.cursor?.encode(),\n hasNextPage: result.hasNextPage,\n });\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/files/:fileKey\",\n outputSchema: fileMetadataSchema,\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n try {\n const file = await this.handlerTx()\n .withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json(toFileMetadata(file));\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"PATCH\",\n path: \"/files/:fileKey\",\n inputSchema: updateFileSchema,\n outputSchema: fileMetadataSchema,\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n try {\n const file = await this.handlerTx()\n .withServiceCalls(() => [services.updateFile(resolvedKey.fileKey, payload)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json(toFileMetadata(file));\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"DELETE\",\n path: \"/files/:fileKey\",\n outputSchema: z.object({ ok: z.literal(true) }),\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n const resolvedConfig = getResolvedConfig();\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n try {\n const file = await this.handlerTx()\n .withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n try {\n await resolvedConfig.storage.deleteObject({ storageKey: file.storageKey });\n } catch {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n await this.handlerTx()\n .withServiceCalls(() => [\n services.markFileDeleted(resolvedKey.fileKey, resolvedKey.fileKeyParts),\n ])\n .execute();\n\n return json({ ok: true });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/files/:fileKey/download-url\",\n outputSchema: z.object({\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n expiresAt: z.date(),\n }),\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n const resolvedConfig = getResolvedConfig();\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n if (!resolvedConfig.storage.getDownloadUrl) {\n return error(\n { message: \"Signed URLs are not supported\", code: \"SIGNED_URL_UNSUPPORTED\" },\n 400,\n );\n }\n\n try {\n const file = await this.handlerTx()\n .withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n let result;\n try {\n result = await resolvedConfig.storage.getDownloadUrl({\n storageKey: file.storageKey,\n expiresInSeconds: resolvedConfig.signedUrlExpiresInSeconds,\n contentType: file.contentType ?? undefined,\n });\n } catch {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n return json(result);\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/files/:fileKey/content\",\n errorCodes,\n handler: async function ({ pathParams }, { error }) {\n const resolvedConfig = getResolvedConfig();\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({ fileKey: pathParams.fileKey });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n if (!resolvedConfig.storage.getDownloadStream) {\n return error(\n { message: \"Download streaming unsupported\", code: \"SIGNED_URL_UNSUPPORTED\" },\n 400,\n );\n }\n\n try {\n const file = await this.handlerTx()\n .withServiceCalls(() => [services.getFileByKey(resolvedKey.fileKey)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n try {\n return await resolvedConfig.storage.getDownloadStream({\n storageKey: file.storageKey,\n });\n } catch {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n ];\n },\n);\n"],"mappings":"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"}
|