@fragno-dev/upload 0.1.1 → 0.1.3
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/README.md +148 -12
- package/dist/browser/client/clients.js +17 -9
- package/dist/browser/client/clients.js.map +1 -1
- package/dist/browser/client/helpers.d.ts +15 -6
- package/dist/browser/client/helpers.d.ts.map +1 -1
- package/dist/browser/client/helpers.js +176 -30
- package/dist/browser/client/helpers.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/{@nanostores_query@0.3.4_nanostores@1.1.0 → @nanostores_query@0.3.4_nanostores@1.2.0}/node_modules/@nanostores/query/dist/nanoquery.js +6 -6
- package/dist/browser/client/node_modules/.pnpm/{@nanostores_query@0.3.4_nanostores@1.1.0 → @nanostores_query@0.3.4_nanostores@1.2.0}/node_modules/@nanostores/query/dist/nanoquery.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/{@nanostores_solid@1.1.1_nanostores@1.1.0_solid-js@1.9.10 → @nanostores_solid@1.1.1_nanostores@1.2.0_solid-js@1.9.10}/node_modules/@nanostores/solid/dist/index.js +2 -2
- package/dist/browser/client/node_modules/.pnpm/{@nanostores_solid@1.1.1_nanostores@1.1.0_solid-js@1.9.10 → @nanostores_solid@1.1.1_nanostores@1.2.0_solid-js@1.9.10}/node_modules/@nanostores/solid/dist/index.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/atom/index.js +2 -1
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/atom/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/clean-stores/index.js +6 -0
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/clean-stores/index.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/computed/index.js +8 -5
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/computed/index.js.map +1 -0
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/lifecycle/index.js +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/lifecycle/index.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/listen-keys/index.js +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/listen-keys/index.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/map/index.js +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/map/index.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/task/index.js +1 -1
- package/dist/browser/client/node_modules/.pnpm/{nanostores@1.1.0 → nanostores@1.2.0}/node_modules/nanostores/task/index.js.map +1 -1
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/warn/index.js +16 -0
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.2.0/node_modules/nanostores/warn/index.js.map +1 -0
- package/dist/browser/client/packages/fragment-upload/src/definition.js +1 -42
- package/dist/browser/client/packages/fragment-upload/src/definition.js.map +1 -1
- package/dist/browser/client/packages/fragment-upload/src/routes/files.js +12 -5
- package/dist/browser/client/packages/fragment-upload/src/routes/files.js.map +1 -1
- package/dist/browser/client/packages/fragment-upload/src/routes/shared.js +3 -4
- package/dist/browser/client/packages/fragment-upload/src/routes/shared.js.map +1 -1
- package/dist/browser/client/packages/fragment-upload/src/routes/uploads.js +32 -21
- package/dist/browser/client/packages/fragment-upload/src/routes/uploads.js.map +1 -1
- package/dist/browser/client/packages/fragment-upload/src/schema.js +33 -3
- package/dist/browser/client/packages/fragment-upload/src/schema.js.map +1 -1
- package/dist/browser/client/packages/fragment-upload/src/types.d.ts +1 -2
- package/dist/browser/client/packages/fragment-upload/src/types.d.ts.map +1 -1
- package/dist/browser/client/packages/fragno/dist/client/client.js +28 -12
- package/dist/browser/client/packages/fragno/dist/client/client.js.map +1 -1
- package/dist/browser/client/packages/fragno/dist/client/client.svelte.js +11 -3
- package/dist/browser/client/packages/fragno/dist/client/client.svelte.js.map +1 -1
- package/dist/browser/client/packages/fragno/dist/client/react.js +104 -12
- package/dist/browser/client/packages/fragno/dist/client/react.js.map +1 -1
- package/dist/browser/client/packages/fragno/dist/client/solid.js +25 -11
- package/dist/browser/client/packages/fragno/dist/client/solid.js.map +1 -1
- package/dist/browser/client/packages/fragno/dist/client/vanilla.js +21 -1
- package/dist/browser/client/packages/fragno/dist/client/vanilla.js.map +1 -1
- package/dist/browser/client/packages/fragno/dist/client/vue.js +19 -11
- package/dist/browser/client/packages/fragno/dist/client/vue.js.map +1 -1
- package/dist/browser/client/react.d.ts +215 -192
- package/dist/browser/client/react.d.ts.map +1 -1
- package/dist/browser/client/react.js.map +1 -1
- package/dist/browser/client/solid.d.ts +218 -196
- package/dist/browser/client/solid.d.ts.map +1 -1
- package/dist/browser/client/solid.js.map +1 -1
- package/dist/browser/client/svelte.d.ts +216 -193
- package/dist/browser/client/svelte.d.ts.map +1 -1
- package/dist/browser/client/svelte.js.map +1 -1
- package/dist/browser/client/vanilla.d.ts +217 -195
- package/dist/browser/client/vanilla.d.ts.map +1 -1
- package/dist/browser/client/vanilla.js.map +1 -1
- package/dist/browser/client/vue.d.ts +217 -194
- package/dist/browser/client/vue.d.ts.map +1 -1
- package/dist/browser/client/vue.js.map +1 -1
- package/dist/cli/commands/files/delete.d.ts +4 -4
- package/dist/cli/commands/files/delete.d.ts.map +1 -1
- package/dist/cli/commands/files/delete.js +8 -10
- package/dist/cli/commands/files/delete.js.map +1 -1
- package/dist/cli/commands/files/download-url.d.ts +4 -4
- package/dist/cli/commands/files/download-url.d.ts.map +1 -1
- package/dist/cli/commands/files/download-url.js +8 -10
- package/dist/cli/commands/files/download-url.js.map +1 -1
- package/dist/cli/commands/files/download.d.ts +4 -4
- package/dist/cli/commands/files/download.d.ts.map +1 -1
- package/dist/cli/commands/files/download.js +10 -12
- package/dist/cli/commands/files/download.js.map +1 -1
- package/dist/cli/commands/files/get.d.ts +4 -4
- package/dist/cli/commands/files/get.d.ts.map +1 -1
- package/dist/cli/commands/files/get.js +8 -10
- package/dist/cli/commands/files/get.js.map +1 -1
- package/dist/cli/commands/files/list.d.ts +4 -4
- package/dist/cli/commands/files/list.d.ts.map +1 -1
- package/dist/cli/commands/files/list.js +6 -8
- package/dist/cli/commands/files/list.js.map +1 -1
- package/dist/cli/commands/files/update.d.ts +4 -4
- package/dist/cli/commands/files/update.d.ts.map +1 -1
- package/dist/cli/commands/files/update.js +8 -10
- package/dist/cli/commands/files/update.js.map +1 -1
- package/dist/cli/commands/files/upload.d.ts +4 -4
- package/dist/cli/commands/files/upload.d.ts.map +1 -1
- package/dist/cli/commands/files/upload.js +10 -12
- package/dist/cli/commands/files/upload.js.map +1 -1
- package/dist/cli/commands/uploads/abort.d.ts +2 -2
- package/dist/cli/commands/uploads/abort.d.ts.map +1 -1
- package/dist/cli/commands/uploads/abort.js.map +1 -1
- package/dist/cli/commands/uploads/complete.d.ts +2 -2
- package/dist/cli/commands/uploads/complete.d.ts.map +1 -1
- package/dist/cli/commands/uploads/complete.js.map +1 -1
- package/dist/cli/commands/uploads/content.d.ts +2 -2
- package/dist/cli/commands/uploads/content.d.ts.map +1 -1
- package/dist/cli/commands/uploads/content.js +1 -1
- package/dist/cli/commands/uploads/content.js.map +1 -1
- package/dist/cli/commands/uploads/create.d.ts +4 -4
- package/dist/cli/commands/uploads/create.d.ts.map +1 -1
- package/dist/cli/commands/uploads/create.js +8 -11
- package/dist/cli/commands/uploads/create.js.map +1 -1
- package/dist/cli/commands/uploads/get.d.ts +2 -2
- package/dist/cli/commands/uploads/get.d.ts.map +1 -1
- package/dist/cli/commands/uploads/get.js.map +1 -1
- package/dist/cli/commands/uploads/parts-complete.d.ts +2 -2
- package/dist/cli/commands/uploads/parts-complete.d.ts.map +1 -1
- package/dist/cli/commands/uploads/parts-complete.js.map +1 -1
- package/dist/cli/commands/uploads/parts-list.d.ts +2 -2
- package/dist/cli/commands/uploads/parts-list.d.ts.map +1 -1
- package/dist/cli/commands/uploads/parts-list.js.map +1 -1
- package/dist/cli/commands/uploads/parts-urls.d.ts +2 -2
- package/dist/cli/commands/uploads/parts-urls.d.ts.map +1 -1
- package/dist/cli/commands/uploads/parts-urls.js.map +1 -1
- package/dist/cli/commands/uploads/progress.d.ts +2 -2
- package/dist/cli/commands/uploads/progress.d.ts.map +1 -1
- package/dist/cli/commands/uploads/progress.js.map +1 -1
- package/dist/cli/commands/uploads/transfer.d.ts +4 -4
- package/dist/cli/commands/uploads/transfer.d.ts.map +1 -1
- package/dist/cli/commands/uploads/transfer.js +9 -12
- package/dist/cli/commands/uploads/transfer.js.map +1 -1
- package/dist/cli/index.d.ts +13 -13
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +14 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/client.js +22 -5
- package/dist/cli/utils/client.js.map +1 -1
- package/dist/cli/utils/options.js +7 -43
- package/dist/cli/utils/options.js.map +1 -1
- package/dist/node/cli/commands/files/delete.d.ts +4 -4
- package/dist/node/cli/commands/files/delete.d.ts.map +1 -1
- package/dist/node/cli/commands/files/delete.js +8 -10
- package/dist/node/cli/commands/files/delete.js.map +1 -1
- package/dist/node/cli/commands/files/download-url.d.ts +4 -4
- package/dist/node/cli/commands/files/download-url.d.ts.map +1 -1
- package/dist/node/cli/commands/files/download-url.js +8 -10
- package/dist/node/cli/commands/files/download-url.js.map +1 -1
- package/dist/node/cli/commands/files/download.d.ts +4 -4
- package/dist/node/cli/commands/files/download.d.ts.map +1 -1
- package/dist/node/cli/commands/files/download.js +9 -11
- package/dist/node/cli/commands/files/download.js.map +1 -1
- package/dist/node/cli/commands/files/get.d.ts +4 -4
- package/dist/node/cli/commands/files/get.d.ts.map +1 -1
- package/dist/node/cli/commands/files/get.js +8 -10
- package/dist/node/cli/commands/files/get.js.map +1 -1
- package/dist/node/cli/commands/files/list.d.ts +4 -4
- package/dist/node/cli/commands/files/list.d.ts.map +1 -1
- package/dist/node/cli/commands/files/list.js +6 -8
- package/dist/node/cli/commands/files/list.js.map +1 -1
- package/dist/node/cli/commands/files/update.d.ts +4 -4
- package/dist/node/cli/commands/files/update.d.ts.map +1 -1
- package/dist/node/cli/commands/files/update.js +8 -10
- package/dist/node/cli/commands/files/update.js.map +1 -1
- package/dist/node/cli/commands/files/upload.d.ts +4 -4
- package/dist/node/cli/commands/files/upload.d.ts.map +1 -1
- package/dist/node/cli/commands/files/upload.js +9 -11
- package/dist/node/cli/commands/files/upload.js.map +1 -1
- package/dist/node/cli/commands/uploads/abort.d.ts +2 -2
- package/dist/node/cli/commands/uploads/abort.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/abort.js.map +1 -1
- package/dist/node/cli/commands/uploads/complete.d.ts +2 -2
- package/dist/node/cli/commands/uploads/complete.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/complete.js.map +1 -1
- package/dist/node/cli/commands/uploads/content.d.ts +2 -2
- package/dist/node/cli/commands/uploads/content.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/content.js.map +1 -1
- package/dist/node/cli/commands/uploads/create.d.ts +4 -4
- package/dist/node/cli/commands/uploads/create.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/create.js +8 -11
- package/dist/node/cli/commands/uploads/create.js.map +1 -1
- package/dist/node/cli/commands/uploads/get.d.ts +2 -2
- package/dist/node/cli/commands/uploads/get.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/get.js.map +1 -1
- package/dist/node/cli/commands/uploads/parts-complete.d.ts +2 -2
- package/dist/node/cli/commands/uploads/parts-complete.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/parts-complete.js.map +1 -1
- package/dist/node/cli/commands/uploads/parts-list.d.ts +2 -2
- package/dist/node/cli/commands/uploads/parts-list.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/parts-list.js.map +1 -1
- package/dist/node/cli/commands/uploads/parts-urls.d.ts +2 -2
- package/dist/node/cli/commands/uploads/parts-urls.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/parts-urls.js.map +1 -1
- package/dist/node/cli/commands/uploads/progress.d.ts +2 -2
- package/dist/node/cli/commands/uploads/progress.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/progress.js.map +1 -1
- package/dist/node/cli/commands/uploads/transfer.d.ts +4 -4
- package/dist/node/cli/commands/uploads/transfer.d.ts.map +1 -1
- package/dist/node/cli/commands/uploads/transfer.js +8 -11
- package/dist/node/cli/commands/uploads/transfer.js.map +1 -1
- package/dist/node/cli/index.d.ts +13 -13
- package/dist/node/cli/index.d.ts.map +1 -1
- package/dist/node/cli/index.js +14 -14
- package/dist/node/cli/index.js.map +1 -1
- package/dist/node/cli/utils/client.js +22 -5
- package/dist/node/cli/utils/client.js.map +1 -1
- package/dist/node/cli/utils/options.js +7 -43
- package/dist/node/cli/utils/options.js.map +1 -1
- package/dist/node/client/clients.d.ts +217 -194
- package/dist/node/client/clients.d.ts.map +1 -1
- package/dist/node/client/clients.js +17 -9
- package/dist/node/client/clients.js.map +1 -1
- package/dist/node/client/helpers.d.ts +15 -6
- package/dist/node/client/helpers.d.ts.map +1 -1
- package/dist/node/client/helpers.js +176 -30
- package/dist/node/client/helpers.js.map +1 -1
- package/dist/node/client/react.d.ts +217 -194
- package/dist/node/client/react.d.ts.map +1 -1
- package/dist/node/client/react.js.map +1 -1
- package/dist/node/client/solid.d.ts +218 -196
- package/dist/node/client/solid.d.ts.map +1 -1
- package/dist/node/client/solid.js.map +1 -1
- package/dist/node/client/svelte.d.ts +216 -193
- package/dist/node/client/svelte.d.ts.map +1 -1
- package/dist/node/client/svelte.js.map +1 -1
- package/dist/node/client/vanilla.d.ts +217 -195
- package/dist/node/client/vanilla.d.ts.map +1 -1
- package/dist/node/client/vanilla.js.map +1 -1
- package/dist/node/client/vue.d.ts +217 -194
- package/dist/node/client/vue.d.ts.map +1 -1
- package/dist/node/client/vue.js.map +1 -1
- package/dist/node/config.d.ts +6 -6
- package/dist/node/config.d.ts.map +1 -1
- package/dist/node/config.js.map +1 -1
- package/dist/node/definition.d.ts +588 -219
- package/dist/node/definition.d.ts.map +1 -1
- package/dist/node/definition.js +27 -3
- package/dist/node/definition.js.map +1 -1
- package/dist/node/file-key.d.ts +19 -0
- package/dist/node/file-key.d.ts.map +1 -0
- package/dist/node/file-key.js +47 -0
- package/dist/node/file-key.js.map +1 -0
- package/dist/node/index.d.ts +582 -175
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +3 -2
- package/dist/node/index.js.map +1 -1
- package/dist/node/routes/files.js +99 -64
- package/dist/node/routes/files.js.map +1 -1
- package/dist/node/routes/index.d.ts +1497 -721
- package/dist/node/routes/index.d.ts.map +1 -1
- package/dist/node/routes/shared.js +5 -9
- package/dist/node/routes/shared.js.map +1 -1
- package/dist/node/routes/uploads.js +105 -47
- package/dist/node/routes/uploads.js.map +1 -1
- package/dist/node/schema.d.ts +6 -6
- package/dist/node/schema.d.ts.map +1 -1
- package/dist/node/schema.js +12 -3
- package/dist/node/schema.js.map +1 -1
- package/dist/node/services/files.d.ts +6 -2
- package/dist/node/services/files.d.ts.map +1 -1
- package/dist/node/services/files.js +22 -20
- package/dist/node/services/files.js.map +1 -1
- package/dist/node/services/helpers.js +37 -15
- package/dist/node/services/helpers.js.map +1 -1
- package/dist/node/services/uploads.d.ts +10 -5
- package/dist/node/services/uploads.d.ts.map +1 -1
- package/dist/node/services/uploads.js +340 -63
- package/dist/node/services/uploads.js.map +1 -1
- package/dist/node/storage/fs.d.ts.map +1 -1
- package/dist/node/storage/fs.js +16 -10
- package/dist/node/storage/fs.js.map +1 -1
- package/dist/node/storage/object-key.js +36 -0
- package/dist/node/storage/object-key.js.map +1 -0
- package/dist/node/storage/r2-binding.d.ts +59 -0
- package/dist/node/storage/r2-binding.d.ts.map +1 -0
- package/dist/node/storage/r2-binding.js +245 -0
- package/dist/node/storage/r2-binding.js.map +1 -0
- package/dist/node/storage/r2.d.ts +6 -5
- package/dist/node/storage/r2.d.ts.map +1 -1
- package/dist/node/storage/s3.d.ts.map +1 -1
- package/dist/node/storage/s3.js +16 -10
- package/dist/node/storage/s3.js.map +1 -1
- package/dist/node/storage/types.d.ts +6 -5
- package/dist/node/storage/types.d.ts.map +1 -1
- package/dist/node/types.d.ts +1 -2
- package/dist/node/types.d.ts.map +1 -1
- package/package.json +26 -46
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/atom/index.js.map +0 -1
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/clean-stores/index.js +0 -6
- package/dist/browser/client/node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/computed/index.js.map +0 -1
- package/dist/browser/client/packages/fragment-upload/src/keys.d.ts +0 -7
- package/dist/browser/client/packages/fragment-upload/src/keys.d.ts.map +0 -1
- package/dist/browser/client/packages/fragment-upload/src/keys.js +0 -28
- package/dist/browser/client/packages/fragment-upload/src/keys.js.map +0 -1
- package/dist/browser/index-BdjKPO4J.d.ts +0 -177
- package/dist/browser/index-BdjKPO4J.d.ts.map +0 -1
- package/dist/browser/index.js +0 -3
- package/dist/browser/src-vdNJUbjT.js +0 -1982
- package/dist/browser/src-vdNJUbjT.js.map +0 -1
- package/dist/cli/keys.js +0 -32
- package/dist/cli/keys.js.map +0 -1
- package/dist/node/keys.d.ts +0 -12
- package/dist/node/keys.d.ts.map +0 -1
- package/dist/node/keys.js +0 -63
- package/dist/node/keys.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/routes/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;cAGa,2CAAY,aAAoD,oBAAA;kBAApD;;;;;;;;;;;MAAZ,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/routes/index.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import "../schema.js";
|
|
2
|
-
import { decodeFileKey } from "../keys.js";
|
|
3
2
|
import { z } from "zod";
|
|
4
3
|
|
|
5
4
|
//#region src/routes/shared.ts
|
|
6
|
-
const fileKeyPartsSchema = z.array(z.union([z.string(), z.number().int()]));
|
|
7
5
|
const checksumSchema = z.object({
|
|
8
6
|
algo: z.enum(["sha256", "md5"]),
|
|
9
7
|
value: z.string()
|
|
10
8
|
}).nullable().optional();
|
|
9
|
+
const providerNamespaceSchema = z.string().trim().min(1).refine((value) => value !== "." && value !== ".." && !value.includes("/") && !value.includes("\\"), { message: "Invalid provider" });
|
|
11
10
|
const visibilitySchema = z.enum([
|
|
12
11
|
"private",
|
|
13
12
|
"public",
|
|
@@ -15,7 +14,6 @@ const visibilitySchema = z.enum([
|
|
|
15
14
|
]);
|
|
16
15
|
const fileMetadataSchema = z.object({
|
|
17
16
|
fileKey: z.string(),
|
|
18
|
-
fileKeyParts: fileKeyPartsSchema,
|
|
19
17
|
uploaderId: z.string().nullable(),
|
|
20
18
|
filename: z.string(),
|
|
21
19
|
sizeBytes: z.number(),
|
|
@@ -28,7 +26,7 @@ const fileMetadataSchema = z.object({
|
|
|
28
26
|
tags: z.array(z.string()).nullable(),
|
|
29
27
|
metadata: z.record(z.string(), z.unknown()).nullable(),
|
|
30
28
|
status: z.enum(["ready", "deleted"]),
|
|
31
|
-
|
|
29
|
+
provider: providerNamespaceSchema,
|
|
32
30
|
createdAt: z.string(),
|
|
33
31
|
updatedAt: z.string(),
|
|
34
32
|
completedAt: z.string().nullable(),
|
|
@@ -37,11 +35,9 @@ const fileMetadataSchema = z.object({
|
|
|
37
35
|
errorMessage: z.string().nullable()
|
|
38
36
|
});
|
|
39
37
|
const toFileMetadata = (file) => {
|
|
40
|
-
const fileKeyParts = Array.from(decodeFileKey(file.fileKey));
|
|
41
38
|
const toIsoString = (value) => value ? value.toISOString() : null;
|
|
42
39
|
return {
|
|
43
|
-
fileKey: file.
|
|
44
|
-
fileKeyParts,
|
|
40
|
+
fileKey: file.key,
|
|
45
41
|
uploaderId: file.uploaderId,
|
|
46
42
|
filename: file.filename,
|
|
47
43
|
sizeBytes: Number(file.sizeBytes),
|
|
@@ -51,7 +47,7 @@ const toFileMetadata = (file) => {
|
|
|
51
47
|
tags: file.tags,
|
|
52
48
|
metadata: file.metadata,
|
|
53
49
|
status: file.status,
|
|
54
|
-
|
|
50
|
+
provider: file.provider,
|
|
55
51
|
createdAt: file.createdAt.toISOString(),
|
|
56
52
|
updatedAt: file.updatedAt.toISOString(),
|
|
57
53
|
completedAt: toIsoString(file.completedAt),
|
|
@@ -62,5 +58,5 @@ const toFileMetadata = (file) => {
|
|
|
62
58
|
};
|
|
63
59
|
|
|
64
60
|
//#endregion
|
|
65
|
-
export { checksumSchema,
|
|
61
|
+
export { checksumSchema, fileMetadataSchema, providerNamespaceSchema, toFileMetadata, visibilitySchema };
|
|
66
62
|
//# sourceMappingURL=shared.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","names":[],"sources":["../../../src/routes/shared.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"shared.js","names":[],"sources":["../../../src/routes/shared.ts"],"sourcesContent":["import type { TableToColumnValues } from \"@fragno-dev/db/query\";\nimport { z } from \"zod\";\n\nimport { uploadSchema } from \"../schema\";\nimport type { FileMetadata } from \"../types\";\n\ntype FileRow = TableToColumnValues<typeof uploadSchema.tables.file>;\ntype FileMetadataSource = Omit<FileRow, \"id\"> & { id?: unknown };\n\nexport const checksumSchema = z\n .object({\n algo: z.enum([\"sha256\", \"md5\"]),\n value: z.string(),\n })\n .nullable()\n .optional();\n\nexport const providerNamespaceSchema = z\n .string()\n .trim()\n .min(1)\n .refine(\n (value) => value !== \".\" && value !== \"..\" && !value.includes(\"/\") && !value.includes(\"\\\\\"),\n {\n message: \"Invalid provider\",\n },\n );\n\nexport const visibilitySchema = z.enum([\"private\", \"public\", \"unlisted\"]);\n\nexport const fileMetadataSchema = z.object({\n fileKey: z.string(),\n uploaderId: z.string().nullable(),\n filename: z.string(),\n sizeBytes: z.number(),\n contentType: z.string(),\n checksum: z\n .object({\n algo: z.enum([\"sha256\", \"md5\"]),\n value: z.string(),\n })\n .nullable(),\n visibility: visibilitySchema,\n tags: z.array(z.string()).nullable(),\n metadata: z.record(z.string(), z.unknown()).nullable(),\n status: z.enum([\"ready\", \"deleted\"]),\n provider: providerNamespaceSchema,\n createdAt: z.string(),\n updatedAt: z.string(),\n completedAt: z.string().nullable(),\n deletedAt: z.string().nullable(),\n errorCode: z.string().nullable(),\n errorMessage: z.string().nullable(),\n});\n\nexport const toFileMetadata = (file: FileMetadataSource): FileMetadata => {\n const toIsoString = (value: Date | null | undefined) => (value ? value.toISOString() : null);\n\n return {\n fileKey: file.key,\n uploaderId: file.uploaderId,\n filename: file.filename,\n sizeBytes: Number(file.sizeBytes),\n contentType: file.contentType,\n checksum: file.checksum as FileMetadata[\"checksum\"],\n visibility: file.visibility as FileMetadata[\"visibility\"],\n tags: file.tags as FileMetadata[\"tags\"],\n metadata: file.metadata as FileMetadata[\"metadata\"],\n status: file.status as FileMetadata[\"status\"],\n provider: file.provider,\n createdAt: file.createdAt.toISOString(),\n updatedAt: file.updatedAt.toISOString(),\n completedAt: toIsoString(file.completedAt),\n deletedAt: toIsoString(file.deletedAt),\n errorCode: file.errorCode,\n errorMessage: file.errorMessage,\n };\n};\n"],"mappings":";;;;AASA,MAAa,iBAAiB,EAC3B,OAAO;CACN,MAAM,EAAE,KAAK,CAAC,UAAU,MAAM,CAAC;CAC/B,OAAO,EAAE,QAAQ;CAClB,CAAC,CACD,UAAU,CACV,UAAU;AAEb,MAAa,0BAA0B,EACpC,QAAQ,CACR,MAAM,CACN,IAAI,EAAE,CACN,QACE,UAAU,UAAU,OAAO,UAAU,QAAQ,CAAC,MAAM,SAAS,IAAI,IAAI,CAAC,MAAM,SAAS,KAAK,EAC3F,EACE,SAAS,oBACV,CACF;AAEH,MAAa,mBAAmB,EAAE,KAAK;CAAC;CAAW;CAAU;CAAW,CAAC;AAEzE,MAAa,qBAAqB,EAAE,OAAO;CACzC,SAAS,EAAE,QAAQ;CACnB,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,UAAU,EAAE,QAAQ;CACpB,WAAW,EAAE,QAAQ;CACrB,aAAa,EAAE,QAAQ;CACvB,UAAU,EACP,OAAO;EACN,MAAM,EAAE,KAAK,CAAC,UAAU,MAAM,CAAC;EAC/B,OAAO,EAAE,QAAQ;EAClB,CAAC,CACD,UAAU;CACb,YAAY;CACZ,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CACpC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU;CACtD,QAAQ,EAAE,KAAK,CAAC,SAAS,UAAU,CAAC;CACpC,UAAU;CACV,WAAW,EAAE,QAAQ;CACrB,WAAW,EAAE,QAAQ;CACrB,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,cAAc,EAAE,QAAQ,CAAC,UAAU;CACpC,CAAC;AAEF,MAAa,kBAAkB,SAA2C;CACxE,MAAM,eAAe,UAAoC,QAAQ,MAAM,aAAa,GAAG;AAEvF,QAAO;EACL,SAAS,KAAK;EACd,YAAY,KAAK;EACjB,UAAU,KAAK;EACf,WAAW,OAAO,KAAK,UAAU;EACjC,aAAa,KAAK;EAClB,UAAU,KAAK;EACf,YAAY,KAAK;EACjB,MAAM,KAAK;EACX,UAAU,KAAK;EACf,QAAQ,KAAK;EACb,UAAU,KAAK;EACf,WAAW,KAAK,UAAU,aAAa;EACvC,WAAW,KAAK,UAAU,aAAa;EACvC,aAAa,YAAY,KAAK,YAAY;EAC1C,WAAW,YAAY,KAAK,UAAU;EACtC,WAAW,KAAK;EAChB,cAAc,KAAK;EACpB"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { resolveUploadFragmentConfig } from "../config.js";
|
|
2
2
|
import { resolveFileKeyInput } from "../services/helpers.js";
|
|
3
|
+
import { buildUploadSessionRouteData } from "../services/uploads.js";
|
|
3
4
|
import { uploadFragmentDefinition } from "../definition.js";
|
|
4
|
-
import {
|
|
5
|
+
import { buildStorageObjectVersionSegment } from "../storage/object-key.js";
|
|
6
|
+
import { checksumSchema, fileMetadataSchema, providerNamespaceSchema, toFileMetadata } from "./shared.js";
|
|
5
7
|
import { defineRoutes } from "@fragno-dev/core";
|
|
6
8
|
import { z } from "zod";
|
|
7
9
|
|
|
@@ -12,8 +14,10 @@ const uploadStrategySchema = z.enum([
|
|
|
12
14
|
"proxy"
|
|
13
15
|
]);
|
|
14
16
|
const safeIntSchema = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
17
|
+
const legacyFileKeyPartsSchema = z.array(z.union([z.string(), z.number().int()]));
|
|
15
18
|
const createUploadInputSchema = z.object({
|
|
16
|
-
|
|
19
|
+
provider: providerNamespaceSchema.optional(),
|
|
20
|
+
keyParts: legacyFileKeyPartsSchema.optional(),
|
|
17
21
|
fileKey: z.string().optional(),
|
|
18
22
|
filename: z.string().min(1),
|
|
19
23
|
sizeBytes: safeIntSchema,
|
|
@@ -42,7 +46,32 @@ const completeUploadSchema = z.object({ parts: z.array(z.object({
|
|
|
42
46
|
partNumber: z.number().int().min(1),
|
|
43
47
|
etag: z.string().min(1)
|
|
44
48
|
})).optional() });
|
|
45
|
-
const
|
|
49
|
+
const uploadRouteDataSchema = z.object({
|
|
50
|
+
provider: z.string(),
|
|
51
|
+
upload: z.object({
|
|
52
|
+
mode: z.enum(["single", "multipart"]),
|
|
53
|
+
transport: z.enum(["direct", "proxy"]),
|
|
54
|
+
uploadUrl: z.string().optional(),
|
|
55
|
+
uploadHeaders: z.record(z.string(), z.string()).optional(),
|
|
56
|
+
partSizeBytes: z.number().optional(),
|
|
57
|
+
maxParts: z.number().optional(),
|
|
58
|
+
statusEndpoint: z.string(),
|
|
59
|
+
progressEndpoint: z.string(),
|
|
60
|
+
partsEndpoint: z.string().optional(),
|
|
61
|
+
partsCompleteEndpoint: z.string().optional(),
|
|
62
|
+
completeEndpoint: z.string(),
|
|
63
|
+
abortEndpoint: z.string(),
|
|
64
|
+
contentEndpoint: z.string().optional()
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
const createUploadOutputSchema = uploadRouteDataSchema.extend({
|
|
68
|
+
uploadId: z.string(),
|
|
69
|
+
fileKey: z.string(),
|
|
70
|
+
status: z.enum(["created", "in_progress"]),
|
|
71
|
+
strategy: uploadStrategySchema,
|
|
72
|
+
expiresAt: z.date()
|
|
73
|
+
});
|
|
74
|
+
const uploadStatusSchema = uploadRouteDataSchema.extend({
|
|
46
75
|
uploadId: z.string(),
|
|
47
76
|
fileKey: z.string(),
|
|
48
77
|
status: z.enum([
|
|
@@ -72,11 +101,35 @@ const errorCodes = [
|
|
|
72
101
|
"FILE_ALREADY_EXISTS",
|
|
73
102
|
"UPLOAD_EXPIRED",
|
|
74
103
|
"UPLOAD_INVALID_STATE",
|
|
104
|
+
"PROVIDER_MISMATCH",
|
|
75
105
|
"INVALID_FILE_KEY",
|
|
76
106
|
"INVALID_CHECKSUM",
|
|
77
107
|
"INVALID_REQUEST",
|
|
78
108
|
"STORAGE_ERROR"
|
|
79
109
|
];
|
|
110
|
+
const rejectInactiveUpload = (upload, error) => {
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
if (upload.status === "completed") return error({
|
|
113
|
+
message: "File already exists",
|
|
114
|
+
code: "FILE_ALREADY_EXISTS"
|
|
115
|
+
}, 409);
|
|
116
|
+
if (upload.status === "expired" || upload.expiresAt.getTime() <= now) return error({
|
|
117
|
+
message: "Upload expired",
|
|
118
|
+
code: "UPLOAD_EXPIRED"
|
|
119
|
+
}, 410);
|
|
120
|
+
if (upload.status === "aborted" || upload.status === "failed") return error({
|
|
121
|
+
message: "Upload invalid state",
|
|
122
|
+
code: "UPLOAD_INVALID_STATE"
|
|
123
|
+
}, 409);
|
|
124
|
+
return null;
|
|
125
|
+
};
|
|
126
|
+
const rejectProviderMismatch = (upload, activeProvider, error) => {
|
|
127
|
+
if (upload.provider === activeProvider) return null;
|
|
128
|
+
return error({
|
|
129
|
+
message: "Upload provider mismatch",
|
|
130
|
+
code: "PROVIDER_MISMATCH"
|
|
131
|
+
}, 409);
|
|
132
|
+
};
|
|
80
133
|
const handleServiceError = (err, error) => {
|
|
81
134
|
if (!(err instanceof Error)) throw err;
|
|
82
135
|
switch (err.message) {
|
|
@@ -104,6 +157,10 @@ const handleServiceError = (err, error) => {
|
|
|
104
157
|
message: "Upload invalid state",
|
|
105
158
|
code: "UPLOAD_INVALID_STATE"
|
|
106
159
|
}, 409);
|
|
160
|
+
case "PROVIDER_MISMATCH": return error({
|
|
161
|
+
message: "Upload provider mismatch",
|
|
162
|
+
code: "PROVIDER_MISMATCH"
|
|
163
|
+
}, 409);
|
|
107
164
|
case "INVALID_FILE_KEY": return error({
|
|
108
165
|
message: "Invalid file key",
|
|
109
166
|
code: "INVALID_FILE_KEY"
|
|
@@ -130,28 +187,12 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
130
187
|
method: "POST",
|
|
131
188
|
path: "/uploads",
|
|
132
189
|
inputSchema: createUploadInputSchema,
|
|
133
|
-
outputSchema:
|
|
134
|
-
uploadId: z.string(),
|
|
135
|
-
fileKey: z.string(),
|
|
136
|
-
status: z.enum(["created", "in_progress"]),
|
|
137
|
-
strategy: uploadStrategySchema,
|
|
138
|
-
expiresAt: z.date(),
|
|
139
|
-
upload: z.object({
|
|
140
|
-
mode: z.enum(["single", "multipart"]),
|
|
141
|
-
transport: z.enum(["direct", "proxy"]),
|
|
142
|
-
uploadUrl: z.string().optional(),
|
|
143
|
-
uploadHeaders: z.record(z.string(), z.string()).optional(),
|
|
144
|
-
partSizeBytes: z.number().optional(),
|
|
145
|
-
maxParts: z.number().optional(),
|
|
146
|
-
partsEndpoint: z.string().optional(),
|
|
147
|
-
completeEndpoint: z.string(),
|
|
148
|
-
contentEndpoint: z.string().optional()
|
|
149
|
-
})
|
|
150
|
-
}),
|
|
190
|
+
outputSchema: createUploadOutputSchema,
|
|
151
191
|
errorCodes,
|
|
152
192
|
handler: async function({ input }, { json, error }) {
|
|
153
193
|
const payload = await input.valid();
|
|
154
194
|
const resolvedConfig = getResolvedConfig();
|
|
195
|
+
const provider = payload.provider ?? resolvedConfig.storage.name;
|
|
155
196
|
let resolvedKey;
|
|
156
197
|
try {
|
|
157
198
|
resolvedKey = resolveFileKeyInput({
|
|
@@ -161,21 +202,17 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
161
202
|
} catch (err) {
|
|
162
203
|
return handleServiceError(err, error);
|
|
163
204
|
}
|
|
164
|
-
|
|
165
|
-
const existing = await this.handlerTx().withServiceCalls(() => [services.checkUploadAvailability(payload, { allowIdempotentReuse: true })]).transform(({ serviceResult: [result] }) => result).execute();
|
|
166
|
-
if (existing) return json(existing);
|
|
167
|
-
} catch (err) {
|
|
168
|
-
return handleServiceError(err, error);
|
|
169
|
-
}
|
|
205
|
+
const objectKeyVersionSegment = buildStorageObjectVersionSegment();
|
|
170
206
|
let storageInit;
|
|
171
207
|
try {
|
|
172
208
|
storageInit = await resolvedConfig.storage.initUpload({
|
|
209
|
+
provider,
|
|
173
210
|
fileKey: resolvedKey.fileKey,
|
|
174
|
-
fileKeyParts: resolvedKey.fileKeyParts,
|
|
175
211
|
sizeBytes: BigInt(payload.sizeBytes),
|
|
176
212
|
contentType: payload.contentType,
|
|
177
213
|
checksum: payload.checksum ?? null,
|
|
178
|
-
metadata: payload.metadata ?? null
|
|
214
|
+
metadata: payload.metadata ?? null,
|
|
215
|
+
objectKeyVersionSegment
|
|
179
216
|
});
|
|
180
217
|
} catch (err) {
|
|
181
218
|
if (err instanceof Error && err.message === "INVALID_CHECKSUM") return error({
|
|
@@ -190,6 +227,7 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
190
227
|
try {
|
|
191
228
|
const result = await this.handlerTx().withServiceCalls(() => [services.createUploadRecord({
|
|
192
229
|
...payload,
|
|
230
|
+
provider,
|
|
193
231
|
storageInit,
|
|
194
232
|
allowIdempotentReuse: true
|
|
195
233
|
})]).transform(({ serviceResult: [created] }) => created).execute();
|
|
@@ -217,11 +255,21 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
217
255
|
outputSchema: uploadStatusSchema,
|
|
218
256
|
errorCodes,
|
|
219
257
|
handler: async function({ pathParams }, { json, error }) {
|
|
258
|
+
const resolvedConfig = getResolvedConfig();
|
|
220
259
|
try {
|
|
221
260
|
const upload = await this.handlerTx().withServiceCalls(() => [services.getUploadStatus(pathParams.uploadId)]).transform(({ serviceResult: [result] }) => result).execute();
|
|
261
|
+
const uploadHeaders = upload.uploadHeaders;
|
|
222
262
|
return json({
|
|
223
263
|
uploadId: upload.id.toString(),
|
|
224
|
-
fileKey: upload.
|
|
264
|
+
fileKey: upload.key,
|
|
265
|
+
...buildUploadSessionRouteData(resolvedConfig.storage, {
|
|
266
|
+
uploadId: upload.id.toString(),
|
|
267
|
+
provider: upload.provider,
|
|
268
|
+
strategy: upload.strategy,
|
|
269
|
+
uploadUrl: upload.uploadUrl ?? void 0,
|
|
270
|
+
uploadHeaders: uploadHeaders ?? void 0,
|
|
271
|
+
partSizeBytes: upload.partSizeBytes ?? void 0
|
|
272
|
+
}),
|
|
225
273
|
status: upload.status,
|
|
226
274
|
strategy: upload.strategy,
|
|
227
275
|
expectedSizeBytes: Number(upload.expectedSizeBytes),
|
|
@@ -277,6 +325,8 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
277
325
|
const resolvedConfig = getResolvedConfig();
|
|
278
326
|
try {
|
|
279
327
|
const upload = await this.handlerTx().withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)]).transform(({ serviceResult: [result] }) => result).execute();
|
|
328
|
+
const providerMismatch = rejectProviderMismatch(upload, resolvedConfig.storage.name, error);
|
|
329
|
+
if (providerMismatch) return providerMismatch;
|
|
280
330
|
if (upload.strategy !== "direct-multipart") return error({
|
|
281
331
|
message: "Upload invalid state",
|
|
282
332
|
code: "UPLOAD_INVALID_STATE"
|
|
@@ -286,7 +336,7 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
286
336
|
code: "STORAGE_ERROR"
|
|
287
337
|
}, 502);
|
|
288
338
|
return json({ parts: await resolvedConfig.storage.getPartUploadUrls({
|
|
289
|
-
storageKey: upload.
|
|
339
|
+
storageKey: upload.objectKey,
|
|
290
340
|
storageUploadId: upload.storageUploadId ?? "",
|
|
291
341
|
partNumbers: payload.partNumbers,
|
|
292
342
|
partSizeBytes: upload.partSizeBytes ?? 0
|
|
@@ -352,10 +402,13 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
352
402
|
const resolvedConfig = getResolvedConfig();
|
|
353
403
|
try {
|
|
354
404
|
const upload = await this.handlerTx().withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)]).transform(({ serviceResult: [result] }) => result).execute();
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
405
|
+
const providerMismatch = rejectProviderMismatch(upload, resolvedConfig.storage.name, error);
|
|
406
|
+
if (providerMismatch) return providerMismatch;
|
|
407
|
+
const inactiveResponse = rejectInactiveUpload({
|
|
408
|
+
status: upload.status,
|
|
409
|
+
expiresAt: upload.expiresAt
|
|
410
|
+
}, error);
|
|
411
|
+
if (inactiveResponse) return inactiveResponse;
|
|
359
412
|
let finalizeResult;
|
|
360
413
|
if (upload.strategy === "direct-multipart") {
|
|
361
414
|
if (!resolvedConfig.storage.completeMultipartUpload) return error({
|
|
@@ -367,16 +420,16 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
367
420
|
code: "UPLOAD_INVALID_STATE"
|
|
368
421
|
}, 409);
|
|
369
422
|
await resolvedConfig.storage.completeMultipartUpload({
|
|
370
|
-
storageKey: upload.
|
|
423
|
+
storageKey: upload.objectKey,
|
|
371
424
|
storageUploadId: upload.storageUploadId ?? "",
|
|
372
425
|
parts: payload.parts
|
|
373
426
|
});
|
|
374
427
|
} else if (resolvedConfig.storage.finalizeUpload) finalizeResult = await resolvedConfig.storage.finalizeUpload({
|
|
375
|
-
storageKey: upload.
|
|
428
|
+
storageKey: upload.objectKey,
|
|
376
429
|
expectedSizeBytes: upload.expectedSizeBytes,
|
|
377
430
|
checksum: upload.checksum
|
|
378
431
|
});
|
|
379
|
-
return json(toFileMetadata((await this.handlerTx().withServiceCalls(() => [services.
|
|
432
|
+
return json(toFileMetadata((await this.handlerTx().withServiceCalls(() => [services.markUploadCompleteFromSnapshot(upload, finalizeResult?.sizeBytes ? { sizeBytes: finalizeResult.sizeBytes } : void 0)]).transform(({ serviceResult: [result] }) => result).execute()).file));
|
|
380
433
|
} catch (err) {
|
|
381
434
|
return handleServiceError(err, error);
|
|
382
435
|
}
|
|
@@ -391,11 +444,13 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
391
444
|
const resolvedConfig = getResolvedConfig();
|
|
392
445
|
try {
|
|
393
446
|
const upload = await this.handlerTx().withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)]).transform(({ serviceResult: [result] }) => result).execute();
|
|
447
|
+
const providerMismatch = rejectProviderMismatch(upload, resolvedConfig.storage.name, error);
|
|
448
|
+
if (providerMismatch) return providerMismatch;
|
|
394
449
|
if (upload.strategy === "direct-multipart" && resolvedConfig.storage.abortMultipartUpload) await resolvedConfig.storage.abortMultipartUpload({
|
|
395
|
-
storageKey: upload.
|
|
450
|
+
storageKey: upload.objectKey,
|
|
396
451
|
storageUploadId: upload.storageUploadId ?? ""
|
|
397
452
|
});
|
|
398
|
-
await this.handlerTx().withServiceCalls(() => [services.
|
|
453
|
+
await this.handlerTx().withServiceCalls(() => [services.markUploadAbortedFromSnapshot(upload)]).execute();
|
|
399
454
|
return json({ ok: true });
|
|
400
455
|
} catch (err) {
|
|
401
456
|
return handleServiceError(err, error);
|
|
@@ -413,14 +468,17 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
413
468
|
const resolvedConfig = getResolvedConfig();
|
|
414
469
|
try {
|
|
415
470
|
const upload = await this.handlerTx().withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)]).transform(({ serviceResult: [result$1] }) => result$1).execute();
|
|
471
|
+
const providerMismatch = rejectProviderMismatch(upload, resolvedConfig.storage.name, error);
|
|
472
|
+
if (providerMismatch) return providerMismatch;
|
|
416
473
|
if (upload.strategy !== "proxy") return error({
|
|
417
474
|
message: "Upload invalid state",
|
|
418
475
|
code: "UPLOAD_INVALID_STATE"
|
|
419
476
|
}, 409);
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
},
|
|
477
|
+
const inactiveResponse = rejectInactiveUpload({
|
|
478
|
+
status: upload.status,
|
|
479
|
+
expiresAt: upload.expiresAt
|
|
480
|
+
}, error);
|
|
481
|
+
if (inactiveResponse) return inactiveResponse;
|
|
424
482
|
if (!resolvedConfig.storage.writeStream) return error({
|
|
425
483
|
message: "Storage error",
|
|
426
484
|
code: "STORAGE_ERROR"
|
|
@@ -428,19 +486,19 @@ const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(({ ser
|
|
|
428
486
|
let result;
|
|
429
487
|
try {
|
|
430
488
|
result = await resolvedConfig.storage.writeStream({
|
|
431
|
-
storageKey: upload.
|
|
489
|
+
storageKey: upload.objectKey,
|
|
432
490
|
body: context.bodyStream(),
|
|
433
491
|
contentType: upload.contentType,
|
|
434
492
|
sizeBytes: upload.expectedSizeBytes
|
|
435
493
|
});
|
|
436
494
|
} catch {
|
|
437
|
-
await this.handlerTx().withServiceCalls(() => [services.
|
|
495
|
+
await this.handlerTx().withServiceCalls(() => [services.markUploadFailedFromSnapshot(upload, "STORAGE_ERROR", "Storage upload failed")]).execute();
|
|
438
496
|
return error({
|
|
439
497
|
message: "Storage error",
|
|
440
498
|
code: "STORAGE_ERROR"
|
|
441
499
|
}, 502);
|
|
442
500
|
}
|
|
443
|
-
return json(toFileMetadata((await this.handlerTx().withServiceCalls(() => [services.
|
|
501
|
+
return json(toFileMetadata((await this.handlerTx().withServiceCalls(() => [services.markUploadCompleteFromSnapshot(upload, result?.sizeBytes ? { sizeBytes: result.sizeBytes } : void 0)]).transform(({ serviceResult: [done] }) => done).execute()).file));
|
|
444
502
|
} catch (err) {
|
|
445
503
|
return handleServiceError(err, error);
|
|
446
504
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploads.js","names":["finalizeResult: { sizeBytes?: bigint } | undefined","result","result: Awaited<ReturnType<NonNullable<typeof resolvedConfig.storage.writeStream>>>"],"sources":["../../../src/routes/uploads.ts"],"sourcesContent":["import { defineRoutes } from \"@fragno-dev/core\";\nimport type { FragnoRouteConfig } from \"@fragno-dev/core\";\nimport { z } from \"zod\";\nimport { resolveUploadFragmentConfig } from \"../config\";\nimport { uploadFragmentDefinition } from \"../definition\";\nimport { resolveFileKeyInput } from \"../services/helpers\";\nimport { checksumSchema, fileKeyPartsSchema, fileMetadataSchema, toFileMetadata } from \"./shared\";\nimport type { UploadStatus, UploadStrategy } from \"../types\";\nimport type { UploadChecksum } from \"../storage/types\";\n\nconst uploadStrategySchema = z.enum([\"direct-single\", \"direct-multipart\", \"proxy\"]);\nconst safeIntSchema = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);\n\nconst createUploadInputSchema = z.object({\n keyParts: fileKeyPartsSchema.optional(),\n fileKey: z.string().optional(),\n filename: z.string().min(1),\n sizeBytes: safeIntSchema,\n contentType: z.string().min(1),\n checksum: checksumSchema.optional(),\n tags: z.array(z.string()).optional(),\n visibility: z.enum([\"private\", \"public\", \"unlisted\"]).optional(),\n uploaderId: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst progressSchema = z.object({\n bytesUploaded: safeIntSchema.optional(),\n partsUploaded: z.number().int().min(0).optional(),\n});\n\nconst partNumbersSchema = z.object({\n partNumbers: z.array(z.number().int().min(1)).min(1),\n});\n\nconst completePartsSchema = z.object({\n parts: z\n .array(\n z.object({\n partNumber: z.number().int().min(1),\n etag: z.string().min(1),\n sizeBytes: safeIntSchema,\n }),\n )\n .min(1),\n});\n\nconst completeUploadSchema = z.object({\n parts: z\n .array(\n z.object({\n partNumber: z.number().int().min(1),\n etag: z.string().min(1),\n }),\n )\n .optional(),\n});\n\nconst uploadStatusSchema = z.object({\n uploadId: z.string(),\n fileKey: z.string(),\n status: z.enum([\"created\", \"in_progress\", \"completed\", \"aborted\", \"failed\", \"expired\"]),\n strategy: uploadStrategySchema,\n expectedSizeBytes: z.number(),\n bytesUploaded: z.number(),\n partsUploaded: z.number(),\n partSizeBytes: z.number().nullable(),\n expiresAt: z.date(),\n createdAt: z.date(),\n updatedAt: z.date(),\n completedAt: z.date().nullable(),\n errorCode: z.string().nullable(),\n errorMessage: z.string().nullable(),\n});\n\nconst errorCodes = [\n \"UPLOAD_NOT_FOUND\",\n \"UPLOAD_ALREADY_ACTIVE\",\n \"UPLOAD_METADATA_MISMATCH\",\n \"FILE_ALREADY_EXISTS\",\n \"UPLOAD_EXPIRED\",\n \"UPLOAD_INVALID_STATE\",\n \"INVALID_FILE_KEY\",\n \"INVALID_CHECKSUM\",\n \"INVALID_REQUEST\",\n \"STORAGE_ERROR\",\n] as const;\n\ntype UploadErrorCode = (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 UploadErrorCode>(\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 \"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_METADATA_MISMATCH\":\n return error(\n { message: \"Upload metadata mismatch\", code: \"UPLOAD_METADATA_MISMATCH\" 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 case \"STORAGE_ERROR\":\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" as Code }, 502);\n default:\n throw err;\n }\n};\n\nexport const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(\n ({ services, defineRoute, config }) => {\n const getResolvedConfig = () => resolveUploadFragmentConfig(config);\n\n return [\n defineRoute({\n method: \"POST\",\n path: \"/uploads\",\n inputSchema: createUploadInputSchema,\n outputSchema: z.object({\n uploadId: z.string(),\n fileKey: z.string(),\n status: z.enum([\"created\", \"in_progress\"]),\n strategy: uploadStrategySchema,\n expiresAt: z.date(),\n upload: z.object({\n mode: z.enum([\"single\", \"multipart\"]),\n transport: z.enum([\"direct\", \"proxy\"]),\n uploadUrl: z.string().optional(),\n uploadHeaders: z.record(z.string(), z.string()).optional(),\n partSizeBytes: z.number().optional(),\n maxParts: z.number().optional(),\n partsEndpoint: z.string().optional(),\n completeEndpoint: z.string(),\n contentEndpoint: z.string().optional(),\n }),\n }),\n errorCodes,\n handler: async function ({ input }, { json, error }) {\n const payload = await input.valid();\n const resolvedConfig = getResolvedConfig();\n\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({\n keyParts: payload.keyParts,\n fileKey: payload.fileKey,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n try {\n const existing = await this.handlerTx()\n .withServiceCalls(() => [\n services.checkUploadAvailability(payload, { allowIdempotentReuse: true }),\n ])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (existing) {\n return json(existing);\n }\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n let storageInit;\n try {\n storageInit = await resolvedConfig.storage.initUpload({\n fileKey: resolvedKey.fileKey,\n fileKeyParts: resolvedKey.fileKeyParts,\n sizeBytes: BigInt(payload.sizeBytes),\n contentType: payload.contentType,\n checksum: payload.checksum ?? null,\n metadata: payload.metadata ?? null,\n });\n } catch (err) {\n if (err instanceof Error && err.message === \"INVALID_CHECKSUM\") {\n return error({ message: \"Invalid checksum\", code: \"INVALID_CHECKSUM\" }, 400);\n }\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n try {\n const result = await this.handlerTx()\n .withServiceCalls(() => [\n services.createUploadRecord({\n ...payload,\n storageInit,\n allowIdempotentReuse: true,\n }),\n ])\n .transform(({ serviceResult: [created] }) => created)\n .execute();\n\n if (\n result.reused &&\n storageInit.strategy === \"direct-multipart\" &&\n resolvedConfig.storage.abortMultipartUpload &&\n storageInit.storageUploadId\n ) {\n try {\n await resolvedConfig.storage.abortMultipartUpload({\n storageKey: storageInit.storageKey,\n storageUploadId: storageInit.storageUploadId,\n });\n } catch {\n // Ignore abort failures for races.\n }\n }\n\n return json(result.result);\n } catch (err) {\n if (\n storageInit.strategy === \"direct-multipart\" &&\n resolvedConfig.storage.abortMultipartUpload &&\n storageInit.storageUploadId\n ) {\n try {\n await resolvedConfig.storage.abortMultipartUpload({\n storageKey: storageInit.storageKey,\n storageUploadId: storageInit.storageUploadId,\n });\n } catch {\n // Ignore abort failures for races.\n }\n }\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/uploads/:uploadId\",\n outputSchema: uploadStatusSchema,\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n try {\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStatus(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json({\n uploadId: upload.id.toString(),\n fileKey: upload.fileKey,\n status: upload.status as UploadStatus,\n strategy: upload.strategy as UploadStrategy,\n expectedSizeBytes: Number(upload.expectedSizeBytes),\n bytesUploaded: Number(upload.bytesUploaded),\n partsUploaded: upload.partsUploaded,\n partSizeBytes: upload.partSizeBytes,\n expiresAt: upload.expiresAt,\n createdAt: upload.createdAt,\n updatedAt: upload.updatedAt,\n completedAt: upload.completedAt,\n errorCode: upload.errorCode,\n errorMessage: upload.errorMessage,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/progress\",\n inputSchema: progressSchema,\n outputSchema: z.object({\n bytesUploaded: z.number(),\n partsUploaded: z.number(),\n }),\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n try {\n const result = await this.handlerTx()\n .withServiceCalls(() => [services.recordUploadProgress(pathParams.uploadId, payload)])\n .transform(({ serviceResult: [updated] }) => updated)\n .execute();\n\n return json({\n bytesUploaded: Number(result.bytesUploaded),\n partsUploaded: result.partsUploaded,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/parts\",\n inputSchema: partNumbersSchema,\n outputSchema: z.object({\n parts: z.array(\n z.object({\n partNumber: z.number(),\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n }),\n ),\n }),\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n const resolvedConfig = getResolvedConfig();\n try {\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (upload.strategy !== \"direct-multipart\") {\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" }, 409);\n }\n\n if (!resolvedConfig.storage.getPartUploadUrls) {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n const parts = await resolvedConfig.storage.getPartUploadUrls({\n storageKey: upload.storageKey,\n storageUploadId: upload.storageUploadId ?? \"\",\n partNumbers: payload.partNumbers,\n partSizeBytes: upload.partSizeBytes ?? 0,\n });\n\n return json({ parts });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/uploads/:uploadId/parts\",\n outputSchema: z.object({\n parts: z.array(\n z.object({\n partNumber: z.number(),\n etag: z.string(),\n sizeBytes: z.number(),\n createdAt: z.date(),\n }),\n ),\n }),\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n try {\n const parts = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadParts(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const typedParts = parts as {\n partNumber: number;\n etag: string;\n sizeBytes: bigint;\n createdAt: Date;\n }[];\n\n return json({\n parts: typedParts.map((part) => ({\n partNumber: part.partNumber,\n etag: part.etag,\n sizeBytes: Number(part.sizeBytes),\n createdAt: part.createdAt,\n })),\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/parts/complete\",\n inputSchema: completePartsSchema,\n outputSchema: z.object({\n bytesUploaded: z.number(),\n partsUploaded: z.number(),\n }),\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n try {\n const result = await this.handlerTx()\n .withServiceCalls(() => [services.recordUploadParts(pathParams.uploadId, payload)])\n .transform(({ serviceResult: [updated] }) => updated)\n .execute();\n\n return json({\n bytesUploaded: Number(result.bytesUploaded),\n partsUploaded: result.partsUploaded,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/complete\",\n inputSchema: completeUploadSchema,\n outputSchema: fileMetadataSchema,\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n const resolvedConfig = getResolvedConfig();\n try {\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const existingFile = await this.handlerTx()\n .withServiceCalls(() => [services.findFileByKey(upload.fileKey)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (existingFile) {\n return error({ message: \"File already exists\", code: \"FILE_ALREADY_EXISTS\" }, 409);\n }\n\n let finalizeResult: { sizeBytes?: bigint } | undefined;\n\n if (upload.strategy === \"direct-multipart\") {\n if (!resolvedConfig.storage.completeMultipartUpload) {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n if (!payload.parts || payload.parts.length === 0) {\n return error(\n { message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" },\n 409,\n );\n }\n\n await resolvedConfig.storage.completeMultipartUpload({\n storageKey: upload.storageKey,\n storageUploadId: upload.storageUploadId ?? \"\",\n parts: payload.parts,\n });\n } else if (resolvedConfig.storage.finalizeUpload) {\n finalizeResult = await resolvedConfig.storage.finalizeUpload({\n storageKey: upload.storageKey,\n expectedSizeBytes: upload.expectedSizeBytes,\n checksum: upload.checksum as UploadChecksum | null,\n });\n }\n\n const completed = await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadComplete(\n upload.id.toString(),\n upload.fileKey,\n finalizeResult?.sizeBytes ? { sizeBytes: finalizeResult.sizeBytes } : undefined,\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: \"POST\",\n path: \"/uploads/:uploadId/abort\",\n outputSchema: z.object({ ok: z.literal(true) }),\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n const resolvedConfig = getResolvedConfig();\n try {\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (\n upload.strategy === \"direct-multipart\" &&\n resolvedConfig.storage.abortMultipartUpload\n ) {\n await resolvedConfig.storage.abortMultipartUpload({\n storageKey: upload.storageKey,\n storageUploadId: upload.storageUploadId ?? \"\",\n });\n }\n\n await this.handlerTx()\n .withServiceCalls(() => [services.markUploadAborted(upload.id.toString())])\n .execute();\n\n return json({ ok: true });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"PUT\",\n path: \"/uploads/:uploadId/content\",\n contentType: \"application/octet-stream\",\n outputSchema: fileMetadataSchema,\n errorCodes,\n handler: async function (context, { json, error }) {\n const { pathParams } = context;\n const resolvedConfig = getResolvedConfig();\n try {\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (upload.strategy !== \"proxy\") {\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" }, 409);\n }\n\n const existingFile = await this.handlerTx()\n .withServiceCalls(() => [services.findFileByKey(upload.fileKey)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (existingFile) {\n return error({ message: \"File already exists\", code: \"FILE_ALREADY_EXISTS\" }, 409);\n }\n\n if (!resolvedConfig.storage.writeStream) {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n let result: Awaited<ReturnType<NonNullable<typeof resolvedConfig.storage.writeStream>>>;\n try {\n result = await resolvedConfig.storage.writeStream({\n storageKey: upload.storageKey,\n body: context.bodyStream(),\n contentType: upload.contentType,\n sizeBytes: upload.expectedSizeBytes,\n });\n } catch {\n await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadFailed(\n upload.id.toString(),\n \"STORAGE_ERROR\",\n \"Storage upload failed\",\n ),\n ])\n .execute();\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n const completed = await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadComplete(\n upload.id.toString(),\n upload.fileKey,\n result?.sizeBytes ? { sizeBytes: result.sizeBytes } : undefined,\n ),\n ])\n .transform(({ serviceResult: [done] }) => done)\n .execute();\n\n return json(toFileMetadata(completed.file));\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n ];\n },\n);\n"],"mappings":";;;;;;;;AAUA,MAAM,uBAAuB,EAAE,KAAK;CAAC;CAAiB;CAAoB;CAAQ,CAAC;AACnF,MAAM,gBAAgB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,iBAAiB;AAE1E,MAAM,0BAA0B,EAAE,OAAO;CACvC,UAAU,mBAAmB,UAAU;CACvC,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC3B,WAAW;CACX,aAAa,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC9B,UAAU,eAAe,UAAU;CACnC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CACpC,YAAY,EAAE,KAAK;EAAC;EAAW;EAAU;EAAW,CAAC,CAAC,UAAU;CAChE,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU;CACvD,CAAC;AAEF,MAAM,iBAAiB,EAAE,OAAO;CAC9B,eAAe,cAAc,UAAU;CACvC,eAAe,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU;CAClD,CAAC;AAEF,MAAM,oBAAoB,EAAE,OAAO,EACjC,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EACrD,CAAC;AAEF,MAAM,sBAAsB,EAAE,OAAO,EACnC,OAAO,EACJ,MACC,EAAE,OAAO;CACP,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACnC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE;CACvB,WAAW;CACZ,CAAC,CACH,CACA,IAAI,EAAE,EACV,CAAC;AAEF,MAAM,uBAAuB,EAAE,OAAO,EACpC,OAAO,EACJ,MACC,EAAE,OAAO;CACP,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE;CACnC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE;CACxB,CAAC,CACH,CACA,UAAU,EACd,CAAC;AAEF,MAAM,qBAAqB,EAAE,OAAO;CAClC,UAAU,EAAE,QAAQ;CACpB,SAAS,EAAE,QAAQ;CACnB,QAAQ,EAAE,KAAK;EAAC;EAAW;EAAe;EAAa;EAAW;EAAU;EAAU,CAAC;CACvF,UAAU;CACV,mBAAmB,EAAE,QAAQ;CAC7B,eAAe,EAAE,QAAQ;CACzB,eAAe,EAAE,QAAQ;CACzB,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,WAAW,EAAE,MAAM;CACnB,WAAW,EAAE,MAAM;CACnB,WAAW,EAAE,MAAM;CACnB,aAAa,EAAE,MAAM,CAAC,UAAU;CAChC,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,cAAc,EAAE,QAAQ,CAAC,UAAU;CACpC,CAAC;AAEF,MAAM,aAAa;CACjB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAQD,MAAM,sBACJ,KACA,UACa;AACb,KAAI,EAAE,eAAe,OACnB,OAAM;AAGR,SAAQ,IAAI,SAAZ;EACE,KAAK,mBACH,QAAO,MAAM;GAAE,SAAS;GAAoB,MAAM;GAA4B,EAAE,IAAI;EACtF,KAAK,sBACH,QAAO,MAAM;GAAE,SAAS;GAAuB,MAAM;GAA+B,EAAE,IAAI;EAC5F,KAAK,wBACH,QAAO,MACL;GAAE,SAAS;GAAyB,MAAM;GAAiC,EAC3E,IACD;EACH,KAAK,2BACH,QAAO,MACL;GAAE,SAAS;GAA4B,MAAM;GAAoC,EACjF,IACD;EACH,KAAK,iBACH,QAAO,MAAM;GAAE,SAAS;GAAkB,MAAM;GAA0B,EAAE,IAAI;EAClF,KAAK,uBACH,QAAO,MAAM;GAAE,SAAS;GAAwB,MAAM;GAAgC,EAAE,IAAI;EAC9F,KAAK,mBACH,QAAO,MAAM;GAAE,SAAS;GAAoB,MAAM;GAA4B,EAAE,IAAI;EACtF,KAAK,mBACH,QAAO,MAAM;GAAE,SAAS;GAAoB,MAAM;GAA4B,EAAE,IAAI;EACtF,KAAK,kBACH,QAAO,MAAM;GAAE,SAAS;GAAmB,MAAM;GAA2B,EAAE,IAAI;EACpF,KAAK,gBACH,QAAO,MAAM;GAAE,SAAS;GAAiB,MAAM;GAAyB,EAAE,IAAI;EAChF,QACE,OAAM;;;AAIZ,MAAa,sBAAsB,aAAa,yBAAyB,CAAC,QACvE,EAAE,UAAU,aAAa,aAAa;CACrC,MAAM,0BAA0B,4BAA4B,OAAO;AAEnE,QAAO;EACL,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc,EAAE,OAAO;IACrB,UAAU,EAAE,QAAQ;IACpB,SAAS,EAAE,QAAQ;IACnB,QAAQ,EAAE,KAAK,CAAC,WAAW,cAAc,CAAC;IAC1C,UAAU;IACV,WAAW,EAAE,MAAM;IACnB,QAAQ,EAAE,OAAO;KACf,MAAM,EAAE,KAAK,CAAC,UAAU,YAAY,CAAC;KACrC,WAAW,EAAE,KAAK,CAAC,UAAU,QAAQ,CAAC;KACtC,WAAW,EAAE,QAAQ,CAAC,UAAU;KAChC,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC,UAAU;KAC1D,eAAe,EAAE,QAAQ,CAAC,UAAU;KACpC,UAAU,EAAE,QAAQ,CAAC,UAAU;KAC/B,eAAe,EAAE,QAAQ,CAAC,UAAU;KACpC,kBAAkB,EAAE,QAAQ;KAC5B,iBAAiB,EAAE,QAAQ,CAAC,UAAU;KACvC,CAAC;IACH,CAAC;GACF;GACA,SAAS,eAAgB,EAAE,SAAS,EAAE,MAAM,SAAS;IACnD,MAAM,UAAU,MAAM,MAAM,OAAO;IACnC,MAAM,iBAAiB,mBAAmB;IAE1C,IAAI;AACJ,QAAI;AACF,mBAAc,oBAAoB;MAChC,UAAU,QAAQ;MAClB,SAAS,QAAQ;MAClB,CAAC;aACK,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;AAGvC,QAAI;KACF,MAAM,WAAW,MAAM,KAAK,WAAW,CACpC,uBAAuB,CACtB,SAAS,wBAAwB,SAAS,EAAE,sBAAsB,MAAM,CAAC,CAC1E,CAAC,CACD,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,SAAI,SACF,QAAO,KAAK,SAAS;aAEhB,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;IAGvC,IAAI;AACJ,QAAI;AACF,mBAAc,MAAM,eAAe,QAAQ,WAAW;MACpD,SAAS,YAAY;MACrB,cAAc,YAAY;MAC1B,WAAW,OAAO,QAAQ,UAAU;MACpC,aAAa,QAAQ;MACrB,UAAU,QAAQ,YAAY;MAC9B,UAAU,QAAQ,YAAY;MAC/B,CAAC;aACK,KAAK;AACZ,SAAI,eAAe,SAAS,IAAI,YAAY,mBAC1C,QAAO,MAAM;MAAE,SAAS;MAAoB,MAAM;MAAoB,EAAE,IAAI;AAE9E,YAAO,MAAM;MAAE,SAAS;MAAiB,MAAM;MAAiB,EAAE,IAAI;;AAGxE,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CACtB,SAAS,mBAAmB;MAC1B,GAAG;MACH;MACA,sBAAsB;MACvB,CAAC,CACH,CAAC,CACD,WAAW,EAAE,eAAe,CAAC,eAAe,QAAQ,CACpD,SAAS;AAEZ,SACE,OAAO,UACP,YAAY,aAAa,sBACzB,eAAe,QAAQ,wBACvB,YAAY,gBAEZ,KAAI;AACF,YAAM,eAAe,QAAQ,qBAAqB;OAChD,YAAY,YAAY;OACxB,iBAAiB,YAAY;OAC9B,CAAC;aACI;AAKV,YAAO,KAAK,OAAO,OAAO;aACnB,KAAK;AACZ,SACE,YAAY,aAAa,sBACzB,eAAe,QAAQ,wBACvB,YAAY,gBAEZ,KAAI;AACF,YAAM,eAAe,QAAQ,qBAAqB;OAChD,YAAY,YAAY;OACxB,iBAAiB,YAAY;OAC9B,CAAC;aACI;AAIV,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc;GACd;GACA,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;AACxD,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,gBAAgB,WAAW,SAAS,CAAC,CAAC,CACvE,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,YAAO,KAAK;MACV,UAAU,OAAO,GAAG,UAAU;MAC9B,SAAS,OAAO;MAChB,QAAQ,OAAO;MACf,UAAU,OAAO;MACjB,mBAAmB,OAAO,OAAO,kBAAkB;MACnD,eAAe,OAAO,OAAO,cAAc;MAC3C,eAAe,OAAO;MACtB,eAAe,OAAO;MACtB,WAAW,OAAO;MAClB,WAAW,OAAO;MAClB,WAAW,OAAO;MAClB,aAAa,OAAO;MACpB,WAAW,OAAO;MAClB,cAAc,OAAO;MACtB,CAAC;aACK,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc,EAAE,OAAO;IACrB,eAAe,EAAE,QAAQ;IACzB,eAAe,EAAE,QAAQ;IAC1B,CAAC;GACF;GACA,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,MAAM,SAAS;IAC/D,MAAM,UAAU,MAAM,MAAM,OAAO;AACnC,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,qBAAqB,WAAW,UAAU,QAAQ,CAAC,CAAC,CACrF,WAAW,EAAE,eAAe,CAAC,eAAe,QAAQ,CACpD,SAAS;AAEZ,YAAO,KAAK;MACV,eAAe,OAAO,OAAO,cAAc;MAC3C,eAAe,OAAO;MACvB,CAAC;aACK,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc,EAAE,OAAO,EACrB,OAAO,EAAE,MACP,EAAE,OAAO;IACP,YAAY,EAAE,QAAQ;IACtB,KAAK,EAAE,QAAQ;IACf,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC,UAAU;IACrD,CAAC,CACH,EACF,CAAC;GACF;GACA,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,MAAM,SAAS;IAC/D,MAAM,UAAU,MAAM,MAAM,OAAO;IACnC,MAAM,iBAAiB,mBAAmB;AAC1C,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,qBAAqB,WAAW,SAAS,CAAC,CAAC,CAC5E,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,SAAI,OAAO,aAAa,mBACtB,QAAO,MAAM;MAAE,SAAS;MAAwB,MAAM;MAAwB,EAAE,IAAI;AAGtF,SAAI,CAAC,eAAe,QAAQ,kBAC1B,QAAO,MAAM;MAAE,SAAS;MAAiB,MAAM;MAAiB,EAAE,IAAI;AAUxE,YAAO,KAAK,EAAE,OAPA,MAAM,eAAe,QAAQ,kBAAkB;MAC3D,YAAY,OAAO;MACnB,iBAAiB,OAAO,mBAAmB;MAC3C,aAAa,QAAQ;MACrB,eAAe,OAAO,iBAAiB;MACxC,CAAC,EAEmB,CAAC;aACf,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc,EAAE,OAAO,EACrB,OAAO,EAAE,MACP,EAAE,OAAO;IACP,YAAY,EAAE,QAAQ;IACtB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,QAAQ;IACrB,WAAW,EAAE,MAAM;IACpB,CAAC,CACH,EACF,CAAC;GACF;GACA,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;AACxD,QAAI;AAaF,YAAO,KAAK,EACV,QAbY,MAAM,KAAK,WAAW,CACjC,uBAAuB,CAAC,SAAS,eAAe,WAAW,SAAS,CAAC,CAAC,CACtE,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS,EAUQ,KAAK,UAAU;MAC/B,YAAY,KAAK;MACjB,MAAM,KAAK;MACX,WAAW,OAAO,KAAK,UAAU;MACjC,WAAW,KAAK;MACjB,EAAE,EACJ,CAAC;aACK,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc,EAAE,OAAO;IACrB,eAAe,EAAE,QAAQ;IACzB,eAAe,EAAE,QAAQ;IAC1B,CAAC;GACF;GACA,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,MAAM,SAAS;IAC/D,MAAM,UAAU,MAAM,MAAM,OAAO;AACnC,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,kBAAkB,WAAW,UAAU,QAAQ,CAAC,CAAC,CAClF,WAAW,EAAE,eAAe,CAAC,eAAe,QAAQ,CACpD,SAAS;AAEZ,YAAO,KAAK;MACV,eAAe,OAAO,OAAO,cAAc;MAC3C,eAAe,OAAO;MACvB,CAAC;aACK,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd;GACA,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,MAAM,SAAS;IAC/D,MAAM,UAAU,MAAM,MAAM,OAAO;IACnC,MAAM,iBAAiB,mBAAmB;AAC1C,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,qBAAqB,WAAW,SAAS,CAAC,CAAC,CAC5E,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAOZ,SALqB,MAAM,KAAK,WAAW,CACxC,uBAAuB,CAAC,SAAS,cAAc,OAAO,QAAQ,CAAC,CAAC,CAChE,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS,CAGV,QAAO,MAAM;MAAE,SAAS;MAAuB,MAAM;MAAuB,EAAE,IAAI;KAGpF,IAAIA;AAEJ,SAAI,OAAO,aAAa,oBAAoB;AAC1C,UAAI,CAAC,eAAe,QAAQ,wBAC1B,QAAO,MAAM;OAAE,SAAS;OAAiB,MAAM;OAAiB,EAAE,IAAI;AAGxE,UAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,WAAW,EAC7C,QAAO,MACL;OAAE,SAAS;OAAwB,MAAM;OAAwB,EACjE,IACD;AAGH,YAAM,eAAe,QAAQ,wBAAwB;OACnD,YAAY,OAAO;OACnB,iBAAiB,OAAO,mBAAmB;OAC3C,OAAO,QAAQ;OAChB,CAAC;gBACO,eAAe,QAAQ,eAChC,kBAAiB,MAAM,eAAe,QAAQ,eAAe;MAC3D,YAAY,OAAO;MACnB,mBAAmB,OAAO;MAC1B,UAAU,OAAO;MAClB,CAAC;AAcJ,YAAO,KAAK,gBAXM,MAAM,KAAK,WAAW,CACrC,uBAAuB,CACtB,SAAS,mBACP,OAAO,GAAG,UAAU,EACpB,OAAO,SACP,gBAAgB,YAAY,EAAE,WAAW,eAAe,WAAW,GAAG,OACvE,CACF,CAAC,CACD,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS,EAEyB,KAAK,CAAC;aACpC,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,KAAK,EAAE,CAAC;GAC/C;GACA,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;IACxD,MAAM,iBAAiB,mBAAmB;AAC1C,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,qBAAqB,WAAW,SAAS,CAAC,CAAC,CAC5E,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,SACE,OAAO,aAAa,sBACpB,eAAe,QAAQ,qBAEvB,OAAM,eAAe,QAAQ,qBAAqB;MAChD,YAAY,OAAO;MACnB,iBAAiB,OAAO,mBAAmB;MAC5C,CAAC;AAGJ,WAAM,KAAK,WAAW,CACnB,uBAAuB,CAAC,SAAS,kBAAkB,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAC1E,SAAS;AAEZ,YAAO,KAAK,EAAE,IAAI,MAAM,CAAC;aAClB,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd;GACA,SAAS,eAAgB,SAAS,EAAE,MAAM,SAAS;IACjD,MAAM,EAAE,eAAe;IACvB,MAAM,iBAAiB,mBAAmB;AAC1C,QAAI;KACF,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,qBAAqB,WAAW,SAAS,CAAC,CAAC,CAC5E,WAAW,EAAE,eAAe,CAACC,gBAAcA,SAAO,CAClD,SAAS;AAEZ,SAAI,OAAO,aAAa,QACtB,QAAO,MAAM;MAAE,SAAS;MAAwB,MAAM;MAAwB,EAAE,IAAI;AAQtF,SALqB,MAAM,KAAK,WAAW,CACxC,uBAAuB,CAAC,SAAS,cAAc,OAAO,QAAQ,CAAC,CAAC,CAChE,WAAW,EAAE,eAAe,CAACA,gBAAcA,SAAO,CAClD,SAAS,CAGV,QAAO,MAAM;MAAE,SAAS;MAAuB,MAAM;MAAuB,EAAE,IAAI;AAGpF,SAAI,CAAC,eAAe,QAAQ,YAC1B,QAAO,MAAM;MAAE,SAAS;MAAiB,MAAM;MAAiB,EAAE,IAAI;KAGxE,IAAIC;AACJ,SAAI;AACF,eAAS,MAAM,eAAe,QAAQ,YAAY;OAChD,YAAY,OAAO;OACnB,MAAM,QAAQ,YAAY;OAC1B,aAAa,OAAO;OACpB,WAAW,OAAO;OACnB,CAAC;aACI;AACN,YAAM,KAAK,WAAW,CACnB,uBAAuB,CACtB,SAAS,iBACP,OAAO,GAAG,UAAU,EACpB,iBACA,wBACD,CACF,CAAC,CACD,SAAS;AACZ,aAAO,MAAM;OAAE,SAAS;OAAiB,MAAM;OAAiB,EAAE,IAAI;;AAcxE,YAAO,KAAK,gBAXM,MAAM,KAAK,WAAW,CACrC,uBAAuB,CACtB,SAAS,mBACP,OAAO,GAAG,UAAU,EACpB,OAAO,SACP,QAAQ,YAAY,EAAE,WAAW,OAAO,WAAW,GAAG,OACvD,CACF,CAAC,CACD,WAAW,EAAE,eAAe,CAAC,YAAY,KAAK,CAC9C,SAAS,EAEyB,KAAK,CAAC;aACpC,KAAK;AACZ,YAAO,mBAAmB,KAAK,MAAM;;;GAG1C,CAAC;EACH;EAEJ"}
|
|
1
|
+
{"version":3,"file":"uploads.js","names":["finalizeResult: { sizeBytes?: bigint } | undefined","result","result: Awaited<ReturnType<NonNullable<typeof resolvedConfig.storage.writeStream>>>"],"sources":["../../../src/routes/uploads.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { defineRoutes } from \"@fragno-dev/core\";\nimport type { FragnoRouteConfig } from \"@fragno-dev/core\";\n\nimport { resolveUploadFragmentConfig } from \"../config\";\nimport { uploadFragmentDefinition } from \"../definition\";\nimport { resolveFileKeyInput } from \"../services/helpers\";\nimport { buildUploadSessionRouteData } from \"../services/uploads\";\nimport { buildStorageObjectVersionSegment } from \"../storage/object-key\";\nimport type { UploadChecksum } from \"../storage/types\";\nimport type { UploadStatus, UploadStrategy } from \"../types\";\nimport {\n checksumSchema,\n fileMetadataSchema,\n providerNamespaceSchema,\n toFileMetadata,\n} from \"./shared\";\n\nconst uploadStrategySchema = z.enum([\"direct-single\", \"direct-multipart\", \"proxy\"]);\nconst safeIntSchema = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);\nconst legacyFileKeyPartsSchema = z.array(z.union([z.string(), z.number().int()]));\n\nconst createUploadInputSchema = z.object({\n provider: providerNamespaceSchema.optional(),\n keyParts: legacyFileKeyPartsSchema.optional(),\n fileKey: z.string().optional(),\n filename: z.string().min(1),\n sizeBytes: safeIntSchema,\n contentType: z.string().min(1),\n checksum: checksumSchema.optional(),\n tags: z.array(z.string()).optional(),\n visibility: z.enum([\"private\", \"public\", \"unlisted\"]).optional(),\n uploaderId: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst progressSchema = z.object({\n bytesUploaded: safeIntSchema.optional(),\n partsUploaded: z.number().int().min(0).optional(),\n});\n\nconst partNumbersSchema = z.object({\n partNumbers: z.array(z.number().int().min(1)).min(1),\n});\n\nconst completePartsSchema = z.object({\n parts: z\n .array(\n z.object({\n partNumber: z.number().int().min(1),\n etag: z.string().min(1),\n sizeBytes: safeIntSchema,\n }),\n )\n .min(1),\n});\n\nconst completeUploadSchema = z.object({\n parts: z\n .array(\n z.object({\n partNumber: z.number().int().min(1),\n etag: z.string().min(1),\n }),\n )\n .optional(),\n});\n\nconst uploadRouteDataSchema = z.object({\n provider: z.string(),\n upload: z.object({\n mode: z.enum([\"single\", \"multipart\"]),\n transport: z.enum([\"direct\", \"proxy\"]),\n uploadUrl: z.string().optional(),\n uploadHeaders: z.record(z.string(), z.string()).optional(),\n partSizeBytes: z.number().optional(),\n maxParts: z.number().optional(),\n statusEndpoint: z.string(),\n progressEndpoint: z.string(),\n partsEndpoint: z.string().optional(),\n partsCompleteEndpoint: z.string().optional(),\n completeEndpoint: z.string(),\n abortEndpoint: z.string(),\n contentEndpoint: z.string().optional(),\n }),\n});\n\nconst createUploadOutputSchema = uploadRouteDataSchema.extend({\n uploadId: z.string(),\n fileKey: z.string(),\n status: z.enum([\"created\", \"in_progress\"]),\n strategy: uploadStrategySchema,\n expiresAt: z.date(),\n});\n\nconst uploadStatusSchema = uploadRouteDataSchema.extend({\n uploadId: z.string(),\n fileKey: z.string(),\n status: z.enum([\"created\", \"in_progress\", \"completed\", \"aborted\", \"failed\", \"expired\"]),\n strategy: uploadStrategySchema,\n expectedSizeBytes: z.number(),\n bytesUploaded: z.number(),\n partsUploaded: z.number(),\n partSizeBytes: z.number().nullable(),\n expiresAt: z.date(),\n createdAt: z.date(),\n updatedAt: z.date(),\n completedAt: z.date().nullable(),\n errorCode: z.string().nullable(),\n errorMessage: z.string().nullable(),\n});\n\nconst errorCodes = [\n \"UPLOAD_NOT_FOUND\",\n \"UPLOAD_ALREADY_ACTIVE\",\n \"UPLOAD_METADATA_MISMATCH\",\n \"FILE_ALREADY_EXISTS\",\n \"UPLOAD_EXPIRED\",\n \"UPLOAD_INVALID_STATE\",\n \"PROVIDER_MISMATCH\",\n \"INVALID_FILE_KEY\",\n \"INVALID_CHECKSUM\",\n \"INVALID_REQUEST\",\n \"STORAGE_ERROR\",\n] as const;\n\ntype UploadErrorCode = (typeof errorCodes)[number];\n\ntype ErrorFn<Code extends string> = Parameters<\n FragnoRouteConfig<\"GET\", \"/__error\", undefined, undefined, Code>[\"handler\"]\n>[1][\"error\"];\n\nconst rejectInactiveUpload = (\n upload: { status: UploadStatus; expiresAt: Date },\n error: ErrorFn<UploadErrorCode>,\n): Response | null => {\n const now = Date.now();\n\n if (upload.status === \"completed\") {\n return error({ message: \"File already exists\", code: \"FILE_ALREADY_EXISTS\" }, 409);\n }\n\n if (upload.status === \"expired\" || upload.expiresAt.getTime() <= now) {\n return error({ message: \"Upload expired\", code: \"UPLOAD_EXPIRED\" }, 410);\n }\n\n if (upload.status === \"aborted\" || upload.status === \"failed\") {\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" }, 409);\n }\n\n return null;\n};\n\nconst rejectProviderMismatch = (\n upload: { provider: string },\n activeProvider: string,\n error: ErrorFn<UploadErrorCode>,\n): Response | null => {\n if (upload.provider === activeProvider) {\n return null;\n }\n\n return error({ message: \"Upload provider mismatch\", code: \"PROVIDER_MISMATCH\" }, 409);\n};\n\nconst handleServiceError = <Code extends UploadErrorCode>(\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 \"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 {\n message: \"Upload already active\",\n code: \"UPLOAD_ALREADY_ACTIVE\" as Code,\n },\n 409,\n );\n case \"UPLOAD_METADATA_MISMATCH\":\n return error(\n {\n message: \"Upload metadata mismatch\",\n code: \"UPLOAD_METADATA_MISMATCH\" as Code,\n },\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(\n {\n message: \"Upload invalid state\",\n code: \"UPLOAD_INVALID_STATE\" as Code,\n },\n 409,\n );\n case \"PROVIDER_MISMATCH\":\n return error(\n {\n message: \"Upload provider mismatch\",\n code: \"PROVIDER_MISMATCH\" as Code,\n },\n 409,\n );\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 case \"STORAGE_ERROR\":\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" as Code }, 502);\n default:\n throw err;\n }\n};\n\nexport const uploadRoutesFactory = defineRoutes(uploadFragmentDefinition).create(\n ({ services, defineRoute, config }) => {\n const getResolvedConfig = () => resolveUploadFragmentConfig(config);\n\n return [\n defineRoute({\n method: \"POST\",\n path: \"/uploads\",\n inputSchema: createUploadInputSchema,\n outputSchema: createUploadOutputSchema,\n errorCodes,\n handler: async function ({ input }, { json, error }) {\n const payload = await input.valid();\n const resolvedConfig = getResolvedConfig();\n const provider = payload.provider ?? resolvedConfig.storage.name;\n\n let resolvedKey;\n try {\n resolvedKey = resolveFileKeyInput({\n keyParts: payload.keyParts,\n fileKey: payload.fileKey,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n\n const objectKeyVersionSegment = buildStorageObjectVersionSegment();\n\n let storageInit;\n try {\n storageInit = await resolvedConfig.storage.initUpload({\n provider,\n fileKey: resolvedKey.fileKey,\n sizeBytes: BigInt(payload.sizeBytes),\n contentType: payload.contentType,\n checksum: payload.checksum ?? null,\n metadata: payload.metadata ?? null,\n objectKeyVersionSegment,\n });\n } catch (err) {\n if (err instanceof Error && err.message === \"INVALID_CHECKSUM\") {\n return error({ message: \"Invalid checksum\", code: \"INVALID_CHECKSUM\" }, 400);\n }\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n try {\n const result = await this.handlerTx()\n .withServiceCalls(() => [\n services.createUploadRecord({\n ...payload,\n provider,\n storageInit,\n allowIdempotentReuse: true,\n }),\n ])\n .transform(({ serviceResult: [created] }) => created)\n .execute();\n\n if (\n result.reused &&\n storageInit.strategy === \"direct-multipart\" &&\n resolvedConfig.storage.abortMultipartUpload &&\n storageInit.storageUploadId\n ) {\n try {\n await resolvedConfig.storage.abortMultipartUpload({\n storageKey: storageInit.storageKey,\n storageUploadId: storageInit.storageUploadId,\n });\n } catch {\n // Ignore abort failures for races.\n }\n }\n\n return json(result.result);\n } catch (err) {\n if (\n storageInit.strategy === \"direct-multipart\" &&\n resolvedConfig.storage.abortMultipartUpload &&\n storageInit.storageUploadId\n ) {\n try {\n await resolvedConfig.storage.abortMultipartUpload({\n storageKey: storageInit.storageKey,\n storageUploadId: storageInit.storageUploadId,\n });\n } catch {\n // Ignore abort failures for races.\n }\n }\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/uploads/:uploadId\",\n outputSchema: uploadStatusSchema,\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n const resolvedConfig = getResolvedConfig();\n try {\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStatus(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const uploadHeaders = upload.uploadHeaders as Record<string, string> | null;\n\n return json({\n uploadId: upload.id.toString(),\n fileKey: upload.key,\n ...buildUploadSessionRouteData(resolvedConfig.storage, {\n uploadId: upload.id.toString(),\n provider: upload.provider,\n strategy: upload.strategy as UploadStrategy,\n uploadUrl: upload.uploadUrl ?? undefined,\n uploadHeaders: uploadHeaders ?? undefined,\n partSizeBytes: upload.partSizeBytes ?? undefined,\n }),\n status: upload.status as UploadStatus,\n strategy: upload.strategy as UploadStrategy,\n expectedSizeBytes: Number(upload.expectedSizeBytes),\n bytesUploaded: Number(upload.bytesUploaded),\n partsUploaded: upload.partsUploaded,\n partSizeBytes: upload.partSizeBytes,\n expiresAt: upload.expiresAt,\n createdAt: upload.createdAt,\n updatedAt: upload.updatedAt,\n completedAt: upload.completedAt,\n errorCode: upload.errorCode,\n errorMessage: upload.errorMessage,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/progress\",\n inputSchema: progressSchema,\n outputSchema: z.object({\n bytesUploaded: z.number(),\n partsUploaded: z.number(),\n }),\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n try {\n const result = await this.handlerTx()\n .withServiceCalls(() => [services.recordUploadProgress(pathParams.uploadId, payload)])\n .transform(({ serviceResult: [updated] }) => updated)\n .execute();\n\n return json({\n bytesUploaded: Number(result.bytesUploaded),\n partsUploaded: result.partsUploaded,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/parts\",\n inputSchema: partNumbersSchema,\n outputSchema: z.object({\n parts: z.array(\n z.object({\n partNumber: z.number(),\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n }),\n ),\n }),\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n const resolvedConfig = getResolvedConfig();\n try {\n // Rule of Fragno exception: read -> storage I/O -> mutate.\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const providerMismatch = rejectProviderMismatch(\n upload,\n resolvedConfig.storage.name,\n error,\n );\n if (providerMismatch) {\n return providerMismatch;\n }\n\n if (upload.strategy !== \"direct-multipart\") {\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" }, 409);\n }\n\n if (!resolvedConfig.storage.getPartUploadUrls) {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n const parts = await resolvedConfig.storage.getPartUploadUrls({\n storageKey: upload.objectKey,\n storageUploadId: upload.storageUploadId ?? \"\",\n partNumbers: payload.partNumbers,\n partSizeBytes: upload.partSizeBytes ?? 0,\n });\n\n return json({ parts });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/uploads/:uploadId/parts\",\n outputSchema: z.object({\n parts: z.array(\n z.object({\n partNumber: z.number(),\n etag: z.string(),\n sizeBytes: z.number(),\n createdAt: z.date(),\n }),\n ),\n }),\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n try {\n const parts = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadParts(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const typedParts = parts as {\n partNumber: number;\n etag: string;\n sizeBytes: bigint;\n createdAt: Date;\n }[];\n\n return json({\n parts: typedParts.map((part) => ({\n partNumber: part.partNumber,\n etag: part.etag,\n sizeBytes: Number(part.sizeBytes),\n createdAt: part.createdAt,\n })),\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/parts/complete\",\n inputSchema: completePartsSchema,\n outputSchema: z.object({\n bytesUploaded: z.number(),\n partsUploaded: z.number(),\n }),\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n try {\n const result = await this.handlerTx()\n .withServiceCalls(() => [services.recordUploadParts(pathParams.uploadId, payload)])\n .transform(({ serviceResult: [updated] }) => updated)\n .execute();\n\n return json({\n bytesUploaded: Number(result.bytesUploaded),\n partsUploaded: result.partsUploaded,\n });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/uploads/:uploadId/complete\",\n inputSchema: completeUploadSchema,\n outputSchema: fileMetadataSchema,\n errorCodes,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n const resolvedConfig = getResolvedConfig();\n try {\n // Rule of Fragno exception: read -> storage I/O -> mutate.\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const providerMismatch = rejectProviderMismatch(\n upload,\n resolvedConfig.storage.name,\n error,\n );\n if (providerMismatch) {\n return providerMismatch;\n }\n\n const inactiveResponse = rejectInactiveUpload(\n {\n status: upload.status as UploadStatus,\n expiresAt: upload.expiresAt,\n },\n error,\n );\n if (inactiveResponse) {\n return inactiveResponse;\n }\n\n let finalizeResult: { sizeBytes?: bigint } | undefined;\n\n if (upload.strategy === \"direct-multipart\") {\n if (!resolvedConfig.storage.completeMultipartUpload) {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n if (!payload.parts || payload.parts.length === 0) {\n return error(\n {\n message: \"Upload invalid state\",\n code: \"UPLOAD_INVALID_STATE\",\n },\n 409,\n );\n }\n\n await resolvedConfig.storage.completeMultipartUpload({\n storageKey: upload.objectKey,\n storageUploadId: upload.storageUploadId ?? \"\",\n parts: payload.parts,\n });\n } else if (resolvedConfig.storage.finalizeUpload) {\n finalizeResult = await resolvedConfig.storage.finalizeUpload({\n storageKey: upload.objectKey,\n expectedSizeBytes: upload.expectedSizeBytes,\n checksum: upload.checksum as UploadChecksum | null,\n });\n }\n\n const completed = await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadCompleteFromSnapshot(\n upload,\n finalizeResult?.sizeBytes ? { sizeBytes: finalizeResult.sizeBytes } : undefined,\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: \"POST\",\n path: \"/uploads/:uploadId/abort\",\n outputSchema: z.object({ ok: z.literal(true) }),\n errorCodes,\n handler: async function ({ pathParams }, { json, error }) {\n const resolvedConfig = getResolvedConfig();\n try {\n // Rule of Fragno exception: read -> storage I/O -> mutate.\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const providerMismatch = rejectProviderMismatch(\n upload,\n resolvedConfig.storage.name,\n error,\n );\n if (providerMismatch) {\n return providerMismatch;\n }\n\n if (\n upload.strategy === \"direct-multipart\" &&\n resolvedConfig.storage.abortMultipartUpload\n ) {\n await resolvedConfig.storage.abortMultipartUpload({\n storageKey: upload.objectKey,\n storageUploadId: upload.storageUploadId ?? \"\",\n });\n }\n\n await this.handlerTx()\n .withServiceCalls(() => [services.markUploadAbortedFromSnapshot(upload)])\n .execute();\n\n return json({ ok: true });\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n\n defineRoute({\n method: \"PUT\",\n path: \"/uploads/:uploadId/content\",\n contentType: \"application/octet-stream\",\n outputSchema: fileMetadataSchema,\n errorCodes,\n handler: async function (context, { json, error }) {\n const { pathParams } = context;\n const resolvedConfig = getResolvedConfig();\n try {\n // Rule of Fragno exception: read -> storage I/O -> mutate.\n const upload = await this.handlerTx()\n .withServiceCalls(() => [services.getUploadStorageInfo(pathParams.uploadId)])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n const providerMismatch = rejectProviderMismatch(\n upload,\n resolvedConfig.storage.name,\n error,\n );\n if (providerMismatch) {\n return providerMismatch;\n }\n\n if (upload.strategy !== \"proxy\") {\n return error({ message: \"Upload invalid state\", code: \"UPLOAD_INVALID_STATE\" }, 409);\n }\n\n const inactiveResponse = rejectInactiveUpload(\n {\n status: upload.status as UploadStatus,\n expiresAt: upload.expiresAt,\n },\n error,\n );\n if (inactiveResponse) {\n return inactiveResponse;\n }\n\n if (!resolvedConfig.storage.writeStream) {\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n let result: Awaited<ReturnType<NonNullable<typeof resolvedConfig.storage.writeStream>>>;\n try {\n result = await resolvedConfig.storage.writeStream({\n storageKey: upload.objectKey,\n body: context.bodyStream(),\n contentType: upload.contentType,\n sizeBytes: upload.expectedSizeBytes,\n });\n } catch {\n await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadFailedFromSnapshot(\n upload,\n \"STORAGE_ERROR\",\n \"Storage upload failed\",\n ),\n ])\n .execute();\n return error({ message: \"Storage error\", code: \"STORAGE_ERROR\" }, 502);\n }\n\n const completed = await this.handlerTx()\n .withServiceCalls(() => [\n services.markUploadCompleteFromSnapshot(\n upload,\n result?.sizeBytes ? { sizeBytes: result.sizeBytes } : undefined,\n ),\n ])\n .transform(({ serviceResult: [done] }) => done)\n .execute();\n\n return json(toFileMetadata(completed.file));\n } catch (err) {\n return handleServiceError(err, error);\n }\n },\n }),\n ];\n },\n);\n"],"mappings":"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"}
|