@vryzel/file-next 0.4.2 → 0.4.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 CHANGED
@@ -159,6 +159,16 @@ if (!listed.ok) throw listed.error;
159
159
 
160
160
  `listFiles` / `listTrash` accept `cursor` + `limit`.
161
161
 
162
+ `createShare` returns `{ token, url }` where `url` is `/api/share/{token}` (your domain, not the bucket). Mount:
163
+
164
+ ```ts
165
+ // app/api/share/[token]/route.ts
166
+ import { createShareRouteHandler } from "@vryzel/file-next/server";
167
+ export const GET = createShareRouteHandler({ store, fs });
168
+ ```
169
+
170
+ The handler streams the object through Next.js. Folders cannot be shared this way. Optional `sharePathPrefix` on `createServerActions` (default `/api/share`).
171
+
162
172
  ### 8. Route handlers (upload / download)
163
173
 
164
174
  ```ts
@@ -231,6 +231,7 @@ var zodErr = (message, parsed) => err(
231
231
  );
232
232
  var createServerActions = (deps) => {
233
233
  const { store, writeThrough, fs, getAuth } = deps;
234
+ const sharePathPrefix = (deps.sharePathPrefix ?? "/api/share").replace(/\/+$/, "");
234
235
  const wrap = (e, code, message) => {
235
236
  if (e instanceof FileSystemError) return e;
236
237
  return new FileSystemError({
@@ -433,10 +434,27 @@ var createServerActions = (deps) => {
433
434
  if (!parsed.success) return zodErr("Invalid createShare input", parsed);
434
435
  try {
435
436
  const auth = await authTenant();
436
- return store.createShare({
437
- tenantId: asTenantId(auth.tenantId),
437
+ const tenantId = asTenantId(auth.tenantId);
438
+ const node = await store.getNode({ tenantId, id: parsed.data.id });
439
+ if (!node.ok) return node;
440
+ if (!node.value || node.value.kind !== "file" || !node.value.s3Key) {
441
+ return err(
442
+ new FileSystemError({
443
+ code: "Conflict",
444
+ message: "Only files can be shared as an openable link",
445
+ retryable: false
446
+ })
447
+ );
448
+ }
449
+ const share = await store.createShare({
450
+ tenantId,
438
451
  nodeId: parsed.data.id
439
452
  });
453
+ if (!share.ok) return share;
454
+ return ok({
455
+ token: share.value.token,
456
+ url: `${sharePathPrefix}/${share.value.token}`
457
+ });
440
458
  } catch (e) {
441
459
  return err(wrap(e, "InternalError", "createShare failed"));
442
460
  }
@@ -635,8 +653,70 @@ var createDownloadRouteHandler = (opts) => {
635
653
  };
636
654
  };
637
655
 
656
+ // src/server/route-handlers/share.ts
657
+ var tokenFromRequest = (req) => {
658
+ const url = new URL(req.url);
659
+ const query = url.searchParams.get("token");
660
+ if (query && query.length > 0) return query;
661
+ const parts = url.pathname.replace(/\/+$/, "").split("/");
662
+ const last = parts[parts.length - 1];
663
+ if (!last || last === "share") return null;
664
+ return last;
665
+ };
666
+ var createShareRouteHandler = (opts) => {
667
+ return async (req) => {
668
+ const token = tokenFromRequest(req);
669
+ if (!token) {
670
+ return Response.json(
671
+ { ok: false, error: { code: "InternalError", message: "Missing share token" } },
672
+ { status: 400 }
673
+ );
674
+ }
675
+ const resolved = await opts.store.resolveShare({ token });
676
+ if (!resolved.ok) {
677
+ return Response.json(
678
+ { ok: false, error: { code: resolved.error.code, message: resolved.error.message } },
679
+ { status: 500 }
680
+ );
681
+ }
682
+ const node = resolved.value;
683
+ if (!node || node.kind !== "file" || !node.s3Key) {
684
+ return Response.json(
685
+ { ok: false, error: { code: "NotFound", message: "Share not found" } },
686
+ { status: 404 }
687
+ );
688
+ }
689
+ const adapter = opts.fs.forTenant(node.tenantId).adapter;
690
+ const rangeHeader = req.headers.get("range") ?? void 0;
691
+ const read = await adapter.read({
692
+ key: asS3Key(node.s3Key),
693
+ range: rangeHeader ?? void 0
694
+ });
695
+ if (!read.ok) {
696
+ return Response.json(
697
+ { ok: false, error: { code: read.error.code, message: read.error.message } },
698
+ { status: 404 }
699
+ );
700
+ }
701
+ const download = new URL(req.url).searchParams.get("download") === "1";
702
+ const headers = new Headers();
703
+ headers.set(
704
+ "Content-Type",
705
+ node.mimeType || read.value.contentType || "application/octet-stream"
706
+ );
707
+ headers.set(
708
+ "Content-Disposition",
709
+ `${download ? "attachment" : "inline"}; filename*=UTF-8''${encodeURIComponent(node.name)}`
710
+ );
711
+ headers.set("Cache-Control", "private, no-store");
712
+ headers.set("Content-Length", String(read.value.body.byteLength));
713
+ return new Response(Buffer.from(read.value.body), { status: 200, headers });
714
+ };
715
+ };
716
+
638
717
  exports.createDownloadRouteHandler = createDownloadRouteHandler;
639
718
  exports.createServerActions = createServerActions;
719
+ exports.createShareRouteHandler = createShareRouteHandler;
640
720
  exports.createUploadRouteHandler = createUploadRouteHandler;
641
721
  //# sourceMappingURL=index.cjs.map
642
722
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/result.ts","../../src/errors/mappers.ts","../../src/errors/index.ts","../../src/types/branded.ts","../../src/server/actions.ts","../../src/server/route-handlers/upload.ts","../../src/server/route-handlers/download.ts"],"names":["err","z","MAX_EXPIRES_IN_SECONDS","DEFAULT_EXPIRES_IN_SECONDS","assertExpiresIn"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Discriminated `Result<T, E>` for typed error returns.\n *\n * Why Result over throw at boundaries:\n * - No `any` at the call site (vs try/catch which loses the type).\n * - `switch (r.ok)` narrows the type in consumer code.\n * - The wire shape `{ ok, value | error }` is JSON-serializable,\n * so it survives the RSC boundary without an extra DTO.\n * - Helpers (`map`, `andThen`, `unwrap`) make the common shapes\n * (chain, bail-out, recover) terse and exhaustive.\n *\n * The default error type is `FileSystemError` (see `@/errors`).\n * Consumers can specialize: `Result<User, ZodError>`.\n *\n * All helpers are pure functions; they do NOT allocate closures in\n * hot paths beyond what the spec demands (no `try`/`catch` wrapping).\n */\n\nimport { FileSystemError } from \"@/errors\";\n\nexport type Result<T, E = FileSystemError> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: E };\n\nexport const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });\n\nexport const err = <E>(error: E): Result<never, E> => ({ ok: false, error });\n\nexport const map = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => U,\n): Result<U, E> => (r.ok ? ok(f(r.value)) : r);\n\nexport const mapErr = <T, E, F>(\n r: Result<T, E>,\n f: (e: E) => F,\n): Result<T, F> => (r.ok ? r : err(f(r.error)));\n\nexport const andThen = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => Result<U, E>,\n): Result<U, E> => (r.ok ? f(r.value) : r);\n\nexport const unwrap = <T, E>(r: Result<T, E>): T => {\n if (r.ok) return r.value;\n throw r.error;\n};\n\nexport const unwrapOr = <T, E>(r: Result<T, E>, fallback: T): T =>\n r.ok ? r.value : fallback;\n","/**\n * Upstream error mappers for FileSystemError.\n *\n * Each mapper is a pure function `(*unknown) -> FileSystemError`.\n * The class re-exposes them as static methods (FileSystemError.fromAws\n * etc.) so callers can pick the import style that fits.\n *\n * Mapping strategy:\n * 1. If the input is already a FileSystemError, return it as-is\n * (we never re-wrap our own errors).\n * 2. Try the most specific signal first: S3 `name`, Postgres\n * SQLSTATE, SQLite extended code.\n * 3. Fall back to the HTTP status code (AWS SDK v3 exposes\n * `$metadata.httpStatusCode`).\n * 4. Last resort: InternalError, retryable, with the original\n * payload in `cause`.\n *\n * Provider-specific codes are preserved on `cause.code` (e.g. S3\n * \"NoSuchKey\", Postgres \"23505\") so callers can still branch on\n * them while the top-level `code` stays in the 11-code spec catalog.\n *\n * Mapping notes (post-C' merge, see\n * `sdd/file-next/decisions/error-codes-deviation`):\n * - S3 `SlowDown` -> QuotaExceeded (broader than RateLimited;\n * SlowDown means reduce request rate, which\n * is conceptually quota pressure, not\n * throttling of a single call).\n * - S3 `BadDigest` -> ChecksumMismatch (checksum verified by\n * S3 on upload did not match the client).\n * - HTTP 429 -> RateLimited (was QuotaExceeded in the\n * pre-C' catalog; RateLimited is the more\n * specific code for throttling responses).\n * - HTTP 408 -> NetworkError (transient transport error).\n * - HTTP 400 / Postgres 23514 / S3 InvalidRequest\n * -> fall through to the 4xx branch (no\n * top-level 400 code in the C' catalog;\n * these inputs are usually caught by the\n * name/SQLSTATE mapping first anyway).\n */\n\nimport { FileSystemError, type FileSystemErrorCode } from \"./index\";\n\n/* ---------------------------------------------------------------- *\n * Mapping tables (private) *\n * ---------------------------------------------------------------- */\n\ninterface CodeMapping {\n code: FileSystemErrorCode;\n retryable: boolean;\n}\n\nconst HTTP_STATUS_TO_CODE: Readonly<Record<number, CodeMapping>> = {\n 401: { code: \"Unauthorized\", retryable: false },\n 403: { code: \"Forbidden\", retryable: false },\n 404: { code: \"NotFound\", retryable: false },\n 408: { code: \"NetworkError\", retryable: true },\n 409: { code: \"Conflict\", retryable: false },\n 413: { code: \"PayloadTooLarge\", retryable: false },\n 415: { code: \"UnsupportedMediaType\", retryable: false },\n 429: { code: \"RateLimited\", retryable: true },\n};\n\nconst AWS_NAME_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n NoSuchKey: { code: \"NotFound\", retryable: false },\n NoSuchBucket: { code: \"NotFound\", retryable: false },\n // v0.2 multipart: unknown/aborted/expired uploadId.\n NoSuchUpload: { code: \"NotFound\", retryable: false },\n AccessDenied: { code: \"Forbidden\", retryable: false },\n SlowDown: { code: \"QuotaExceeded\", retryable: true },\n BadDigest: { code: \"ChecksumMismatch\", retryable: true },\n XAmzContentSHA256Mismatch: { code: \"ChecksumMismatch\", retryable: true },\n NetworkingError: { code: \"NetworkError\", retryable: true },\n TimeoutError: { code: \"NetworkError\", retryable: true },\n};\n\nconst PG_SQLSTATE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n \"23505\": { code: \"Conflict\", retryable: false },\n};\n\nconst SQLITE_CODE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n SQLITE_CONSTRAINT_UNIQUE: { code: \"Conflict\", retryable: false },\n SQLITE_CONSTRAINT_PRIMARYKEY: { code: \"Conflict\", retryable: false },\n};\n\n/* ---------------------------------------------------------------- *\n * Public mappers *\n * ---------------------------------------------------------------- */\n\nconst toCause = (code: string, message: string, extra?: Record<string, unknown>) => ({\n code,\n message,\n ...(extra ?? {}),\n});\n\nconst fallback = (err: unknown): FileSystemError =>\n new FileSystemError({\n code: \"InternalError\",\n message: err instanceof Error ? err.message : String(err),\n retryable: true,\n cause: toCause(\n \"Unknown\",\n err instanceof Error ? err.message : String(err),\n ),\n });\n\nexport const fromAws = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const awsErr = err as {\n name?: unknown;\n message?: unknown;\n $metadata?: { httpStatusCode?: unknown };\n };\n const name = typeof awsErr.name === \"string\" ? awsErr.name : undefined;\n const message =\n typeof awsErr.message === \"string\" ? awsErr.message : `AWS error: ${name ?? \"unknown\"}`;\n const status =\n typeof awsErr.$metadata?.httpStatusCode === \"number\"\n ? awsErr.$metadata.httpStatusCode\n : undefined;\n\n const cause = toCause(\n name ?? (status !== undefined ? String(status) : \"Unknown\"),\n message,\n status !== undefined ? { httpStatusCode: status } : undefined,\n );\n\n // 1) name-based mapping wins (more specific than HTTP status)\n if (name && name in AWS_NAME_TO_CODE) {\n const m = AWS_NAME_TO_CODE[name]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 2) HTTP status mapping\n if (status !== undefined && status in HTTP_STATUS_TO_CODE) {\n const m = HTTP_STATUS_TO_CODE[status]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 3) 5xx bucket\n if (status !== undefined && status >= 500 && status < 600) {\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n }\n\n // 4) anything else 4xx-shaped\n if (status !== undefined && status >= 400 && status < 500) {\n return new FileSystemError({ code: \"Forbidden\", message, retryable: false, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromPg = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const pgErr = err as { code?: unknown; message?: unknown };\n const sqlstate = typeof pgErr.code === \"string\" ? pgErr.code : undefined;\n const message =\n typeof pgErr.message === \"string\" ? pgErr.message : `Postgres error: ${sqlstate ?? \"unknown\"}`;\n const cause = toCause(sqlstate ?? \"Unknown\", message);\n\n if (sqlstate && sqlstate in PG_SQLSTATE_TO_CODE) {\n const m = PG_SQLSTATE_TO_CODE[sqlstate]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromSqlite = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const sqlErr = err as { code?: unknown; message?: unknown };\n const code = typeof sqlErr.code === \"string\" ? sqlErr.code : undefined;\n const message =\n typeof sqlErr.message === \"string\" ? sqlErr.message : `SQLite error: ${code ?? \"unknown\"}`;\n const cause = toCause(code ?? \"Unknown\", message);\n\n if (code && code in SQLITE_CODE_TO_CODE) {\n const m = SQLITE_CODE_TO_CODE[code]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n","/**\n * FileSystemError — the single error class every adapter, store,\n * server action, and route handler in `file-next` returns or throws.\n *\n * Spec reference: requirement \"FileSystemError discriminated union\"\n * in `sdd/file-next/spec`. The 11 codes are the CLOSED set; any\n * provider-specific code (e.g. S3 `NoSuchKey`, Postgres `23505`) is\n * preserved on `cause.code` so callers can still distinguish upstream\n * reasons while the top-level `code` stays in the catalog.\n *\n * The catalog is a merge of spec + impl: the 6 fixed codes\n * (NotFound, Forbidden, Conflict, QuotaExceeded, NetworkError,\n * InternalError) are non-negotiable; the remaining 5 keep the wire\n * aligned with both the HTTP boundary (route handlers map the\n * top-level `code` to a status directly) and the storage boundary\n * (`RateLimited` and `ChecksumMismatch` carry semantics that have\n * no natural HTTP equivalent). See\n * `sdd/file-next/decisions/error-codes-deviation` for the\n * deviation log and rationale.\n *\n * Retryability table is the design's `error-mapping` excerpt; see\n * `sdd/file-next/design` §C. Any future code MUST add an entry in\n * `RETRYABLE_BY_CODE` (the catalog test enforces this).\n *\n * The placeholder from T-006 is replaced by this file in T-007a.\n * The upstream mappers (fromAws / fromPg / fromSqlite) land in T-007b\n * in `mappers.ts`.\n */\n\nexport const FILE_SYSTEM_ERROR_CODES = [\n \"NotFound\",\n \"Forbidden\",\n \"Conflict\",\n \"QuotaExceeded\",\n \"NetworkError\",\n \"InternalError\",\n \"Unauthorized\",\n \"PayloadTooLarge\",\n \"UnsupportedMediaType\",\n \"RateLimited\",\n \"ChecksumMismatch\",\n] as const satisfies readonly string[];\n\nexport type FileSystemErrorCode = (typeof FILE_SYSTEM_ERROR_CODES)[number];\n\nexport const RETRYABLE_BY_CODE: Readonly<Record<FileSystemErrorCode, boolean>> = {\n NotFound: false,\n Forbidden: false,\n Conflict: false,\n QuotaExceeded: true,\n NetworkError: true,\n InternalError: true,\n Unauthorized: false,\n PayloadTooLarge: false,\n UnsupportedMediaType: false,\n RateLimited: true,\n ChecksumMismatch: true,\n};\n\nexport interface FileSystemErrorOptions {\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport interface FileSystemErrorJson {\n name: string;\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport class FileSystemError extends Error {\n readonly code: FileSystemErrorCode;\n readonly retryable: boolean;\n override readonly cause?: { code: string; message: string; [k: string]: unknown };\n\n constructor(opts: FileSystemErrorOptions) {\n super(opts.message);\n this.name = \"FileSystemError\";\n this.code = opts.code;\n this.retryable = opts.retryable;\n if (opts.cause !== undefined) {\n this.cause = opts.cause;\n }\n }\n\n /**\n * Stable JSON shape for RSC pass-through. Error.prototype.message\n * is non-enumerable, so plain `JSON.stringify(err)` would emit `{}`\n * and lose the message + code + retryable flag. `cause` is omitted\n * entirely (not set to undefined) when absent so the shape stays\n * stable for hash-based caches.\n */\n toJSON(): FileSystemErrorJson {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n ...(this.cause !== undefined ? { cause: this.cause } : {}),\n };\n }\n\n /**\n * Mappers from upstream error shapes (AWS SDK v3, node-postgres,\n * better-sqlite3) to FileSystemError. See `./mappers.ts` for the\n * mapping tables. Re-exposed as static methods so callers can pick\n * the import style that fits; the free functions are the canonical\n * implementation.\n */\n static fromAws(err: unknown): FileSystemError {\n // Lazy import via the runtime binding avoids the static-field\n // circular-dep trap in ESM. The mapper file imports this class\n // for instanceof checks; we look up the function at call time.\n return _fromAws(err);\n }\n\n static fromPg(err: unknown): FileSystemError {\n return _fromPg(err);\n }\n\n static fromSqlite(err: unknown): FileSystemError {\n return _fromSqlite(err);\n }\n}\n\n// Imported here as bindings (not values) so the static methods above\n// can resolve them lazily. The actual implementation lives in mappers.ts.\nimport { fromAws as _fromAws, fromPg as _fromPg, fromSqlite as _fromSqlite } from \"./mappers\";\nexport { fromAws, fromPg, fromSqlite } from \"./mappers\";\n","/**\n * Branded string types and their constructors/guards.\n *\n * Brands are TypeScript-only fictions: a `Path` and an `S3Key` are\n * both strings at runtime, but the type system treats them as\n * distinct nominal types so the compiler catches accidental\n * cross-assignment (e.g. passing an S3Key where a TenantId is\n * expected).\n *\n * Conventions:\n * - `as*` is a zero-cost cast: trust the caller, brand the value.\n * Use it at trust boundaries you have already validated.\n * - `assert*` is a runtime guard: throws TypeError on invalid\n * input. Use it at the edge (parsing user/env input).\n *\n * Validation rules are intentionally minimal in v0.1 and can be\n * tightened as the spec evolves. None of them touch the network or\n * allocate; they are safe in hot paths.\n */\n\nexport type Path = string & { readonly __brand: \"Path\" };\nexport type Prefix = string & { readonly __brand: \"Prefix\" };\nexport type S3Key = string & { readonly __brand: \"S3Key\" };\nexport type TenantId = string & { readonly __brand: \"TenantId\" };\nexport type UserId = string & { readonly __brand: \"UserId\" };\n\n/**\n * POSIX file path. Non-empty, '/' is allowed as the root.\n */\nexport const asPath = (s: string): Path => s as Path;\nexport const assertPath = (s: string): Path => {\n if (s.length === 0) {\n throw new TypeError(\"Path must be a non-empty string\");\n }\n return s as Path;\n};\n\n/**\n * S3 prefix. Empty string is the root prefix. Non-empty prefixes\n * MUST end with '/' so concatenation with a key never produces\n * 'usersfile.jpg' by accident.\n */\nexport const asPrefix = (s: string): Prefix => s as Prefix;\nexport const assertPrefix = (s: string): Prefix => {\n if (s.length > 0 && !s.endsWith(\"/\")) {\n throw new TypeError(\n `Prefix must end with \"/\" or be empty: ${JSON.stringify(s)}`,\n );\n }\n return s as Prefix;\n};\n\n/**\n * S3 object key. No leading slash, no empty segments, no '..' hops.\n */\nexport const asS3Key = (s: string): S3Key => s as S3Key;\nexport const assertS3Key = (s: string): S3Key => {\n if (s.length === 0) {\n throw new TypeError(\"S3Key must be a non-empty string\");\n }\n if (s.startsWith(\"/\")) {\n throw new TypeError(\n `S3Key must not start with a slash: ${JSON.stringify(s)}`,\n );\n }\n if (s.includes(\"..\")) {\n throw new TypeError(\n `S3Key must not contain '..' segments: ${JSON.stringify(s)}`,\n );\n }\n return s as S3Key;\n};\n\n/**\n * Tenant identifier. Alphanumerics, dashes, underscores only.\n */\nexport const asTenantId = (s: string): TenantId => s as TenantId;\nexport const assertTenantId = (s: string): TenantId => {\n if (s.length === 0 || !/^[a-zA-Z0-9_-]+$/.test(s)) {\n throw new TypeError(`Invalid TenantId: ${JSON.stringify(s)}`);\n }\n return s as TenantId;\n};\n\n/**\n * Opaque user identifier. Non-empty; the format is provider-defined.\n */\nexport const asUserId = (s: string): UserId => s as UserId;\nexport const assertUserId = (s: string): UserId => {\n if (s.length === 0) {\n throw new TypeError(\"UserId must be a non-empty string\");\n }\n return s as UserId;\n};\n","/**\n * Server actions — tenant comes from getAuth(), never from the client.\n */\nimport { z } from \"zod\";\nimport { ok, err, type Result } from \"@/types/result\";\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key, asTenantId, type TenantId } from \"@/types/branded\";\nimport type { AuthContext } from \"../auth/with-auth\";\nimport type { MetadataStore, FileNode } from \"../metadata/store\";\nimport type { FileSystem } from \"../storage/filesystem\";\nimport type { createWriteThrough } from \"../sync/write-through\";\n\ntype CreateWriteThrough = ReturnType<typeof createWriteThrough>;\n\nconst NodeIdSchema = z.string().min(1, \"id is required\");\nconst PathSchema = z.string().nullable();\n\nexport const ListFilesInputSchema = z.object({\n parentId: PathSchema,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional(),\n});\n\nexport const DeleteFileInputSchema = z.object({\n id: NodeIdSchema,\n recursive: z.boolean().optional(),\n});\n\nexport const MoveFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const CopyFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const SetMetadataInputSchema = z.object({\n id: NodeIdSchema,\n metadata: z.record(z.string()),\n replace: z.boolean().optional(),\n});\n\nexport const CreateFolderInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n});\n\nexport const PrepareUploadInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().min(1),\n contentLength: z.number().int().nonnegative(),\n});\n\nexport const ConfirmUploadInputSchema = z.object({\n id: NodeIdSchema,\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n});\n\nexport const SearchFilesInputSchema = z.object({\n query: z.string(),\n parentId: z.string().optional(),\n limit: z.number().int().positive().optional(),\n});\n\nexport const RestoreNodeInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const CreateShareInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const ResolveShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nexport const RevokeShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nconst zodErr = (message: string, parsed: z.SafeParseError<unknown>) =>\n err(\n new FileSystemError({\n code: \"InternalError\",\n message,\n retryable: false,\n cause: { code: \"ZodError\", message: parsed.error.message, issues: parsed.error.issues },\n }),\n );\n\nexport interface ServerActionsDeps {\n readonly store: MetadataStore;\n readonly writeThrough: CreateWriteThrough;\n readonly fs: FileSystem;\n readonly getAuth: () => AuthContext | Promise<AuthContext>;\n}\n\nexport const createServerActions = (deps: ServerActionsDeps) => {\n const { store, writeThrough, fs, getAuth } = deps;\n\n const wrap = (e: unknown, code: FileSystemError[\"code\"], message: string): FileSystemError => {\n if (e instanceof FileSystemError) return e;\n return new FileSystemError({\n code,\n message: `${message}: ${e instanceof Error ? e.message : String(e)}`,\n retryable: true,\n });\n };\n\n const authTenant = async (): Promise<AuthContext> => getAuth();\n\n const listFiles = async (\n input: z.infer<typeof ListFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = ListFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid listFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.listChildren({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n cursor: parsed.data.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listFiles failed\"));\n }\n };\n\n const deleteFile = async (\n input: z.infer<typeof DeleteFileInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = DeleteFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid deleteFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.deleteThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n recursive: parsed.data.recursive,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"deleteFile failed\"));\n }\n };\n\n const moveFile = async (\n input: z.infer<typeof MoveFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = MoveFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid moveFile input\", parsed);\n try {\n const auth = await authTenant();\n return store.moveNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"moveFile failed\"));\n }\n };\n\n const copyFile = async (\n input: z.infer<typeof CopyFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CopyFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid copyFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.copyThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"copyFile failed\"));\n }\n };\n\n const setMetadata = async (\n input: z.infer<typeof SetMetadataInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = SetMetadataInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid setMetadata input\", parsed);\n try {\n const auth = await authTenant();\n return store.updateMetadata({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n metadata: parsed.data.metadata,\n replace: parsed.data.replace,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"setMetadata failed\"));\n }\n };\n\n const createFolder = async (\n input: z.infer<typeof CreateFolderInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CreateFolderInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createFolder input\", parsed);\n try {\n const auth = await authTenant();\n return store.createNode({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n kind: \"folder\",\n size: 0,\n mimeType: \"\",\n s3Key: \"\",\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createFolder failed\"));\n }\n };\n\n const prepareUpload = async (\n input: z.infer<typeof PrepareUploadInputSchema>,\n ): Promise<Result<PrepareUploadOutput, FileSystemError>> => {\n const parsed = PrepareUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid prepareUpload input\", parsed);\n try {\n const auth = await authTenant();\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const signed = await fs.forTenant(auth.tenantId).adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: parsed.data.contentType,\n expiresIn: 900,\n });\n if (!signed.ok) return signed;\n return ok({\n id,\n key: id,\n url: signed.value.url,\n method: signed.value.method,\n headers: signed.value.requiredHeaders ?? {},\n expiresAt: new Date(Date.now() + 900_000).toISOString(),\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"prepareUpload failed\"));\n }\n };\n\n const confirmUpload = async (\n input: z.infer<typeof ConfirmUploadInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = ConfirmUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid confirmUpload input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.confirmUpload({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n contentType: parsed.data.contentType,\n size: parsed.data.size,\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"confirmUpload failed\"));\n }\n };\n\n const searchFiles = async (\n input: z.infer<typeof SearchFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = SearchFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid searchFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.search({\n tenantId: asTenantId(auth.tenantId),\n query: parsed.data.query,\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"searchFiles failed\"));\n }\n };\n\n const listTrash = async (\n input: { limit?: number; cursor?: string } = {},\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n try {\n const auth = await authTenant();\n return store.listTrash({\n tenantId: asTenantId(auth.tenantId),\n limit: input.limit,\n cursor: input.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listTrash failed\"));\n }\n };\n\n const restoreNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid restoreNode input\", parsed);\n try {\n const auth = await authTenant();\n return store.restoreNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"restoreNode failed\"));\n }\n };\n\n const purgeNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid purgeNode input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.purgeThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"purgeNode failed\"));\n }\n };\n\n const createShare = async (\n input: z.infer<typeof CreateShareInputSchema>,\n ): Promise<Result<{ token: string }, FileSystemError>> => {\n const parsed = CreateShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createShare input\", parsed);\n try {\n const auth = await authTenant();\n return store.createShare({\n tenantId: asTenantId(auth.tenantId),\n nodeId: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createShare failed\"));\n }\n };\n\n const resolveShare = async (\n input: z.infer<typeof ResolveShareInputSchema>,\n ): Promise<Result<FileNode | null, FileSystemError>> => {\n const parsed = ResolveShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid resolveShare input\", parsed);\n try {\n return store.resolveShare({ token: parsed.data.token });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"resolveShare failed\"));\n }\n };\n\n const revokeShare = async (\n input: z.infer<typeof RevokeShareInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RevokeShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid revokeShare input\", parsed);\n try {\n const auth = await authTenant();\n return store.revokeShare({\n tenantId: asTenantId(auth.tenantId),\n token: parsed.data.token,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"revokeShare failed\"));\n }\n };\n\n return {\n listFiles,\n deleteFile,\n moveFile,\n copyFile,\n setMetadata,\n createFolder,\n prepareUpload,\n confirmUpload,\n searchFiles,\n listTrash,\n restoreNode,\n purgeNode,\n createShare,\n resolveShare,\n revokeShare,\n };\n};\n\nexport interface ListFilesOutput {\n readonly items: ReadonlyArray<FileNode>;\n readonly nextCursor?: string;\n}\n\nexport interface PrepareUploadOutput {\n readonly id: string;\n readonly key: string;\n readonly url: string;\n readonly method: \"PUT\" | \"POST\";\n readonly headers: Record<string, string>;\n readonly expiresAt: string;\n}\n\nexport type { TenantId };\n","/**\n * `createUploadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL upload flow.\n *\n * The client flow:\n * 1. Client POSTs `{ key, contentType, contentLength }` to this\n * route (typically `/api/files/upload`).\n * 2. Route validates `contentLength` against `maxBytes` (413) and\n * `contentType` against `allowedContentTypes` (415). No URL\n * is signed on a rejected request.\n * 3. Route calls `fs.adapter.createPresignedUploadUrl({ key,\n * contentType, expiresIn })` and returns `{ url, key,\n * expiresAt }`.\n * 4. Client PUTs the file body to the signed URL (bypassing the\n * Next.js server entirely).\n *\n * Spec scenarios: `route-handlers#1` (maxBytes), `route-handlers#2`\n * (allowedContentTypes).\n *\n * Construction-time validation: `expiresIn` is validated when the\n * factory is called (synchronous throw), per decision\n * `sdd/file-next/design/decision/expiresin-cap-timing`. A handler\n * built with `expiresIn: 30 * 86400` should never reach runtime —\n * the developer should see the error at server startup, not on\n * the first user request.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\n/**\n * Convert a glob pattern (`image/*`) to a regex; convert a literal\n * (`image/png`) to an exact match. Both forms are common in\n * `allowedContentTypes` arrays.\n */\nconst matchesContentType = (pattern: string, actual: string): boolean => {\n if (pattern === actual) return true;\n if (pattern.endsWith(\"/*\")) {\n const prefix = pattern.slice(0, -1); // \"image/*\" → \"image/\"\n return actual.startsWith(prefix);\n }\n return false;\n};\n\nexport interface CreateUploadRouteHandlerOptions {\n readonly fs: FileSystem;\n /** Resolve the caller. 401 when it returns null. */\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Reject requests whose `contentLength` exceeds this. Omit for no cap. */\n readonly maxBytes?: number;\n /**\n * Reject requests whose `contentType` is not in this list.\n * Each entry is a literal (`image/png`) or a wildcard (`image/*`).\n * Omit for no restriction.\n */\n readonly allowedContentTypes?: ReadonlyArray<string>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface UploadRouteHandlerRequest {\n key: string;\n contentType: string;\n contentLength: number;\n}\n\nexport interface UploadRouteHandlerResult {\n url: string;\n key: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range. The top-level code stays in the\n * closed 11-code catalog; the specific reason lives on `cause`.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned upload URL after validating the request.\n */\nexport const createUploadRouteHandler = (\n opts: CreateUploadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n // Construction-time validation: fail-fast on misconfiguration.\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n let body: UploadRouteHandlerRequest;\n try {\n body = (await req.json()) as UploadRouteHandlerRequest;\n } catch {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Request body must be valid JSON\" } },\n { status: 400 },\n );\n }\n\n // 1. maxBytes — reject BEFORE signing\n if (typeof opts.maxBytes === \"number\" && body.contentLength > opts.maxBytes) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"PayloadTooLarge\",\n message: `contentLength ${body.contentLength} exceeds maxBytes ${opts.maxBytes}`,\n },\n },\n { status: 413 },\n );\n }\n\n // 2. allowedContentTypes — reject BEFORE signing\n if (opts.allowedContentTypes && opts.allowedContentTypes.length > 0) {\n const allowed = opts.allowedContentTypes.some((p) => matchesContentType(p, body.contentType));\n if (!allowed) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"UnsupportedMediaType\",\n message: `contentType \"${body.contentType}\" is not in the allowed list`,\n },\n },\n { status: 415 },\n );\n }\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const r = await fs.adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: body.contentType,\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: {\n url: r.value.url,\n key: id,\n id,\n method: r.value.method,\n headers: r.value.requiredHeaders ?? {},\n expiresAt,\n },\n });\n };\n};\n","/**\n * `createDownloadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL download flow.\n *\n * The client flow:\n * 1. Client GETs `/api/files/download?key=uploads/report.pdf`.\n * 2. Route calls `fs.adapter.createPresignedDownloadUrl({ key,\n * expiresIn })` and returns `{ url, expiresAt }`.\n * 3. Client GETs the signed URL (bypassing the Next.js server).\n *\n * Spec scenario: `route-handlers#3` — `X-Amz-Expires=900` is present\n * in the signed URL and `expiresAt` is `now + 900s`.\n *\n * Construction-time validation: same `expiresIn` policy as the\n * upload handler (see `expiresin-cap-timing` decision). The cap\n * lives at the factory level, not the adapter, so a misconfigured\n * handler fails fast at server startup.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\nexport interface CreateDownloadRouteHandlerOptions {\n readonly fs: FileSystem;\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface DownloadRouteHandlerResult {\n url: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned GET URL.\n *\n * The `key` is read from the `?key=` query param. The handler does\n * NOT do any body / content-type / size validation (downloads\n * don't have those concerns); the only chokepoint is the\n * construction-time `expiresIn` cap.\n */\nexport const createDownloadRouteHandler = (\n opts: CreateDownloadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n const url = new URL(req.url);\n const key = url.searchParams.get(\"key\");\n if (!key) {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Missing required query param: key\" } },\n { status: 400 },\n );\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const r = await fs.adapter.createPresignedDownloadUrl({\n key: asS3Key(key),\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: { url: r.value.url, expiresAt },\n });\n };\n};\n"]}
1
+ {"version":3,"sources":["../../src/types/result.ts","../../src/errors/mappers.ts","../../src/errors/index.ts","../../src/types/branded.ts","../../src/server/actions.ts","../../src/server/route-handlers/upload.ts","../../src/server/route-handlers/download.ts","../../src/server/route-handlers/share.ts"],"names":["err","z","MAX_EXPIRES_IN_SECONDS","DEFAULT_EXPIRES_IN_SECONDS","assertExpiresIn"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Discriminated `Result<T, E>` for typed error returns.\n *\n * Why Result over throw at boundaries:\n * - No `any` at the call site (vs try/catch which loses the type).\n * - `switch (r.ok)` narrows the type in consumer code.\n * - The wire shape `{ ok, value | error }` is JSON-serializable,\n * so it survives the RSC boundary without an extra DTO.\n * - Helpers (`map`, `andThen`, `unwrap`) make the common shapes\n * (chain, bail-out, recover) terse and exhaustive.\n *\n * The default error type is `FileSystemError` (see `@/errors`).\n * Consumers can specialize: `Result<User, ZodError>`.\n *\n * All helpers are pure functions; they do NOT allocate closures in\n * hot paths beyond what the spec demands (no `try`/`catch` wrapping).\n */\n\nimport { FileSystemError } from \"@/errors\";\n\nexport type Result<T, E = FileSystemError> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: E };\n\nexport const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });\n\nexport const err = <E>(error: E): Result<never, E> => ({ ok: false, error });\n\nexport const map = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => U,\n): Result<U, E> => (r.ok ? ok(f(r.value)) : r);\n\nexport const mapErr = <T, E, F>(\n r: Result<T, E>,\n f: (e: E) => F,\n): Result<T, F> => (r.ok ? r : err(f(r.error)));\n\nexport const andThen = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => Result<U, E>,\n): Result<U, E> => (r.ok ? f(r.value) : r);\n\nexport const unwrap = <T, E>(r: Result<T, E>): T => {\n if (r.ok) return r.value;\n throw r.error;\n};\n\nexport const unwrapOr = <T, E>(r: Result<T, E>, fallback: T): T =>\n r.ok ? r.value : fallback;\n","/**\n * Upstream error mappers for FileSystemError.\n *\n * Each mapper is a pure function `(*unknown) -> FileSystemError`.\n * The class re-exposes them as static methods (FileSystemError.fromAws\n * etc.) so callers can pick the import style that fits.\n *\n * Mapping strategy:\n * 1. If the input is already a FileSystemError, return it as-is\n * (we never re-wrap our own errors).\n * 2. Try the most specific signal first: S3 `name`, Postgres\n * SQLSTATE, SQLite extended code.\n * 3. Fall back to the HTTP status code (AWS SDK v3 exposes\n * `$metadata.httpStatusCode`).\n * 4. Last resort: InternalError, retryable, with the original\n * payload in `cause`.\n *\n * Provider-specific codes are preserved on `cause.code` (e.g. S3\n * \"NoSuchKey\", Postgres \"23505\") so callers can still branch on\n * them while the top-level `code` stays in the 11-code spec catalog.\n *\n * Mapping notes (post-C' merge, see\n * `sdd/file-next/decisions/error-codes-deviation`):\n * - S3 `SlowDown` -> QuotaExceeded (broader than RateLimited;\n * SlowDown means reduce request rate, which\n * is conceptually quota pressure, not\n * throttling of a single call).\n * - S3 `BadDigest` -> ChecksumMismatch (checksum verified by\n * S3 on upload did not match the client).\n * - HTTP 429 -> RateLimited (was QuotaExceeded in the\n * pre-C' catalog; RateLimited is the more\n * specific code for throttling responses).\n * - HTTP 408 -> NetworkError (transient transport error).\n * - HTTP 400 / Postgres 23514 / S3 InvalidRequest\n * -> fall through to the 4xx branch (no\n * top-level 400 code in the C' catalog;\n * these inputs are usually caught by the\n * name/SQLSTATE mapping first anyway).\n */\n\nimport { FileSystemError, type FileSystemErrorCode } from \"./index\";\n\n/* ---------------------------------------------------------------- *\n * Mapping tables (private) *\n * ---------------------------------------------------------------- */\n\ninterface CodeMapping {\n code: FileSystemErrorCode;\n retryable: boolean;\n}\n\nconst HTTP_STATUS_TO_CODE: Readonly<Record<number, CodeMapping>> = {\n 401: { code: \"Unauthorized\", retryable: false },\n 403: { code: \"Forbidden\", retryable: false },\n 404: { code: \"NotFound\", retryable: false },\n 408: { code: \"NetworkError\", retryable: true },\n 409: { code: \"Conflict\", retryable: false },\n 413: { code: \"PayloadTooLarge\", retryable: false },\n 415: { code: \"UnsupportedMediaType\", retryable: false },\n 429: { code: \"RateLimited\", retryable: true },\n};\n\nconst AWS_NAME_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n NoSuchKey: { code: \"NotFound\", retryable: false },\n NoSuchBucket: { code: \"NotFound\", retryable: false },\n // v0.2 multipart: unknown/aborted/expired uploadId.\n NoSuchUpload: { code: \"NotFound\", retryable: false },\n AccessDenied: { code: \"Forbidden\", retryable: false },\n SlowDown: { code: \"QuotaExceeded\", retryable: true },\n BadDigest: { code: \"ChecksumMismatch\", retryable: true },\n XAmzContentSHA256Mismatch: { code: \"ChecksumMismatch\", retryable: true },\n NetworkingError: { code: \"NetworkError\", retryable: true },\n TimeoutError: { code: \"NetworkError\", retryable: true },\n};\n\nconst PG_SQLSTATE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n \"23505\": { code: \"Conflict\", retryable: false },\n};\n\nconst SQLITE_CODE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n SQLITE_CONSTRAINT_UNIQUE: { code: \"Conflict\", retryable: false },\n SQLITE_CONSTRAINT_PRIMARYKEY: { code: \"Conflict\", retryable: false },\n};\n\n/* ---------------------------------------------------------------- *\n * Public mappers *\n * ---------------------------------------------------------------- */\n\nconst toCause = (code: string, message: string, extra?: Record<string, unknown>) => ({\n code,\n message,\n ...(extra ?? {}),\n});\n\nconst fallback = (err: unknown): FileSystemError =>\n new FileSystemError({\n code: \"InternalError\",\n message: err instanceof Error ? err.message : String(err),\n retryable: true,\n cause: toCause(\n \"Unknown\",\n err instanceof Error ? err.message : String(err),\n ),\n });\n\nexport const fromAws = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const awsErr = err as {\n name?: unknown;\n message?: unknown;\n $metadata?: { httpStatusCode?: unknown };\n };\n const name = typeof awsErr.name === \"string\" ? awsErr.name : undefined;\n const message =\n typeof awsErr.message === \"string\" ? awsErr.message : `AWS error: ${name ?? \"unknown\"}`;\n const status =\n typeof awsErr.$metadata?.httpStatusCode === \"number\"\n ? awsErr.$metadata.httpStatusCode\n : undefined;\n\n const cause = toCause(\n name ?? (status !== undefined ? String(status) : \"Unknown\"),\n message,\n status !== undefined ? { httpStatusCode: status } : undefined,\n );\n\n // 1) name-based mapping wins (more specific than HTTP status)\n if (name && name in AWS_NAME_TO_CODE) {\n const m = AWS_NAME_TO_CODE[name]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 2) HTTP status mapping\n if (status !== undefined && status in HTTP_STATUS_TO_CODE) {\n const m = HTTP_STATUS_TO_CODE[status]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 3) 5xx bucket\n if (status !== undefined && status >= 500 && status < 600) {\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n }\n\n // 4) anything else 4xx-shaped\n if (status !== undefined && status >= 400 && status < 500) {\n return new FileSystemError({ code: \"Forbidden\", message, retryable: false, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromPg = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const pgErr = err as { code?: unknown; message?: unknown };\n const sqlstate = typeof pgErr.code === \"string\" ? pgErr.code : undefined;\n const message =\n typeof pgErr.message === \"string\" ? pgErr.message : `Postgres error: ${sqlstate ?? \"unknown\"}`;\n const cause = toCause(sqlstate ?? \"Unknown\", message);\n\n if (sqlstate && sqlstate in PG_SQLSTATE_TO_CODE) {\n const m = PG_SQLSTATE_TO_CODE[sqlstate]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromSqlite = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const sqlErr = err as { code?: unknown; message?: unknown };\n const code = typeof sqlErr.code === \"string\" ? sqlErr.code : undefined;\n const message =\n typeof sqlErr.message === \"string\" ? sqlErr.message : `SQLite error: ${code ?? \"unknown\"}`;\n const cause = toCause(code ?? \"Unknown\", message);\n\n if (code && code in SQLITE_CODE_TO_CODE) {\n const m = SQLITE_CODE_TO_CODE[code]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n","/**\n * FileSystemError — the single error class every adapter, store,\n * server action, and route handler in `file-next` returns or throws.\n *\n * Spec reference: requirement \"FileSystemError discriminated union\"\n * in `sdd/file-next/spec`. The 11 codes are the CLOSED set; any\n * provider-specific code (e.g. S3 `NoSuchKey`, Postgres `23505`) is\n * preserved on `cause.code` so callers can still distinguish upstream\n * reasons while the top-level `code` stays in the catalog.\n *\n * The catalog is a merge of spec + impl: the 6 fixed codes\n * (NotFound, Forbidden, Conflict, QuotaExceeded, NetworkError,\n * InternalError) are non-negotiable; the remaining 5 keep the wire\n * aligned with both the HTTP boundary (route handlers map the\n * top-level `code` to a status directly) and the storage boundary\n * (`RateLimited` and `ChecksumMismatch` carry semantics that have\n * no natural HTTP equivalent). See\n * `sdd/file-next/decisions/error-codes-deviation` for the\n * deviation log and rationale.\n *\n * Retryability table is the design's `error-mapping` excerpt; see\n * `sdd/file-next/design` §C. Any future code MUST add an entry in\n * `RETRYABLE_BY_CODE` (the catalog test enforces this).\n *\n * The placeholder from T-006 is replaced by this file in T-007a.\n * The upstream mappers (fromAws / fromPg / fromSqlite) land in T-007b\n * in `mappers.ts`.\n */\n\nexport const FILE_SYSTEM_ERROR_CODES = [\n \"NotFound\",\n \"Forbidden\",\n \"Conflict\",\n \"QuotaExceeded\",\n \"NetworkError\",\n \"InternalError\",\n \"Unauthorized\",\n \"PayloadTooLarge\",\n \"UnsupportedMediaType\",\n \"RateLimited\",\n \"ChecksumMismatch\",\n] as const satisfies readonly string[];\n\nexport type FileSystemErrorCode = (typeof FILE_SYSTEM_ERROR_CODES)[number];\n\nexport const RETRYABLE_BY_CODE: Readonly<Record<FileSystemErrorCode, boolean>> = {\n NotFound: false,\n Forbidden: false,\n Conflict: false,\n QuotaExceeded: true,\n NetworkError: true,\n InternalError: true,\n Unauthorized: false,\n PayloadTooLarge: false,\n UnsupportedMediaType: false,\n RateLimited: true,\n ChecksumMismatch: true,\n};\n\nexport interface FileSystemErrorOptions {\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport interface FileSystemErrorJson {\n name: string;\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport class FileSystemError extends Error {\n readonly code: FileSystemErrorCode;\n readonly retryable: boolean;\n override readonly cause?: { code: string; message: string; [k: string]: unknown };\n\n constructor(opts: FileSystemErrorOptions) {\n super(opts.message);\n this.name = \"FileSystemError\";\n this.code = opts.code;\n this.retryable = opts.retryable;\n if (opts.cause !== undefined) {\n this.cause = opts.cause;\n }\n }\n\n /**\n * Stable JSON shape for RSC pass-through. Error.prototype.message\n * is non-enumerable, so plain `JSON.stringify(err)` would emit `{}`\n * and lose the message + code + retryable flag. `cause` is omitted\n * entirely (not set to undefined) when absent so the shape stays\n * stable for hash-based caches.\n */\n toJSON(): FileSystemErrorJson {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n ...(this.cause !== undefined ? { cause: this.cause } : {}),\n };\n }\n\n /**\n * Mappers from upstream error shapes (AWS SDK v3, node-postgres,\n * better-sqlite3) to FileSystemError. See `./mappers.ts` for the\n * mapping tables. Re-exposed as static methods so callers can pick\n * the import style that fits; the free functions are the canonical\n * implementation.\n */\n static fromAws(err: unknown): FileSystemError {\n // Lazy import via the runtime binding avoids the static-field\n // circular-dep trap in ESM. The mapper file imports this class\n // for instanceof checks; we look up the function at call time.\n return _fromAws(err);\n }\n\n static fromPg(err: unknown): FileSystemError {\n return _fromPg(err);\n }\n\n static fromSqlite(err: unknown): FileSystemError {\n return _fromSqlite(err);\n }\n}\n\n// Imported here as bindings (not values) so the static methods above\n// can resolve them lazily. The actual implementation lives in mappers.ts.\nimport { fromAws as _fromAws, fromPg as _fromPg, fromSqlite as _fromSqlite } from \"./mappers\";\nexport { fromAws, fromPg, fromSqlite } from \"./mappers\";\n","/**\n * Branded string types and their constructors/guards.\n *\n * Brands are TypeScript-only fictions: a `Path` and an `S3Key` are\n * both strings at runtime, but the type system treats them as\n * distinct nominal types so the compiler catches accidental\n * cross-assignment (e.g. passing an S3Key where a TenantId is\n * expected).\n *\n * Conventions:\n * - `as*` is a zero-cost cast: trust the caller, brand the value.\n * Use it at trust boundaries you have already validated.\n * - `assert*` is a runtime guard: throws TypeError on invalid\n * input. Use it at the edge (parsing user/env input).\n *\n * Validation rules are intentionally minimal in v0.1 and can be\n * tightened as the spec evolves. None of them touch the network or\n * allocate; they are safe in hot paths.\n */\n\nexport type Path = string & { readonly __brand: \"Path\" };\nexport type Prefix = string & { readonly __brand: \"Prefix\" };\nexport type S3Key = string & { readonly __brand: \"S3Key\" };\nexport type TenantId = string & { readonly __brand: \"TenantId\" };\nexport type UserId = string & { readonly __brand: \"UserId\" };\n\n/**\n * POSIX file path. Non-empty, '/' is allowed as the root.\n */\nexport const asPath = (s: string): Path => s as Path;\nexport const assertPath = (s: string): Path => {\n if (s.length === 0) {\n throw new TypeError(\"Path must be a non-empty string\");\n }\n return s as Path;\n};\n\n/**\n * S3 prefix. Empty string is the root prefix. Non-empty prefixes\n * MUST end with '/' so concatenation with a key never produces\n * 'usersfile.jpg' by accident.\n */\nexport const asPrefix = (s: string): Prefix => s as Prefix;\nexport const assertPrefix = (s: string): Prefix => {\n if (s.length > 0 && !s.endsWith(\"/\")) {\n throw new TypeError(\n `Prefix must end with \"/\" or be empty: ${JSON.stringify(s)}`,\n );\n }\n return s as Prefix;\n};\n\n/**\n * S3 object key. No leading slash, no empty segments, no '..' hops.\n */\nexport const asS3Key = (s: string): S3Key => s as S3Key;\nexport const assertS3Key = (s: string): S3Key => {\n if (s.length === 0) {\n throw new TypeError(\"S3Key must be a non-empty string\");\n }\n if (s.startsWith(\"/\")) {\n throw new TypeError(\n `S3Key must not start with a slash: ${JSON.stringify(s)}`,\n );\n }\n if (s.includes(\"..\")) {\n throw new TypeError(\n `S3Key must not contain '..' segments: ${JSON.stringify(s)}`,\n );\n }\n return s as S3Key;\n};\n\n/**\n * Tenant identifier. Alphanumerics, dashes, underscores only.\n */\nexport const asTenantId = (s: string): TenantId => s as TenantId;\nexport const assertTenantId = (s: string): TenantId => {\n if (s.length === 0 || !/^[a-zA-Z0-9_-]+$/.test(s)) {\n throw new TypeError(`Invalid TenantId: ${JSON.stringify(s)}`);\n }\n return s as TenantId;\n};\n\n/**\n * Opaque user identifier. Non-empty; the format is provider-defined.\n */\nexport const asUserId = (s: string): UserId => s as UserId;\nexport const assertUserId = (s: string): UserId => {\n if (s.length === 0) {\n throw new TypeError(\"UserId must be a non-empty string\");\n }\n return s as UserId;\n};\n","/**\n * Server actions — tenant comes from getAuth(), never from the client.\n */\nimport { z } from \"zod\";\nimport { ok, err, type Result } from \"@/types/result\";\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key, asTenantId, type TenantId } from \"@/types/branded\";\nimport type { AuthContext } from \"../auth/with-auth\";\nimport type { MetadataStore, FileNode } from \"../metadata/store\";\nimport type { FileSystem } from \"../storage/filesystem\";\nimport type { createWriteThrough } from \"../sync/write-through\";\n\ntype CreateWriteThrough = ReturnType<typeof createWriteThrough>;\n\nconst NodeIdSchema = z.string().min(1, \"id is required\");\nconst PathSchema = z.string().nullable();\n\nexport const ListFilesInputSchema = z.object({\n parentId: PathSchema,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional(),\n});\n\nexport const DeleteFileInputSchema = z.object({\n id: NodeIdSchema,\n recursive: z.boolean().optional(),\n});\n\nexport const MoveFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const CopyFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const SetMetadataInputSchema = z.object({\n id: NodeIdSchema,\n metadata: z.record(z.string()),\n replace: z.boolean().optional(),\n});\n\nexport const CreateFolderInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n});\n\nexport const PrepareUploadInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().min(1),\n contentLength: z.number().int().nonnegative(),\n});\n\nexport const ConfirmUploadInputSchema = z.object({\n id: NodeIdSchema,\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n});\n\nexport const SearchFilesInputSchema = z.object({\n query: z.string(),\n parentId: z.string().optional(),\n limit: z.number().int().positive().optional(),\n});\n\nexport const RestoreNodeInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const CreateShareInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const ResolveShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nexport const RevokeShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nconst zodErr = (message: string, parsed: z.SafeParseError<unknown>) =>\n err(\n new FileSystemError({\n code: \"InternalError\",\n message,\n retryable: false,\n cause: { code: \"ZodError\", message: parsed.error.message, issues: parsed.error.issues },\n }),\n );\n\nexport interface ServerActionsDeps {\n readonly store: MetadataStore;\n readonly writeThrough: CreateWriteThrough;\n readonly fs: FileSystem;\n readonly getAuth: () => AuthContext | Promise<AuthContext>;\n /** App path prefix for share links. Default `/api/share`. */\n readonly sharePathPrefix?: string;\n}\n\nexport const createServerActions = (deps: ServerActionsDeps) => {\n const { store, writeThrough, fs, getAuth } = deps;\n const sharePathPrefix = (deps.sharePathPrefix ?? \"/api/share\").replace(/\\/+$/, \"\");\n\n const wrap = (e: unknown, code: FileSystemError[\"code\"], message: string): FileSystemError => {\n if (e instanceof FileSystemError) return e;\n return new FileSystemError({\n code,\n message: `${message}: ${e instanceof Error ? e.message : String(e)}`,\n retryable: true,\n });\n };\n\n const authTenant = async (): Promise<AuthContext> => getAuth();\n\n const listFiles = async (\n input: z.infer<typeof ListFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = ListFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid listFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.listChildren({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n cursor: parsed.data.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listFiles failed\"));\n }\n };\n\n const deleteFile = async (\n input: z.infer<typeof DeleteFileInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = DeleteFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid deleteFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.deleteThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n recursive: parsed.data.recursive,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"deleteFile failed\"));\n }\n };\n\n const moveFile = async (\n input: z.infer<typeof MoveFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = MoveFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid moveFile input\", parsed);\n try {\n const auth = await authTenant();\n return store.moveNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"moveFile failed\"));\n }\n };\n\n const copyFile = async (\n input: z.infer<typeof CopyFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CopyFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid copyFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.copyThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"copyFile failed\"));\n }\n };\n\n const setMetadata = async (\n input: z.infer<typeof SetMetadataInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = SetMetadataInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid setMetadata input\", parsed);\n try {\n const auth = await authTenant();\n return store.updateMetadata({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n metadata: parsed.data.metadata,\n replace: parsed.data.replace,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"setMetadata failed\"));\n }\n };\n\n const createFolder = async (\n input: z.infer<typeof CreateFolderInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CreateFolderInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createFolder input\", parsed);\n try {\n const auth = await authTenant();\n return store.createNode({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n kind: \"folder\",\n size: 0,\n mimeType: \"\",\n s3Key: \"\",\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createFolder failed\"));\n }\n };\n\n const prepareUpload = async (\n input: z.infer<typeof PrepareUploadInputSchema>,\n ): Promise<Result<PrepareUploadOutput, FileSystemError>> => {\n const parsed = PrepareUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid prepareUpload input\", parsed);\n try {\n const auth = await authTenant();\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const signed = await fs.forTenant(auth.tenantId).adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: parsed.data.contentType,\n expiresIn: 900,\n });\n if (!signed.ok) return signed;\n return ok({\n id,\n key: id,\n url: signed.value.url,\n method: signed.value.method,\n headers: signed.value.requiredHeaders ?? {},\n expiresAt: new Date(Date.now() + 900_000).toISOString(),\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"prepareUpload failed\"));\n }\n };\n\n const confirmUpload = async (\n input: z.infer<typeof ConfirmUploadInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = ConfirmUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid confirmUpload input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.confirmUpload({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n contentType: parsed.data.contentType,\n size: parsed.data.size,\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"confirmUpload failed\"));\n }\n };\n\n const searchFiles = async (\n input: z.infer<typeof SearchFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = SearchFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid searchFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.search({\n tenantId: asTenantId(auth.tenantId),\n query: parsed.data.query,\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"searchFiles failed\"));\n }\n };\n\n const listTrash = async (\n input: { limit?: number; cursor?: string } = {},\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n try {\n const auth = await authTenant();\n return store.listTrash({\n tenantId: asTenantId(auth.tenantId),\n limit: input.limit,\n cursor: input.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listTrash failed\"));\n }\n };\n\n const restoreNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid restoreNode input\", parsed);\n try {\n const auth = await authTenant();\n return store.restoreNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"restoreNode failed\"));\n }\n };\n\n const purgeNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid purgeNode input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.purgeThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"purgeNode failed\"));\n }\n };\n\n const createShare = async (\n input: z.infer<typeof CreateShareInputSchema>,\n ): Promise<Result<{ token: string; url: string }, FileSystemError>> => {\n const parsed = CreateShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createShare input\", parsed);\n try {\n const auth = await authTenant();\n const tenantId = asTenantId(auth.tenantId);\n const node = await store.getNode({ tenantId, id: parsed.data.id });\n if (!node.ok) return node;\n if (!node.value || node.value.kind !== \"file\" || !node.value.s3Key) {\n return err(\n new FileSystemError({\n code: \"Conflict\",\n message: \"Only files can be shared as an openable link\",\n retryable: false,\n }),\n );\n }\n const share = await store.createShare({\n tenantId,\n nodeId: parsed.data.id,\n });\n if (!share.ok) return share;\n return ok({\n token: share.value.token,\n url: `${sharePathPrefix}/${share.value.token}`,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createShare failed\"));\n }\n };\n\n const resolveShare = async (\n input: z.infer<typeof ResolveShareInputSchema>,\n ): Promise<Result<FileNode | null, FileSystemError>> => {\n const parsed = ResolveShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid resolveShare input\", parsed);\n try {\n return store.resolveShare({ token: parsed.data.token });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"resolveShare failed\"));\n }\n };\n\n const revokeShare = async (\n input: z.infer<typeof RevokeShareInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RevokeShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid revokeShare input\", parsed);\n try {\n const auth = await authTenant();\n return store.revokeShare({\n tenantId: asTenantId(auth.tenantId),\n token: parsed.data.token,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"revokeShare failed\"));\n }\n };\n\n return {\n listFiles,\n deleteFile,\n moveFile,\n copyFile,\n setMetadata,\n createFolder,\n prepareUpload,\n confirmUpload,\n searchFiles,\n listTrash,\n restoreNode,\n purgeNode,\n createShare,\n resolveShare,\n revokeShare,\n };\n};\n\nexport interface ListFilesOutput {\n readonly items: ReadonlyArray<FileNode>;\n readonly nextCursor?: string;\n}\n\nexport interface PrepareUploadOutput {\n readonly id: string;\n readonly key: string;\n readonly url: string;\n readonly method: \"PUT\" | \"POST\";\n readonly headers: Record<string, string>;\n readonly expiresAt: string;\n}\n\nexport type { TenantId };\n","/**\n * `createUploadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL upload flow.\n *\n * The client flow:\n * 1. Client POSTs `{ key, contentType, contentLength }` to this\n * route (typically `/api/files/upload`).\n * 2. Route validates `contentLength` against `maxBytes` (413) and\n * `contentType` against `allowedContentTypes` (415). No URL\n * is signed on a rejected request.\n * 3. Route calls `fs.adapter.createPresignedUploadUrl({ key,\n * contentType, expiresIn })` and returns `{ url, key,\n * expiresAt }`.\n * 4. Client PUTs the file body to the signed URL (bypassing the\n * Next.js server entirely).\n *\n * Spec scenarios: `route-handlers#1` (maxBytes), `route-handlers#2`\n * (allowedContentTypes).\n *\n * Construction-time validation: `expiresIn` is validated when the\n * factory is called (synchronous throw), per decision\n * `sdd/file-next/design/decision/expiresin-cap-timing`. A handler\n * built with `expiresIn: 30 * 86400` should never reach runtime —\n * the developer should see the error at server startup, not on\n * the first user request.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\n/**\n * Convert a glob pattern (`image/*`) to a regex; convert a literal\n * (`image/png`) to an exact match. Both forms are common in\n * `allowedContentTypes` arrays.\n */\nconst matchesContentType = (pattern: string, actual: string): boolean => {\n if (pattern === actual) return true;\n if (pattern.endsWith(\"/*\")) {\n const prefix = pattern.slice(0, -1); // \"image/*\" → \"image/\"\n return actual.startsWith(prefix);\n }\n return false;\n};\n\nexport interface CreateUploadRouteHandlerOptions {\n readonly fs: FileSystem;\n /** Resolve the caller. 401 when it returns null. */\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Reject requests whose `contentLength` exceeds this. Omit for no cap. */\n readonly maxBytes?: number;\n /**\n * Reject requests whose `contentType` is not in this list.\n * Each entry is a literal (`image/png`) or a wildcard (`image/*`).\n * Omit for no restriction.\n */\n readonly allowedContentTypes?: ReadonlyArray<string>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface UploadRouteHandlerRequest {\n key: string;\n contentType: string;\n contentLength: number;\n}\n\nexport interface UploadRouteHandlerResult {\n url: string;\n key: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range. The top-level code stays in the\n * closed 11-code catalog; the specific reason lives on `cause`.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned upload URL after validating the request.\n */\nexport const createUploadRouteHandler = (\n opts: CreateUploadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n // Construction-time validation: fail-fast on misconfiguration.\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n let body: UploadRouteHandlerRequest;\n try {\n body = (await req.json()) as UploadRouteHandlerRequest;\n } catch {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Request body must be valid JSON\" } },\n { status: 400 },\n );\n }\n\n // 1. maxBytes — reject BEFORE signing\n if (typeof opts.maxBytes === \"number\" && body.contentLength > opts.maxBytes) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"PayloadTooLarge\",\n message: `contentLength ${body.contentLength} exceeds maxBytes ${opts.maxBytes}`,\n },\n },\n { status: 413 },\n );\n }\n\n // 2. allowedContentTypes — reject BEFORE signing\n if (opts.allowedContentTypes && opts.allowedContentTypes.length > 0) {\n const allowed = opts.allowedContentTypes.some((p) => matchesContentType(p, body.contentType));\n if (!allowed) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"UnsupportedMediaType\",\n message: `contentType \"${body.contentType}\" is not in the allowed list`,\n },\n },\n { status: 415 },\n );\n }\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const r = await fs.adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: body.contentType,\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: {\n url: r.value.url,\n key: id,\n id,\n method: r.value.method,\n headers: r.value.requiredHeaders ?? {},\n expiresAt,\n },\n });\n };\n};\n","/**\n * `createDownloadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL download flow.\n *\n * The client flow:\n * 1. Client GETs `/api/files/download?key=uploads/report.pdf`.\n * 2. Route calls `fs.adapter.createPresignedDownloadUrl({ key,\n * expiresIn })` and returns `{ url, expiresAt }`.\n * 3. Client GETs the signed URL (bypassing the Next.js server).\n *\n * Spec scenario: `route-handlers#3` — `X-Amz-Expires=900` is present\n * in the signed URL and `expiresAt` is `now + 900s`.\n *\n * Construction-time validation: same `expiresIn` policy as the\n * upload handler (see `expiresin-cap-timing` decision). The cap\n * lives at the factory level, not the adapter, so a misconfigured\n * handler fails fast at server startup.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\nexport interface CreateDownloadRouteHandlerOptions {\n readonly fs: FileSystem;\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface DownloadRouteHandlerResult {\n url: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned GET URL.\n *\n * The `key` is read from the `?key=` query param. The handler does\n * NOT do any body / content-type / size validation (downloads\n * don't have those concerns); the only chokepoint is the\n * construction-time `expiresIn` cap.\n */\nexport const createDownloadRouteHandler = (\n opts: CreateDownloadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n const url = new URL(req.url);\n const key = url.searchParams.get(\"key\");\n if (!key) {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Missing required query param: key\" } },\n { status: 400 },\n );\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const r = await fs.adapter.createPresignedDownloadUrl({\n key: asS3Key(key),\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: { url: r.value.url, expiresAt },\n });\n };\n};\n","/**\n * Public share download: GET /api/share/[token]\n * Streams the object through the app. The client never sees the bucket or key.\n */\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { MetadataStore } from \"../../metadata/store\";\n\nexport interface CreateShareRouteHandlerOptions {\n readonly store: MetadataStore;\n readonly fs: FileSystem;\n}\n\nconst tokenFromRequest = (req: Request): string | null => {\n const url = new URL(req.url);\n const query = url.searchParams.get(\"token\");\n if (query && query.length > 0) return query;\n const parts = url.pathname.replace(/\\/+$/, \"\").split(\"/\");\n const last = parts[parts.length - 1];\n if (!last || last === \"share\") return null;\n return last;\n};\n\nexport const createShareRouteHandler = (\n opts: CreateShareRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n return async (req: Request): Promise<Response> => {\n const token = tokenFromRequest(req);\n if (!token) {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Missing share token\" } },\n { status: 400 },\n );\n }\n\n const resolved = await opts.store.resolveShare({ token });\n if (!resolved.ok) {\n return Response.json(\n { ok: false, error: { code: resolved.error.code, message: resolved.error.message } },\n { status: 500 },\n );\n }\n const node = resolved.value;\n if (!node || node.kind !== \"file\" || !node.s3Key) {\n return Response.json(\n { ok: false, error: { code: \"NotFound\", message: \"Share not found\" } },\n { status: 404 },\n );\n }\n\n const adapter = opts.fs.forTenant(node.tenantId).adapter;\n const rangeHeader = req.headers.get(\"range\") ?? undefined;\n const read = await adapter.read({\n key: asS3Key(node.s3Key),\n range: rangeHeader ?? undefined,\n });\n if (!read.ok) {\n return Response.json(\n { ok: false, error: { code: read.error.code, message: read.error.message } },\n { status: 404 },\n );\n }\n\n const download = new URL(req.url).searchParams.get(\"download\") === \"1\";\n const headers = new Headers();\n headers.set(\n \"Content-Type\",\n node.mimeType || read.value.contentType || \"application/octet-stream\",\n );\n headers.set(\n \"Content-Disposition\",\n `${download ? \"attachment\" : \"inline\"}; filename*=UTF-8''${encodeURIComponent(node.name)}`,\n );\n headers.set(\"Cache-Control\", \"private, no-store\");\n headers.set(\"Content-Length\", String(read.value.body.byteLength));\n\n return new Response(Buffer.from(read.value.body), { status: 200, headers });\n };\n};\n"]}
@@ -162,6 +162,8 @@ interface ServerActionsDeps {
162
162
  readonly writeThrough: CreateWriteThrough;
163
163
  readonly fs: FileSystem;
164
164
  readonly getAuth: () => AuthContext | Promise<AuthContext>;
165
+ /** App path prefix for share links. Default `/api/share`. */
166
+ readonly sharePathPrefix?: string;
165
167
  }
166
168
  declare const createServerActions: (deps: ServerActionsDeps) => {
167
169
  listFiles: (input: z.infer<typeof ListFilesInputSchema>) => Promise<Result<ListFilesOutput, FileSystemError>>;
@@ -181,6 +183,7 @@ declare const createServerActions: (deps: ServerActionsDeps) => {
181
183
  purgeNode: (input: z.infer<typeof RestoreNodeInputSchema>) => Promise<Result<void, FileSystemError>>;
182
184
  createShare: (input: z.infer<typeof CreateShareInputSchema>) => Promise<Result<{
183
185
  token: string;
186
+ url: string;
184
187
  }, FileSystemError>>;
185
188
  resolveShare: (input: z.infer<typeof ResolveShareInputSchema>) => Promise<Result<FileNode | null, FileSystemError>>;
186
189
  revokeShare: (input: z.infer<typeof RevokeShareInputSchema>) => Promise<Result<void, FileSystemError>>;
@@ -250,4 +253,10 @@ interface DownloadRouteHandlerResult {
250
253
  */
251
254
  declare const createDownloadRouteHandler: (opts: CreateDownloadRouteHandlerOptions) => ((req: Request) => Promise<Response>);
252
255
 
253
- export { type CreateDownloadRouteHandlerOptions, type CreateUploadRouteHandlerOptions, type DownloadRouteHandlerResult, type ListFilesOutput, type PrepareUploadOutput, type ServerActionsDeps, type UploadRouteHandlerRequest, type UploadRouteHandlerResult, createDownloadRouteHandler, createServerActions, createUploadRouteHandler };
256
+ interface CreateShareRouteHandlerOptions {
257
+ readonly store: MetadataStore;
258
+ readonly fs: FileSystem;
259
+ }
260
+ declare const createShareRouteHandler: (opts: CreateShareRouteHandlerOptions) => ((req: Request) => Promise<Response>);
261
+
262
+ export { type CreateDownloadRouteHandlerOptions, type CreateShareRouteHandlerOptions, type CreateUploadRouteHandlerOptions, type DownloadRouteHandlerResult, type ListFilesOutput, type PrepareUploadOutput, type ServerActionsDeps, type UploadRouteHandlerRequest, type UploadRouteHandlerResult, createDownloadRouteHandler, createServerActions, createShareRouteHandler, createUploadRouteHandler };
@@ -162,6 +162,8 @@ interface ServerActionsDeps {
162
162
  readonly writeThrough: CreateWriteThrough;
163
163
  readonly fs: FileSystem;
164
164
  readonly getAuth: () => AuthContext | Promise<AuthContext>;
165
+ /** App path prefix for share links. Default `/api/share`. */
166
+ readonly sharePathPrefix?: string;
165
167
  }
166
168
  declare const createServerActions: (deps: ServerActionsDeps) => {
167
169
  listFiles: (input: z.infer<typeof ListFilesInputSchema>) => Promise<Result<ListFilesOutput, FileSystemError>>;
@@ -181,6 +183,7 @@ declare const createServerActions: (deps: ServerActionsDeps) => {
181
183
  purgeNode: (input: z.infer<typeof RestoreNodeInputSchema>) => Promise<Result<void, FileSystemError>>;
182
184
  createShare: (input: z.infer<typeof CreateShareInputSchema>) => Promise<Result<{
183
185
  token: string;
186
+ url: string;
184
187
  }, FileSystemError>>;
185
188
  resolveShare: (input: z.infer<typeof ResolveShareInputSchema>) => Promise<Result<FileNode | null, FileSystemError>>;
186
189
  revokeShare: (input: z.infer<typeof RevokeShareInputSchema>) => Promise<Result<void, FileSystemError>>;
@@ -250,4 +253,10 @@ interface DownloadRouteHandlerResult {
250
253
  */
251
254
  declare const createDownloadRouteHandler: (opts: CreateDownloadRouteHandlerOptions) => ((req: Request) => Promise<Response>);
252
255
 
253
- export { type CreateDownloadRouteHandlerOptions, type CreateUploadRouteHandlerOptions, type DownloadRouteHandlerResult, type ListFilesOutput, type PrepareUploadOutput, type ServerActionsDeps, type UploadRouteHandlerRequest, type UploadRouteHandlerResult, createDownloadRouteHandler, createServerActions, createUploadRouteHandler };
256
+ interface CreateShareRouteHandlerOptions {
257
+ readonly store: MetadataStore;
258
+ readonly fs: FileSystem;
259
+ }
260
+ declare const createShareRouteHandler: (opts: CreateShareRouteHandlerOptions) => ((req: Request) => Promise<Response>);
261
+
262
+ export { type CreateDownloadRouteHandlerOptions, type CreateShareRouteHandlerOptions, type CreateUploadRouteHandlerOptions, type DownloadRouteHandlerResult, type ListFilesOutput, type PrepareUploadOutput, type ServerActionsDeps, type UploadRouteHandlerRequest, type UploadRouteHandlerResult, createDownloadRouteHandler, createServerActions, createShareRouteHandler, createUploadRouteHandler };
@@ -229,6 +229,7 @@ var zodErr = (message, parsed) => err(
229
229
  );
230
230
  var createServerActions = (deps) => {
231
231
  const { store, writeThrough, fs, getAuth } = deps;
232
+ const sharePathPrefix = (deps.sharePathPrefix ?? "/api/share").replace(/\/+$/, "");
232
233
  const wrap = (e, code, message) => {
233
234
  if (e instanceof FileSystemError) return e;
234
235
  return new FileSystemError({
@@ -431,10 +432,27 @@ var createServerActions = (deps) => {
431
432
  if (!parsed.success) return zodErr("Invalid createShare input", parsed);
432
433
  try {
433
434
  const auth = await authTenant();
434
- return store.createShare({
435
- tenantId: asTenantId(auth.tenantId),
435
+ const tenantId = asTenantId(auth.tenantId);
436
+ const node = await store.getNode({ tenantId, id: parsed.data.id });
437
+ if (!node.ok) return node;
438
+ if (!node.value || node.value.kind !== "file" || !node.value.s3Key) {
439
+ return err(
440
+ new FileSystemError({
441
+ code: "Conflict",
442
+ message: "Only files can be shared as an openable link",
443
+ retryable: false
444
+ })
445
+ );
446
+ }
447
+ const share = await store.createShare({
448
+ tenantId,
436
449
  nodeId: parsed.data.id
437
450
  });
451
+ if (!share.ok) return share;
452
+ return ok({
453
+ token: share.value.token,
454
+ url: `${sharePathPrefix}/${share.value.token}`
455
+ });
438
456
  } catch (e) {
439
457
  return err(wrap(e, "InternalError", "createShare failed"));
440
458
  }
@@ -633,6 +651,67 @@ var createDownloadRouteHandler = (opts) => {
633
651
  };
634
652
  };
635
653
 
636
- export { createDownloadRouteHandler, createServerActions, createUploadRouteHandler };
654
+ // src/server/route-handlers/share.ts
655
+ var tokenFromRequest = (req) => {
656
+ const url = new URL(req.url);
657
+ const query = url.searchParams.get("token");
658
+ if (query && query.length > 0) return query;
659
+ const parts = url.pathname.replace(/\/+$/, "").split("/");
660
+ const last = parts[parts.length - 1];
661
+ if (!last || last === "share") return null;
662
+ return last;
663
+ };
664
+ var createShareRouteHandler = (opts) => {
665
+ return async (req) => {
666
+ const token = tokenFromRequest(req);
667
+ if (!token) {
668
+ return Response.json(
669
+ { ok: false, error: { code: "InternalError", message: "Missing share token" } },
670
+ { status: 400 }
671
+ );
672
+ }
673
+ const resolved = await opts.store.resolveShare({ token });
674
+ if (!resolved.ok) {
675
+ return Response.json(
676
+ { ok: false, error: { code: resolved.error.code, message: resolved.error.message } },
677
+ { status: 500 }
678
+ );
679
+ }
680
+ const node = resolved.value;
681
+ if (!node || node.kind !== "file" || !node.s3Key) {
682
+ return Response.json(
683
+ { ok: false, error: { code: "NotFound", message: "Share not found" } },
684
+ { status: 404 }
685
+ );
686
+ }
687
+ const adapter = opts.fs.forTenant(node.tenantId).adapter;
688
+ const rangeHeader = req.headers.get("range") ?? void 0;
689
+ const read = await adapter.read({
690
+ key: asS3Key(node.s3Key),
691
+ range: rangeHeader ?? void 0
692
+ });
693
+ if (!read.ok) {
694
+ return Response.json(
695
+ { ok: false, error: { code: read.error.code, message: read.error.message } },
696
+ { status: 404 }
697
+ );
698
+ }
699
+ const download = new URL(req.url).searchParams.get("download") === "1";
700
+ const headers = new Headers();
701
+ headers.set(
702
+ "Content-Type",
703
+ node.mimeType || read.value.contentType || "application/octet-stream"
704
+ );
705
+ headers.set(
706
+ "Content-Disposition",
707
+ `${download ? "attachment" : "inline"}; filename*=UTF-8''${encodeURIComponent(node.name)}`
708
+ );
709
+ headers.set("Cache-Control", "private, no-store");
710
+ headers.set("Content-Length", String(read.value.body.byteLength));
711
+ return new Response(Buffer.from(read.value.body), { status: 200, headers });
712
+ };
713
+ };
714
+
715
+ export { createDownloadRouteHandler, createServerActions, createShareRouteHandler, createUploadRouteHandler };
637
716
  //# sourceMappingURL=index.js.map
638
717
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/result.ts","../../src/errors/mappers.ts","../../src/errors/index.ts","../../src/types/branded.ts","../../src/server/actions.ts","../../src/server/route-handlers/upload.ts","../../src/server/route-handlers/download.ts"],"names":["err","MAX_EXPIRES_IN_SECONDS","DEFAULT_EXPIRES_IN_SECONDS","assertExpiresIn"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Discriminated `Result<T, E>` for typed error returns.\n *\n * Why Result over throw at boundaries:\n * - No `any` at the call site (vs try/catch which loses the type).\n * - `switch (r.ok)` narrows the type in consumer code.\n * - The wire shape `{ ok, value | error }` is JSON-serializable,\n * so it survives the RSC boundary without an extra DTO.\n * - Helpers (`map`, `andThen`, `unwrap`) make the common shapes\n * (chain, bail-out, recover) terse and exhaustive.\n *\n * The default error type is `FileSystemError` (see `@/errors`).\n * Consumers can specialize: `Result<User, ZodError>`.\n *\n * All helpers are pure functions; they do NOT allocate closures in\n * hot paths beyond what the spec demands (no `try`/`catch` wrapping).\n */\n\nimport { FileSystemError } from \"@/errors\";\n\nexport type Result<T, E = FileSystemError> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: E };\n\nexport const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });\n\nexport const err = <E>(error: E): Result<never, E> => ({ ok: false, error });\n\nexport const map = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => U,\n): Result<U, E> => (r.ok ? ok(f(r.value)) : r);\n\nexport const mapErr = <T, E, F>(\n r: Result<T, E>,\n f: (e: E) => F,\n): Result<T, F> => (r.ok ? r : err(f(r.error)));\n\nexport const andThen = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => Result<U, E>,\n): Result<U, E> => (r.ok ? f(r.value) : r);\n\nexport const unwrap = <T, E>(r: Result<T, E>): T => {\n if (r.ok) return r.value;\n throw r.error;\n};\n\nexport const unwrapOr = <T, E>(r: Result<T, E>, fallback: T): T =>\n r.ok ? r.value : fallback;\n","/**\n * Upstream error mappers for FileSystemError.\n *\n * Each mapper is a pure function `(*unknown) -> FileSystemError`.\n * The class re-exposes them as static methods (FileSystemError.fromAws\n * etc.) so callers can pick the import style that fits.\n *\n * Mapping strategy:\n * 1. If the input is already a FileSystemError, return it as-is\n * (we never re-wrap our own errors).\n * 2. Try the most specific signal first: S3 `name`, Postgres\n * SQLSTATE, SQLite extended code.\n * 3. Fall back to the HTTP status code (AWS SDK v3 exposes\n * `$metadata.httpStatusCode`).\n * 4. Last resort: InternalError, retryable, with the original\n * payload in `cause`.\n *\n * Provider-specific codes are preserved on `cause.code` (e.g. S3\n * \"NoSuchKey\", Postgres \"23505\") so callers can still branch on\n * them while the top-level `code` stays in the 11-code spec catalog.\n *\n * Mapping notes (post-C' merge, see\n * `sdd/file-next/decisions/error-codes-deviation`):\n * - S3 `SlowDown` -> QuotaExceeded (broader than RateLimited;\n * SlowDown means reduce request rate, which\n * is conceptually quota pressure, not\n * throttling of a single call).\n * - S3 `BadDigest` -> ChecksumMismatch (checksum verified by\n * S3 on upload did not match the client).\n * - HTTP 429 -> RateLimited (was QuotaExceeded in the\n * pre-C' catalog; RateLimited is the more\n * specific code for throttling responses).\n * - HTTP 408 -> NetworkError (transient transport error).\n * - HTTP 400 / Postgres 23514 / S3 InvalidRequest\n * -> fall through to the 4xx branch (no\n * top-level 400 code in the C' catalog;\n * these inputs are usually caught by the\n * name/SQLSTATE mapping first anyway).\n */\n\nimport { FileSystemError, type FileSystemErrorCode } from \"./index\";\n\n/* ---------------------------------------------------------------- *\n * Mapping tables (private) *\n * ---------------------------------------------------------------- */\n\ninterface CodeMapping {\n code: FileSystemErrorCode;\n retryable: boolean;\n}\n\nconst HTTP_STATUS_TO_CODE: Readonly<Record<number, CodeMapping>> = {\n 401: { code: \"Unauthorized\", retryable: false },\n 403: { code: \"Forbidden\", retryable: false },\n 404: { code: \"NotFound\", retryable: false },\n 408: { code: \"NetworkError\", retryable: true },\n 409: { code: \"Conflict\", retryable: false },\n 413: { code: \"PayloadTooLarge\", retryable: false },\n 415: { code: \"UnsupportedMediaType\", retryable: false },\n 429: { code: \"RateLimited\", retryable: true },\n};\n\nconst AWS_NAME_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n NoSuchKey: { code: \"NotFound\", retryable: false },\n NoSuchBucket: { code: \"NotFound\", retryable: false },\n // v0.2 multipart: unknown/aborted/expired uploadId.\n NoSuchUpload: { code: \"NotFound\", retryable: false },\n AccessDenied: { code: \"Forbidden\", retryable: false },\n SlowDown: { code: \"QuotaExceeded\", retryable: true },\n BadDigest: { code: \"ChecksumMismatch\", retryable: true },\n XAmzContentSHA256Mismatch: { code: \"ChecksumMismatch\", retryable: true },\n NetworkingError: { code: \"NetworkError\", retryable: true },\n TimeoutError: { code: \"NetworkError\", retryable: true },\n};\n\nconst PG_SQLSTATE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n \"23505\": { code: \"Conflict\", retryable: false },\n};\n\nconst SQLITE_CODE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n SQLITE_CONSTRAINT_UNIQUE: { code: \"Conflict\", retryable: false },\n SQLITE_CONSTRAINT_PRIMARYKEY: { code: \"Conflict\", retryable: false },\n};\n\n/* ---------------------------------------------------------------- *\n * Public mappers *\n * ---------------------------------------------------------------- */\n\nconst toCause = (code: string, message: string, extra?: Record<string, unknown>) => ({\n code,\n message,\n ...(extra ?? {}),\n});\n\nconst fallback = (err: unknown): FileSystemError =>\n new FileSystemError({\n code: \"InternalError\",\n message: err instanceof Error ? err.message : String(err),\n retryable: true,\n cause: toCause(\n \"Unknown\",\n err instanceof Error ? err.message : String(err),\n ),\n });\n\nexport const fromAws = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const awsErr = err as {\n name?: unknown;\n message?: unknown;\n $metadata?: { httpStatusCode?: unknown };\n };\n const name = typeof awsErr.name === \"string\" ? awsErr.name : undefined;\n const message =\n typeof awsErr.message === \"string\" ? awsErr.message : `AWS error: ${name ?? \"unknown\"}`;\n const status =\n typeof awsErr.$metadata?.httpStatusCode === \"number\"\n ? awsErr.$metadata.httpStatusCode\n : undefined;\n\n const cause = toCause(\n name ?? (status !== undefined ? String(status) : \"Unknown\"),\n message,\n status !== undefined ? { httpStatusCode: status } : undefined,\n );\n\n // 1) name-based mapping wins (more specific than HTTP status)\n if (name && name in AWS_NAME_TO_CODE) {\n const m = AWS_NAME_TO_CODE[name]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 2) HTTP status mapping\n if (status !== undefined && status in HTTP_STATUS_TO_CODE) {\n const m = HTTP_STATUS_TO_CODE[status]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 3) 5xx bucket\n if (status !== undefined && status >= 500 && status < 600) {\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n }\n\n // 4) anything else 4xx-shaped\n if (status !== undefined && status >= 400 && status < 500) {\n return new FileSystemError({ code: \"Forbidden\", message, retryable: false, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromPg = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const pgErr = err as { code?: unknown; message?: unknown };\n const sqlstate = typeof pgErr.code === \"string\" ? pgErr.code : undefined;\n const message =\n typeof pgErr.message === \"string\" ? pgErr.message : `Postgres error: ${sqlstate ?? \"unknown\"}`;\n const cause = toCause(sqlstate ?? \"Unknown\", message);\n\n if (sqlstate && sqlstate in PG_SQLSTATE_TO_CODE) {\n const m = PG_SQLSTATE_TO_CODE[sqlstate]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromSqlite = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const sqlErr = err as { code?: unknown; message?: unknown };\n const code = typeof sqlErr.code === \"string\" ? sqlErr.code : undefined;\n const message =\n typeof sqlErr.message === \"string\" ? sqlErr.message : `SQLite error: ${code ?? \"unknown\"}`;\n const cause = toCause(code ?? \"Unknown\", message);\n\n if (code && code in SQLITE_CODE_TO_CODE) {\n const m = SQLITE_CODE_TO_CODE[code]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n","/**\n * FileSystemError — the single error class every adapter, store,\n * server action, and route handler in `file-next` returns or throws.\n *\n * Spec reference: requirement \"FileSystemError discriminated union\"\n * in `sdd/file-next/spec`. The 11 codes are the CLOSED set; any\n * provider-specific code (e.g. S3 `NoSuchKey`, Postgres `23505`) is\n * preserved on `cause.code` so callers can still distinguish upstream\n * reasons while the top-level `code` stays in the catalog.\n *\n * The catalog is a merge of spec + impl: the 6 fixed codes\n * (NotFound, Forbidden, Conflict, QuotaExceeded, NetworkError,\n * InternalError) are non-negotiable; the remaining 5 keep the wire\n * aligned with both the HTTP boundary (route handlers map the\n * top-level `code` to a status directly) and the storage boundary\n * (`RateLimited` and `ChecksumMismatch` carry semantics that have\n * no natural HTTP equivalent). See\n * `sdd/file-next/decisions/error-codes-deviation` for the\n * deviation log and rationale.\n *\n * Retryability table is the design's `error-mapping` excerpt; see\n * `sdd/file-next/design` §C. Any future code MUST add an entry in\n * `RETRYABLE_BY_CODE` (the catalog test enforces this).\n *\n * The placeholder from T-006 is replaced by this file in T-007a.\n * The upstream mappers (fromAws / fromPg / fromSqlite) land in T-007b\n * in `mappers.ts`.\n */\n\nexport const FILE_SYSTEM_ERROR_CODES = [\n \"NotFound\",\n \"Forbidden\",\n \"Conflict\",\n \"QuotaExceeded\",\n \"NetworkError\",\n \"InternalError\",\n \"Unauthorized\",\n \"PayloadTooLarge\",\n \"UnsupportedMediaType\",\n \"RateLimited\",\n \"ChecksumMismatch\",\n] as const satisfies readonly string[];\n\nexport type FileSystemErrorCode = (typeof FILE_SYSTEM_ERROR_CODES)[number];\n\nexport const RETRYABLE_BY_CODE: Readonly<Record<FileSystemErrorCode, boolean>> = {\n NotFound: false,\n Forbidden: false,\n Conflict: false,\n QuotaExceeded: true,\n NetworkError: true,\n InternalError: true,\n Unauthorized: false,\n PayloadTooLarge: false,\n UnsupportedMediaType: false,\n RateLimited: true,\n ChecksumMismatch: true,\n};\n\nexport interface FileSystemErrorOptions {\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport interface FileSystemErrorJson {\n name: string;\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport class FileSystemError extends Error {\n readonly code: FileSystemErrorCode;\n readonly retryable: boolean;\n override readonly cause?: { code: string; message: string; [k: string]: unknown };\n\n constructor(opts: FileSystemErrorOptions) {\n super(opts.message);\n this.name = \"FileSystemError\";\n this.code = opts.code;\n this.retryable = opts.retryable;\n if (opts.cause !== undefined) {\n this.cause = opts.cause;\n }\n }\n\n /**\n * Stable JSON shape for RSC pass-through. Error.prototype.message\n * is non-enumerable, so plain `JSON.stringify(err)` would emit `{}`\n * and lose the message + code + retryable flag. `cause` is omitted\n * entirely (not set to undefined) when absent so the shape stays\n * stable for hash-based caches.\n */\n toJSON(): FileSystemErrorJson {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n ...(this.cause !== undefined ? { cause: this.cause } : {}),\n };\n }\n\n /**\n * Mappers from upstream error shapes (AWS SDK v3, node-postgres,\n * better-sqlite3) to FileSystemError. See `./mappers.ts` for the\n * mapping tables. Re-exposed as static methods so callers can pick\n * the import style that fits; the free functions are the canonical\n * implementation.\n */\n static fromAws(err: unknown): FileSystemError {\n // Lazy import via the runtime binding avoids the static-field\n // circular-dep trap in ESM. The mapper file imports this class\n // for instanceof checks; we look up the function at call time.\n return _fromAws(err);\n }\n\n static fromPg(err: unknown): FileSystemError {\n return _fromPg(err);\n }\n\n static fromSqlite(err: unknown): FileSystemError {\n return _fromSqlite(err);\n }\n}\n\n// Imported here as bindings (not values) so the static methods above\n// can resolve them lazily. The actual implementation lives in mappers.ts.\nimport { fromAws as _fromAws, fromPg as _fromPg, fromSqlite as _fromSqlite } from \"./mappers\";\nexport { fromAws, fromPg, fromSqlite } from \"./mappers\";\n","/**\n * Branded string types and their constructors/guards.\n *\n * Brands are TypeScript-only fictions: a `Path` and an `S3Key` are\n * both strings at runtime, but the type system treats them as\n * distinct nominal types so the compiler catches accidental\n * cross-assignment (e.g. passing an S3Key where a TenantId is\n * expected).\n *\n * Conventions:\n * - `as*` is a zero-cost cast: trust the caller, brand the value.\n * Use it at trust boundaries you have already validated.\n * - `assert*` is a runtime guard: throws TypeError on invalid\n * input. Use it at the edge (parsing user/env input).\n *\n * Validation rules are intentionally minimal in v0.1 and can be\n * tightened as the spec evolves. None of them touch the network or\n * allocate; they are safe in hot paths.\n */\n\nexport type Path = string & { readonly __brand: \"Path\" };\nexport type Prefix = string & { readonly __brand: \"Prefix\" };\nexport type S3Key = string & { readonly __brand: \"S3Key\" };\nexport type TenantId = string & { readonly __brand: \"TenantId\" };\nexport type UserId = string & { readonly __brand: \"UserId\" };\n\n/**\n * POSIX file path. Non-empty, '/' is allowed as the root.\n */\nexport const asPath = (s: string): Path => s as Path;\nexport const assertPath = (s: string): Path => {\n if (s.length === 0) {\n throw new TypeError(\"Path must be a non-empty string\");\n }\n return s as Path;\n};\n\n/**\n * S3 prefix. Empty string is the root prefix. Non-empty prefixes\n * MUST end with '/' so concatenation with a key never produces\n * 'usersfile.jpg' by accident.\n */\nexport const asPrefix = (s: string): Prefix => s as Prefix;\nexport const assertPrefix = (s: string): Prefix => {\n if (s.length > 0 && !s.endsWith(\"/\")) {\n throw new TypeError(\n `Prefix must end with \"/\" or be empty: ${JSON.stringify(s)}`,\n );\n }\n return s as Prefix;\n};\n\n/**\n * S3 object key. No leading slash, no empty segments, no '..' hops.\n */\nexport const asS3Key = (s: string): S3Key => s as S3Key;\nexport const assertS3Key = (s: string): S3Key => {\n if (s.length === 0) {\n throw new TypeError(\"S3Key must be a non-empty string\");\n }\n if (s.startsWith(\"/\")) {\n throw new TypeError(\n `S3Key must not start with a slash: ${JSON.stringify(s)}`,\n );\n }\n if (s.includes(\"..\")) {\n throw new TypeError(\n `S3Key must not contain '..' segments: ${JSON.stringify(s)}`,\n );\n }\n return s as S3Key;\n};\n\n/**\n * Tenant identifier. Alphanumerics, dashes, underscores only.\n */\nexport const asTenantId = (s: string): TenantId => s as TenantId;\nexport const assertTenantId = (s: string): TenantId => {\n if (s.length === 0 || !/^[a-zA-Z0-9_-]+$/.test(s)) {\n throw new TypeError(`Invalid TenantId: ${JSON.stringify(s)}`);\n }\n return s as TenantId;\n};\n\n/**\n * Opaque user identifier. Non-empty; the format is provider-defined.\n */\nexport const asUserId = (s: string): UserId => s as UserId;\nexport const assertUserId = (s: string): UserId => {\n if (s.length === 0) {\n throw new TypeError(\"UserId must be a non-empty string\");\n }\n return s as UserId;\n};\n","/**\n * Server actions — tenant comes from getAuth(), never from the client.\n */\nimport { z } from \"zod\";\nimport { ok, err, type Result } from \"@/types/result\";\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key, asTenantId, type TenantId } from \"@/types/branded\";\nimport type { AuthContext } from \"../auth/with-auth\";\nimport type { MetadataStore, FileNode } from \"../metadata/store\";\nimport type { FileSystem } from \"../storage/filesystem\";\nimport type { createWriteThrough } from \"../sync/write-through\";\n\ntype CreateWriteThrough = ReturnType<typeof createWriteThrough>;\n\nconst NodeIdSchema = z.string().min(1, \"id is required\");\nconst PathSchema = z.string().nullable();\n\nexport const ListFilesInputSchema = z.object({\n parentId: PathSchema,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional(),\n});\n\nexport const DeleteFileInputSchema = z.object({\n id: NodeIdSchema,\n recursive: z.boolean().optional(),\n});\n\nexport const MoveFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const CopyFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const SetMetadataInputSchema = z.object({\n id: NodeIdSchema,\n metadata: z.record(z.string()),\n replace: z.boolean().optional(),\n});\n\nexport const CreateFolderInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n});\n\nexport const PrepareUploadInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().min(1),\n contentLength: z.number().int().nonnegative(),\n});\n\nexport const ConfirmUploadInputSchema = z.object({\n id: NodeIdSchema,\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n});\n\nexport const SearchFilesInputSchema = z.object({\n query: z.string(),\n parentId: z.string().optional(),\n limit: z.number().int().positive().optional(),\n});\n\nexport const RestoreNodeInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const CreateShareInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const ResolveShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nexport const RevokeShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nconst zodErr = (message: string, parsed: z.SafeParseError<unknown>) =>\n err(\n new FileSystemError({\n code: \"InternalError\",\n message,\n retryable: false,\n cause: { code: \"ZodError\", message: parsed.error.message, issues: parsed.error.issues },\n }),\n );\n\nexport interface ServerActionsDeps {\n readonly store: MetadataStore;\n readonly writeThrough: CreateWriteThrough;\n readonly fs: FileSystem;\n readonly getAuth: () => AuthContext | Promise<AuthContext>;\n}\n\nexport const createServerActions = (deps: ServerActionsDeps) => {\n const { store, writeThrough, fs, getAuth } = deps;\n\n const wrap = (e: unknown, code: FileSystemError[\"code\"], message: string): FileSystemError => {\n if (e instanceof FileSystemError) return e;\n return new FileSystemError({\n code,\n message: `${message}: ${e instanceof Error ? e.message : String(e)}`,\n retryable: true,\n });\n };\n\n const authTenant = async (): Promise<AuthContext> => getAuth();\n\n const listFiles = async (\n input: z.infer<typeof ListFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = ListFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid listFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.listChildren({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n cursor: parsed.data.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listFiles failed\"));\n }\n };\n\n const deleteFile = async (\n input: z.infer<typeof DeleteFileInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = DeleteFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid deleteFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.deleteThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n recursive: parsed.data.recursive,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"deleteFile failed\"));\n }\n };\n\n const moveFile = async (\n input: z.infer<typeof MoveFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = MoveFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid moveFile input\", parsed);\n try {\n const auth = await authTenant();\n return store.moveNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"moveFile failed\"));\n }\n };\n\n const copyFile = async (\n input: z.infer<typeof CopyFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CopyFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid copyFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.copyThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"copyFile failed\"));\n }\n };\n\n const setMetadata = async (\n input: z.infer<typeof SetMetadataInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = SetMetadataInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid setMetadata input\", parsed);\n try {\n const auth = await authTenant();\n return store.updateMetadata({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n metadata: parsed.data.metadata,\n replace: parsed.data.replace,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"setMetadata failed\"));\n }\n };\n\n const createFolder = async (\n input: z.infer<typeof CreateFolderInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CreateFolderInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createFolder input\", parsed);\n try {\n const auth = await authTenant();\n return store.createNode({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n kind: \"folder\",\n size: 0,\n mimeType: \"\",\n s3Key: \"\",\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createFolder failed\"));\n }\n };\n\n const prepareUpload = async (\n input: z.infer<typeof PrepareUploadInputSchema>,\n ): Promise<Result<PrepareUploadOutput, FileSystemError>> => {\n const parsed = PrepareUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid prepareUpload input\", parsed);\n try {\n const auth = await authTenant();\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const signed = await fs.forTenant(auth.tenantId).adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: parsed.data.contentType,\n expiresIn: 900,\n });\n if (!signed.ok) return signed;\n return ok({\n id,\n key: id,\n url: signed.value.url,\n method: signed.value.method,\n headers: signed.value.requiredHeaders ?? {},\n expiresAt: new Date(Date.now() + 900_000).toISOString(),\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"prepareUpload failed\"));\n }\n };\n\n const confirmUpload = async (\n input: z.infer<typeof ConfirmUploadInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = ConfirmUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid confirmUpload input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.confirmUpload({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n contentType: parsed.data.contentType,\n size: parsed.data.size,\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"confirmUpload failed\"));\n }\n };\n\n const searchFiles = async (\n input: z.infer<typeof SearchFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = SearchFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid searchFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.search({\n tenantId: asTenantId(auth.tenantId),\n query: parsed.data.query,\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"searchFiles failed\"));\n }\n };\n\n const listTrash = async (\n input: { limit?: number; cursor?: string } = {},\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n try {\n const auth = await authTenant();\n return store.listTrash({\n tenantId: asTenantId(auth.tenantId),\n limit: input.limit,\n cursor: input.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listTrash failed\"));\n }\n };\n\n const restoreNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid restoreNode input\", parsed);\n try {\n const auth = await authTenant();\n return store.restoreNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"restoreNode failed\"));\n }\n };\n\n const purgeNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid purgeNode input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.purgeThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"purgeNode failed\"));\n }\n };\n\n const createShare = async (\n input: z.infer<typeof CreateShareInputSchema>,\n ): Promise<Result<{ token: string }, FileSystemError>> => {\n const parsed = CreateShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createShare input\", parsed);\n try {\n const auth = await authTenant();\n return store.createShare({\n tenantId: asTenantId(auth.tenantId),\n nodeId: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createShare failed\"));\n }\n };\n\n const resolveShare = async (\n input: z.infer<typeof ResolveShareInputSchema>,\n ): Promise<Result<FileNode | null, FileSystemError>> => {\n const parsed = ResolveShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid resolveShare input\", parsed);\n try {\n return store.resolveShare({ token: parsed.data.token });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"resolveShare failed\"));\n }\n };\n\n const revokeShare = async (\n input: z.infer<typeof RevokeShareInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RevokeShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid revokeShare input\", parsed);\n try {\n const auth = await authTenant();\n return store.revokeShare({\n tenantId: asTenantId(auth.tenantId),\n token: parsed.data.token,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"revokeShare failed\"));\n }\n };\n\n return {\n listFiles,\n deleteFile,\n moveFile,\n copyFile,\n setMetadata,\n createFolder,\n prepareUpload,\n confirmUpload,\n searchFiles,\n listTrash,\n restoreNode,\n purgeNode,\n createShare,\n resolveShare,\n revokeShare,\n };\n};\n\nexport interface ListFilesOutput {\n readonly items: ReadonlyArray<FileNode>;\n readonly nextCursor?: string;\n}\n\nexport interface PrepareUploadOutput {\n readonly id: string;\n readonly key: string;\n readonly url: string;\n readonly method: \"PUT\" | \"POST\";\n readonly headers: Record<string, string>;\n readonly expiresAt: string;\n}\n\nexport type { TenantId };\n","/**\n * `createUploadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL upload flow.\n *\n * The client flow:\n * 1. Client POSTs `{ key, contentType, contentLength }` to this\n * route (typically `/api/files/upload`).\n * 2. Route validates `contentLength` against `maxBytes` (413) and\n * `contentType` against `allowedContentTypes` (415). No URL\n * is signed on a rejected request.\n * 3. Route calls `fs.adapter.createPresignedUploadUrl({ key,\n * contentType, expiresIn })` and returns `{ url, key,\n * expiresAt }`.\n * 4. Client PUTs the file body to the signed URL (bypassing the\n * Next.js server entirely).\n *\n * Spec scenarios: `route-handlers#1` (maxBytes), `route-handlers#2`\n * (allowedContentTypes).\n *\n * Construction-time validation: `expiresIn` is validated when the\n * factory is called (synchronous throw), per decision\n * `sdd/file-next/design/decision/expiresin-cap-timing`. A handler\n * built with `expiresIn: 30 * 86400` should never reach runtime —\n * the developer should see the error at server startup, not on\n * the first user request.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\n/**\n * Convert a glob pattern (`image/*`) to a regex; convert a literal\n * (`image/png`) to an exact match. Both forms are common in\n * `allowedContentTypes` arrays.\n */\nconst matchesContentType = (pattern: string, actual: string): boolean => {\n if (pattern === actual) return true;\n if (pattern.endsWith(\"/*\")) {\n const prefix = pattern.slice(0, -1); // \"image/*\" → \"image/\"\n return actual.startsWith(prefix);\n }\n return false;\n};\n\nexport interface CreateUploadRouteHandlerOptions {\n readonly fs: FileSystem;\n /** Resolve the caller. 401 when it returns null. */\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Reject requests whose `contentLength` exceeds this. Omit for no cap. */\n readonly maxBytes?: number;\n /**\n * Reject requests whose `contentType` is not in this list.\n * Each entry is a literal (`image/png`) or a wildcard (`image/*`).\n * Omit for no restriction.\n */\n readonly allowedContentTypes?: ReadonlyArray<string>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface UploadRouteHandlerRequest {\n key: string;\n contentType: string;\n contentLength: number;\n}\n\nexport interface UploadRouteHandlerResult {\n url: string;\n key: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range. The top-level code stays in the\n * closed 11-code catalog; the specific reason lives on `cause`.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned upload URL after validating the request.\n */\nexport const createUploadRouteHandler = (\n opts: CreateUploadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n // Construction-time validation: fail-fast on misconfiguration.\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n let body: UploadRouteHandlerRequest;\n try {\n body = (await req.json()) as UploadRouteHandlerRequest;\n } catch {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Request body must be valid JSON\" } },\n { status: 400 },\n );\n }\n\n // 1. maxBytes — reject BEFORE signing\n if (typeof opts.maxBytes === \"number\" && body.contentLength > opts.maxBytes) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"PayloadTooLarge\",\n message: `contentLength ${body.contentLength} exceeds maxBytes ${opts.maxBytes}`,\n },\n },\n { status: 413 },\n );\n }\n\n // 2. allowedContentTypes — reject BEFORE signing\n if (opts.allowedContentTypes && opts.allowedContentTypes.length > 0) {\n const allowed = opts.allowedContentTypes.some((p) => matchesContentType(p, body.contentType));\n if (!allowed) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"UnsupportedMediaType\",\n message: `contentType \"${body.contentType}\" is not in the allowed list`,\n },\n },\n { status: 415 },\n );\n }\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const r = await fs.adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: body.contentType,\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: {\n url: r.value.url,\n key: id,\n id,\n method: r.value.method,\n headers: r.value.requiredHeaders ?? {},\n expiresAt,\n },\n });\n };\n};\n","/**\n * `createDownloadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL download flow.\n *\n * The client flow:\n * 1. Client GETs `/api/files/download?key=uploads/report.pdf`.\n * 2. Route calls `fs.adapter.createPresignedDownloadUrl({ key,\n * expiresIn })` and returns `{ url, expiresAt }`.\n * 3. Client GETs the signed URL (bypassing the Next.js server).\n *\n * Spec scenario: `route-handlers#3` — `X-Amz-Expires=900` is present\n * in the signed URL and `expiresAt` is `now + 900s`.\n *\n * Construction-time validation: same `expiresIn` policy as the\n * upload handler (see `expiresin-cap-timing` decision). The cap\n * lives at the factory level, not the adapter, so a misconfigured\n * handler fails fast at server startup.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\nexport interface CreateDownloadRouteHandlerOptions {\n readonly fs: FileSystem;\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface DownloadRouteHandlerResult {\n url: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned GET URL.\n *\n * The `key` is read from the `?key=` query param. The handler does\n * NOT do any body / content-type / size validation (downloads\n * don't have those concerns); the only chokepoint is the\n * construction-time `expiresIn` cap.\n */\nexport const createDownloadRouteHandler = (\n opts: CreateDownloadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n const url = new URL(req.url);\n const key = url.searchParams.get(\"key\");\n if (!key) {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Missing required query param: key\" } },\n { status: 400 },\n );\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const r = await fs.adapter.createPresignedDownloadUrl({\n key: asS3Key(key),\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: { url: r.value.url, expiresAt },\n });\n };\n};\n"]}
1
+ {"version":3,"sources":["../../src/types/result.ts","../../src/errors/mappers.ts","../../src/errors/index.ts","../../src/types/branded.ts","../../src/server/actions.ts","../../src/server/route-handlers/upload.ts","../../src/server/route-handlers/download.ts","../../src/server/route-handlers/share.ts"],"names":["err","MAX_EXPIRES_IN_SECONDS","DEFAULT_EXPIRES_IN_SECONDS","assertExpiresIn"],"mappings":";;;;;;AAwBO,IAAM,KAAK,CAAI,KAAA,MAAgC,EAAE,EAAA,EAAI,MAAM,KAAA,EAAM,CAAA;AAEjE,IAAM,MAAM,CAAI,KAAA,MAAgC,EAAE,EAAA,EAAI,OAAO,KAAA,EAAM,CAAA;;;ACyB1E,IAAM,mBAAA,GAA6D;AAAA,EACjE,GAAA,EAAK,EAAE,IAAA,EAAM,cAAA,EAAgB,WAAW,KAAA,EAAM;AAAA,EAC9C,GAAA,EAAK,EAAE,IAAA,EAAM,WAAA,EAAa,WAAW,KAAA,EAAM;AAAA,EAC3C,GAAA,EAAK,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA,EAAM;AAAA,EAC1C,GAAA,EAAK,EAAE,IAAA,EAAM,cAAA,EAAgB,WAAW,IAAA,EAAK;AAAA,EAC7C,GAAA,EAAK,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA,EAAM;AAAA,EAC1C,GAAA,EAAK,EAAE,IAAA,EAAM,iBAAA,EAAmB,WAAW,KAAA,EAAM;AAAA,EACjD,GAAA,EAAK,EAAE,IAAA,EAAM,sBAAA,EAAwB,WAAW,KAAA,EAAM;AAAA,EACtD,GAAA,EAAK,EAAE,IAAA,EAAM,aAAA,EAAe,WAAW,IAAA;AACzC,CAAA;AAEA,IAAM,gBAAA,GAA0D;AAAA,EAC9D,SAAA,EAAW,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA,EAAM;AAAA,EAChD,YAAA,EAAc,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA,EAAM;AAAA;AAAA,EAEnD,YAAA,EAAc,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA,EAAM;AAAA,EACnD,YAAA,EAAc,EAAE,IAAA,EAAM,WAAA,EAAa,WAAW,KAAA,EAAM;AAAA,EACpD,QAAA,EAAU,EAAE,IAAA,EAAM,eAAA,EAAiB,WAAW,IAAA,EAAK;AAAA,EACnD,SAAA,EAAW,EAAE,IAAA,EAAM,kBAAA,EAAoB,WAAW,IAAA,EAAK;AAAA,EACvD,yBAAA,EAA2B,EAAE,IAAA,EAAM,kBAAA,EAAoB,WAAW,IAAA,EAAK;AAAA,EACvE,eAAA,EAAiB,EAAE,IAAA,EAAM,cAAA,EAAgB,WAAW,IAAA,EAAK;AAAA,EACzD,YAAA,EAAc,EAAE,IAAA,EAAM,cAAA,EAAgB,WAAW,IAAA;AACnD,CAAA;AAEA,IAAM,mBAAA,GAA6D;AAAA,EACjE,OAAA,EAAS,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA;AAC1C,CAAA;AAEA,IAAM,mBAAA,GAA6D;AAAA,EACjE,wBAAA,EAA0B,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA,EAAM;AAAA,EAC/D,4BAAA,EAA8B,EAAE,IAAA,EAAM,UAAA,EAAY,WAAW,KAAA;AAC/D,CAAA;AAMA,IAAM,OAAA,GAAU,CAAC,IAAA,EAAc,OAAA,EAAiB,KAAA,MAAqC;AAAA,EACnF,IAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAI,SAAS;AACf,CAAA,CAAA;AAEA,IAAM,QAAA,GAAW,CAACA,IAAAA,KAChB,IAAI,eAAA,CAAgB;AAAA,EAClB,IAAA,EAAM,eAAA;AAAA,EACN,SAASA,IAAAA,YAAe,KAAA,GAAQA,IAAAA,CAAI,OAAA,GAAU,OAAOA,IAAG,CAAA;AAAA,EACxD,SAAA,EAAW,IAAA;AAAA,EACX,KAAA,EAAO,OAAA;AAAA,IACL,SAAA;AAAA,IACAA,IAAAA,YAAe,KAAA,GAAQA,IAAAA,CAAI,OAAA,GAAU,OAAOA,IAAG;AAAA;AAEnD,CAAC,CAAA;AAEI,IAAM,OAAA,GAAU,CAACA,IAAAA,KAAkC;AACxD,EAAA,IAAIA,IAAAA,YAAe,iBAAiB,OAAOA,IAAAA;AAE3C,EAAA,IAAI,OAAOA,IAAAA,KAAQ,QAAA,IAAYA,SAAQ,IAAA,EAAM,OAAO,SAASA,IAAG,CAAA;AAEhE,EAAA,MAAM,MAAA,GAASA,IAAAA;AAKf,EAAA,MAAM,OAAO,OAAO,MAAA,CAAO,IAAA,KAAS,QAAA,GAAW,OAAO,IAAA,GAAO,MAAA;AAC7D,EAAA,MAAM,OAAA,GACJ,OAAO,MAAA,CAAO,OAAA,KAAY,WAAW,MAAA,CAAO,OAAA,GAAU,CAAA,WAAA,EAAc,IAAA,IAAQ,SAAS,CAAA,CAAA;AACvF,EAAA,MAAM,MAAA,GACJ,OAAO,MAAA,CAAO,SAAA,EAAW,mBAAmB,QAAA,GACxC,MAAA,CAAO,UAAU,cAAA,GACjB,MAAA;AAEN,EAAA,MAAM,KAAA,GAAQ,OAAA;AAAA,IACZ,IAAA,KAAS,MAAA,KAAW,MAAA,GAAY,MAAA,CAAO,MAAM,CAAA,GAAI,SAAA,CAAA;AAAA,IACjD,OAAA;AAAA,IACA,MAAA,KAAW,MAAA,GAAY,EAAE,cAAA,EAAgB,QAAO,GAAI;AAAA,GACtD;AAGA,EAAA,IAAI,IAAA,IAAQ,QAAQ,gBAAA,EAAkB;AACpC,IAAA,MAAM,CAAA,GAAI,iBAAiB,IAAI,CAAA;AAC/B,IAAA,OAAO,IAAI,eAAA,CAAgB,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,OAAA,EAAS,SAAA,EAAW,CAAA,CAAE,SAAA,EAAW,KAAA,EAAO,CAAA;AAAA,EACrF;AAGA,EAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,IAAU,mBAAA,EAAqB;AACzD,IAAA,MAAM,CAAA,GAAI,oBAAoB,MAAM,CAAA;AACpC,IAAA,OAAO,IAAI,eAAA,CAAgB,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,OAAA,EAAS,SAAA,EAAW,CAAA,CAAE,SAAA,EAAW,KAAA,EAAO,CAAA;AAAA,EACrF;AAGA,EAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,IAAU,GAAA,IAAO,SAAS,GAAA,EAAK;AACzD,IAAA,OAAO,IAAI,gBAAgB,EAAE,IAAA,EAAM,iBAAiB,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,EACvF;AAGA,EAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,IAAU,GAAA,IAAO,SAAS,GAAA,EAAK;AACzD,IAAA,OAAO,IAAI,gBAAgB,EAAE,IAAA,EAAM,aAAa,OAAA,EAAS,SAAA,EAAW,KAAA,EAAO,KAAA,EAAO,CAAA;AAAA,EACpF;AAEA,EAAA,OAAO,IAAI,gBAAgB,EAAE,IAAA,EAAM,iBAAiB,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,CAAA;AACvF,CAAA;AAEO,IAAM,MAAA,GAAS,CAACA,IAAAA,KAAkC;AACvD,EAAA,IAAIA,IAAAA,YAAe,iBAAiB,OAAOA,IAAAA;AAE3C,EAAA,IAAI,OAAOA,IAAAA,KAAQ,QAAA,IAAYA,SAAQ,IAAA,EAAM,OAAO,SAASA,IAAG,CAAA;AAEhE,EAAA,MAAM,KAAA,GAAQA,IAAAA;AACd,EAAA,MAAM,WAAW,OAAO,KAAA,CAAM,IAAA,KAAS,QAAA,GAAW,MAAM,IAAA,GAAO,MAAA;AAC/D,EAAA,MAAM,OAAA,GACJ,OAAO,KAAA,CAAM,OAAA,KAAY,WAAW,KAAA,CAAM,OAAA,GAAU,CAAA,gBAAA,EAAmB,QAAA,IAAY,SAAS,CAAA,CAAA;AAC9F,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,QAAA,IAAY,SAAA,EAAW,OAAO,CAAA;AAEpD,EAAA,IAAI,QAAA,IAAY,YAAY,mBAAA,EAAqB;AAC/C,IAAA,MAAM,CAAA,GAAI,oBAAoB,QAAQ,CAAA;AACtC,IAAA,OAAO,IAAI,eAAA,CAAgB,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,OAAA,EAAS,SAAA,EAAW,CAAA,CAAE,SAAA,EAAW,KAAA,EAAO,CAAA;AAAA,EACrF;AAEA,EAAA,OAAO,IAAI,gBAAgB,EAAE,IAAA,EAAM,iBAAiB,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,CAAA;AACvF,CAAA;AAEO,IAAM,UAAA,GAAa,CAACA,IAAAA,KAAkC;AAC3D,EAAA,IAAIA,IAAAA,YAAe,iBAAiB,OAAOA,IAAAA;AAE3C,EAAA,IAAI,OAAOA,IAAAA,KAAQ,QAAA,IAAYA,SAAQ,IAAA,EAAM,OAAO,SAASA,IAAG,CAAA;AAEhE,EAAA,MAAM,MAAA,GAASA,IAAAA;AACf,EAAA,MAAM,OAAO,OAAO,MAAA,CAAO,IAAA,KAAS,QAAA,GAAW,OAAO,IAAA,GAAO,MAAA;AAC7D,EAAA,MAAM,OAAA,GACJ,OAAO,MAAA,CAAO,OAAA,KAAY,WAAW,MAAA,CAAO,OAAA,GAAU,CAAA,cAAA,EAAiB,IAAA,IAAQ,SAAS,CAAA,CAAA;AAC1F,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,IAAA,IAAQ,SAAA,EAAW,OAAO,CAAA;AAEhD,EAAA,IAAI,IAAA,IAAQ,QAAQ,mBAAA,EAAqB;AACvC,IAAA,MAAM,CAAA,GAAI,oBAAoB,IAAI,CAAA;AAClC,IAAA,OAAO,IAAI,eAAA,CAAgB,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,OAAA,EAAS,SAAA,EAAW,CAAA,CAAE,SAAA,EAAW,KAAA,EAAO,CAAA;AAAA,EACrF;AAEA,EAAA,OAAO,IAAI,gBAAgB,EAAE,IAAA,EAAM,iBAAiB,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,CAAA;AACvF,CAAA;;;ACpHO,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EAChC,IAAA;AAAA,EACA,SAAA;AAAA,EACS,KAAA;AAAA,EAElB,YAAY,IAAA,EAA8B;AACxC,IAAA,KAAA,CAAM,KAAK,OAAO,CAAA;AAClB,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AACZ,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA;AACjB,IAAA,IAAA,CAAK,YAAY,IAAA,CAAK,SAAA;AACtB,IAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAW;AAC5B,MAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAA,GAA8B;AAC5B,IAAA,OAAO;AAAA,MACL,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,GAAI,KAAK,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,IAAA,CAAK,KAAA,EAAM,GAAI;AAAC,KAC1D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,QAAQA,IAAAA,EAA+B;AAI5C,IAAA,OAAO,QAASA,IAAG,CAAA;AAAA,EACrB;AAAA,EAEA,OAAO,OAAOA,IAAAA,EAA+B;AAC3C,IAAA,OAAO,OAAQA,IAAG,CAAA;AAAA,EACpB;AAAA,EAEA,OAAO,WAAWA,IAAAA,EAA+B;AAC/C,IAAA,OAAO,WAAYA,IAAG,CAAA;AAAA,EACxB;AACF,CAAA;;;ACxEO,IAAM,OAAA,GAAU,CAAC,CAAA,KAAqB,CAAA;AAqBtC,IAAM,UAAA,GAAa,CAAC,CAAA,KAAwB,CAAA;;;AC9DnD,IAAM,eAAe,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,gBAAgB,CAAA;AACvD,IAAM,UAAA,GAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAEhC,IAAM,oBAAA,GAAuB,EAAE,MAAA,CAAO;AAAA,EAC3C,QAAA,EAAU,UAAA;AAAA,EACV,KAAA,EAAO,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAC5C,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACrB,CAAC,CAAA;AAEM,IAAM,qBAAA,GAAwB,EAAE,MAAA,CAAO;AAAA,EAC5C,EAAA,EAAI,YAAA;AAAA,EACJ,SAAA,EAAW,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA;AACzB,CAAC,CAAA;AAEM,IAAM,mBAAA,GAAsB,EAAE,MAAA,CAAO;AAAA,EAC1C,EAAA,EAAI,YAAA;AAAA,EACJ,WAAA,EAAa,UAAA;AAAA,EACb,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA;AACtC,CAAC,CAAA;AAEM,IAAM,mBAAA,GAAsB,EAAE,MAAA,CAAO;AAAA,EAC1C,EAAA,EAAI,YAAA;AAAA,EACJ,WAAA,EAAa,UAAA;AAAA,EACb,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA;AACtC,CAAC,CAAA;AAEM,IAAM,sBAAA,GAAyB,EAAE,MAAA,CAAO;AAAA,EAC7C,EAAA,EAAI,YAAA;AAAA,EACJ,QAAA,EAAU,CAAA,CAAE,MAAA,CAAO,CAAA,CAAE,QAAQ,CAAA;AAAA,EAC7B,OAAA,EAAS,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA;AACvB,CAAC,CAAA;AAEM,IAAM,uBAAA,GAA0B,EAAE,MAAA,CAAO;AAAA,EAC9C,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG;AACjC,CAAC,CAAA;AAEM,IAAM,wBAAA,GAA2B,EAAE,MAAA,CAAO;AAAA,EAC/C,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAAA,EAC/B,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EAC7B,eAAe,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,WAAA;AAClC,CAAC,CAAA;AAEM,IAAM,wBAAA,GAA2B,EAAE,MAAA,CAAO;AAAA,EAC/C,EAAA,EAAI,YAAA;AAAA,EACJ,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAAA,EAC/B,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,IAAA,EAAM,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,WAAA,GAAc,QAAA;AACvC,CAAC,CAAA;AAEM,IAAM,sBAAA,GAAyB,EAAE,MAAA,CAAO;AAAA,EAC7C,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,EAChB,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC9B,KAAA,EAAO,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AACrC,CAAC,CAAA;AAEM,IAAM,sBAAA,GAAyB,EAAE,MAAA,CAAO;AAAA,EAC7C,EAAA,EAAI;AACN,CAAC,CAAA;AAEM,IAAM,sBAAA,GAAyB,EAAE,MAAA,CAAO;AAAA,EAC7C,EAAA,EAAI;AACN,CAAC,CAAA;AAEM,IAAM,uBAAA,GAA0B,EAAE,MAAA,CAAO;AAAA,EAC9C,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC;AACzB,CAAC,CAAA;AAEM,IAAM,sBAAA,GAAyB,EAAE,MAAA,CAAO;AAAA,EAC7C,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC;AACzB,CAAC,CAAA;AAED,IAAM,MAAA,GAAS,CAAC,OAAA,EAAiB,MAAA,KAC/B,GAAA;AAAA,EACE,IAAI,eAAA,CAAgB;AAAA,IAClB,IAAA,EAAM,eAAA;AAAA,IACN,OAAA;AAAA,IACA,SAAA,EAAW,KAAA;AAAA,IACX,KAAA,EAAO,EAAE,IAAA,EAAM,UAAA,EAAY,OAAA,EAAS,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS,MAAA,EAAQ,MAAA,CAAO,KAAA,CAAM,MAAA;AAAO,GACvF;AACH,CAAA;AAWK,IAAM,mBAAA,GAAsB,CAAC,IAAA,KAA4B;AAC9D,EAAA,MAAM,EAAE,KAAA,EAAO,YAAA,EAAc,EAAA,EAAI,SAAQ,GAAI,IAAA;AAC7C,EAAA,MAAM,mBAAmB,IAAA,CAAK,eAAA,IAAmB,YAAA,EAAc,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAEjF,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,EAAY,IAAA,EAA+B,OAAA,KAAqC;AAC5F,IAAA,IAAI,CAAA,YAAa,iBAAiB,OAAO,CAAA;AACzC,IAAA,OAAO,IAAI,eAAA,CAAgB;AAAA,MACzB,IAAA;AAAA,MACA,OAAA,EAAS,CAAA,EAAG,OAAO,CAAA,EAAA,EAAK,CAAA,YAAa,QAAQ,CAAA,CAAE,OAAA,GAAU,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA;AAAA,MAClE,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,YAAkC,OAAA,EAAQ;AAE7D,EAAA,MAAM,SAAA,GAAY,OAChB,KAAA,KACsD;AACtD,IAAA,MAAM,MAAA,GAAS,oBAAA,CAAqB,SAAA,CAAU,KAAK,CAAA;AACnD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,2BAA2B,MAAM,CAAA;AACpE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,YAAA,CAAa;AAAA,QACxB,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA;AAAA,QACtB,KAAA,EAAO,OAAO,IAAA,CAAK,KAAA;AAAA,QACnB,MAAA,EAAQ,OAAO,IAAA,CAAK;AAAA,OACrB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,kBAAkB,CAAC,CAAA;AAAA,IACzD;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,OACjB,KAAA,KAC2C;AAC3C,IAAA,MAAM,MAAA,GAAS,qBAAA,CAAsB,SAAA,CAAU,KAAK,CAAA;AACpD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,4BAA4B,MAAM,CAAA;AACrE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,aAAa,iBAAA,CAAkB;AAAA,QACpC,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,EAAA,EAAI,OAAO,IAAA,CAAK,EAAA;AAAA,QAChB,SAAA,EAAW,OAAO,IAAA,CAAK;AAAA,OACxB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,mBAAmB,CAAC,CAAA;AAAA,IAC1D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,OACf,KAAA,KAC+C;AAC/C,IAAA,MAAM,MAAA,GAAS,mBAAA,CAAoB,SAAA,CAAU,KAAK,CAAA;AAClD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,0BAA0B,MAAM,CAAA;AACnE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,QAAA,CAAS;AAAA,QACpB,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,EAAA,EAAI,OAAO,IAAA,CAAK,EAAA;AAAA,QAChB,WAAA,EAAa,OAAO,IAAA,CAAK,WAAA;AAAA,QACzB,OAAA,EAAS,OAAO,IAAA,CAAK;AAAA,OACtB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,iBAAiB,CAAC,CAAA;AAAA,IACxD;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,OACf,KAAA,KAC+C;AAC/C,IAAA,MAAM,MAAA,GAAS,mBAAA,CAAoB,SAAA,CAAU,KAAK,CAAA;AAClD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,0BAA0B,MAAM,CAAA;AACnE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,aAAa,eAAA,CAAgB;AAAA,QAClC,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,EAAA,EAAI,OAAO,IAAA,CAAK,EAAA;AAAA,QAChB,WAAA,EAAa,OAAO,IAAA,CAAK,WAAA;AAAA,QACzB,OAAA,EAAS,OAAO,IAAA,CAAK;AAAA,OACtB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,iBAAiB,CAAC,CAAA;AAAA,IACxD;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAClB,KAAA,KAC+C;AAC/C,IAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,SAAA,CAAU,KAAK,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,6BAA6B,MAAM,CAAA;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,cAAA,CAAe;AAAA,QAC1B,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,EAAA,EAAI,OAAO,IAAA,CAAK,EAAA;AAAA,QAChB,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA;AAAA,QACtB,OAAA,EAAS,OAAO,IAAA,CAAK;AAAA,OACtB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,oBAAoB,CAAC,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,OACnB,KAAA,KAC+C;AAC/C,IAAA,MAAM,MAAA,GAAS,uBAAA,CAAwB,SAAA,CAAU,KAAK,CAAA;AACtD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,8BAA8B,MAAM,CAAA;AACvE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,UAAA,CAAW;AAAA,QACtB,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA;AAAA,QACtB,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA;AAAA,QAClB,IAAA,EAAM,QAAA;AAAA,QACN,IAAA,EAAM,CAAA;AAAA,QACN,QAAA,EAAU,EAAA;AAAA,QACV,KAAA,EAAO,EAAA;AAAA,QACP,SAAS,IAAA,CAAK;AAAA,OACf,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,qBAAqB,CAAC,CAAA;AAAA,IAC5D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,OACpB,KAAA,KAC0D;AAC1D,IAAA,MAAM,MAAA,GAAS,wBAAA,CAAyB,SAAA,CAAU,KAAK,CAAA;AACvD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,+BAA+B,MAAM,CAAA;AACxE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,MAAM,EAAA,GACJ,OAAO,UAAA,CAAW,MAAA,EAAQ,UAAA,KAAe,UAAA,GACrC,UAAA,CAAW,MAAA,CAAO,UAAA,EAAW,GAC7B,CAAA,IAAA,EAAO,IAAA,CAAK,KAAK,CAAA,CAAA;AACvB,MAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,SAAA,CAAU,KAAK,QAAQ,CAAA,CAAE,QAAQ,wBAAA,CAAyB;AAAA,QAChF,GAAA,EAAK,QAAQ,EAAE,CAAA;AAAA,QACf,WAAA,EAAa,OAAO,IAAA,CAAK,WAAA;AAAA,QACzB,SAAA,EAAW;AAAA,OACZ,CAAA;AACD,MAAA,IAAI,CAAC,MAAA,CAAO,EAAA,EAAI,OAAO,MAAA;AACvB,MAAA,OAAO,EAAA,CAAG;AAAA,QACR,EAAA;AAAA,QACA,GAAA,EAAK,EAAA;AAAA,QACL,GAAA,EAAK,OAAO,KAAA,CAAM,GAAA;AAAA,QAClB,MAAA,EAAQ,OAAO,KAAA,CAAM,MAAA;AAAA,QACrB,OAAA,EAAS,MAAA,CAAO,KAAA,CAAM,eAAA,IAAmB,EAAC;AAAA,QAC1C,SAAA,EAAW,IAAI,IAAA,CAAK,IAAA,CAAK,KAAI,GAAI,GAAO,EAAE,WAAA;AAAY,OACvD,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,sBAAsB,CAAC,CAAA;AAAA,IAC7D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,OACpB,KAAA,KAC+C;AAC/C,IAAA,MAAM,MAAA,GAAS,wBAAA,CAAyB,SAAA,CAAU,KAAK,CAAA;AACvD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,+BAA+B,MAAM,CAAA;AACxE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,aAAa,aAAA,CAAc;AAAA,QAChC,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,EAAA,EAAI,OAAO,IAAA,CAAK,EAAA;AAAA,QAChB,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA;AAAA,QACtB,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA;AAAA,QAClB,WAAA,EAAa,OAAO,IAAA,CAAK,WAAA;AAAA,QACzB,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA;AAAA,QAClB,SAAS,IAAA,CAAK;AAAA,OACf,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,sBAAsB,CAAC,CAAA;AAAA,IAC7D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAClB,KAAA,KACsD;AACtD,IAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,SAAA,CAAU,KAAK,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,6BAA6B,MAAM,CAAA;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,MAAA,CAAO;AAAA,QAClB,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,KAAA,EAAO,OAAO,IAAA,CAAK,KAAA;AAAA,QACnB,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA;AAAA,QACtB,KAAA,EAAO,OAAO,IAAA,CAAK;AAAA,OACpB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,oBAAoB,CAAC,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,OAChB,KAAA,GAA6C,EAAC,KACQ;AACtD,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,SAAA,CAAU;AAAA,QACrB,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,QAAQ,KAAA,CAAM;AAAA,OACf,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,kBAAkB,CAAC,CAAA;AAAA,IACzD;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAClB,KAAA,KAC+C;AAC/C,IAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,SAAA,CAAU,KAAK,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,6BAA6B,MAAM,CAAA;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,WAAA,CAAY;AAAA,QACvB,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,EAAA,EAAI,OAAO,IAAA,CAAK;AAAA,OACjB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,oBAAoB,CAAC,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,OAChB,KAAA,KAC2C;AAC3C,IAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,SAAA,CAAU,KAAK,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,2BAA2B,MAAM,CAAA;AACpE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,aAAa,gBAAA,CAAiB;AAAA,QACnC,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,EAAA,EAAI,OAAO,IAAA,CAAK;AAAA,OACjB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,kBAAkB,CAAC,CAAA;AAAA,IACzD;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAClB,KAAA,KACqE;AACrE,IAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,SAAA,CAAU,KAAK,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,6BAA6B,MAAM,CAAA;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,MAAM,QAAA,GAAW,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AACzC,MAAA,MAAM,IAAA,GAAO,MAAM,KAAA,CAAM,OAAA,CAAQ,EAAE,UAAU,EAAA,EAAI,MAAA,CAAO,IAAA,CAAK,EAAA,EAAI,CAAA;AACjE,MAAA,IAAI,CAAC,IAAA,CAAK,EAAA,EAAI,OAAO,IAAA;AACrB,MAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,KAAA,CAAM,SAAS,MAAA,IAAU,CAAC,IAAA,CAAK,KAAA,CAAM,KAAA,EAAO;AAClE,QAAA,OAAO,GAAA;AAAA,UACL,IAAI,eAAA,CAAgB;AAAA,YAClB,IAAA,EAAM,UAAA;AAAA,YACN,OAAA,EAAS,8CAAA;AAAA,YACT,SAAA,EAAW;AAAA,WACZ;AAAA,SACH;AAAA,MACF;AACA,MAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,CAAM,WAAA,CAAY;AAAA,QACpC,QAAA;AAAA,QACA,MAAA,EAAQ,OAAO,IAAA,CAAK;AAAA,OACrB,CAAA;AACD,MAAA,IAAI,CAAC,KAAA,CAAM,EAAA,EAAI,OAAO,KAAA;AACtB,MAAA,OAAO,EAAA,CAAG;AAAA,QACR,KAAA,EAAO,MAAM,KAAA,CAAM,KAAA;AAAA,QACnB,KAAK,CAAA,EAAG,eAAe,CAAA,CAAA,EAAI,KAAA,CAAM,MAAM,KAAK,CAAA;AAAA,OAC7C,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,oBAAoB,CAAC,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,OACnB,KAAA,KACsD;AACtD,IAAA,MAAM,MAAA,GAAS,uBAAA,CAAwB,SAAA,CAAU,KAAK,CAAA;AACtD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,8BAA8B,MAAM,CAAA;AACvE,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,YAAA,CAAa,EAAE,OAAO,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,IACxD,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,qBAAqB,CAAC,CAAA;AAAA,IAC5D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAClB,KAAA,KAC2C;AAC3C,IAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,SAAA,CAAU,KAAK,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,6BAA6B,MAAM,CAAA;AACtE,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW;AAC9B,MAAA,OAAO,MAAM,WAAA,CAAY;AAAA,QACvB,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA;AAAA,QAClC,KAAA,EAAO,OAAO,IAAA,CAAK;AAAA,OACpB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAA,EAAG,eAAA,EAAiB,oBAAoB,CAAC,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,UAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AACF;;;AC3YA,IAAM,sBAAA,GAAyB,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,EAAA;AAE7C,IAAM,0BAAA,GAA6B,GAAA;AAOnC,IAAM,kBAAA,GAAqB,CAAC,OAAA,EAAiB,MAAA,KAA4B;AACvE,EAAA,IAAI,OAAA,KAAY,QAAQ,OAAO,IAAA;AAC/B,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,EAAG;AAC1B,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAClC,IAAA,OAAO,MAAA,CAAO,WAAW,MAAM,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,KAAA;AACT,CAAA;AAoCA,IAAM,eAAA,GAAkB,CAAC,SAAA,KAA4B;AACnD,EAAA,IAAI,CAAC,OAAO,QAAA,CAAS,SAAS,KAAK,SAAA,GAAY,CAAA,IAAK,YAAY,sBAAA,EAAwB;AACtF,IAAA,MAAM,IAAI,eAAA,CAAgB;AAAA,MACxB,IAAA,EAAM,eAAA;AAAA,MACN,OAAA,EAAS,mCAAmC,sBAAsB,CAAA,yBAAA,CAAA;AAAA,MAClE,SAAA,EAAW,KAAA;AAAA,MACX,OAAO,EAAE,IAAA,EAAM,mBAAmB,OAAA,EAAS,CAAA,UAAA,EAAa,SAAS,CAAA,CAAA;AAAG,KACrE,CAAA;AAAA,EACH;AACF,CAAA;AAMO,IAAM,wBAAA,GAA2B,CACtC,IAAA,KAC0C;AAC1C,EAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,0BAAA;AAEpC,EAAA,eAAA,CAAgB,SAAS,CAAA;AAEzB,EAAA,OAAO,OAAO,GAAA,KAAoC;AAChD,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI;AACF,MAAA,IAAA,GAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,IACzB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,eAAA,EAAiB,OAAA,EAAS,iCAAA,EAAkC,EAAE;AAAA,QAC1F,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAGA,IAAA,IAAI,OAAO,IAAA,CAAK,QAAA,KAAa,YAAY,IAAA,CAAK,aAAA,GAAgB,KAAK,QAAA,EAAU;AAC3E,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd;AAAA,UACE,EAAA,EAAI,KAAA;AAAA,UACJ,KAAA,EAAO;AAAA,YACL,IAAA,EAAM,iBAAA;AAAA,YACN,SAAS,CAAA,cAAA,EAAiB,IAAA,CAAK,aAAa,CAAA,kBAAA,EAAqB,KAAK,QAAQ,CAAA;AAAA;AAChF,SACF;AAAA,QACA,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAGA,IAAA,IAAI,IAAA,CAAK,mBAAA,IAAuB,IAAA,CAAK,mBAAA,CAAoB,SAAS,CAAA,EAAG;AACnE,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,mBAAA,CAAoB,IAAA,CAAK,CAAC,MAAM,kBAAA,CAAmB,CAAA,EAAG,IAAA,CAAK,WAAW,CAAC,CAAA;AAC5F,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,OAAO,QAAA,CAAS,IAAA;AAAA,UACd;AAAA,YACE,EAAA,EAAI,KAAA;AAAA,YACJ,KAAA,EAAO;AAAA,cACL,IAAA,EAAM,sBAAA;AAAA,cACN,OAAA,EAAS,CAAA,aAAA,EAAgB,IAAA,CAAK,WAAW,CAAA,4BAAA;AAAA;AAC3C,WACF;AAAA,UACA,EAAE,QAAQ,GAAA;AAAI,SAChB;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,KAAK,IAAA,CAAK,EAAA;AACd,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACnC,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO,QAAA,CAAS,IAAA;AAAA,UACd,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,mBAAA,EAAoB,EAAE;AAAA,UAC3E,EAAE,QAAQ,GAAA;AAAI,SAChB;AAAA,MACF;AACA,MAAA,EAAA,GAAK,IAAA,CAAK,EAAA,CAAG,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA;AAAA,IACtC;AAEA,IAAA,MAAM,EAAA,GACJ,OAAO,UAAA,CAAW,MAAA,EAAQ,UAAA,KAAe,UAAA,GACrC,UAAA,CAAW,MAAA,CAAO,UAAA,EAAW,GAC7B,CAAA,IAAA,EAAO,IAAA,CAAK,KAAK,CAAA,CAAA;AACvB,IAAA,MAAM,CAAA,GAAI,MAAM,EAAA,CAAG,OAAA,CAAQ,wBAAA,CAAyB;AAAA,MAClD,GAAA,EAAK,QAAQ,EAAE,CAAA;AAAA,MACf,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB;AAAA,KACD,CAAA;AACD,IAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACT,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS,CAAA,CAAE,KAAA,CAAM,SAAQ,EAAE;AAAA,QACrE,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,IAAA,CAAK,KAAI,GAAI,SAAA,GAAY,GAAI,CAAA,CAAE,WAAA,EAAY;AACtE,IAAA,OAAO,SAAS,IAAA,CAAK;AAAA,MACnB,EAAA,EAAI,IAAA;AAAA,MACJ,KAAA,EAAO;AAAA,QACL,GAAA,EAAK,EAAE,KAAA,CAAM,GAAA;AAAA,QACb,GAAA,EAAK,EAAA;AAAA,QACL,EAAA;AAAA,QACA,MAAA,EAAQ,EAAE,KAAA,CAAM,MAAA;AAAA,QAChB,OAAA,EAAS,CAAA,CAAE,KAAA,CAAM,eAAA,IAAmB,EAAC;AAAA,QACrC;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AACF;;;ACrKA,IAAMC,uBAAAA,GAAyB,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,EAAA;AAE7C,IAAMC,2BAAAA,GAA6B,GAAA;AAmBnC,IAAMC,gBAAAA,GAAkB,CAAC,SAAA,KAA4B;AACnD,EAAA,IAAI,CAAC,OAAO,QAAA,CAAS,SAAS,KAAK,SAAA,GAAY,CAAA,IAAK,YAAYF,uBAAAA,EAAwB;AACtF,IAAA,MAAM,IAAI,eAAA,CAAgB;AAAA,MACxB,IAAA,EAAM,eAAA;AAAA,MACN,OAAA,EAAS,mCAAmCA,uBAAsB,CAAA,yBAAA,CAAA;AAAA,MAClE,SAAA,EAAW,KAAA;AAAA,MACX,OAAO,EAAE,IAAA,EAAM,mBAAmB,OAAA,EAAS,CAAA,UAAA,EAAa,SAAS,CAAA,CAAA;AAAG,KACrE,CAAA;AAAA,EACH;AACF,CAAA;AAWO,IAAM,0BAAA,GAA6B,CACxC,IAAA,KAC0C;AAC1C,EAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAaC,2BAAAA;AACpC,EAAAC,iBAAgB,SAAS,CAAA;AAEzB,EAAA,OAAO,OAAO,GAAA,KAAoC;AAChD,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAC3B,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA;AACtC,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,eAAA,EAAiB,OAAA,EAAS,mCAAA,EAAoC,EAAE;AAAA,QAC5F,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAEA,IAAA,IAAI,KAAK,IAAA,CAAK,EAAA;AACd,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACnC,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO,QAAA,CAAS,IAAA;AAAA,UACd,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,mBAAA,EAAoB,EAAE;AAAA,UAC3E,EAAE,QAAQ,GAAA;AAAI,SAChB;AAAA,MACF;AACA,MAAA,EAAA,GAAK,IAAA,CAAK,EAAA,CAAG,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA;AAAA,IACtC;AAEA,IAAA,MAAM,CAAA,GAAI,MAAM,EAAA,CAAG,OAAA,CAAQ,0BAAA,CAA2B;AAAA,MACpD,GAAA,EAAK,QAAQ,GAAG,CAAA;AAAA,MAChB;AAAA,KACD,CAAA;AACD,IAAA,IAAI,CAAC,EAAE,EAAA,EAAI;AACT,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS,CAAA,CAAE,KAAA,CAAM,SAAQ,EAAE;AAAA,QACrE,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,IAAA,CAAK,KAAI,GAAI,SAAA,GAAY,GAAI,CAAA,CAAE,WAAA,EAAY;AACtE,IAAA,OAAO,SAAS,IAAA,CAAK;AAAA,MACnB,EAAA,EAAI,IAAA;AAAA,MACJ,OAAO,EAAE,GAAA,EAAK,CAAA,CAAE,KAAA,CAAM,KAAK,SAAA;AAAU,KACtC,CAAA;AAAA,EACH,CAAA;AACF;;;ACjGA,IAAM,gBAAA,GAAmB,CAAC,GAAA,KAAgC;AACxD,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAC3B,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AAC1C,EAAA,IAAI,KAAA,IAAS,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,KAAA;AACtC,EAAA,MAAM,KAAA,GAAQ,IAAI,QAAA,CAAS,OAAA,CAAQ,QAAQ,EAAE,CAAA,CAAE,MAAM,GAAG,CAAA;AACxD,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AACnC,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,KAAS,OAAA,EAAS,OAAO,IAAA;AACtC,EAAA,OAAO,IAAA;AACT,CAAA;AAEO,IAAM,uBAAA,GAA0B,CACrC,IAAA,KAC0C;AAC1C,EAAA,OAAO,OAAO,GAAA,KAAoC;AAChD,IAAA,MAAM,KAAA,GAAQ,iBAAiB,GAAG,CAAA;AAClC,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,eAAA,EAAiB,OAAA,EAAS,qBAAA,EAAsB,EAAE;AAAA,QAC9E,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAEA,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,MAAM,YAAA,CAAa,EAAE,OAAO,CAAA;AACxD,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS,QAAA,CAAS,KAAA,CAAM,SAAQ,EAAE;AAAA,QACnF,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AACA,IAAA,MAAM,OAAO,QAAA,CAAS,KAAA;AACtB,IAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,SAAS,MAAA,IAAU,CAAC,KAAK,KAAA,EAAO;AAChD,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,IAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,UAAA,EAAY,OAAA,EAAS,iBAAA,EAAkB,EAAE;AAAA,QACrE,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,IAAA,CAAK,EAAA,CAAG,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA,CAAE,OAAA;AACjD,IAAA,MAAM,WAAA,GAAc,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,IAAK,MAAA;AAChD,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,IAAA,CAAK;AAAA,MAC9B,GAAA,EAAK,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA;AAAA,MACvB,OAAO,WAAA,IAAe;AAAA,KACvB,CAAA;AACD,IAAA,IAAI,CAAC,KAAK,EAAA,EAAI;AACZ,MAAA,OAAO,QAAA,CAAS,IAAA;AAAA,QACd,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS,IAAA,CAAK,KAAA,CAAM,SAAQ,EAAE;AAAA,QAC3E,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,CAAE,YAAA,CAAa,GAAA,CAAI,UAAU,CAAA,KAAM,GAAA;AACnE,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAC5B,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN,cAAA;AAAA,MACA,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,KAAA,CAAM,WAAA,IAAe;AAAA,KAC7C;AACA,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN,qBAAA;AAAA,MACA,CAAA,EAAG,WAAW,YAAA,GAAe,QAAQ,sBAAsB,kBAAA,CAAmB,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KAC1F;AACA,IAAA,OAAA,CAAQ,GAAA,CAAI,iBAAiB,mBAAmB,CAAA;AAChD,IAAA,OAAA,CAAQ,IAAI,gBAAA,EAAkB,MAAA,CAAO,KAAK,KAAA,CAAM,IAAA,CAAK,UAAU,CAAC,CAAA;AAEhE,IAAA,OAAO,IAAI,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,EAAG,EAAE,MAAA,EAAQ,GAAA,EAAK,OAAA,EAAS,CAAA;AAAA,EAC5E,CAAA;AACF","file":"index.js","sourcesContent":["/**\n * Discriminated `Result<T, E>` for typed error returns.\n *\n * Why Result over throw at boundaries:\n * - No `any` at the call site (vs try/catch which loses the type).\n * - `switch (r.ok)` narrows the type in consumer code.\n * - The wire shape `{ ok, value | error }` is JSON-serializable,\n * so it survives the RSC boundary without an extra DTO.\n * - Helpers (`map`, `andThen`, `unwrap`) make the common shapes\n * (chain, bail-out, recover) terse and exhaustive.\n *\n * The default error type is `FileSystemError` (see `@/errors`).\n * Consumers can specialize: `Result<User, ZodError>`.\n *\n * All helpers are pure functions; they do NOT allocate closures in\n * hot paths beyond what the spec demands (no `try`/`catch` wrapping).\n */\n\nimport { FileSystemError } from \"@/errors\";\n\nexport type Result<T, E = FileSystemError> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: E };\n\nexport const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });\n\nexport const err = <E>(error: E): Result<never, E> => ({ ok: false, error });\n\nexport const map = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => U,\n): Result<U, E> => (r.ok ? ok(f(r.value)) : r);\n\nexport const mapErr = <T, E, F>(\n r: Result<T, E>,\n f: (e: E) => F,\n): Result<T, F> => (r.ok ? r : err(f(r.error)));\n\nexport const andThen = <T, U, E>(\n r: Result<T, E>,\n f: (t: T) => Result<U, E>,\n): Result<U, E> => (r.ok ? f(r.value) : r);\n\nexport const unwrap = <T, E>(r: Result<T, E>): T => {\n if (r.ok) return r.value;\n throw r.error;\n};\n\nexport const unwrapOr = <T, E>(r: Result<T, E>, fallback: T): T =>\n r.ok ? r.value : fallback;\n","/**\n * Upstream error mappers for FileSystemError.\n *\n * Each mapper is a pure function `(*unknown) -> FileSystemError`.\n * The class re-exposes them as static methods (FileSystemError.fromAws\n * etc.) so callers can pick the import style that fits.\n *\n * Mapping strategy:\n * 1. If the input is already a FileSystemError, return it as-is\n * (we never re-wrap our own errors).\n * 2. Try the most specific signal first: S3 `name`, Postgres\n * SQLSTATE, SQLite extended code.\n * 3. Fall back to the HTTP status code (AWS SDK v3 exposes\n * `$metadata.httpStatusCode`).\n * 4. Last resort: InternalError, retryable, with the original\n * payload in `cause`.\n *\n * Provider-specific codes are preserved on `cause.code` (e.g. S3\n * \"NoSuchKey\", Postgres \"23505\") so callers can still branch on\n * them while the top-level `code` stays in the 11-code spec catalog.\n *\n * Mapping notes (post-C' merge, see\n * `sdd/file-next/decisions/error-codes-deviation`):\n * - S3 `SlowDown` -> QuotaExceeded (broader than RateLimited;\n * SlowDown means reduce request rate, which\n * is conceptually quota pressure, not\n * throttling of a single call).\n * - S3 `BadDigest` -> ChecksumMismatch (checksum verified by\n * S3 on upload did not match the client).\n * - HTTP 429 -> RateLimited (was QuotaExceeded in the\n * pre-C' catalog; RateLimited is the more\n * specific code for throttling responses).\n * - HTTP 408 -> NetworkError (transient transport error).\n * - HTTP 400 / Postgres 23514 / S3 InvalidRequest\n * -> fall through to the 4xx branch (no\n * top-level 400 code in the C' catalog;\n * these inputs are usually caught by the\n * name/SQLSTATE mapping first anyway).\n */\n\nimport { FileSystemError, type FileSystemErrorCode } from \"./index\";\n\n/* ---------------------------------------------------------------- *\n * Mapping tables (private) *\n * ---------------------------------------------------------------- */\n\ninterface CodeMapping {\n code: FileSystemErrorCode;\n retryable: boolean;\n}\n\nconst HTTP_STATUS_TO_CODE: Readonly<Record<number, CodeMapping>> = {\n 401: { code: \"Unauthorized\", retryable: false },\n 403: { code: \"Forbidden\", retryable: false },\n 404: { code: \"NotFound\", retryable: false },\n 408: { code: \"NetworkError\", retryable: true },\n 409: { code: \"Conflict\", retryable: false },\n 413: { code: \"PayloadTooLarge\", retryable: false },\n 415: { code: \"UnsupportedMediaType\", retryable: false },\n 429: { code: \"RateLimited\", retryable: true },\n};\n\nconst AWS_NAME_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n NoSuchKey: { code: \"NotFound\", retryable: false },\n NoSuchBucket: { code: \"NotFound\", retryable: false },\n // v0.2 multipart: unknown/aborted/expired uploadId.\n NoSuchUpload: { code: \"NotFound\", retryable: false },\n AccessDenied: { code: \"Forbidden\", retryable: false },\n SlowDown: { code: \"QuotaExceeded\", retryable: true },\n BadDigest: { code: \"ChecksumMismatch\", retryable: true },\n XAmzContentSHA256Mismatch: { code: \"ChecksumMismatch\", retryable: true },\n NetworkingError: { code: \"NetworkError\", retryable: true },\n TimeoutError: { code: \"NetworkError\", retryable: true },\n};\n\nconst PG_SQLSTATE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n \"23505\": { code: \"Conflict\", retryable: false },\n};\n\nconst SQLITE_CODE_TO_CODE: Readonly<Record<string, CodeMapping>> = {\n SQLITE_CONSTRAINT_UNIQUE: { code: \"Conflict\", retryable: false },\n SQLITE_CONSTRAINT_PRIMARYKEY: { code: \"Conflict\", retryable: false },\n};\n\n/* ---------------------------------------------------------------- *\n * Public mappers *\n * ---------------------------------------------------------------- */\n\nconst toCause = (code: string, message: string, extra?: Record<string, unknown>) => ({\n code,\n message,\n ...(extra ?? {}),\n});\n\nconst fallback = (err: unknown): FileSystemError =>\n new FileSystemError({\n code: \"InternalError\",\n message: err instanceof Error ? err.message : String(err),\n retryable: true,\n cause: toCause(\n \"Unknown\",\n err instanceof Error ? err.message : String(err),\n ),\n });\n\nexport const fromAws = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const awsErr = err as {\n name?: unknown;\n message?: unknown;\n $metadata?: { httpStatusCode?: unknown };\n };\n const name = typeof awsErr.name === \"string\" ? awsErr.name : undefined;\n const message =\n typeof awsErr.message === \"string\" ? awsErr.message : `AWS error: ${name ?? \"unknown\"}`;\n const status =\n typeof awsErr.$metadata?.httpStatusCode === \"number\"\n ? awsErr.$metadata.httpStatusCode\n : undefined;\n\n const cause = toCause(\n name ?? (status !== undefined ? String(status) : \"Unknown\"),\n message,\n status !== undefined ? { httpStatusCode: status } : undefined,\n );\n\n // 1) name-based mapping wins (more specific than HTTP status)\n if (name && name in AWS_NAME_TO_CODE) {\n const m = AWS_NAME_TO_CODE[name]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 2) HTTP status mapping\n if (status !== undefined && status in HTTP_STATUS_TO_CODE) {\n const m = HTTP_STATUS_TO_CODE[status]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n // 3) 5xx bucket\n if (status !== undefined && status >= 500 && status < 600) {\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n }\n\n // 4) anything else 4xx-shaped\n if (status !== undefined && status >= 400 && status < 500) {\n return new FileSystemError({ code: \"Forbidden\", message, retryable: false, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromPg = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const pgErr = err as { code?: unknown; message?: unknown };\n const sqlstate = typeof pgErr.code === \"string\" ? pgErr.code : undefined;\n const message =\n typeof pgErr.message === \"string\" ? pgErr.message : `Postgres error: ${sqlstate ?? \"unknown\"}`;\n const cause = toCause(sqlstate ?? \"Unknown\", message);\n\n if (sqlstate && sqlstate in PG_SQLSTATE_TO_CODE) {\n const m = PG_SQLSTATE_TO_CODE[sqlstate]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n\nexport const fromSqlite = (err: unknown): FileSystemError => {\n if (err instanceof FileSystemError) return err;\n\n if (typeof err !== \"object\" || err === null) return fallback(err);\n\n const sqlErr = err as { code?: unknown; message?: unknown };\n const code = typeof sqlErr.code === \"string\" ? sqlErr.code : undefined;\n const message =\n typeof sqlErr.message === \"string\" ? sqlErr.message : `SQLite error: ${code ?? \"unknown\"}`;\n const cause = toCause(code ?? \"Unknown\", message);\n\n if (code && code in SQLITE_CODE_TO_CODE) {\n const m = SQLITE_CODE_TO_CODE[code]!;\n return new FileSystemError({ code: m.code, message, retryable: m.retryable, cause });\n }\n\n return new FileSystemError({ code: \"InternalError\", message, retryable: true, cause });\n};\n","/**\n * FileSystemError — the single error class every adapter, store,\n * server action, and route handler in `file-next` returns or throws.\n *\n * Spec reference: requirement \"FileSystemError discriminated union\"\n * in `sdd/file-next/spec`. The 11 codes are the CLOSED set; any\n * provider-specific code (e.g. S3 `NoSuchKey`, Postgres `23505`) is\n * preserved on `cause.code` so callers can still distinguish upstream\n * reasons while the top-level `code` stays in the catalog.\n *\n * The catalog is a merge of spec + impl: the 6 fixed codes\n * (NotFound, Forbidden, Conflict, QuotaExceeded, NetworkError,\n * InternalError) are non-negotiable; the remaining 5 keep the wire\n * aligned with both the HTTP boundary (route handlers map the\n * top-level `code` to a status directly) and the storage boundary\n * (`RateLimited` and `ChecksumMismatch` carry semantics that have\n * no natural HTTP equivalent). See\n * `sdd/file-next/decisions/error-codes-deviation` for the\n * deviation log and rationale.\n *\n * Retryability table is the design's `error-mapping` excerpt; see\n * `sdd/file-next/design` §C. Any future code MUST add an entry in\n * `RETRYABLE_BY_CODE` (the catalog test enforces this).\n *\n * The placeholder from T-006 is replaced by this file in T-007a.\n * The upstream mappers (fromAws / fromPg / fromSqlite) land in T-007b\n * in `mappers.ts`.\n */\n\nexport const FILE_SYSTEM_ERROR_CODES = [\n \"NotFound\",\n \"Forbidden\",\n \"Conflict\",\n \"QuotaExceeded\",\n \"NetworkError\",\n \"InternalError\",\n \"Unauthorized\",\n \"PayloadTooLarge\",\n \"UnsupportedMediaType\",\n \"RateLimited\",\n \"ChecksumMismatch\",\n] as const satisfies readonly string[];\n\nexport type FileSystemErrorCode = (typeof FILE_SYSTEM_ERROR_CODES)[number];\n\nexport const RETRYABLE_BY_CODE: Readonly<Record<FileSystemErrorCode, boolean>> = {\n NotFound: false,\n Forbidden: false,\n Conflict: false,\n QuotaExceeded: true,\n NetworkError: true,\n InternalError: true,\n Unauthorized: false,\n PayloadTooLarge: false,\n UnsupportedMediaType: false,\n RateLimited: true,\n ChecksumMismatch: true,\n};\n\nexport interface FileSystemErrorOptions {\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport interface FileSystemErrorJson {\n name: string;\n code: FileSystemErrorCode;\n message: string;\n retryable: boolean;\n cause?: { code: string; message: string; [k: string]: unknown };\n}\n\nexport class FileSystemError extends Error {\n readonly code: FileSystemErrorCode;\n readonly retryable: boolean;\n override readonly cause?: { code: string; message: string; [k: string]: unknown };\n\n constructor(opts: FileSystemErrorOptions) {\n super(opts.message);\n this.name = \"FileSystemError\";\n this.code = opts.code;\n this.retryable = opts.retryable;\n if (opts.cause !== undefined) {\n this.cause = opts.cause;\n }\n }\n\n /**\n * Stable JSON shape for RSC pass-through. Error.prototype.message\n * is non-enumerable, so plain `JSON.stringify(err)` would emit `{}`\n * and lose the message + code + retryable flag. `cause` is omitted\n * entirely (not set to undefined) when absent so the shape stays\n * stable for hash-based caches.\n */\n toJSON(): FileSystemErrorJson {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n ...(this.cause !== undefined ? { cause: this.cause } : {}),\n };\n }\n\n /**\n * Mappers from upstream error shapes (AWS SDK v3, node-postgres,\n * better-sqlite3) to FileSystemError. See `./mappers.ts` for the\n * mapping tables. Re-exposed as static methods so callers can pick\n * the import style that fits; the free functions are the canonical\n * implementation.\n */\n static fromAws(err: unknown): FileSystemError {\n // Lazy import via the runtime binding avoids the static-field\n // circular-dep trap in ESM. The mapper file imports this class\n // for instanceof checks; we look up the function at call time.\n return _fromAws(err);\n }\n\n static fromPg(err: unknown): FileSystemError {\n return _fromPg(err);\n }\n\n static fromSqlite(err: unknown): FileSystemError {\n return _fromSqlite(err);\n }\n}\n\n// Imported here as bindings (not values) so the static methods above\n// can resolve them lazily. The actual implementation lives in mappers.ts.\nimport { fromAws as _fromAws, fromPg as _fromPg, fromSqlite as _fromSqlite } from \"./mappers\";\nexport { fromAws, fromPg, fromSqlite } from \"./mappers\";\n","/**\n * Branded string types and their constructors/guards.\n *\n * Brands are TypeScript-only fictions: a `Path` and an `S3Key` are\n * both strings at runtime, but the type system treats them as\n * distinct nominal types so the compiler catches accidental\n * cross-assignment (e.g. passing an S3Key where a TenantId is\n * expected).\n *\n * Conventions:\n * - `as*` is a zero-cost cast: trust the caller, brand the value.\n * Use it at trust boundaries you have already validated.\n * - `assert*` is a runtime guard: throws TypeError on invalid\n * input. Use it at the edge (parsing user/env input).\n *\n * Validation rules are intentionally minimal in v0.1 and can be\n * tightened as the spec evolves. None of them touch the network or\n * allocate; they are safe in hot paths.\n */\n\nexport type Path = string & { readonly __brand: \"Path\" };\nexport type Prefix = string & { readonly __brand: \"Prefix\" };\nexport type S3Key = string & { readonly __brand: \"S3Key\" };\nexport type TenantId = string & { readonly __brand: \"TenantId\" };\nexport type UserId = string & { readonly __brand: \"UserId\" };\n\n/**\n * POSIX file path. Non-empty, '/' is allowed as the root.\n */\nexport const asPath = (s: string): Path => s as Path;\nexport const assertPath = (s: string): Path => {\n if (s.length === 0) {\n throw new TypeError(\"Path must be a non-empty string\");\n }\n return s as Path;\n};\n\n/**\n * S3 prefix. Empty string is the root prefix. Non-empty prefixes\n * MUST end with '/' so concatenation with a key never produces\n * 'usersfile.jpg' by accident.\n */\nexport const asPrefix = (s: string): Prefix => s as Prefix;\nexport const assertPrefix = (s: string): Prefix => {\n if (s.length > 0 && !s.endsWith(\"/\")) {\n throw new TypeError(\n `Prefix must end with \"/\" or be empty: ${JSON.stringify(s)}`,\n );\n }\n return s as Prefix;\n};\n\n/**\n * S3 object key. No leading slash, no empty segments, no '..' hops.\n */\nexport const asS3Key = (s: string): S3Key => s as S3Key;\nexport const assertS3Key = (s: string): S3Key => {\n if (s.length === 0) {\n throw new TypeError(\"S3Key must be a non-empty string\");\n }\n if (s.startsWith(\"/\")) {\n throw new TypeError(\n `S3Key must not start with a slash: ${JSON.stringify(s)}`,\n );\n }\n if (s.includes(\"..\")) {\n throw new TypeError(\n `S3Key must not contain '..' segments: ${JSON.stringify(s)}`,\n );\n }\n return s as S3Key;\n};\n\n/**\n * Tenant identifier. Alphanumerics, dashes, underscores only.\n */\nexport const asTenantId = (s: string): TenantId => s as TenantId;\nexport const assertTenantId = (s: string): TenantId => {\n if (s.length === 0 || !/^[a-zA-Z0-9_-]+$/.test(s)) {\n throw new TypeError(`Invalid TenantId: ${JSON.stringify(s)}`);\n }\n return s as TenantId;\n};\n\n/**\n * Opaque user identifier. Non-empty; the format is provider-defined.\n */\nexport const asUserId = (s: string): UserId => s as UserId;\nexport const assertUserId = (s: string): UserId => {\n if (s.length === 0) {\n throw new TypeError(\"UserId must be a non-empty string\");\n }\n return s as UserId;\n};\n","/**\n * Server actions — tenant comes from getAuth(), never from the client.\n */\nimport { z } from \"zod\";\nimport { ok, err, type Result } from \"@/types/result\";\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key, asTenantId, type TenantId } from \"@/types/branded\";\nimport type { AuthContext } from \"../auth/with-auth\";\nimport type { MetadataStore, FileNode } from \"../metadata/store\";\nimport type { FileSystem } from \"../storage/filesystem\";\nimport type { createWriteThrough } from \"../sync/write-through\";\n\ntype CreateWriteThrough = ReturnType<typeof createWriteThrough>;\n\nconst NodeIdSchema = z.string().min(1, \"id is required\");\nconst PathSchema = z.string().nullable();\n\nexport const ListFilesInputSchema = z.object({\n parentId: PathSchema,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional(),\n});\n\nexport const DeleteFileInputSchema = z.object({\n id: NodeIdSchema,\n recursive: z.boolean().optional(),\n});\n\nexport const MoveFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const CopyFileInputSchema = z.object({\n id: NodeIdSchema,\n newParentId: PathSchema,\n newName: z.string().min(1).max(255).optional(),\n});\n\nexport const SetMetadataInputSchema = z.object({\n id: NodeIdSchema,\n metadata: z.record(z.string()),\n replace: z.boolean().optional(),\n});\n\nexport const CreateFolderInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n});\n\nexport const PrepareUploadInputSchema = z.object({\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().min(1),\n contentLength: z.number().int().nonnegative(),\n});\n\nexport const ConfirmUploadInputSchema = z.object({\n id: NodeIdSchema,\n parentId: PathSchema,\n name: z.string().min(1).max(255),\n contentType: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n});\n\nexport const SearchFilesInputSchema = z.object({\n query: z.string(),\n parentId: z.string().optional(),\n limit: z.number().int().positive().optional(),\n});\n\nexport const RestoreNodeInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const CreateShareInputSchema = z.object({\n id: NodeIdSchema,\n});\n\nexport const ResolveShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nexport const RevokeShareInputSchema = z.object({\n token: z.string().min(1),\n});\n\nconst zodErr = (message: string, parsed: z.SafeParseError<unknown>) =>\n err(\n new FileSystemError({\n code: \"InternalError\",\n message,\n retryable: false,\n cause: { code: \"ZodError\", message: parsed.error.message, issues: parsed.error.issues },\n }),\n );\n\nexport interface ServerActionsDeps {\n readonly store: MetadataStore;\n readonly writeThrough: CreateWriteThrough;\n readonly fs: FileSystem;\n readonly getAuth: () => AuthContext | Promise<AuthContext>;\n /** App path prefix for share links. Default `/api/share`. */\n readonly sharePathPrefix?: string;\n}\n\nexport const createServerActions = (deps: ServerActionsDeps) => {\n const { store, writeThrough, fs, getAuth } = deps;\n const sharePathPrefix = (deps.sharePathPrefix ?? \"/api/share\").replace(/\\/+$/, \"\");\n\n const wrap = (e: unknown, code: FileSystemError[\"code\"], message: string): FileSystemError => {\n if (e instanceof FileSystemError) return e;\n return new FileSystemError({\n code,\n message: `${message}: ${e instanceof Error ? e.message : String(e)}`,\n retryable: true,\n });\n };\n\n const authTenant = async (): Promise<AuthContext> => getAuth();\n\n const listFiles = async (\n input: z.infer<typeof ListFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = ListFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid listFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.listChildren({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n cursor: parsed.data.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listFiles failed\"));\n }\n };\n\n const deleteFile = async (\n input: z.infer<typeof DeleteFileInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = DeleteFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid deleteFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.deleteThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n recursive: parsed.data.recursive,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"deleteFile failed\"));\n }\n };\n\n const moveFile = async (\n input: z.infer<typeof MoveFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = MoveFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid moveFile input\", parsed);\n try {\n const auth = await authTenant();\n return store.moveNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"moveFile failed\"));\n }\n };\n\n const copyFile = async (\n input: z.infer<typeof CopyFileInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CopyFileInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid copyFile input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.copyThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n newParentId: parsed.data.newParentId,\n newName: parsed.data.newName,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"copyFile failed\"));\n }\n };\n\n const setMetadata = async (\n input: z.infer<typeof SetMetadataInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = SetMetadataInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid setMetadata input\", parsed);\n try {\n const auth = await authTenant();\n return store.updateMetadata({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n metadata: parsed.data.metadata,\n replace: parsed.data.replace,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"setMetadata failed\"));\n }\n };\n\n const createFolder = async (\n input: z.infer<typeof CreateFolderInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = CreateFolderInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createFolder input\", parsed);\n try {\n const auth = await authTenant();\n return store.createNode({\n tenantId: asTenantId(auth.tenantId),\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n kind: \"folder\",\n size: 0,\n mimeType: \"\",\n s3Key: \"\",\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createFolder failed\"));\n }\n };\n\n const prepareUpload = async (\n input: z.infer<typeof PrepareUploadInputSchema>,\n ): Promise<Result<PrepareUploadOutput, FileSystemError>> => {\n const parsed = PrepareUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid prepareUpload input\", parsed);\n try {\n const auth = await authTenant();\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const signed = await fs.forTenant(auth.tenantId).adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: parsed.data.contentType,\n expiresIn: 900,\n });\n if (!signed.ok) return signed;\n return ok({\n id,\n key: id,\n url: signed.value.url,\n method: signed.value.method,\n headers: signed.value.requiredHeaders ?? {},\n expiresAt: new Date(Date.now() + 900_000).toISOString(),\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"prepareUpload failed\"));\n }\n };\n\n const confirmUpload = async (\n input: z.infer<typeof ConfirmUploadInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = ConfirmUploadInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid confirmUpload input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.confirmUpload({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n parentId: parsed.data.parentId,\n name: parsed.data.name,\n contentType: parsed.data.contentType,\n size: parsed.data.size,\n ownerId: auth.userId,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"confirmUpload failed\"));\n }\n };\n\n const searchFiles = async (\n input: z.infer<typeof SearchFilesInputSchema>,\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n const parsed = SearchFilesInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid searchFiles input\", parsed);\n try {\n const auth = await authTenant();\n return store.search({\n tenantId: asTenantId(auth.tenantId),\n query: parsed.data.query,\n parentId: parsed.data.parentId,\n limit: parsed.data.limit,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"searchFiles failed\"));\n }\n };\n\n const listTrash = async (\n input: { limit?: number; cursor?: string } = {},\n ): Promise<Result<ListFilesOutput, FileSystemError>> => {\n try {\n const auth = await authTenant();\n return store.listTrash({\n tenantId: asTenantId(auth.tenantId),\n limit: input.limit,\n cursor: input.cursor,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"listTrash failed\"));\n }\n };\n\n const restoreNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<FileNode, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid restoreNode input\", parsed);\n try {\n const auth = await authTenant();\n return store.restoreNode({\n tenantId: asTenantId(auth.tenantId),\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"restoreNode failed\"));\n }\n };\n\n const purgeNode = async (\n input: z.infer<typeof RestoreNodeInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RestoreNodeInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid purgeNode input\", parsed);\n try {\n const auth = await authTenant();\n return writeThrough.purgeThroughFile({\n tenantId: auth.tenantId,\n id: parsed.data.id,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"purgeNode failed\"));\n }\n };\n\n const createShare = async (\n input: z.infer<typeof CreateShareInputSchema>,\n ): Promise<Result<{ token: string; url: string }, FileSystemError>> => {\n const parsed = CreateShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid createShare input\", parsed);\n try {\n const auth = await authTenant();\n const tenantId = asTenantId(auth.tenantId);\n const node = await store.getNode({ tenantId, id: parsed.data.id });\n if (!node.ok) return node;\n if (!node.value || node.value.kind !== \"file\" || !node.value.s3Key) {\n return err(\n new FileSystemError({\n code: \"Conflict\",\n message: \"Only files can be shared as an openable link\",\n retryable: false,\n }),\n );\n }\n const share = await store.createShare({\n tenantId,\n nodeId: parsed.data.id,\n });\n if (!share.ok) return share;\n return ok({\n token: share.value.token,\n url: `${sharePathPrefix}/${share.value.token}`,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"createShare failed\"));\n }\n };\n\n const resolveShare = async (\n input: z.infer<typeof ResolveShareInputSchema>,\n ): Promise<Result<FileNode | null, FileSystemError>> => {\n const parsed = ResolveShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid resolveShare input\", parsed);\n try {\n return store.resolveShare({ token: parsed.data.token });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"resolveShare failed\"));\n }\n };\n\n const revokeShare = async (\n input: z.infer<typeof RevokeShareInputSchema>,\n ): Promise<Result<void, FileSystemError>> => {\n const parsed = RevokeShareInputSchema.safeParse(input);\n if (!parsed.success) return zodErr(\"Invalid revokeShare input\", parsed);\n try {\n const auth = await authTenant();\n return store.revokeShare({\n tenantId: asTenantId(auth.tenantId),\n token: parsed.data.token,\n });\n } catch (e) {\n return err(wrap(e, \"InternalError\", \"revokeShare failed\"));\n }\n };\n\n return {\n listFiles,\n deleteFile,\n moveFile,\n copyFile,\n setMetadata,\n createFolder,\n prepareUpload,\n confirmUpload,\n searchFiles,\n listTrash,\n restoreNode,\n purgeNode,\n createShare,\n resolveShare,\n revokeShare,\n };\n};\n\nexport interface ListFilesOutput {\n readonly items: ReadonlyArray<FileNode>;\n readonly nextCursor?: string;\n}\n\nexport interface PrepareUploadOutput {\n readonly id: string;\n readonly key: string;\n readonly url: string;\n readonly method: \"PUT\" | \"POST\";\n readonly headers: Record<string, string>;\n readonly expiresAt: string;\n}\n\nexport type { TenantId };\n","/**\n * `createUploadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL upload flow.\n *\n * The client flow:\n * 1. Client POSTs `{ key, contentType, contentLength }` to this\n * route (typically `/api/files/upload`).\n * 2. Route validates `contentLength` against `maxBytes` (413) and\n * `contentType` against `allowedContentTypes` (415). No URL\n * is signed on a rejected request.\n * 3. Route calls `fs.adapter.createPresignedUploadUrl({ key,\n * contentType, expiresIn })` and returns `{ url, key,\n * expiresAt }`.\n * 4. Client PUTs the file body to the signed URL (bypassing the\n * Next.js server entirely).\n *\n * Spec scenarios: `route-handlers#1` (maxBytes), `route-handlers#2`\n * (allowedContentTypes).\n *\n * Construction-time validation: `expiresIn` is validated when the\n * factory is called (synchronous throw), per decision\n * `sdd/file-next/design/decision/expiresin-cap-timing`. A handler\n * built with `expiresIn: 30 * 86400` should never reach runtime —\n * the developer should see the error at server startup, not on\n * the first user request.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\n/**\n * Convert a glob pattern (`image/*`) to a regex; convert a literal\n * (`image/png`) to an exact match. Both forms are common in\n * `allowedContentTypes` arrays.\n */\nconst matchesContentType = (pattern: string, actual: string): boolean => {\n if (pattern === actual) return true;\n if (pattern.endsWith(\"/*\")) {\n const prefix = pattern.slice(0, -1); // \"image/*\" → \"image/\"\n return actual.startsWith(prefix);\n }\n return false;\n};\n\nexport interface CreateUploadRouteHandlerOptions {\n readonly fs: FileSystem;\n /** Resolve the caller. 401 when it returns null. */\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Reject requests whose `contentLength` exceeds this. Omit for no cap. */\n readonly maxBytes?: number;\n /**\n * Reject requests whose `contentType` is not in this list.\n * Each entry is a literal (`image/png`) or a wildcard (`image/*`).\n * Omit for no restriction.\n */\n readonly allowedContentTypes?: ReadonlyArray<string>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface UploadRouteHandlerRequest {\n key: string;\n contentType: string;\n contentLength: number;\n}\n\nexport interface UploadRouteHandlerResult {\n url: string;\n key: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range. The top-level code stays in the\n * closed 11-code catalog; the specific reason lives on `cause`.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned upload URL after validating the request.\n */\nexport const createUploadRouteHandler = (\n opts: CreateUploadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n // Construction-time validation: fail-fast on misconfiguration.\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n let body: UploadRouteHandlerRequest;\n try {\n body = (await req.json()) as UploadRouteHandlerRequest;\n } catch {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Request body must be valid JSON\" } },\n { status: 400 },\n );\n }\n\n // 1. maxBytes — reject BEFORE signing\n if (typeof opts.maxBytes === \"number\" && body.contentLength > opts.maxBytes) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"PayloadTooLarge\",\n message: `contentLength ${body.contentLength} exceeds maxBytes ${opts.maxBytes}`,\n },\n },\n { status: 413 },\n );\n }\n\n // 2. allowedContentTypes — reject BEFORE signing\n if (opts.allowedContentTypes && opts.allowedContentTypes.length > 0) {\n const allowed = opts.allowedContentTypes.some((p) => matchesContentType(p, body.contentType));\n if (!allowed) {\n return Response.json(\n {\n ok: false,\n error: {\n code: \"UnsupportedMediaType\",\n message: `contentType \"${body.contentType}\" is not in the allowed list`,\n },\n },\n { status: 415 },\n );\n }\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const id =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID()\n : `upl-${Date.now()}`;\n const r = await fs.adapter.createPresignedUploadUrl({\n key: asS3Key(id),\n contentType: body.contentType,\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: {\n url: r.value.url,\n key: id,\n id,\n method: r.value.method,\n headers: r.value.requiredHeaders ?? {},\n expiresAt,\n },\n });\n };\n};\n","/**\n * `createDownloadRouteHandler` — the Next.js Route Handler factory\n * for the presigned-URL download flow.\n *\n * The client flow:\n * 1. Client GETs `/api/files/download?key=uploads/report.pdf`.\n * 2. Route calls `fs.adapter.createPresignedDownloadUrl({ key,\n * expiresIn })` and returns `{ url, expiresAt }`.\n * 3. Client GETs the signed URL (bypassing the Next.js server).\n *\n * Spec scenario: `route-handlers#3` — `X-Amz-Expires=900` is present\n * in the signed URL and `expiresAt` is `now + 900s`.\n *\n * Construction-time validation: same `expiresIn` policy as the\n * upload handler (see `expiresin-cap-timing` decision). The cap\n * lives at the factory level, not the adapter, so a misconfigured\n * handler fails fast at server startup.\n */\nimport { FileSystemError } from \"@/errors\";\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { AuthContext } from \"../../auth/with-auth\";\n\n/** S3 SigV4 presign hard cap. The SDK itself rejects anything longer. */\nconst MAX_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;\n/** Default 15 minutes — matches the adapter default and the AWS SDK default. */\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\nexport interface CreateDownloadRouteHandlerOptions {\n readonly fs: FileSystem;\n readonly getAuth?: (req: Request) => Promise<AuthContext | null>;\n /** Presigned URL lifetime in seconds. Default 900, max 7d (S3 SigV4). */\n readonly expiresIn?: number;\n}\n\nexport interface DownloadRouteHandlerResult {\n url: string;\n expiresAt: string;\n}\n\n/**\n * Validate `expiresIn` against the S3 SigV4 hard cap. Throws\n * `FileSystemError(InternalError)` with `cause.code: \"InvalidArgument\"`\n * if the value is out of range.\n */\nconst assertExpiresIn = (expiresIn: number): void => {\n if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > MAX_EXPIRES_IN_SECONDS) {\n throw new FileSystemError({\n code: \"InternalError\",\n message: `expiresIn must be between 1 and ${MAX_EXPIRES_IN_SECONDS} seconds (S3 SigV4 limit)`,\n retryable: false,\n cause: { code: \"InvalidArgument\", message: `expiresIn=${expiresIn}` },\n });\n }\n};\n\n/**\n * Build a Next.js Route Handler `(req) => Response` that signs a\n * presigned GET URL.\n *\n * The `key` is read from the `?key=` query param. The handler does\n * NOT do any body / content-type / size validation (downloads\n * don't have those concerns); the only chokepoint is the\n * construction-time `expiresIn` cap.\n */\nexport const createDownloadRouteHandler = (\n opts: CreateDownloadRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n const expiresIn = opts.expiresIn ?? DEFAULT_EXPIRES_IN_SECONDS;\n assertExpiresIn(expiresIn);\n\n return async (req: Request): Promise<Response> => {\n const url = new URL(req.url);\n const key = url.searchParams.get(\"key\");\n if (!key) {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Missing required query param: key\" } },\n { status: 400 },\n );\n }\n\n let fs = opts.fs;\n if (opts.getAuth) {\n const auth = await opts.getAuth(req);\n if (!auth) {\n return Response.json(\n { ok: false, error: { code: \"Unauthorized\", message: \"Not authenticated\" } },\n { status: 401 },\n );\n }\n fs = opts.fs.forTenant(auth.tenantId);\n }\n\n const r = await fs.adapter.createPresignedDownloadUrl({\n key: asS3Key(key),\n expiresIn,\n });\n if (!r.ok) {\n return Response.json(\n { ok: false, error: { code: r.error.code, message: r.error.message } },\n { status: 500 },\n );\n }\n\n const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n return Response.json({\n ok: true,\n value: { url: r.value.url, expiresAt },\n });\n };\n};\n","/**\n * Public share download: GET /api/share/[token]\n * Streams the object through the app. The client never sees the bucket or key.\n */\nimport { asS3Key } from \"@/types/branded\";\nimport type { FileSystem } from \"@/storage/filesystem\";\nimport type { MetadataStore } from \"../../metadata/store\";\n\nexport interface CreateShareRouteHandlerOptions {\n readonly store: MetadataStore;\n readonly fs: FileSystem;\n}\n\nconst tokenFromRequest = (req: Request): string | null => {\n const url = new URL(req.url);\n const query = url.searchParams.get(\"token\");\n if (query && query.length > 0) return query;\n const parts = url.pathname.replace(/\\/+$/, \"\").split(\"/\");\n const last = parts[parts.length - 1];\n if (!last || last === \"share\") return null;\n return last;\n};\n\nexport const createShareRouteHandler = (\n opts: CreateShareRouteHandlerOptions,\n): ((req: Request) => Promise<Response>) => {\n return async (req: Request): Promise<Response> => {\n const token = tokenFromRequest(req);\n if (!token) {\n return Response.json(\n { ok: false, error: { code: \"InternalError\", message: \"Missing share token\" } },\n { status: 400 },\n );\n }\n\n const resolved = await opts.store.resolveShare({ token });\n if (!resolved.ok) {\n return Response.json(\n { ok: false, error: { code: resolved.error.code, message: resolved.error.message } },\n { status: 500 },\n );\n }\n const node = resolved.value;\n if (!node || node.kind !== \"file\" || !node.s3Key) {\n return Response.json(\n { ok: false, error: { code: \"NotFound\", message: \"Share not found\" } },\n { status: 404 },\n );\n }\n\n const adapter = opts.fs.forTenant(node.tenantId).adapter;\n const rangeHeader = req.headers.get(\"range\") ?? undefined;\n const read = await adapter.read({\n key: asS3Key(node.s3Key),\n range: rangeHeader ?? undefined,\n });\n if (!read.ok) {\n return Response.json(\n { ok: false, error: { code: read.error.code, message: read.error.message } },\n { status: 404 },\n );\n }\n\n const download = new URL(req.url).searchParams.get(\"download\") === \"1\";\n const headers = new Headers();\n headers.set(\n \"Content-Type\",\n node.mimeType || read.value.contentType || \"application/octet-stream\",\n );\n headers.set(\n \"Content-Disposition\",\n `${download ? \"attachment\" : \"inline\"}; filename*=UTF-8''${encodeURIComponent(node.name)}`,\n );\n headers.set(\"Cache-Control\", \"private, no-store\");\n headers.set(\"Content-Length\", String(read.value.body.byteLength));\n\n return new Response(Buffer.from(read.value.body), { status: 200, headers });\n };\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vryzel/file-next",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "File-system abstraction over AWS S3 / Cloudflare R2 for Next.js, with a secondary metadata index and shadcn/ui components.",
5
5
  "type": "module",
6
6
  "license": "MIT",