@nextlyhq/storage-vercel-blob 0.0.2-alpha.71 → 0.0.2-alpha.72

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["put","del","head","BlobNotFoundError","list"],"sources":["../../nextly/dist/nextly-error-CwDiSPDF.mjs","../../nextly/dist/get-trusted-client-ip-CYEbmLA3.mjs","../../nextly/dist/validate-external-url-CnZrcJdP.mjs","../../nextly/dist/storage/read-errors.mjs","../../nextly/dist/storage/fetch-stored-bytes.mjs","../src/adapter.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import { t as __exportAll } from \"./rolldown-runtime-BJohB4LM.mjs\";\n// src/database/errors.ts\nvar DbError = class extends Error {\n\tkind;\n\tdialect;\n\tcode;\n\tmeta;\n\tcause;\n\tconstructor(args) {\n\t\tsuper(args.message);\n\t\tthis.name = \"DbError\";\n\t\tthis.kind = args.kind;\n\t\tthis.dialect = args.dialect;\n\t\tthis.code = args.code;\n\t\tthis.meta = args.meta;\n\t\tthis.cause = args.cause;\n\t}\n};\nfunction isDbError(err) {\n\tif (!err || typeof err !== \"object\") return false;\n\tconst obj = err;\n\treturn obj.name === \"DbError\" && typeof obj.kind === \"string\";\n}\nfunction toDbError(dialect, error, meta) {\n\tif (isDbError(error)) return error;\n\tconst code = safeCode(error);\n\tconst rawMsg = error != null && typeof error === \"object\" && \"message\" in error ? error.message : void 0;\n\tconst message = typeof rawMsg === \"string\" ? rawMsg : \"Database error\";\n\tlet kind = \"internal\";\n\tif (isBusyCode(code)) return new DbError({\n\t\tmessage,\n\t\tkind: \"busy\",\n\t\tdialect,\n\t\tcode,\n\t\tmeta,\n\t\tcause: error\n\t});\n\tswitch (dialect) {\n\t\tcase \"postgresql\":\n\t\t\tkind = mapPostgresCodeToKind(code);\n\t\t\tbreak;\n\t\tcase \"mysql\":\n\t\t\tkind = mapMySqlCodeToKind(code);\n\t\t\tbreak;\n\t\tcase \"sqlite\": kind = mapSqliteCodeToKind(code);\n\t}\n\tif ((dialect === \"mysql\" || dialect === \"sqlite\") && (kind === \"constraint\" || kind === \"internal\") && isLikelyUniqueViolationMessage(dialect, message)) kind = \"unique-violation\";\n\tif (kind === \"internal\" && code) {\n\t\tconst c = code.toUpperCase();\n\t\tif (c === \"ECONNRESET\" || c.includes(\"PROTOCOL_CONNECTION_LOST\")) kind = \"connection-lost\";\n\t\telse if (c === \"ETIMEDOUT\") kind = \"timeout\";\n\t}\n\treturn new DbError({\n\t\tmessage,\n\t\tkind,\n\t\tdialect,\n\t\tcode,\n\t\tmeta,\n\t\tcause: error\n\t});\n}\n/**\n* The driver's own code for an error, wherever that driver puts it.\n*\n* Exported so callers that must distinguish one failure from another classify\n* by the SAME extraction this module's mapping uses. A second reader would go\n* looking in a different set of properties and disagree on exactly the drivers\n* whose codes are hardest to find.\n*/\n/**\n* Whether an error is a duplicate-key rejection.\n*\n* Exposed because a plugin inserting into a table with a unique index has to\n* tell \"this row already exists\" from \"the database is broken\", and the two\n* arrive as the same thrown object. Derived from the existing SQLSTATE\n* classification rather than by matching driver messages: those differ per\n* driver and per version, and a plugin re-deriving it would be a second\n* implementation of a question this module already answers.\n*/\n/**\n* Whether a driver code says the database was busy: the adapters' own code\n* for a request that waited out `pool.connectionTimeoutMs`, the same on\n* every dialect, or SQLITE_BUSY and its extended codes, another process\n* holding the SQLite file past `busyTimeout`. Neither depends on the dialect,\n* which is what lets {@link isDatabaseBusy} answer without one.\n*/\nfunction isBusyCode(code) {\n\tif (code === void 0) return false;\n\treturn code === \"NEXTLY_POOL_WAIT_TIMEOUT\" || code.toUpperCase().startsWith(\"SQLITE_BUSY\");\n}\n/**\n* Whether an error is the database being busy, however it arrives: a DbError\n* of kind \"busy\", or the raw error an adapter or driver threw.\n*\n* For the boundaries that answer a request with whatever its work threw.\n* `withDbErrors` converts only DbErrors, so a raw driver error reaches them\n* unconverted, and without this it would read as an internal fault rather\n* than a request worth retrying.\n*/\nfunction isDatabaseBusy(error) {\n\tif (isDbError(error)) return error.kind === \"busy\";\n\treturn isBusyCode(safeCode(error));\n}\nfunction isUniqueViolation(dialect, error) {\n\treturn toDbError(dialect, error).kind === \"unique-violation\";\n}\nfunction safeCode(error) {\n\tif (!error || typeof error !== \"object\") return void 0;\n\tconst e = error;\n\tlet c = e.code ?? e.sqlState ?? e.state ?? e.errno ?? void 0;\n\tif (!c && typeof e.originalError?.code === \"string\") c = e.originalError.code;\n\tif (!c && typeof e.cause?.code === \"string\") c = e.cause.code;\n\tif (!c && typeof e.severity === \"string\" && typeof e.code === \"string\") c = e.code;\n\tif (typeof c === \"number\") return String(c);\n\tif (typeof c === \"string\" && c.length > 0) return c;\n}\nfunction mapPostgresCodeToKind(code) {\n\tif (!code) return \"internal\";\n\tconst c = code.toUpperCase();\n\tif (c === \"40P01\") return \"deadlock\";\n\tif (c === \"40001\") return \"serialization-failure\";\n\tif (c === \"57014\") return \"timeout\";\n\tif (c === \"23505\") return \"unique-violation\";\n\tif (c === \"23503\") return \"fk-violation\";\n\tif (c === \"23502\") return \"not-null-violation\";\n\tif (c === \"42601\") return \"syntax\";\n\tif (c.startsWith(\"08\") || c === \"57P01\") return \"connection-lost\";\n\tif (c.startsWith(\"23\")) return \"constraint\";\n\treturn \"internal\";\n}\nfunction mapMySqlCodeToKind(code) {\n\tif (!code) return \"internal\";\n\tconst c = code.toUpperCase();\n\tif (c === \"1213\" || c === \"ER_LOCK_DEADLOCK\") return \"deadlock\";\n\tif (c === \"1205\" || c === \"ER_LOCK_WAIT_TIMEOUT\") return \"timeout\";\n\tif (c === \"1062\" || c === \"ER_DUP_ENTRY\") return \"unique-violation\";\n\tif (c === \"23000\") return \"constraint\";\n\tif (c === \"1064\" || c === \"ER_PARSE_ERROR\") return \"syntax\";\n\tif (c === \"1452\" || c === \"ER_NO_REFERENCED_ROW_2\") return \"fk-violation\";\n\tif (c === \"1451\" || c === \"ER_ROW_IS_REFERENCED_2\") return \"fk-violation\";\n\tif (c === \"ECONNRESET\" || c.includes(\"PROTOCOL_CONNECTION_LOST\")) return \"connection-lost\";\n\tif (c === \"ETIMEDOUT\") return \"timeout\";\n\treturn \"internal\";\n}\nfunction mapSqliteCodeToKind(code) {\n\tif (!code) return \"internal\";\n\tconst c = code.toUpperCase();\n\tif (c === \"SQLITE_LOCKED\") return \"deadlock\";\n\tif (c === \"SQLITE_CONSTRAINT_UNIQUE\") return \"unique-violation\";\n\tif (c === \"SQLITE_CONSTRAINT_PRIMARYKEY\") return \"unique-violation\";\n\tif (c === \"SQLITE_CONSTRAINT_FOREIGNKEY\") return \"fk-violation\";\n\tif (c === \"SQLITE_CONSTRAINT_NOTNULL\") return \"not-null-violation\";\n\tif (c === \"SQLITE_INTERRUPT\") return \"timeout\";\n\tif (c === \"SQLITE_ERROR\") return \"syntax\";\n\tif (c.startsWith(\"SQLITE_CONSTRAINT\")) return \"constraint\";\n\treturn \"internal\";\n}\nfunction isLikelyUniqueViolationMessage(dialect, message) {\n\tconst m = message.toLowerCase();\n\tif (dialect === \"mysql\") return m.includes(\"duplicate entry\") || m.includes(\"duplicate key\");\n\tif (dialect === \"sqlite\") return m.includes(\"unique constraint failed\");\n\treturn false;\n}\n// src/errors/error-codes.ts\n/**\n* Canonical NextlyError codes and their HTTP status mappings.\n*\n* Plugin codes outside this enum must always pass an explicit `statusCode`\n* to the NextlyError constructor (no enum lookup happens for unknown codes).\n*/\nconst NEXTLY_ERROR_STATUS = {\n\tVALIDATION_ERROR: 400,\n\tINVALID_INPUT: 400,\n\tAUTH_REQUIRED: 401,\n\tAUTH_INVALID_CREDENTIALS: 401,\n\tTOKEN_EXPIRED: 401,\n\tFORBIDDEN: 403,\n\tEMAIL_NOT_VERIFIED: 403,\n\tBUILDER_DISABLED: 403,\n\tCSRF_FAILED: 403,\n\tSETUP_TOKEN_REQUIRED: 403,\n\tAPI_KEY_ROLE_ABOVE_CREATOR: 403,\n\tNOT_FOUND: 404,\n\tMETHOD_NOT_ALLOWED: 405,\n\tRANGE_NOT_SATISFIABLE: 416,\n\tCONFLICT: 409,\n\tDUPLICATE: 409,\n\tRATE_LIMITED: 429,\n\tPAYLOAD_TOO_LARGE: 413,\n\tUNSUPPORTED_MEDIA_TYPE: 415,\n\tBUSINESS_RULE_VIOLATION: 422,\n\tINTERNAL_ERROR: 500,\n\tDATABASE_ERROR: 500,\n\tDATABASE_BUSY: 503,\n\tEXTERNAL_SERVICE_ERROR: 502,\n\tSERVICE_UNAVAILABLE: 503,\n\tEXTERNAL_URL_BLOCKED: 400,\n\tEXTERNAL_REQUEST_FAILED: 502,\n\tFILENAME_INVALID: 400,\n\tEXTENSION_BLOCKED: 400,\n\tMIME_BLOCKED: 415,\n\tMIME_NOT_ALLOWED: 415,\n\tSIZE_EXCEEDED: 413,\n\tSTORAGE_READ_TOO_LARGE: 413,\n\tSTORAGE_READ_TIMEOUT: 504,\n\tSTORAGE_READ_UNREACHABLE: 502,\n\tMAGIC_BYTE_MISMATCH: 400,\n\tSVG_SANITIZATION_FAILED: 400,\n\tUNSUPPORTED_FOR_BACKEND: 415,\n\tNEXTLY_LEGACY_BOOKKEEPING_DETECTED: 409,\n\tNEXTLY_UPGRADE_TABLE_NAME_COLLISION: 409,\n\tNEXTLY_UPGRADE_IN_PROGRESS: 409,\n\tNEXTLY_MIGRATE_LOCK_BUSY: 409,\n\tNEXTLY_BASELINE_LOCK_NOT_HELD: 409,\n\tNEXTLY_RESOLVE_LOCK_NOT_HELD: 409,\n\tNEXTLY_BOOT_MIGRATIONS_NOT_RUN: 503,\n\tNEXTLY_BOOT_MIGRATIONS_PENDING: 503,\n\tNEXTLY_CORE_DESTRUCTIVE_REFUSED: 409,\n\tNEXTLY_MIGRATION_DRIFT: 409,\n\tNEXTLY_MIGRATION_APPLY_FAILED: 500,\n\tNEXTLY_MIGRATION_FOREIGN_KEY_VIOLATION: 409,\n\tNEXTLY_MIGRATION_PARTIALLY_APPLIED: 500,\n\tNEXTLY_MIGRATION_CONCURRENT_RUN: 409,\n\tNEXTLY_MIGRATION_FILE_MISSING: 404,\n\tNEXTLY_MIGRATION_SNAPSHOT_MISSING: 404,\n\tNEXTLY_MIGRATION_RESOLVE_DRIFT: 409,\n\tNEXTLY_MIGRATION_RESOLVE_PRECONDITION: 409,\n\tNEXTLY_UI_SCHEMA_INVALID: 400,\n\tNEXTLY_SCHEMA_SLUG_COLLISION: 409,\n\tNEXTLY_SCHEMA_RELATION_TARGET_MISSING: 400,\n\tNEXTLY_SCHEMA_RELATION_UNRESOLVED: 400,\n\tNEXTLY_SCHEMA_EXTEND_TARGET_UNKNOWN: 400,\n\tNEXTLY_SCHEMA_EXTEND_FIELD_DUPLICATE: 409,\n\tNEXTLY_SCHEMA_CROSS_PLUGIN_RELATION: 409,\n\tNEXTLY_SCHEMA_RENAME_UNKNOWN_TARGET: 400,\n\tNEXTLY_PLUGIN_CLIENT_CONFIG_INVALID: 500,\n\tNEXTLY_PLUGIN_ADMIN_WIDGET_INVALID: 500,\n\tNEXTLY_ADMIN_COMPONENT_MAP_STALE: 500,\n\tNEXTLY_PLUGIN_DOCUMENT_VIEW_INVALID: 500,\n\tPLUGIN_RESOLUTION_ERROR: 500,\n\tPLUGIN_DEPENDENCY_NOT_INSTALLED: 409,\n\tPLUGIN_HAS_DEPENDENTS: 409,\n\tPLUGIN_UNINSTALL_IRREVERSIBLE: 409,\n\tPLUGIN_UNINSTALL_UNCONFIRMED: 409,\n\tPLUGIN_SCHEMA_BEHIND: 409,\n\tPLUGIN_SCHEMA_UNINSTALLED: 409,\n\tPLUGIN_NOT_INSTALLED: 409,\n\tPLUGIN_DISABLED: 409,\n\tPLUGIN_UNINSTALL_UNFINISHED: 409,\n\tPLUGIN_SCHEMA_VERSION_NOT_ADVANCED: 409,\n\tPLUGIN_MIGRATION_DROPS_CREATED_SCHEMA: 409,\n\tPLUGIN_MIGRATION_ADDS_UNFILLABLE_COLUMN: 409,\n\tPLUGIN_MIGRATION_SQL_MISSING: 409,\n\tPLUGIN_MIGRATIONS_UNAVAILABLE: 409,\n\tDROP_OF_FOREIGN_TABLE: 409,\n\tMIGRATION_CHECKSUM_MISMATCH: 409,\n\tPLUGIN_MIGRATIONS_OUT_OF_ORDER: 409,\n\tPLUGIN_MIGRATION_HISTORY_CHANGED: 409,\n\tNEXTLY_ROUTE_COLLISION: 409,\n\tNEXTLY_ROUTE_INVALID_PATH: 400,\n\tNEXTLY_ROUTE_UNREACHABLE_ROOT: 400,\n\tNEXTLY_ROUTE_INVALID_MOUNT: 400,\n\tNEXTLY_EMAIL_TRANSPORT_UNAVAILABLE: 503,\n\tNEXTLY_CONFIG_TOOLING_UNAVAILABLE: 503,\n\tNEXTLY_POSTGRES_SCHEMA_MISMATCH: 500,\n\tNEXTLY_POSTGRES_SCHEMA_UNSUPPORTED: 500\n};\n/**\n* The codes that REPRESENT their status, when a failure names none.\n*\n* A service that returns `{ success: false, statusCode }` without a code leaves\n* every boundary to infer one, and three boundaries inferring separately is how\n* the same 401 became `AUTH_REQUIRED` through the Direct API and\n* `INTERNAL_ERROR` through the REST dispatcher. This list is the ONE inference,\n* so they cannot disagree.\n*\n* Listed as CODES, not as status numbers: the number for each comes from\n* {@link NEXTLY_ERROR_STATUS} below, so a code whose canonical status changes\n* carries its inference with it instead of leaving a stale literal here.\n*\n* Several codes share a status -- 409 is both `CONFLICT` and `DUPLICATE`, 400\n* is both `VALIDATION_ERROR` and `INVALID_INPUT` -- so this is a choice, not a\n* mechanical inversion. Each entry is the reading that is still safe if the\n* other was meant: `CONFLICT` says \"reload\", which is unhelpful for a name\n* clash, while `DUPLICATE` would say \"already exists\", which is WRONG for a\n* stale write. A producer that knows which it means sets `code` and is\n* believed, and this list is never consulted for it.\n*/\nconst CANONICAL_CODE_FOR_STATUS = [\n\t\"VALIDATION_ERROR\",\n\t\"AUTH_REQUIRED\",\n\t\"FORBIDDEN\",\n\t\"NOT_FOUND\",\n\t\"CONFLICT\",\n\t\"PAYLOAD_TOO_LARGE\",\n\t\"UNSUPPORTED_MEDIA_TYPE\",\n\t\"RATE_LIMITED\",\n\t\"EXTERNAL_SERVICE_ERROR\",\n\t\"SERVICE_UNAVAILABLE\"\n];\n/**\n* 422, which no canonical code claims.\n*\n* `INVALID_INPUT` answers 400 in this system, so it cannot supply this key the\n* way the codes above supply theirs. Legacy envelopes nonetheless use 422 for\n* \"understood but unprocessable\", and reading it as an internal error would\n* report the caller's own mistake as a server fault. Named rather than inlined\n* so it is visibly the one entry that is NOT derived.\n*/\nconst LEGACY_UNPROCESSABLE_STATUS = 422;\nconst STATUS_TO_CODE = {\n\t...Object.fromEntries(CANONICAL_CODE_FOR_STATUS.map((code) => [NEXTLY_ERROR_STATUS[code], code])),\n\t[LEGACY_UNPROCESSABLE_STATUS]: \"INVALID_INPUT\"\n};\n/**\n* The canonical code for a status, for a failure that named none.\n*\n* Anything outside the table is an internal error: an unrecognised status from\n* a legacy envelope says nothing a caller can act on, and inventing a specific\n* code for it would assert a meaning no producer expressed.\n*/\nfunction statusToErrorCode(statusCode) {\n\treturn STATUS_TO_CODE[statusCode] ?? \"INTERNAL_ERROR\";\n}\n/**\n* The sentence a caller reads for a code, when the failure supplied none.\n*\n* Kept beside the status table because they answer the same question together:\n* a code-less envelope's own `message` is NOT usable here. Those envelopes come\n* from legacy converters that store a raw exception's text, so promoting it\n* would put driver output, table names and internal paths on the wire -- the\n* disclosure the public error shape exists to prevent (spec 13.8).\n*\n* Every entry is generic by design. The specific detail stays in `logContext`\n* for the operator, against the same request id.\n*/\nconst GENERIC_PUBLIC_MESSAGE = {\n\tVALIDATION_ERROR: \"Validation failed.\",\n\tINVALID_INPUT: \"The request could not be processed.\",\n\tAUTH_REQUIRED: \"Authentication required.\",\n\tFORBIDDEN: \"You don't have permission to perform this action.\",\n\tNOT_FOUND: \"Not found.\",\n\tMETHOD_NOT_ALLOWED: \"That method is not allowed on this address.\",\n\tRANGE_NOT_SATISFIABLE: \"The requested range is outside the file.\",\n\tCONFLICT: \"The resource has changed since you last loaded it. Please refresh and try again.\",\n\tDUPLICATE: \"Resource already exists.\",\n\tPAYLOAD_TOO_LARGE: \"The request is too large.\",\n\tUNSUPPORTED_MEDIA_TYPE: \"That file type is not supported.\",\n\tRATE_LIMITED: \"Too many requests. Please try again later.\",\n\tEXTERNAL_SERVICE_ERROR: \"An upstream service failed.\",\n\tSERVICE_UNAVAILABLE: \"The service is temporarily unavailable.\",\n\tDATABASE_BUSY: \"The database is busy. Please try again shortly.\",\n\tINTERNAL_ERROR: \"An unexpected error occurred.\"\n};\n/** The generic sentence for a code; the internal one for anything unlisted. */\nfunction genericPublicMessage(code) {\n\treturn GENERIC_PUBLIC_MESSAGE[code] ?? GENERIC_PUBLIC_MESSAGE.INTERNAL_ERROR;\n}\n// src/errors/retry-after.ts\n/**\n* The seconds an error asks its caller to wait before retrying, or\n* `undefined` when it carries no retry hint.\n*\n* Read from the error's public data rather than from its code, so every error\n* that carries a hint is answered with the header, and a code that comes to\n* carry one needs no change here.\n*/\nfunction retryAfterSeconds(error) {\n\tconst data = error.publicData;\n\tif (data && typeof data === \"object\" && \"retryAfterSeconds\" in data && typeof data.retryAfterSeconds === \"number\") return data.retryAfterSeconds;\n}\n/**\n* The Retry-After header for an error: none when it carries no retry hint.\n* Spread into a response's headers by every builder that answers one.\n*/\nfunction retryAfterHeader(error) {\n\tconst seconds = retryAfterSeconds(error);\n\treturn seconds === void 0 ? {} : { \"retry-after\": String(seconds) };\n}\n// src/errors/nextly-error.ts\nvar nextly_error_exports = /* @__PURE__ */ __exportAll({ NextlyError: () => NextlyError });\n/**\n* Default mapping from DbErrorKind to NextlyError contract. Used by\n* `NextlyError.fromDatabaseError`. Public messages are intentionally generic\n* per spec §13.8 — no DB driver text, no constraint names, no field hints.\n*\n* `satisfies Record<DbErrorKind, ...>` makes the mapping exhaustive at\n* compile time: adding a new DbErrorKind without updating this table is a\n* type error.\n*/\nconst DB_ERROR_MAPPING = {\n\t\"unique-violation\": {\n\t\tcode: \"DUPLICATE\",\n\t\tstatusCode: 409,\n\t\tpublicMessage: \"Resource already exists.\"\n\t},\n\t\"fk-violation\": {\n\t\tcode: \"VALIDATION_ERROR\",\n\t\tstatusCode: 400,\n\t\tpublicMessage: \"Referenced record does not exist.\"\n\t},\n\t\"not-null-violation\": {\n\t\tcode: \"VALIDATION_ERROR\",\n\t\tstatusCode: 400,\n\t\tpublicMessage: \"A required field is missing.\"\n\t},\n\tconstraint: {\n\t\tcode: \"VALIDATION_ERROR\",\n\t\tstatusCode: 400,\n\t\tpublicMessage: \"The provided data violates a constraint.\"\n\t},\n\tdeadlock: {\n\t\tcode: \"CONFLICT\",\n\t\tstatusCode: 409,\n\t\tpublicMessage: \"The operation could not be completed. Please retry.\"\n\t},\n\t\"serialization-failure\": {\n\t\tcode: \"CONFLICT\",\n\t\tstatusCode: 409,\n\t\tpublicMessage: \"The operation could not be completed. Please retry.\"\n\t},\n\tbusy: {\n\t\tcode: \"DATABASE_BUSY\",\n\t\tstatusCode: NEXTLY_ERROR_STATUS.DATABASE_BUSY,\n\t\tpublicMessage: genericPublicMessage(\"DATABASE_BUSY\"),\n\t\tpublicData: { retryAfterSeconds: 5 }\n\t},\n\ttimeout: {\n\t\tcode: \"DATABASE_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"The operation timed out. Please try again.\"\n\t},\n\t\"connection-lost\": {\n\t\tcode: \"DATABASE_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"A temporary database error occurred. Please try again.\"\n\t},\n\tsyntax: {\n\t\tcode: \"INTERNAL_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"An unexpected error occurred.\"\n\t},\n\tinternal: {\n\t\tcode: \"INTERNAL_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"An unexpected error occurred.\"\n\t}\n};\nconst NEXTLY_ERROR_BRAND = Symbol.for(\"nextly/NextlyError\");\nfunction hasBrand(value) {\n\tif (value === null || typeof value !== \"object\" && typeof value !== \"function\") return false;\n\treturn value[NEXTLY_ERROR_BRAND] === true;\n}\n/**\n* Unified error class for Nextly. Used at every throw site across services,\n* direct API, auth, and plugins. Carries two distinct payloads:\n*\n* - Public (`code`, `publicMessage`, `publicData`, `statusCode`, `messageKey`)\n* sent in HTTP responses and Server Action results.\n* - Log (`logMessage`, `logContext`, `cause`, stack trace)\n* written to the server logger; never serialised to the wire.\n*\n* Use the static factories (notFound, forbidden, validation, ...) for the\n* common cases. Use the free-form constructor for plugin codes or one-off\n* shapes.\n*/\nvar NextlyError = class NextlyError extends Error {\n\tcode;\n\tstatusCode;\n\tpublicMessage;\n\tpublicData;\n\tmessageKey;\n\tlogMessage;\n\tlogContext;\n\tcause;\n\ttimestamp;\n\tconstructor(opts) {\n\t\tsuper(opts.publicMessage);\n\t\tthis.name = \"NextlyError\";\n\t\tthis.code = opts.code;\n\t\tthis.publicMessage = opts.publicMessage;\n\t\tthis.publicData = opts.publicData;\n\t\tthis.messageKey = opts.messageKey;\n\t\tthis.logMessage = opts.logMessage;\n\t\tthis.logContext = opts.logContext;\n\t\tthis.cause = opts.cause;\n\t\tthis.timestamp = /* @__PURE__ */ new Date();\n\t\tthis.statusCode = NextlyError.resolveStatusCode(opts);\n\t\tError.captureStackTrace?.(this, NextlyError);\n\t}\n\tstatic {\n\t\tNextlyError.prototype[NEXTLY_ERROR_BRAND] = true;\n\t}\n\tstatic resolveStatusCode(opts) {\n\t\tif (typeof opts.statusCode === \"number\") return opts.statusCode;\n\t\tif (opts.code in NEXTLY_ERROR_STATUS) return NEXTLY_ERROR_STATUS[opts.code];\n\t\treturn 500;\n\t}\n\t/** HTTP-safe JSON. Strips logMessage / logContext / cause / stack. */\n\ttoResponseJSON(requestId) {\n\t\tconst json = {\n\t\t\tcode: String(this.code),\n\t\t\tmessage: this.publicMessage,\n\t\t\trequestId\n\t\t};\n\t\tif (this.messageKey) json.messageKey = this.messageKey;\n\t\tif (this.publicData !== void 0) json.data = this.publicData;\n\t\treturn json;\n\t}\n\t/** Operator-facing JSON for log lines. Includes everything. */\n\ttoLogJSON(requestId) {\n\t\treturn {\n\t\t\tcode: this.code,\n\t\t\tstatusCode: this.statusCode,\n\t\t\tpublicMessage: this.publicMessage,\n\t\t\tmessageKey: this.messageKey,\n\t\t\tlogMessage: this.logMessage,\n\t\t\tlogContext: this.logContext,\n\t\t\tcause: this.cause ? {\n\t\t\t\tname: this.cause.name,\n\t\t\t\tmessage: this.cause.message,\n\t\t\t\tstack: this.cause.stack\n\t\t\t} : void 0,\n\t\t\ttimestamp: this.timestamp.toISOString(),\n\t\t\trequestId\n\t\t};\n\t}\n\tstatic invalidCredentials(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"AUTH_INVALID_CREDENTIALS\",\n\t\t\tpublicMessage: \"Invalid email or password.\",\n\t\t\tlogMessage: \"Login failed\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* The password was correct and the address is unverified. Thrown only once\n\t* the password is proven, so only someone who holds it learns the address\n\t* is unverified; every other refusal stays\n\t* {@link NextlyError.invalidCredentials}.\n\t*/\n\tstatic emailNotVerified(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"EMAIL_NOT_VERIFIED\",\n\t\t\tpublicMessage: \"Verify your email address to sign in. Check your inbox for the link.\",\n\t\t\tlogMessage: \"Login refused: email not verified\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic authRequired(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"AUTH_REQUIRED\",\n\t\t\tpublicMessage: \"Authentication required.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* Distinct from `authRequired`: the caller was authenticated but the\n\t* session token expired. Clients key on the TOKEN_EXPIRED *code* to\n\t* silently refresh and retry rather than redirecting to login; the public\n\t* message stays the generic spec §13.6 string (\"Authentication required.\")\n\t* so the wire never reveals the session state — same as `authRequired`.\n\t*/\n\tstatic tokenExpired(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"TOKEN_EXPIRED\",\n\t\t\tpublicMessage: \"Authentication required.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic notFound(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"NOT_FOUND\",\n\t\t\tpublicMessage: opts?.message ?? \"Not found.\",\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic forbidden(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: \"You don't have permission to perform this action.\",\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A collection, Single or component defined in code, which is changed by\n\t* changing its code and not from here. Forbidden, and the message says so:\n\t* it is a fact about the thing, not about the caller's permissions, so it\n\t* names no permission and no policy. The lock's detail goes to the log\n\t* through `logContext`.\n\t*/\n\tstatic definedInCode(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: `This ${opts.thing} is defined in code, so it can't be ${opts.change === \"change\" ? \"changed\" : \"deleted\"} here.`,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\t/**\n\t* An autosave where the collection or Single does not autosave: its owner\n\t* switched autosave off, or it keeps no drafts to autosave into. Forbidden,\n\t* and the message says so, since it is a setting and not a permission.\n\t*/\n\tstatic autosaveOff(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: `Autosave is turned off for this ${opts.scopeKind === \"single\" ? \"Single\" : \"collection\"}.`,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\t/**\n\t* An API key refused because its role allows more than the person creating\n\t* it may do. The sentence is FORBIDDEN's and names no permission; which one\n\t* exceeded goes to the log through `logContext`. The code is its own, so a\n\t* client can tell \"choose a smaller role\" from plain FORBIDDEN.\n\t*/\n\tstatic apiKeyRoleAboveCreator(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"API_KEY_ROLE_ABOVE_CREATOR\",\n\t\t\tpublicMessage: genericPublicMessage(\"FORBIDDEN\"),\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A cookie-authenticated write refused because its origin or CSRF token did\n\t* not check out. The public message names no detail of which check failed;\n\t* that goes to the log through `logMessage`.\n\t*/\n\tstatic csrfFailed(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"CSRF_FAILED\",\n\t\t\tpublicMessage: \"This request could not be verified. Reload the page and try again.\",\n\t\t\tlogMessage: opts?.logMessage,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A call the caller got wrong, where naming the mistake IS the value of the\n\t* error.\n\t*\n\t* The only factory that takes its public message from the caller. The\n\t* generic messages elsewhere exist so an HTTP response cannot leak internal\n\t* detail; this one is for arguments and configuration a developer controls\n\t* and must be told about — a missing option, an unusable combination — where\n\t* `internal()` would reduce the one useful sentence to \"An unexpected error\n\t* occurred.\" Do not pass user-supplied data through it.\n\t*/\n\tstatic invalidInput(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"INVALID_INPUT\",\n\t\t\tpublicMessage: opts.message,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\tstatic validation(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\tpublicMessage: \"Validation failed.\",\n\t\t\tpublicData: { errors: opts.errors },\n\t\t\tcause: opts.cause,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\tstatic conflict(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"CONFLICT\",\n\t\t\tpublicMessage: opts?.message ?? \"The resource has changed since you last loaded it. Please refresh and try again.\",\n\t\t\tpublicData: opts?.data,\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: {\n\t\t\t\treason: opts?.reason,\n\t\t\t\t...opts?.logContext\n\t\t\t}\n\t\t});\n\t}\n\tstatic duplicate(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"DUPLICATE\",\n\t\t\tpublicMessage: \"Resource already exists.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic rateLimited(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"RATE_LIMITED\",\n\t\t\tpublicMessage: \"Too many requests. Please try again later.\",\n\t\t\tpublicData: opts?.retryAfterSeconds !== void 0 ? { retryAfterSeconds: opts.retryAfterSeconds } : void 0,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A request that waited `pool.connectionTimeoutMs` for a database\n\t* connection and was given none. The statement or transaction that waited\n\t* never ran; work committed before it stays committed. The same error\n\t* `fromDatabaseError` gives a busy DbError, from the same table row.\n\t*/\n\tstatic databaseBusy(opts) {\n\t\tconst busy = DB_ERROR_MAPPING.busy;\n\t\treturn new NextlyError({\n\t\t\tcode: busy.code,\n\t\t\tstatusCode: busy.statusCode,\n\t\t\tpublicMessage: busy.publicMessage,\n\t\t\tpublicData: busy.publicData,\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* What a request boundary answers with for a thrown value that is not a\n\t* NextlyError: \"database busy\" when the request waited out its bound for a\n\t* connection, which is retryable and no fault of the server's code, and an\n\t* internal error for anything else.\n\t*\n\t* The busy case has to be read here because it usually arrives raw:\n\t* `withDbErrors` converts only DbErrors, so a driver's error passes through\n\t* services unconverted to the boundary that answers the request.\n\t*/\n\tstatic fromUnexpected(error) {\n\t\treturn NextlyError.busyOr(error, () => NextlyError.internal({ cause: error instanceof Error ? error : void 0 }));\n\t}\n\t/**\n\t* \"Database busy\" when `error` is a request that waited out its bound for\n\t* a connection, and `otherwise()` for anything else.\n\t*\n\t* For a boundary that answers an unexpected failure with an error of its\n\t* own choosing rather than an internal one (a 503 for a flow that must not\n\t* answer on incomplete data), so that a busy database still answers there\n\t* as it does everywhere else. `fromUnexpected` is this rule with the\n\t* internal error as its fallback.\n\t*/\n\tstatic busyOr(error, otherwise) {\n\t\tif (!isDatabaseBusy(error)) return otherwise();\n\t\treturn NextlyError.databaseBusy({ cause: error instanceof Error ? error : void 0 });\n\t}\n\tstatic internal(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"INTERNAL_ERROR\",\n\t\t\tpublicMessage: \"An unexpected error occurred.\",\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic serviceUnavailable(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"SERVICE_UNAVAILABLE\",\n\t\t\tpublicMessage: opts?.publicMessage ?? \"Service unavailable. Please try again later.\",\n\t\t\tlogMessage: opts?.logMessage,\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* Convert a DbError (or arbitrary unknown thrown by the DB layer) to a\n\t* NextlyError with a generic public message and rich logContext. Used by\n\t* `withDbErrors` for auto-conversion (Pattern A) and by services that\n\t* catch DB errors at boundaries (Pattern B). Spec §8.2 mapping table.\n\t*\n\t* Never leaks DB driver text, constraint names, or table names into\n\t* `publicMessage`. All DB context goes into `logContext`. The original\n\t* DbError is preserved as `cause`.\n\t*/\n\tstatic fromDatabaseError(error) {\n\t\tif (isDbError(error)) {\n\t\t\tconst mapping = DB_ERROR_MAPPING[error.kind];\n\t\t\tconst logContext = {\n\t\t\t\tdbKind: error.kind,\n\t\t\t\tdialect: error.dialect\n\t\t\t};\n\t\t\tif (error.code !== void 0) logContext.dbCode = error.code;\n\t\t\tif (error.meta !== void 0) logContext.meta = error.meta;\n\t\t\treturn new NextlyError({\n\t\t\t\tcode: mapping.code,\n\t\t\t\tstatusCode: mapping.statusCode,\n\t\t\t\tpublicMessage: mapping.publicMessage,\n\t\t\t\tpublicData: \"publicData\" in mapping ? mapping.publicData : void 0,\n\t\t\t\tlogMessage: \"Database error\",\n\t\t\t\tlogContext,\n\t\t\t\tcause: error\n\t\t\t});\n\t\t}\n\t\treturn new NextlyError({\n\t\t\tcode: \"INTERNAL_ERROR\",\n\t\t\tstatusCode: 500,\n\t\t\tpublicMessage: \"An unexpected error occurred.\",\n\t\t\tlogMessage: \"Non-DbError passed to fromDatabaseError\",\n\t\t\tcause: error instanceof Error ? error : void 0,\n\t\t\tlogContext: error instanceof Error ? void 0 : { value: String(error) }\n\t\t});\n\t}\n\tstatic is(err) {\n\t\treturn hasBrand(err);\n\t}\n\tstatic isCode(err, code) {\n\t\treturn hasBrand(err) && err.code === code;\n\t}\n\tstatic isNotFound(err) {\n\t\treturn NextlyError.isCode(err, \"NOT_FOUND\");\n\t}\n\tstatic isValidation(err) {\n\t\treturn NextlyError.isCode(err, \"VALIDATION_ERROR\");\n\t}\n\tstatic isAuthRequired(err) {\n\t\treturn NextlyError.isCode(err, \"AUTH_REQUIRED\");\n\t}\n\tstatic isForbidden(err) {\n\t\treturn NextlyError.isCode(err, \"FORBIDDEN\");\n\t}\n\tstatic isConflict(err) {\n\t\treturn NextlyError.isCode(err, \"CONFLICT\");\n\t}\n\tstatic isRateLimited(err) {\n\t\treturn NextlyError.isCode(err, \"RATE_LIMITED\");\n\t}\n};\nexport { NEXTLY_ERROR_STATUS as a, DbError as c, isUniqueViolation as d, safeCode as f, retryAfterSeconds as i, isDatabaseBusy as l, nextly_error_exports as n, genericPublicMessage as o, toDbError as p, retryAfterHeader as r, statusToErrorCode as s, NextlyError as t, isDbError as u };\n","import { t as __exportAll } from \"./rolldown-runtime-BJohB4LM.mjs\";\n// src/utils/get-trusted-client-ip.ts\nvar get_trusted_client_ip_exports = /* @__PURE__ */ __exportAll({\n\tCLIENT_IP_HEADERS: () => CLIENT_IP_HEADERS,\n\tcarriesClientIpHeader: () => carriesClientIpHeader,\n\tgetTrustedClientIp: () => getTrustedClientIp,\n\tipv4ToInt: () => ipv4ToInt,\n\tparseTrustedProxyIpsEnv: () => parseTrustedProxyIpsEnv\n});\n/**\n* Trusted client-IP resolution for Web `Request` objects.\n*\n* The previous `getClientIp` helpers parsed\n* `X-Forwarded-For` unconditionally and returned the *leftmost* hop —\n* which a direct attacker can forge to defeat per-IP rate limits,\n* brute-force lockouts, and refresh-token IP binding.\n*\n* This helper applies the standard \"rightmost-untrusted-hop\" algorithm:\n*\n* - When `trustProxy` is `false` (default), proxy headers are\n* ignored entirely. Returns `null` because Web `Request` does not\n* expose the immediate-peer IP.\n*\n* - When `trustProxy` is `true`, walk `X-Forwarded-For` from the\n* rightmost hop, skipping any value that matches `trustedProxyIps`\n* (CIDR list). Return the first hop that is not in the trust list\n* — that is the closest *untrusted* IP in the chain, i.e. the real\n* client (or the closest claim of one).\n*\n* If no `X-Forwarded-For` is present, fall back to `cf-connecting-ip`\n* (Cloudflare) and `x-real-ip` (Nginx convention).\n*\n* If every hop in the chain is in the trust list, return `null`\n* rather than picking a trusted proxy as \"the client\".\n*\n* Implementation note: this module deliberately avoids `node:net` so\n* downstream packages that bundle for the browser (e.g. `@nextlyhq/admin`)\n* don't fail at build time. IP-family classification is done with\n* regex.\n*\n* @module utils/get-trusted-client-ip\n*/\nconst IPV4_RE = /^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/;\nconst IPV6_CHAR_RE = /^[0-9a-fA-F:.]+$/;\n/** Returns 4 / 6 / 0 (mirrors `net.isIP()` without the Node import). */\nfunction classifyIp(addr) {\n\tif (IPV4_RE.test(addr)) return 4;\n\tif (addr.includes(\":\") && IPV6_CHAR_RE.test(addr) && addr.length <= 45) return 6;\n\treturn 0;\n}\n/**\n* The headers a proxy names the client address in, and the only ones\n* {@link getTrustedClientIp} reads. Exported so a check for \"did this request\n* come through a proxy?\" asks about exactly the headers resolution would use.\n*/\nconst CLIENT_IP_HEADERS = [\n\t\"x-forwarded-for\",\n\t\"cf-connecting-ip\",\n\t\"x-real-ip\"\n];\n/** Whether `request` carries any header a proxy names the client in. */\nfunction carriesClientIpHeader(request) {\n\treturn CLIENT_IP_HEADERS.some((name) => request.headers.has(name));\n}\n/**\n* Resolve the client IP for a Web `Request`, applying the trust-proxy\n* gate described above. Returns `null` when no trusted IP can be\n* identified — callers should treat that as \"unknown\" rather than\n* picking a fallback like `127.0.0.1` (which would collapse all\n* unknown clients into one rate-limit bucket).\n*/\nfunction getTrustedClientIp(request, options) {\n\tif (!options.trustProxy) return null;\n\tconst trustedCidrs = (options.trustedProxyIps ?? []).map(parseCidr).filter((c) => c !== null);\n\tconst xff = request.headers.get(CLIENT_IP_HEADERS[0]);\n\tif (xff) {\n\t\tconst hops = xff.split(\",\").map((h) => h.trim()).filter(Boolean);\n\t\tfor (let i = hops.length - 1; i >= 0; i--) {\n\t\t\tconst hop = stripIpv6Brackets(hops[i]);\n\t\t\tif (!classifyIp(hop)) continue;\n\t\t\tif (!isIpInAnyCidr(hop, trustedCidrs)) return hop;\n\t\t}\n\t\treturn null;\n\t}\n\tconst cfIp = request.headers.get(CLIENT_IP_HEADERS[1])?.trim();\n\tif (cfIp && classifyIp(cfIp)) return cfIp;\n\tconst realIp = request.headers.get(CLIENT_IP_HEADERS[2])?.trim();\n\tif (realIp && classifyIp(realIp)) return realIp;\n\treturn null;\n}\n/**\n* Parse `TRUSTED_PROXY_IPS` env-var format: comma-separated CIDR list\n* with optional whitespace. Empty / unset → empty array.\n*/\nfunction parseTrustedProxyIpsEnv(raw) {\n\tif (!raw) return [];\n\treturn raw.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\nfunction stripIpv6Brackets(ip) {\n\treturn ip.startsWith(\"[\") && ip.endsWith(\"]\") ? ip.slice(1, -1) : ip;\n}\nfunction parseCidr(entry) {\n\tconst [addr, prefixRaw] = entry.split(\"/\");\n\tconst stripped = stripIpv6Brackets(addr);\n\tconst family = classifyIp(stripped);\n\tif (family === 4) {\n\t\tconst prefix = prefixRaw === void 0 ? 32 : Number(prefixRaw);\n\t\tif (!Number.isInteger(prefix) || prefix < 0 || prefix > 32) return null;\n\t\tconst intAddr = ipv4ToInt(stripped);\n\t\tif (intAddr === null) return null;\n\t\treturn {\n\t\t\tfamily: \"ipv4\",\n\t\t\tnetwork: intAddr & (prefix === 0 ? 0 : -1 >>> 32 - prefix << 32 - prefix),\n\t\t\tprefix\n\t\t};\n\t}\n\tif (family === 6) {\n\t\tif (prefixRaw !== void 0 && prefixRaw !== \"128\") return null;\n\t\treturn {\n\t\t\tfamily: \"ipv6\",\n\t\t\tnetwork: stripped.toLowerCase(),\n\t\t\tprefix: 128\n\t\t};\n\t}\n\treturn null;\n}\n/**\n* A dotted-quad IPv4 address as an unsigned 32-bit integer, or null when it is\n* not one. Shared by the client-address, refresh-binding and outbound-URL\n* prefix checks.\n*/\nfunction ipv4ToInt(ip) {\n\tconst parts = ip.split(\".\");\n\tif (parts.length !== 4) return null;\n\tlet acc = 0;\n\tfor (const p of parts) {\n\t\tconst n = Number(p);\n\t\tif (!Number.isInteger(n) || n < 0 || n > 255) return null;\n\t\tacc = acc << 8 | n;\n\t}\n\treturn acc >>> 0;\n}\nfunction isIpInAnyCidr(ip, cidrs) {\n\tif (cidrs.length === 0) return false;\n\tconst family = classifyIp(ip);\n\tif (family === 4) {\n\t\tconst intIp = ipv4ToInt(ip);\n\t\tif (intIp === null) return false;\n\t\tfor (const c of cidrs) {\n\t\t\tif (c.family !== \"ipv4\") continue;\n\t\t\tconst mask = c.prefix === 0 ? 0 : -1 >>> 32 - c.prefix << 32 - c.prefix;\n\t\t\tif ((intIp & mask) >>> 0 === (c.network & mask) >>> 0) return true;\n\t\t}\n\t\treturn false;\n\t}\n\tif (family === 6) {\n\t\tconst lower = ip.toLowerCase();\n\t\tfor (const c of cidrs) if (c.family === \"ipv6\" && c.network === lower) return true;\n\t\treturn false;\n\t}\n\treturn false;\n}\nexport { parseTrustedProxyIpsEnv as a, ipv4ToInt as i, getTrustedClientIp as n, get_trusted_client_ip_exports as r, carriesClientIpHeader as t };\n","import { t as NextlyError } from \"./nextly-error-CwDiSPDF.mjs\";\nimport { i as ipv4ToInt } from \"./get-trusted-client-ip-CYEbmLA3.mjs\";\n// src/utils/validate-external-url.ts\nconst IPV4_RE = /^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/;\n/**\n* IPv4 CIDR ranges that must NEVER be the destination of an outbound\n* fetch sourced from a user-controllable URL. Listed roughly by RFC.\n*/\nconst PRIVATE_IPV4_CIDRS = [\n\t\"0.0.0.0/8\",\n\t\"10.0.0.0/8\",\n\t\"100.64.0.0/10\",\n\t\"127.0.0.0/8\",\n\t\"169.254.0.0/16\",\n\t\"172.16.0.0/12\",\n\t\"192.0.0.0/24\",\n\t\"192.0.2.0/24\",\n\t\"192.168.0.0/16\",\n\t\"198.18.0.0/15\",\n\t\"198.51.100.0/24\",\n\t\"203.0.113.0/24\",\n\t\"224.0.0.0/4\",\n\t\"240.0.0.0/4\"\n];\n/**\n* Cloud-metadata hostnames. These often resolve to private IPs and the\n* private-IP block catches them, but we reject by hostname first so the\n* error message is clear.\n*/\nconst CLOUD_METADATA_HOSTS = /* @__PURE__ */ new Set([\n\t\"metadata.google.internal\",\n\t\"metadata.googleapis.com\",\n\t\"metadata\"\n]);\n/**\n* An outbound URL refused for SSRF safety. Extends `NextlyError` (the package's\n* canonical error) so throw sites honor the error contract, while remaining a\n* distinct class the callers (e.g. the form-builder webhook handler) match with\n* `instanceof`.\n*/\nvar ExternalUrlError = class extends NextlyError {\n\turl;\n\tconstructor(message, url) {\n\t\tsuper({\n\t\t\tcode: \"EXTERNAL_URL_BLOCKED\",\n\t\t\tpublicMessage: message,\n\t\t\tlogContext: { url }\n\t\t});\n\t\tthis.url = url;\n\t\tthis.name = \"ExternalUrlError\";\n\t}\n};\n/** Validate a URL for outbound fetch. Throws `ExternalUrlError` on rejection. */\nasync function validateExternalUrl(rawUrl, options = {}) {\n\tlet parsed;\n\ttry {\n\t\tparsed = new URL(rawUrl);\n\t} catch {\n\t\tthrow new ExternalUrlError(\"Invalid URL\", rawUrl);\n\t}\n\tconst hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n\tconst isLocalhostHostname = hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\";\n\tconst baseProtocols = options.allowedProtocols ?? [\"https:\"];\n\tconst protocols = options.allowLocalhost && isLocalhostHostname ? [...baseProtocols, \"http:\"] : baseProtocols;\n\tif (!protocols.includes(parsed.protocol)) throw new ExternalUrlError(`Protocol ${parsed.protocol} not allowed (allowed: ${protocols.join(\", \")})`, rawUrl);\n\tif (CLOUD_METADATA_HOSTS.has(hostname)) throw new ExternalUrlError(`Cloud-metadata hostname rejected: ${parsed.hostname}`, rawUrl);\n\tif (IPV4_RE.test(hostname)) {\n\t\tif (!isPublicIpv4(hostname, options.allowLocalhost === true && hostname === \"127.0.0.1\")) throw new ExternalUrlError(`Resolved to non-public IP: ${hostname}`, rawUrl);\n\t\treturn {\n\t\t\turl: parsed,\n\t\t\tpinnedIp: hostname,\n\t\t\tfamily: 4\n\t\t};\n\t}\n\tif (hostname.includes(\":\")) {\n\t\tif (!isPublicIpv6(hostname, options.allowLocalhost === true && hostname === \"::1\")) throw new ExternalUrlError(`Resolved to non-public IP: ${hostname}`, rawUrl);\n\t\treturn {\n\t\t\turl: parsed,\n\t\t\tpinnedIp: hostname,\n\t\t\tfamily: 6\n\t\t};\n\t}\n\tconst { lookup } = await import(\"node:dns/promises\");\n\tlet addresses;\n\ttry {\n\t\taddresses = await lookup(hostname, { all: true });\n\t} catch (err) {\n\t\tthrow new ExternalUrlError(`DNS lookup failed: ${err.message}`, rawUrl);\n\t}\n\tif (addresses.length === 0) throw new ExternalUrlError(\"No IPs returned for host\", rawUrl);\n\tfor (const { address, family } of addresses) {\n\t\tconst allow = options.allowLocalhost === true && isLocalhostHostname && family === 4;\n\t\tif (!(family === 4 ? isPublicIpv4(address, allow) : isPublicIpv6(address, allow))) throw new ExternalUrlError(`Resolved to non-public IP: ${address}`, rawUrl);\n\t}\n\tconst first = addresses[0];\n\treturn {\n\t\turl: parsed,\n\t\tpinnedIp: first.address,\n\t\tfamily: first.family === 6 ? 6 : 4\n\t};\n}\n/** Default response body cap: reject anything larger before buffering it all. */\n/**\n* How many bytes a bounded external read may buffer, absent a caller's own cap.\n*\n* Exported for the same reason as the deadline below: an adapter that never\n* touches `safeFetch` still owes callers this default, and restating the number\n* gives the tree two that drift.\n*/\nconst DEFAULT_MAX_RESPONSE_BYTES = 10485760;\n/** Default overall deadline covering DNS + connect + TLS + response. */\n/**\n* How long a bounded external read may take, absent a caller's own limit.\n*\n* Exported so a caller that must begin the clock EARLIER — a storage adapter\n* bounding a metadata lookup as well as the fetch that follows — uses this\n* number rather than restating it. Two spellings of one default agree today and\n* drift the first time either is tuned.\n*/\nconst DEFAULT_TIMEOUT_MS = 3e4;\n/**\n* Raised for fetch-phase failures that are NOT SSRF rejections: an over-large\n* response body, the overall deadline elapsing, or an undecodable content\n* encoding. Extends `NextlyError` (the canonical error contract) while staying a\n* distinct class, so a caller can tell \"URL refused for safety\"\n* (`ExternalUrlError`) apart from \"the request itself failed\".\n*/\nvar SafeFetchError = class extends NextlyError {\n\turl;\n\treason;\n\tstatus;\n\tconstructor(message, url, reason, status) {\n\t\tsuper({\n\t\t\tcode: \"EXTERNAL_REQUEST_FAILED\",\n\t\t\tpublicMessage: message,\n\t\t\tlogContext: {\n\t\t\t\turl,\n\t\t\t\treason\n\t\t\t}\n\t\t});\n\t\tthis.url = url;\n\t\tthis.reason = reason;\n\t\tthis.status = status;\n\t\tthis.name = \"SafeFetchError\";\n\t}\n};\n/**\n* Build a `dns.lookup`-compatible function that ignores the hostname and\n* always resolves to `ip`/`family`. Handing this to `http(s).request` forces\n* the socket to dial the exact address `validateExternalUrl` already vetted,\n* closing the DNS-rebinding window where a second resolution at connect time\n* could return a private IP. Not re-exported from the package barrel; exported\n* for the plugin `ctx.fetch` transport, which pins its vetted address the same\n* way, and so the rebinding invariant can be unit-tested directly.\n*/\nfunction createPinnedLookup(ip, family) {\n\treturn (_hostname, options, callback) => {\n\t\tif (options && options.all) callback(null, [{\n\t\t\taddress: ip,\n\t\t\tfamily\n\t\t}]);\n\t\telse callback(null, ip, family);\n\t};\n}\n/**\n* Validate `rawUrl` then fetch it with the validated IP pinned at the socket.\n* The convenience wrapper for the common case (webhook delivery, email\n* attachment fetch). Node-runtime only.\n*\n* DNS is resolved once by `validateExternalUrl`; `createPinnedLookup` forces\n* the connection to that same address, so an attacker's DNS cannot rebind the\n* request to a private host between validation and connect. Redirects are not\n* followed, the body is capped at `maxResponseBytes`, and the request is\n* bounded by `timeoutMs`.\n*/\nasync function safeFetch(rawUrl, options = {}) {\n\tconst { allowLocalhost, allowedProtocols, method, headers, body, signal, maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES, timeoutMs = DEFAULT_TIMEOUT_MS } = options;\n\tconst controller = new AbortController();\n\tconst forwardAbort = () => controller.abort(signal?.reason);\n\tif (signal) {\n\t\tif (signal.aborted) controller.abort(signal.reason);\n\t\telse signal.addEventListener(\"abort\", forwardAbort, { once: true });\n\t}\n\tconst timer = setTimeout(() => controller.abort(new SafeFetchError(`Request exceeded ${timeoutMs}ms`, rawUrl, \"timeout\")), timeoutMs);\n\ttry {\n\t\treturn await pinnedFetch(await abortable(validateExternalUrl(rawUrl, {\n\t\t\tallowLocalhost,\n\t\t\tallowedProtocols\n\t\t}), controller.signal), {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody,\n\t\t\tsignal: controller.signal,\n\t\t\tmaxResponseBytes\n\t\t});\n\t} finally {\n\t\tclearTimeout(timer);\n\t\tif (signal) signal.removeEventListener(\"abort\", forwardAbort);\n\t}\n}\n/**\n* The signal's abort reason as an `Error`. Our own aborts carry a\n* `SafeFetchError` (timeout); a caller's `AbortController.abort()` carries a\n* DOMException `AbortError`; anything else (a non-Error reason) is surfaced as\n* a standard `AbortError` so downstream `name === \"AbortError\"` checks hold.\n*/\nfunction abortError(signal) {\n\tconst reason = signal.reason;\n\tif (reason instanceof Error) return reason;\n\treturn new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n/**\n* Resolve `promise`, but reject with the signal's reason if it aborts first.\n* Lets a phase that runs before the request (DNS validation) share the overall\n* deadline and caller cancellation.\n*/\nfunction abortable(promise, signal) {\n\tif (signal.aborted) return Promise.reject(abortError(signal));\n\tlet onAbort;\n\tconst aborted = new Promise((_resolve, reject) => {\n\t\tonAbort = () => reject(abortError(signal));\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n\treturn Promise.race([promise, aborted]).finally(() => signal.removeEventListener(\"abort\", onAbort));\n}\n/**\n* Issue the request over `node:http`/`node:https` with the validated IP pinned\n* via a custom `lookup`, then adapt the Node response into a WHATWG `Response`.\n* `agent: false` forces a fresh socket per call so no pooled connection can\n* reuse a differently-resolved address. The overall deadline is enforced by the\n* caller through `init.signal`, so there is no separate timer here.\n*/\nasync function pinnedFetch(validated, init) {\n\tconst { url, pinnedIp, family } = validated;\n\tconst httpMod = url.protocol === \"https:\" ? await import(\"node:https\") : await import(\"node:http\");\n\tconst zlib = await import(\"node:zlib\");\n\tconst lookup = createPinnedLookup(pinnedIp, family);\n\tconst outHeaders = toOutgoingHeaders(init.headers);\n\tif (init.body != null) {\n\t\tdelete outHeaders[\"transfer-encoding\"];\n\t\toutHeaders[\"content-length\"] = String(typeof init.body === \"string\" ? Buffer.byteLength(init.body) : init.body.byteLength);\n\t}\n\treturn new Promise((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst settle = (fn) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tfn();\n\t\t};\n\t\tconst failure = (err) => init.signal.aborted ? abortError(init.signal) : err;\n\t\tconst req = httpMod.request(url, {\n\t\t\tmethod: init.method ?? \"GET\",\n\t\t\theaders: outHeaders,\n\t\t\tlookup,\n\t\t\tagent: false,\n\t\t\tsignal: init.signal\n\t\t}, (res) => {\n\t\t\tconst chunks = [];\n\t\t\tlet received = 0;\n\t\t\tres.on(\"data\", (chunk) => {\n\t\t\t\treceived += chunk.length;\n\t\t\t\tif (received > init.maxResponseBytes) {\n\t\t\t\t\tres.destroy();\n\t\t\t\t\treq.destroy();\n\t\t\t\t\tsettle(() => reject(new SafeFetchError(`Response body exceeded ${init.maxResponseBytes} bytes`, url.href, \"response-too-large\", res.statusCode)));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tchunks.push(chunk);\n\t\t\t});\n\t\t\tres.on(\"end\", () => {\n\t\t\t\tconst decoded = decodeBody(Buffer.concat(chunks), res.headers[\"content-encoding\"], zlib, init.maxResponseBytes, url.href, res.statusCode);\n\t\t\t\tif (decoded instanceof SafeFetchError) {\n\t\t\t\t\tsettle(() => reject(decoded));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsettle(() => resolve(toWhatwgResponse(res, decoded.body, decoded.decoded)));\n\t\t\t});\n\t\t\tres.on(\"error\", (err) => settle(() => reject(failure(err))));\n\t\t});\n\t\treq.on(\"error\", (err) => settle(() => reject(failure(err))));\n\t\tif (!req.destroyed) {\n\t\t\tif (init.body != null) req.write(init.body);\n\t\t\treq.end();\n\t\t}\n\t});\n}\n/**\n* Normalize a `HeadersInit` into Node's outgoing-header shape. Header names are\n* lowercased (they are case-insensitive) so later framing checks\n* (`content-length`) and the Host strip are reliable regardless of caller\n* casing. A caller-supplied `Host` is dropped: it is derived from the validated\n* URL, and honoring an override would let Host-based routing reach an internal\n* vhost behind a validated public IP, defeating the SSRF pin.\n*/\nfunction toOutgoingHeaders(headers) {\n\tconst out = {};\n\tif (!headers) return out;\n\tconst add = (rawKey, value) => {\n\t\tconst key = rawKey.toLowerCase();\n\t\tif (key === \"host\") return;\n\t\tconst existing = out[key];\n\t\tout[key] = existing === void 0 ? value : [].concat(existing, value);\n\t};\n\tif (headers instanceof Headers) headers.forEach((value, key) => add(key, value));\n\telse if (Array.isArray(headers)) for (const [key, value] of headers) add(key, value);\n\telse for (const [key, value] of Object.entries(headers)) add(key, value);\n\treturn out;\n}\n/**\n* Adapt a Node `IncomingMessage` + buffered body into a WHATWG `Response`.\n* Total by construction: a header the WHATWG layer rejects is skipped and the\n* status is clamped to a constructible range, so this never throws (a throw\n* would otherwise escape the `end` handler as an uncaught error).\n*/\nfunction toWhatwgResponse(res, body, stripContentHeaders) {\n\tconst headers = new Headers();\n\tfor (const [key, value] of Object.entries(res.headers)) {\n\t\tif (value == null) continue;\n\t\tconst lower = key.toLowerCase();\n\t\tif (stripContentHeaders && (lower === \"content-encoding\" || lower === \"content-length\")) continue;\n\t\tconst values = Array.isArray(value) ? value : [value];\n\t\tfor (const v of values) try {\n\t\t\theaders.append(key, v);\n\t\t} catch {}\n\t}\n\tconst raw = res.statusCode ?? 502;\n\tconst status = raw >= 200 && raw <= 599 ? raw : 502;\n\tconst nullBody = status === 204 || status === 205 || status === 304;\n\tconst bytes = new Uint8Array(body.byteLength);\n\tbytes.set(body);\n\treturn new Response(nullBody ? null : bytes, {\n\t\tstatus,\n\t\tstatusText: res.statusMessage ?? \"\",\n\t\theaders\n\t});\n}\n/**\n* Content-decode a response body per its `Content-Encoding`. node:http returns\n* raw wire bytes (unlike global fetch), so gzip/deflate/br bodies are inflated\n* here to preserve the previous behavior. `maxOutputLength` bounds the inflated\n* size, turning a decompression bomb into a `SafeFetchError` rather than an OOM.\n* Returns the (possibly decoded) buffer, or a `SafeFetchError` on failure.\n*/\nfunction decodeBody(buf, encoding, zlib, cap, url, status) {\n\tif (!encoding) return {\n\t\tbody: buf,\n\t\tdecoded: false\n\t};\n\tif (buf.length === 0) return {\n\t\tbody: buf,\n\t\tdecoded: true\n\t};\n\tconst layers = encoding.split(\",\").map((e) => e.trim().toLowerCase()).filter(Boolean);\n\tconst opts = { maxOutputLength: cap };\n\tlet current = buf;\n\tlet decoded = false;\n\ttry {\n\t\tfor (let i = layers.length - 1; i >= 0; i--) {\n\t\t\tconst enc = layers[i];\n\t\t\tif (enc === \"identity\") continue;\n\t\t\tif (enc === \"gzip\" || enc === \"x-gzip\") current = zlib.gunzipSync(current, opts);\n\t\t\telse if (enc === \"br\") current = zlib.brotliDecompressSync(current, opts);\n\t\t\telse if (enc === \"deflate\") try {\n\t\t\t\tcurrent = zlib.inflateSync(current, opts);\n\t\t\t} catch (inflateErr) {\n\t\t\t\tif (errorCode(inflateErr) === \"ERR_BUFFER_TOO_LARGE\") throw inflateErr;\n\t\t\t\tcurrent = zlib.inflateRawSync(current, opts);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (decoded) return new SafeFetchError(`Cannot fully decode content-encoding \"${encoding}\"`, url, \"decode-failed\", status);\n\t\t\t\treturn {\n\t\t\t\t\tbody: buf,\n\t\t\t\t\tdecoded: false\n\t\t\t\t};\n\t\t\t}\n\t\t\tdecoded = true;\n\t\t}\n\t\treturn {\n\t\t\tbody: current,\n\t\t\tdecoded\n\t\t};\n\t} catch (err) {\n\t\tconst tooLarge = errorCode(err) === \"ERR_BUFFER_TOO_LARGE\";\n\t\treturn new SafeFetchError(tooLarge ? `Decoded ${encoding} response body exceeded the size cap` : `Failed to decode ${encoding} response body`, url, tooLarge ? \"response-too-large\" : \"decode-failed\", status);\n\t}\n}\n/** The `.code` of a Node system error, if present. */\nfunction errorCode(err) {\n\tif (err != null && typeof err === \"object\" && \"code\" in err) {\n\t\tconst code = err.code;\n\t\treturn typeof code === \"string\" ? code : void 0;\n\t}\n}\nfunction isIpv4InCidr(intIp, cidr) {\n\tconst [addr, prefixRaw] = cidr.split(\"/\");\n\tconst intCidr = ipv4ToInt(addr);\n\tif (intCidr === null) return false;\n\tconst prefix = Number(prefixRaw);\n\tif (!Number.isInteger(prefix) || prefix < 0 || prefix > 32) return false;\n\tconst mask = prefix === 0 ? 0 : -1 >>> 32 - prefix << 32 - prefix;\n\treturn (intIp & mask) >>> 0 === (intCidr & mask) >>> 0;\n}\nfunction isPublicIpv4(addr, allowLoopback) {\n\tconst intIp = ipv4ToInt(addr);\n\tif (intIp === null) return false;\n\tif (allowLoopback && addr === \"127.0.0.1\") return true;\n\tfor (const cidr of PRIVATE_IPV4_CIDRS) if (isIpv4InCidr(intIp, cidr)) return false;\n\treturn true;\n}\n/**\n* Extract the embedded IPv4 of an IPv4-mapped IPv6 address, or null. Handles\n* both the dotted form (`::ffff:1.2.3.4`) and the hex form (`::ffff:7f00:1`)\n* that `URL.hostname` normalizes the dotted literal to — the latter would\n* otherwise skip the IPv4 denylist and pin, e.g., loopback as public.\n*/\nfunction mappedIpv4(lower) {\n\tconst dotted = lower.match(/^::ffff:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/);\n\tif (dotted) return dotted[1];\n\tconst hex = lower.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);\n\tif (hex) {\n\t\tconst hi = parseInt(hex[1], 16);\n\t\tconst lo = parseInt(hex[2], 16);\n\t\treturn [\n\t\t\thi >> 8,\n\t\t\thi & 255,\n\t\t\tlo >> 8,\n\t\t\tlo & 255\n\t\t].join(\".\");\n\t}\n\treturn null;\n}\nfunction isPublicIpv6(addr, allowLoopback) {\n\tconst lower = addr.toLowerCase();\n\tif (allowLoopback && lower === \"::1\") return true;\n\tconst mapped = mappedIpv4(lower);\n\tif (mapped) return isPublicIpv4(mapped, allowLoopback);\n\tif (lower === \"::\" || lower === \"::1\") return false;\n\tconst firstHextet = lower.split(\":\")[0] || \"\";\n\tif (firstHextet.startsWith(\"fc\") || firstHextet.startsWith(\"fd\")) return false;\n\tif (firstHextet.startsWith(\"fe8\") || firstHextet.startsWith(\"fe9\")) return false;\n\tif (firstHextet.startsWith(\"fea\") || firstHextet.startsWith(\"feb\")) return false;\n\tif (firstHextet.startsWith(\"ff\")) return false;\n\treturn true;\n}\nexport { createPinnedLookup as a, SafeFetchError as i, DEFAULT_TIMEOUT_MS as n, safeFetch as o, ExternalUrlError as r, validateExternalUrl as s, DEFAULT_MAX_RESPONSE_BYTES as t };\n","import { t as NextlyError } from \"../nextly-error-CwDiSPDF.mjs\";\n// src/storage/read-errors.ts\n/**\n* The one way the storage layer says a read exceeded the caller's cap.\n*\n* `StorageReadOptions.maxBytes` is part of the adapter contract, so what happens\n* when it is exceeded belongs to the contract too. Without this each backend\n* refuses in its own vocabulary — the URL-addressed ones through a fetch error\n* carrying a `reason`, S3 through whatever its own code threw — and a caller\n* wanting to tell \"too large\" from \"could not read\" has to know which adapter it\n* is talking to. That is the thing an adapter contract exists to stop.\n*\n* Distinct from a generic internal failure because callers ACT on the\n* difference. The email attachment path answers an over-cap read with\n* `ATTACHMENT_SIZE_EXCEEDED`, which tells an author to attach something smaller;\n* a storage failure tells them nothing they can act on. Collapsing the two turns\n* a fixable refusal into an opaque error, which is the same conflation this\n* contract already draws between a missing key and an unreachable store.\n*\n* @module storage/read-errors\n*/\n/**\n* A read refused because the object is larger than the caller allowed.\n*\n* Carries the numbers rather than only a message, so a caller can say what the\n* limit was without parsing prose — and so the message itself stays free of the\n* key, which should not travel to whoever asked for the file.\n*/\nvar StorageReadTooLargeError = class extends NextlyError {\n\tpath;\n\tmaxBytes;\n\tsize;\n\tconstructor(path, maxBytes, size) {\n\t\tsuper({\n\t\t\tcode: \"STORAGE_READ_TOO_LARGE\",\n\t\t\tpublicMessage: \"The stored file is larger than the limit for this read.\",\n\t\t\tlogContext: {\n\t\t\t\tpath,\n\t\t\t\tmaxBytes,\n\t\t\t\t...size === void 0 ? {} : { size }\n\t\t\t}\n\t\t});\n\t\tthis.path = path;\n\t\tthis.maxBytes = maxBytes;\n\t\tthis.size = size;\n\t}\n};\n/**\n* Whether a thrown value is the over-cap refusal.\n*\n* A predicate rather than leaving every caller to write `instanceof`, because\n* this module can be loaded twice — a narrow entry point and a barrel are\n* different module instances, and `instanceof` across them is false for objects\n* that are otherwise identical. Callers that ask here cannot be caught by that.\n*/\nfunction isStorageReadTooLarge(error) {\n\treturn NextlyError.is(error) && error.code === \"STORAGE_READ_TOO_LARGE\";\n}\n/**\n* A read abandoned because the backend did not answer in time.\n*\n* Carried as the abort REASON rather than raised afterwards, which is what\n* makes it reach the caller at all: `AbortSignal.timeout` rejects with a\n* platform `DOMException`, and product code in this package answers in\n* `NextlyError` so a caller can classify what it caught without matching on a\n* name the runtime chose. `safeFetch` already aborts this way for the same\n* reason.\n*\n* Distinct from the over-cap refusal above by what each one KNOWS. The over-cap\n* refusal has measured the object and found it larger than the caller allowed.\n* This one knows only that the read did not finish in time: it may never have\n* opened the object, or may have taken some of it and been cut off part way, so\n* neither the object's size nor its existence follows from this error.\n*/\nvar StorageReadTimeoutError = class extends NextlyError {\n\tpath;\n\ttimeoutMs;\n\tconstructor(path, timeoutMs) {\n\t\tsuper({\n\t\t\tcode: \"STORAGE_READ_TIMEOUT\",\n\t\t\tpublicMessage: \"The stored file could not be read in time.\",\n\t\t\tlogContext: {\n\t\t\t\tpath,\n\t\t\t\ttimeoutMs\n\t\t\t}\n\t\t});\n\t\tthis.path = path;\n\t\tthis.timeoutMs = timeoutMs;\n\t}\n};\n/**\n* Whether a thrown value is the deadline refusal.\n*\n* A predicate for the same reason as `isStorageReadTooLarge`: a narrow entry\n* point and a barrel are different module instances, and `instanceof` across\n* them is false for objects that are otherwise identical.\n*/\nfunction isStorageReadTimeout(error) {\n\treturn NextlyError.is(error) && error.code === \"STORAGE_READ_TIMEOUT\";\n}\nexport { StorageReadTimeoutError, StorageReadTooLargeError, isStorageReadTimeout, isStorageReadTooLarge };\n","import { t as NextlyError } from \"../nextly-error-CwDiSPDF.mjs\";\nimport { i as SafeFetchError, n as DEFAULT_TIMEOUT_MS, o as safeFetch, t as DEFAULT_MAX_RESPONSE_BYTES } from \"../validate-external-url-CnZrcJdP.mjs\";\nimport { StorageReadTimeoutError, StorageReadTooLargeError } from \"./read-errors.mjs\";\n// src/storage/fetch-stored-bytes.ts\n/**\n* Reading bytes back from a storage service that only exposes them over HTTP.\n*\n* The local adapter reads from disk and S3 reads through its own SDK, so\n* neither needs this. The services that address a file by URL — Vercel Blob,\n* UploadThing — all end up doing the same three things, and doing them the same\n* way matters more than it looks: each step below is a place where the obvious\n* shortcut reports the wrong thing to a caller who may act on it.\n*\n* Built on {@link safeFetch} rather than on a bare `fetch`, because \"read a\n* remote object into memory\" already has an implementation here that caps the\n* body, bounds the request and refuses an address that resolves somewhere\n* private. A second capped fetch beside it would be two answers to one\n* question, and the two would drift the first time either learned something.\n* Measured: it costs an adapter package about 80K, against the 1MB the whole\n* storage barrel costs.\n*\n* @module storage/fetch-stored-bytes\n*/\n/**\n* Fetch a stored object's bytes from the URL its service issued.\n*\n* Separates the two answers a read can have, which is the whole reason this is\n* a function rather than three lines inlined twice.\n*\n* `null` means the object is NOT THERE — an ordinary fact about the store. A\n* 404 is that answer even when the lookup just succeeded: these stores are\n* remote and concurrent, so an object can be deleted between resolving its\n* address and fetching it. Reporting that ordinary race as a server failure\n* would make a caller handle an error for something its own contract already\n* has a value for.\n*\n* Anything else THROWS. A dropped connection, a 5xx or a refused request says\n* nothing about whether the object exists, and reporting it as absence invites\n* a caller to treat a live file as deleted and write a replacement over it. The\n* two are easy to state apart and easy to lose when the fetch sits inside the\n* same `try` that catches the lookup.\n*\n* The URL is always one the SERVICE issued, never one assembled from a key.\n* These stores mint addresses carrying suffixes the adapter never chose, so a\n* derived URL is a guess at a string another system owns.\n*\n* @param url - The address the storage service reported for this object\n* @param context - What is being read, for the error message: usually the key\n* @param label - The service's name, so a failure says which store answered\n* @param options - Bounds for the read; see {@link StorageReadOptions}\n* @param signal - A deadline ALREADY RUNNING, covering an earlier phase too\n* @returns The object's bytes, or `null` when the store answers 404\n*/\nasync function fetchStoredBytes(url, context, label, options, signal) {\n\tlet response;\n\ttry {\n\t\tresponse = await safeFetch(url, {\n\t\t\t...options?.maxBytes === void 0 ? {} : { maxResponseBytes: options.maxBytes },\n\t\t\t...signal !== void 0 ? { signal } : options?.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }\n\t\t});\n\t} catch (error) {\n\t\tconst verdict = classifyFetchFailure(error);\n\t\tif (verdict === \"absent\") return null;\n\t\tif (verdict === \"oversized\") throw new StorageReadTooLargeError(context, resolveReadBounds(options).maxBytes);\n\t\tthrow error;\n\t}\n\tif (response.status === 404) return null;\n\tif (!response.ok) throw NextlyError.internal({ logContext: {\n\t\tservice: label,\n\t\tpath: context,\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText\n\t} });\n\treturn Buffer.from(await response.arrayBuffer());\n}\n/**\n* What a failed fetch actually says about the object.\n*\n* Its own function because the three answers are the whole point of this module\n* and they are easy to collapse into each other — each collapse having been a\n* real defect here rather than a hypothetical:\n*\n* - ABSENT. A 404 is absence whatever size its body was. `safeFetch` caps while\n* buffering, so a verbose CDN error page raises before a `Response` exists\n* and the status check further down is never reached; the object is still\n* gone, and must not become an error because the page explaining it was long.\n* - OVERSIZED. Only a SUCCESSFUL response that blew the cap. A failed response\n* can exceed it too, and translating on the reason alone reported a backend\n* outage as \"your file is too big\" — a cause the author would act on, wrongly.\n* - UNKNOWN. Everything else, including a too-large refusal carrying NO status:\n* that means the failure arrived before any status did, which says nothing\n* about whether the object was oversized.\n*/\nfunction classifyFetchFailure(error) {\n\tif (!(error instanceof SafeFetchError)) return \"unknown\";\n\tif (error.status === 404) return \"absent\";\n\tconst successful = error.status !== void 0 && error.status >= 200 && error.status < 300;\n\treturn error.reason === \"response-too-large\" && successful ? \"oversized\" : \"unknown\";\n}\n/** The deadline a stored read runs under when the caller names none. */\nconst DEFAULT_READ_TIMEOUT_MS = DEFAULT_TIMEOUT_MS;\n/** The byte cap a stored read runs under when the caller names none. */\nconst DEFAULT_READ_MAX_BYTES = DEFAULT_MAX_RESPONSE_BYTES;\n/**\n* The bounds a read actually runs under, defaults filled in.\n*\n* ONE place, because every adapter needs the same answer and the ones that\n* derived it themselves diverged: the URL-backed pair inherited `safeFetch`'s\n* cap and deadline for free, while the local and S3 adapters — which never\n* touch `safeFetch` — applied NO bound at all when the caller named none.\n* `StorageReadOptions` promises the default either way, and a production caller\n* reading media without options got it from two of four backends.\n*\n* Filling the defaults here rather than per adapter is what makes the promise\n* true by construction rather than by four implementations agreeing.\n*/\nfunction resolveReadBounds(options) {\n\treturn {\n\t\tmaxBytes: options?.maxBytes ?? DEFAULT_READ_MAX_BYTES,\n\t\ttimeoutMs: options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS\n\t};\n}\n/**\n* A deadline that aborts with a NextlyError rather than a platform exception.\n*\n* `AbortSignal.timeout` rejects with a `DOMException` named `TimeoutError`, and\n* product code in this package answers in `NextlyError` — so a caller can\n* classify what it caught rather than matching a name the runtime chose. Built\n* here rather than per adapter so every storage deadline says the same thing.\n*\n* The timer is unreferenced so a pending deadline is never a reason the process\n* stays alive, and the returned `cancel` clears it once the read settles — the\n* unref alone would leave one scheduled per read for the whole timeout.\n*\n* @param timeoutMs - How long the read may take\n* @param context - What is being read, carried into the refusal's log side\n*/\nfunction deadlineSignal(timeoutMs, context) {\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => {\n\t\tcontroller.abort(new StorageReadTimeoutError(context, timeoutMs));\n\t}, timeoutMs);\n\ttimer.unref?.();\n\treturn {\n\t\tsignal: controller.signal,\n\t\tcancel: () => {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t};\n}\n/**\n* Stop waiting on a promise once the deadline fires.\n*\n* For a lookup whose SDK cannot be cancelled. UploadThing 7.7.4's\n* `getFileUrls` reads only `keyType` and forwards no signal, so handing it one\n* bounds nothing — the option is accepted and ignored, which reads as covered\n* and behaves as absent.\n*\n* This RACES rather than cancels, and the difference is worth stating plainly:\n* the underlying request keeps running to completion in the background. What it\n* buys is that `read` returns within the deadline it advertised, instead of\n* holding its caller for as long as a stalled backend feels like. That is the\n* promise the contract actually makes; genuinely cancelling the work needs an\n* SDK that accepts cancellation, and this one does not.\n*/\nasync function withDeadline(work, signal) {\n\tif (signal === void 0) return await work;\n\treturn await Promise.race([work, new Promise((_, reject) => {\n\t\tif (signal.aborted) {\n\t\t\treject(signal.reason);\n\t\t\treturn;\n\t\t}\n\t\tsignal.addEventListener(\"abort\", () => reject(signal.reason), { once: true });\n\t})]);\n}\nexport { DEFAULT_READ_MAX_BYTES, DEFAULT_READ_TIMEOUT_MS, classifyFetchFailure, deadlineSignal, fetchStoredBytes, resolveReadBounds, withDeadline };\n","/**\n * Vercel Blob Storage Adapter\n *\n * Stores files on Vercel Blob Storage, a globally distributed object storage\n * service powered by Cloudflare R2. Optimized for Vercel deployments with\n * built-in CDN distribution.\n *\n * Features:\n * - Globally distributed CDN-backed storage\n * - Automatic file management with unique filenames\n * - Token-based authentication\n * - Client-side upload support (via handleUpload API)\n * - Serverless-friendly (no filesystem access required)\n *\n * @example Basic usage\n * ```typescript\n * const adapter = new VercelBlobStorageAdapter({\n * token: process.env.BLOB_READ_WRITE_TOKEN,\n * collections: { media: true }\n * });\n *\n * const result = await adapter.upload(buffer, {\n * filename: 'photo.jpg',\n * mimeType: 'image/jpeg'\n * });\n * // result.url: \"https://abc123.public.blob.vercel-storage.com/photo-xyz.jpg\"\n * ```\n */\n\nimport { put, del, head, list, BlobNotFoundError } from \"@vercel/blob\";\nimport { NextlyError } from \"nextly/errors\";\nimport type {\n IStorageAdapter,\n UploadOptions,\n UploadResult,\n StorageAdapterInfo,\n ClientUploadData,\n FileMetadata,\n BulkDeleteResult,\n StorageReadOptions,\n StoredFileEntry,\n} from \"nextly/storage\";\nimport {\n fetchStoredBytes,\n DEFAULT_READ_TIMEOUT_MS,\n} from \"nextly/storage/fetch-stored-bytes\";\n\nimport type {\n VercelBlobStorageConfig,\n ResolvedVercelBlobConfig,\n} from \"./types\";\n\n// ============================================================\n// Vercel Blob Storage Adapter\n// ============================================================\n\n/**\n * Vercel Blob Storage Adapter\n *\n * Implements the IStorageAdapter interface for Vercel Blob Storage.\n * Provides file upload, deletion, existence checks, and metadata retrieval.\n */\nexport class VercelBlobStorageAdapter implements IStorageAdapter {\n private resolvedConfig: ResolvedVercelBlobConfig;\n\n /**\n * Create a new Vercel Blob storage adapter.\n *\n * @param config - Vercel Blob storage configuration\n * @throws Error if token is not provided\n */\n constructor(private config: VercelBlobStorageConfig) {\n // Resolve token from config or environment\n const token = config.token || process.env.BLOB_READ_WRITE_TOKEN || \"\";\n\n if (!token) {\n throw new Error(\n \"@nextly/storage-vercel-blob: token is required.\\n\\n\" +\n \"Either set the BLOB_READ_WRITE_TOKEN environment variable or pass token in config.\\n\" +\n \"Get your token from: Vercel Dashboard > Storage > Blob > Tokens\"\n );\n }\n\n // Resolve config with defaults\n this.resolvedConfig = {\n token,\n addRandomSuffix: config.addRandomSuffix ?? true,\n cacheControlMaxAge: config.cacheControlMaxAge ?? 31536000,\n access: config.access ?? \"public\",\n storeId: config.storeId,\n allowOverwrite: config.allowOverwrite ?? false,\n multipartThreshold: config.multipartThreshold ?? 5 * 1024 * 1024, // 5MB\n };\n }\n\n // ============================================================\n // Core IStorageAdapter Methods\n // ============================================================\n\n /**\n * Upload file to Vercel Blob.\n *\n * Files are stored with globally distributed CDN backing.\n * By default, a random suffix is added to prevent filename collisions.\n *\n * @param buffer - File content as Buffer\n * @param options - Upload options (filename, mimeType, folder, collection)\n * @returns Upload result with URL and storage path\n */\n async upload(buffer: Buffer, options: UploadOptions): Promise<UploadResult> {\n const mimeType = (options.contentType || options.mimeType || \"\")\n .toLowerCase()\n .trim();\n const filename = (options.filename || \"\").toLowerCase();\n const ext = filename.includes(\".\")\n ? filename.slice(filename.lastIndexOf(\".\") + 1)\n : \"\";\n const isHtml =\n mimeType === \"text/html\" ||\n mimeType === \"application/xhtml+xml\" ||\n ext === \"html\" ||\n ext === \"htm\" ||\n ext === \"xhtml\";\n // HTML stays unconditionally rejected. The `downloadUrl` trick that\n // makes SVG safe (see below) doesn't help HTML — a downloaded HTML\n // file is still a usable XSS vector when opened from disk, and\n // Vercel Blob has no equivalent of `Content-Security-Policy` to\n // defang it.\n if (isHtml) {\n throw NextlyError.validation({\n errors: [\n {\n path: \"file\",\n code: \"UNSUPPORTED_FOR_BACKEND\",\n message:\n \"HTML files cannot be hosted on Vercel Blob. Use the S3 or R2 adapter, or upload as another format.\",\n },\n ],\n logContext: {\n adapter: \"vercel-blob\",\n claimedMimeType: options.mimeType,\n reason: \"vercel-blob-rejects-html\",\n filename: options.filename,\n },\n });\n }\n\n const isSvg =\n mimeType === \"image/svg+xml\" || ext === \"svg\" || ext === \"svgz\";\n\n const pathname = this.buildPathname(options.filename, options.folder);\n\n const result = await put(pathname, buffer, {\n access: this.resolvedConfig.access,\n token: this.resolvedConfig.token,\n contentType: options.contentType || options.mimeType,\n addRandomSuffix: this.resolvedConfig.addRandomSuffix,\n cacheControlMaxAge: this.resolvedConfig.cacheControlMaxAge,\n });\n\n // SVGs are served via Vercel Blob's `downloadUrl` (the same URL with\n // `?download=1` appended) so direct top-level navigation forces an\n // attachment download instead of rendering. `<img src>` ignores the\n // `Content-Disposition` header, so legitimate inline rendering still\n // works. The `@vercel/blob` SDK has no `contentDisposition` input\n // option on `put()`, so this query-param-driven approach is the\n // supported mechanism. Caller is responsible for sanitizing SVG\n // contents upstream (handled by `upload-validation`).\n const url =\n isSvg && options.contentDisposition === \"attachment\"\n ? result.downloadUrl\n : result.url;\n\n return {\n url,\n path: result.url,\n };\n }\n\n /**\n * Delete file from Vercel Blob.\n *\n * @param filePath - Full blob URL to delete\n */\n async delete(filePath: string): Promise<void> {\n await del(filePath, {\n token: this.resolvedConfig.token,\n });\n }\n\n /**\n * Delete multiple files from Vercel Blob in chunked batches.\n *\n * Processes deletions in chunks of 10 concurrent calls using Promise.allSettled,\n * collecting successes and failures without short-circuiting.\n *\n * @param filePaths - Array of full blob URLs to delete\n * @returns BulkDeleteResult with successful and failed arrays\n */\n async bulkDelete(filePaths: string[]): Promise<BulkDeleteResult> {\n const successful: string[] = [];\n const failed: Array<{ filePath: string; error: string }> = [];\n const chunkSize = 10;\n\n for (let i = 0; i < filePaths.length; i += chunkSize) {\n const chunk = filePaths.slice(i, i + chunkSize);\n const results = await Promise.allSettled(\n chunk.map(fp => del(fp, { token: this.resolvedConfig.token }))\n );\n\n results.forEach((result, idx) => {\n const fp = chunk[idx];\n if (result.status === \"fulfilled\") {\n successful.push(fp);\n } else {\n failed.push({\n filePath: fp,\n error:\n result.reason instanceof Error\n ? result.reason.message\n : String(result.reason),\n });\n }\n });\n }\n\n return { successful, failed };\n }\n\n /**\n * Check if file exists in Vercel Blob.\n *\n * Uses the head() function which is efficient for existence checks.\n *\n * @param filePath - Full blob URL to check\n * @returns true if file exists, false otherwise\n */\n async exists(filePath: string): Promise<boolean> {\n try {\n await head(filePath, {\n token: this.resolvedConfig.token,\n });\n return true;\n } catch {\n // Vercel Blob throws an error if the blob doesn't exist\n return false;\n }\n }\n\n /**\n * Read a stored blob back as bytes, or `null` when it is not there.\n *\n * A NETWORK round trip, unlike the local adapter's disk read, because the\n * bytes live on Vercel's CDN and there is no other way to reach them. That\n * cost is the reason a caller serving these from its own origin has to cache:\n * the privacy rule that forces same-origin serving does not also make the\n * fetch free, and an uncached proxy pays it on every request.\n *\n * The URL is taken from `head` rather than assembled from `filePath`,\n * because a blob's address is issued by the service — it carries a random\n * suffix this adapter never chose — so deriving one here would be guessing at\n * a string another system owns.\n *\n * `null` for a missing blob rather than a throw, matching {@link exists}.\n *\n * @param filePath - Blob path/key\n * @returns The blob's bytes, or `null` when it does not exist\n */\n async read(\n filePath: string,\n options?: StorageReadOptions\n ): Promise<Buffer | null> {\n /*\n * ONE deadline for both phases, started before the lookup.\n *\n * `head` can stall exactly as the fetch can, and it runs first — so a\n * deadline that begins only at the fetch leaves the lookup unbounded and\n * the read can outlive what the caller was promised. Created here and\n * handed to both.\n *\n * ALWAYS, not only when the caller named a timeout. `safeFetch` applies a\n * default deadline of its own, so a caller stating none was still bounded\n * for the fetch and unbounded for the lookup — which is the commonest call,\n * the email path among them, since it supplies only a byte cap. The default\n * comes from the same constant `safeFetch` uses rather than being restated.\n */\n const deadline = AbortSignal.timeout(\n options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS\n );\n\n let target: string;\n try {\n const meta = await head(filePath, {\n token: this.resolvedConfig.token,\n abortSignal: deadline,\n });\n target = meta.downloadUrl ?? meta.url;\n } catch (error: unknown) {\n /*\n * ONLY the not-found class becomes `null`. `head` also rejects for an\n * expired token, a suspended or missing store, an aborted request and a\n * plain network failure, and every one of those says nothing about\n * whether the blob exists. Catching them all reports an outage as a\n * deletion, which a caller may act on by writing a replacement over a\n * file that is still there.\n *\n * Identified by the CLASS the SDK exports rather than by matching the\n * message, because the message is prose this package does not own.\n */\n if (error instanceof BlobNotFoundError) return null;\n throw error;\n }\n\n /*\n * OUTSIDE the catch above, deliberately, and through the shared helper so\n * that separation is stated once rather than in each adapter. A failed\n * fetch of a blob whose metadata just resolved is a transport failure\n * rather than an absence, and folding it into `null` would report a\n * network outage as a deleted file.\n */\n return await fetchStoredBytes(\n target,\n filePath,\n \"Vercel Blob\",\n options,\n deadline\n );\n }\n\n /**\n * Get public URL for Vercel Blob file.\n *\n * Vercel Blob paths ARE the public URLs - they're already full HTTPS URLs\n * with CDN distribution.\n *\n * @param filePath - Full blob URL\n * @returns The same URL (Vercel Blob paths are already public URLs)\n */\n /**\n * Every blob in the store, by its URL (which is its stored path here), with\n * when it was uploaded, a page at a time.\n */\n async *list(): AsyncIterable<StoredFileEntry> {\n let cursor: string | undefined;\n do {\n const page = await this.listBlobs(undefined, { cursor });\n for (const blob of page.blobs) {\n yield { path: blob.url, lastModified: blob.uploadedAt };\n }\n cursor = page.hasMore ? page.cursor : undefined;\n } while (cursor);\n }\n\n getPublicUrl(filePath: string): string {\n // Vercel Blob paths are already full URLs\n return filePath;\n }\n\n /**\n * Get storage type identifier.\n */\n getType(): \"vercel-blob\" {\n return \"vercel-blob\";\n }\n\n // ============================================================\n // Optional IStorageAdapter Methods\n // ============================================================\n\n /**\n * Get adapter info including capabilities.\n *\n * @returns Adapter info with type, name, and capability flags\n */\n getInfo(): StorageAdapterInfo {\n return {\n type: \"vercel-blob\",\n name: \"VercelBlobStorageAdapter\",\n supportsSignedUrls: false, // Vercel Blob URLs are public by default\n supportsClientUploads: true, // Via handleUpload API\n };\n }\n\n /**\n * Get file metadata from Vercel Blob.\n *\n * Retrieves file information including size, content type, and upload date.\n *\n * @param filePath - Full blob URL\n * @returns File metadata or null if file not found\n */\n async getMetadata(filePath: string): Promise<FileMetadata | null> {\n try {\n const result = await head(filePath, {\n token: this.resolvedConfig.token,\n });\n\n // Extract filename from pathname\n const filename = result.pathname.split(\"/\").pop() || result.pathname;\n\n return {\n id: filePath,\n filename,\n originalFilename: filename,\n mimeType: result.contentType,\n size: result.size,\n url: result.url,\n createdAt: result.uploadedAt.toISOString(),\n };\n } catch {\n // File not found\n return null;\n }\n }\n\n /**\n * Generate pre-signed URL for client-side uploads.\n *\n * Vercel Blob uses a different pattern for client uploads - they require\n * the handleUpload API which handles token generation server-side.\n *\n * This method is not implemented because Vercel Blob's client upload flow\n * requires server-side route handlers with handleUpload().\n *\n * @see https://vercel.com/docs/storage/vercel-blob/client-upload\n * @throws Error always - client uploads require handleUpload API\n */\n getPresignedUploadUrl(\n _key: string,\n _mimeType: string,\n _expiresIn?: number\n ): Promise<ClientUploadData> {\n return Promise.reject(\n new Error(\n \"@nextly/storage-vercel-blob: Client uploads require the handleUpload API.\\n\\n\" +\n \"Vercel Blob uses a different pattern for client-side uploads that involves:\\n\" +\n \"1. A server-side route handler with handleUpload()\\n\" +\n \"2. The @vercel/blob/client upload() function\\n\\n\" +\n \"See: https://vercel.com/docs/storage/vercel-blob/client-upload\\n\\n\" +\n \"For server-side uploads, use the standard upload() method instead.\"\n )\n );\n }\n\n // ============================================================\n // Additional Methods\n // ============================================================\n\n /**\n * List blobs with optional prefix filter.\n *\n * Useful for browsing or batch operations on stored files.\n *\n * @param prefix - Optional prefix to filter results\n * @param options - List options (limit, cursor)\n * @returns List of blob metadata\n */\n async listBlobs(\n prefix?: string,\n options?: { limit?: number; cursor?: string }\n ): Promise<{\n blobs: Array<{\n url: string;\n pathname: string;\n size: number;\n uploadedAt: Date;\n }>;\n hasMore: boolean;\n cursor?: string;\n }> {\n const result = await list({\n token: this.resolvedConfig.token,\n prefix,\n limit: options?.limit,\n cursor: options?.cursor,\n });\n\n return {\n blobs: result.blobs.map(blob => ({\n url: blob.url,\n pathname: blob.pathname,\n size: blob.size,\n uploadedAt: blob.uploadedAt,\n })),\n hasMore: result.hasMore,\n cursor: result.cursor,\n };\n }\n\n // ============================================================\n // Helper Methods\n // ============================================================\n\n /**\n * Build pathname for Vercel Blob upload.\n *\n * Creates pathname in format: {folder}/{filename}\n * If no folder is provided, uses the filename directly.\n *\n * @param filename - Original filename (will be sanitized)\n * @param folder - Optional folder/prefix for organizing uploads\n * @returns Generated pathname\n * @throws Error if folder fails sanitization\n */\n private buildPathname(filename: string, folder?: string): string {\n const sanitized = this.sanitizeFilename(filename);\n if (!folder) return sanitized;\n return `${this.sanitizeFolder(folder)}/${sanitized}`;\n }\n\n /**\n * Sanitize filename to prevent path traversal issues.\n *\n * @param filename - Original filename\n * @returns Sanitized filename\n */\n private sanitizeFilename(filename: string): string {\n const basename = filename.split(/[/\\\\]/).pop() || filename;\n return basename.replace(/[^a-zA-Z0-9._-]/g, \"-\");\n }\n\n /**\n * Reject folder values that would let a caller\n * escape the configured prefix via path traversal or weird\n * separators. Vercel Blob is flat-keyed so `/` is just part of the\n * pathname, but an attacker who controls `folder` could still:\n *\n * - Use `..` to chain a relative-traversal-style key.\n * - Use `\\` (Windows separator) to confuse downstream tooling.\n * - Use control chars / null bytes to truncate the key.\n * - Use a leading `/` to look like an absolute path.\n *\n * Internal `/` segments stay allowed because callers legitimately\n * use nested folders (`docs/2026/...`); a leading `/`, empty\n * segments (`docs//x`), or `..` segments are rejected.\n *\n * @throws Error with a stable message so the storage facade can\n * surface a 400 instead of a 500.\n */\n private sanitizeFolder(folder: string): string {\n const trimmed = folder.replace(/\\/+$/, \"\"); // tolerate one trailing `/`\n if (!trimmed) {\n throw new Error(\"Folder must be a non-empty string.\");\n }\n // eslint-disable-next-line no-control-regex -- the whole point is to reject control chars\n if (/[\\\\\\0\\x01-\\x1f\\x7f]/.test(trimmed)) {\n throw new Error(\n \"Folder contains forbidden characters (backslash, control chars, or null bytes).\"\n );\n }\n if (trimmed.startsWith(\"/\")) {\n throw new Error(\"Folder must not start with `/`.\");\n }\n const segments = trimmed.split(\"/\");\n for (const segment of segments) {\n if (segment === \"\") {\n throw new Error(\"Folder must not contain empty segments (`//`).\");\n }\n if (segment === \"..\") {\n throw new Error(\"Folder must not contain `..` segments.\");\n }\n }\n return trimmed;\n }\n\n // ============================================================\n // Public Accessors\n // ============================================================\n\n /**\n * Get the configured token (masked for logging).\n */\n getTokenMasked(): string {\n const token = this.resolvedConfig.token;\n if (token.length <= 8) return \"****\";\n return `${token.slice(0, 4)}...${token.slice(-4)}`;\n }\n\n /**\n * Check if random suffix is enabled.\n */\n hasRandomSuffix(): boolean {\n return this.resolvedConfig.addRandomSuffix;\n }\n\n /**\n * Get configured cache control max age.\n */\n getCacheControlMaxAge(): number {\n return this.resolvedConfig.cacheControlMaxAge;\n }\n}\n","/**\n * Vercel Blob Storage Plugin\n *\n * Factory function that creates a storage plugin for Vercel Blob Storage.\n * Returns a StoragePlugin that can be registered with MediaStorage.\n *\n * @example Basic usage\n * ```typescript\n * import { vercelBlobStorage } from '@nextly/storage-vercel-blob'\n * import { defineConfig } from 'nextly/config'\n *\n * export default defineConfig({\n * storage: [\n * vercelBlobStorage({\n * token: process.env.BLOB_READ_WRITE_TOKEN,\n * collections: {\n * media: true\n * }\n * })\n * ]\n * })\n * ```\n *\n * @example With client uploads (recommended for Vercel)\n * ```typescript\n * vercelBlobStorage({\n * collections: {\n * media: {\n * clientUploads: true // Bypass 4.5MB serverless limit\n * }\n * }\n * })\n * ```\n *\n * @example With collection-specific configuration\n * ```typescript\n * vercelBlobStorage({\n * addRandomSuffix: true,\n * cacheControlMaxAge: 86400, // 1 day\n * collections: {\n * // Simple enable with defaults\n * media: true,\n *\n * // Full configuration\n * documents: {\n * prefix: 'docs/',\n * addRandomSuffix: false,\n * allowOverwrite: true\n * }\n * }\n * })\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { StoragePlugin, ClientUploadData } from \"nextly/storage\";\n\nimport { VercelBlobStorageAdapter } from \"./adapter\";\nimport type { VercelBlobStorageConfig } from \"./types\";\n\n// ============================================================\n// Plugin Factory Function\n// ============================================================\n\n/**\n * Create a Vercel Blob storage plugin for Nextly.\n *\n * This factory function creates a StoragePlugin that can be added to\n * the `storage` array in `nextly.config.ts`. Vercel Blob is optimized\n * for Vercel deployments with:\n *\n * - Global CDN distribution\n * - Simple token-based authentication\n * - Client-side upload support (via handleUpload API)\n * - Automatic file management\n *\n * @param config - Vercel Blob storage configuration\n * @returns A StoragePlugin that MediaStorage can register\n *\n * @throws Error if token is not provided (via adapter)\n */\nexport function vercelBlobStorage(\n config: VercelBlobStorageConfig\n): StoragePlugin {\n // Handle disabled plugin\n // When disabled, return a plugin with no collections and null adapter\n // MediaStorage.registerPlugin() checks for null adapter and skips registration\n if (config.enabled === false) {\n return {\n name: \"vercel-blob-storage\",\n type: \"vercel-blob\",\n collections: {},\n adapter: null as unknown as StoragePlugin[\"adapter\"],\n };\n }\n\n // Create the Vercel Blob adapter\n // Adapter constructor validates required config (token)\n const adapter = new VercelBlobStorageAdapter(config);\n\n // Build and return the plugin\n const plugin: StoragePlugin = {\n name: \"vercel-blob-storage\",\n type: \"vercel-blob\",\n collections: config.collections,\n adapter,\n\n /**\n * Generate upload URL for client-side uploads.\n *\n * Note: Vercel Blob uses a different pattern for client uploads.\n * Instead of pre-signed URLs, it uses the handleUpload() API which\n * requires server-side route handlers.\n *\n * This method throws an error explaining the correct approach.\n *\n * @see https://vercel.com/docs/storage/vercel-blob/client-upload\n */\n getClientUploadUrl(\n _filename: string,\n _mimeType: string,\n _collection: string\n ): Promise<ClientUploadData> {\n // Vercel Blob doesn't use pre-signed URLs like S3\n // Instead, it requires using the handleUpload API with @vercel/blob/client\n return Promise.reject(\n new Error(\n \"@nextly/storage-vercel-blob: Client uploads require the handleUpload API.\\n\\n\" +\n \"Vercel Blob uses a different pattern than S3 for client-side uploads:\\n\\n\" +\n \"1. Create a server-side route handler with handleUpload()\\n\" +\n \"2. Use upload() from @vercel/blob/client on the frontend\\n\\n\" +\n \"See: https://vercel.com/docs/storage/vercel-blob/client-upload\"\n )\n );\n },\n\n /**\n * Get signed download URL for file access.\n *\n * Note: Vercel Blob URLs are public by default and do not support\n * signed/temporary URLs. All uploaded blobs are accessible via their\n * public URL.\n *\n * @param path - Storage path (full blob URL)\n * @returns The same URL (Vercel Blob URLs are public)\n */\n getSignedDownloadUrl(path: string): Promise<string> {\n // Vercel Blob URLs are public by default\n // No signed URL support - just return the public URL\n return Promise.resolve(path);\n },\n };\n\n return plugin;\n}\n","/**\n * @nextly/storage-vercel-blob\n *\n * Vercel Blob storage adapter for Nextly CMS.\n * Optimized for Vercel deployments with client-side upload support\n * to bypass serverless function size limits (4.5MB).\n *\n * @example Basic usage\n * ```typescript\n * import { vercelBlobStorage } from '@nextly/storage-vercel-blob'\n * import { defineConfig } from 'nextly/config'\n *\n * export default defineConfig({\n * storage: [\n * vercelBlobStorage({\n * token: process.env.BLOB_READ_WRITE_TOKEN,\n * collections: {\n * media: true\n * }\n * })\n * ]\n * })\n * ```\n *\n * @example With client uploads (recommended for Vercel)\n * ```typescript\n * vercelBlobStorage({\n * collections: {\n * media: {\n * clientUploads: true // Bypass 4.5MB serverless limit\n * }\n * }\n * })\n * ```\n *\n * @packageDocumentation\n */\n\n// ============================================================\n// Vercel Blob Storage Plugin Export (Primary API)\n// ============================================================\n\nexport { vercelBlobStorage } from \"./plugin\";\n\n// ============================================================\n// Vercel Blob Storage Adapter Export\n// ============================================================\n\nexport { VercelBlobStorageAdapter } from \"./adapter\";\n\n// ============================================================\n// Vercel Blob Types Export\n// ============================================================\n\nexport type {\n VercelBlobStorageConfig,\n VercelBlobCollectionConfig,\n VercelBlobCollectionStorageMap,\n ResolvedVercelBlobConfig,\n} from \"./types\";\n\n// ============================================================\n// Package Metadata\n// ============================================================\n\nexport const PACKAGE_NAME = \"@nextly/storage-vercel-blob\";\nexport const PACKAGE_VERSION = \"0.1.0\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["put","del","head","BlobNotFoundError","list"],"sources":["../../nextly/dist/nextly-error-DetCjZnO.mjs","../../nextly/dist/get-trusted-client-ip-CYEbmLA3.mjs","../../nextly/dist/validate-external-url-CfT2WjgH.mjs","../../nextly/dist/storage/read-errors.mjs","../../nextly/dist/storage/fetch-stored-bytes.mjs","../src/adapter.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import { t as __exportAll } from \"./rolldown-runtime-BJohB4LM.mjs\";\n// src/database/errors.ts\nvar DbError = class extends Error {\n\tkind;\n\tdialect;\n\tcode;\n\tmeta;\n\tcause;\n\tconstructor(args) {\n\t\tsuper(args.message);\n\t\tthis.name = \"DbError\";\n\t\tthis.kind = args.kind;\n\t\tthis.dialect = args.dialect;\n\t\tthis.code = args.code;\n\t\tthis.meta = args.meta;\n\t\tthis.cause = args.cause;\n\t}\n};\nfunction isDbError(err) {\n\tif (!err || typeof err !== \"object\") return false;\n\tconst obj = err;\n\treturn obj.name === \"DbError\" && typeof obj.kind === \"string\";\n}\nfunction toDbError(dialect, error, meta) {\n\tif (isDbError(error)) return error;\n\tconst code = safeCode(error);\n\tconst rawMsg = error != null && typeof error === \"object\" && \"message\" in error ? error.message : void 0;\n\tconst message = typeof rawMsg === \"string\" ? rawMsg : \"Database error\";\n\tlet kind = \"internal\";\n\tif (isBusyCode(code)) return new DbError({\n\t\tmessage,\n\t\tkind: \"busy\",\n\t\tdialect,\n\t\tcode,\n\t\tmeta,\n\t\tcause: error\n\t});\n\tswitch (dialect) {\n\t\tcase \"postgresql\":\n\t\t\tkind = mapPostgresCodeToKind(code);\n\t\t\tbreak;\n\t\tcase \"mysql\":\n\t\t\tkind = mapMySqlCodeToKind(code);\n\t\t\tbreak;\n\t\tcase \"sqlite\": kind = mapSqliteCodeToKind(code);\n\t}\n\tif ((dialect === \"mysql\" || dialect === \"sqlite\") && (kind === \"constraint\" || kind === \"internal\") && isLikelyUniqueViolationMessage(dialect, message)) kind = \"unique-violation\";\n\tif (kind === \"internal\" && code) {\n\t\tconst c = code.toUpperCase();\n\t\tif (c === \"ECONNRESET\" || c.includes(\"PROTOCOL_CONNECTION_LOST\")) kind = \"connection-lost\";\n\t\telse if (c === \"ETIMEDOUT\") kind = \"timeout\";\n\t}\n\treturn new DbError({\n\t\tmessage,\n\t\tkind,\n\t\tdialect,\n\t\tcode,\n\t\tmeta,\n\t\tcause: error\n\t});\n}\n/**\n* The driver's own code for an error, wherever that driver puts it.\n*\n* Exported so callers that must distinguish one failure from another classify\n* by the SAME extraction this module's mapping uses. A second reader would go\n* looking in a different set of properties and disagree on exactly the drivers\n* whose codes are hardest to find.\n*/\n/**\n* Whether an error is a duplicate-key rejection.\n*\n* Exposed because a plugin inserting into a table with a unique index has to\n* tell \"this row already exists\" from \"the database is broken\", and the two\n* arrive as the same thrown object. Derived from the existing SQLSTATE\n* classification rather than by matching driver messages: those differ per\n* driver and per version, and a plugin re-deriving it would be a second\n* implementation of a question this module already answers.\n*/\n/**\n* Whether a driver code says the database was busy: the adapters' own code\n* for a request that waited out `pool.connectionTimeoutMs`, the same on\n* every dialect, or SQLITE_BUSY and its extended codes, another process\n* holding the SQLite file past `busyTimeout`. Neither depends on the dialect,\n* which is what lets {@link isDatabaseBusy} answer without one.\n*/\nfunction isBusyCode(code) {\n\tif (code === void 0) return false;\n\treturn code === \"NEXTLY_POOL_WAIT_TIMEOUT\" || code.toUpperCase().startsWith(\"SQLITE_BUSY\");\n}\n/**\n* Whether an error is the database being busy, however it arrives: a DbError\n* of kind \"busy\", or the raw error an adapter or driver threw.\n*\n* For the boundaries that answer a request with whatever its work threw.\n* `withDbErrors` converts only DbErrors, so a raw driver error reaches them\n* unconverted, and without this it would read as an internal fault rather\n* than a request worth retrying.\n*/\nfunction isDatabaseBusy(error) {\n\tif (isDbError(error)) return error.kind === \"busy\";\n\treturn isBusyCode(safeCode(error));\n}\nfunction isUniqueViolation(dialect, error) {\n\treturn toDbError(dialect, error).kind === \"unique-violation\";\n}\nfunction safeCode(error) {\n\tif (!error || typeof error !== \"object\") return void 0;\n\tconst e = error;\n\tlet c = e.code ?? e.sqlState ?? e.state ?? e.errno ?? void 0;\n\tif (!c && typeof e.originalError?.code === \"string\") c = e.originalError.code;\n\tif (!c && typeof e.cause?.code === \"string\") c = e.cause.code;\n\tif (!c && typeof e.severity === \"string\" && typeof e.code === \"string\") c = e.code;\n\tif (typeof c === \"number\") return String(c);\n\tif (typeof c === \"string\" && c.length > 0) return c;\n}\nfunction mapPostgresCodeToKind(code) {\n\tif (!code) return \"internal\";\n\tconst c = code.toUpperCase();\n\tif (c === \"40P01\") return \"deadlock\";\n\tif (c === \"40001\") return \"serialization-failure\";\n\tif (c === \"57014\") return \"timeout\";\n\tif (c === \"23505\") return \"unique-violation\";\n\tif (c === \"23503\") return \"fk-violation\";\n\tif (c === \"23502\") return \"not-null-violation\";\n\tif (c === \"42601\") return \"syntax\";\n\tif (c.startsWith(\"08\") || c === \"57P01\") return \"connection-lost\";\n\tif (c.startsWith(\"23\")) return \"constraint\";\n\treturn \"internal\";\n}\nfunction mapMySqlCodeToKind(code) {\n\tif (!code) return \"internal\";\n\tconst c = code.toUpperCase();\n\tif (c === \"1213\" || c === \"ER_LOCK_DEADLOCK\") return \"deadlock\";\n\tif (c === \"1205\" || c === \"ER_LOCK_WAIT_TIMEOUT\") return \"timeout\";\n\tif (c === \"1062\" || c === \"ER_DUP_ENTRY\") return \"unique-violation\";\n\tif (c === \"23000\") return \"constraint\";\n\tif (c === \"1064\" || c === \"ER_PARSE_ERROR\") return \"syntax\";\n\tif (c === \"1452\" || c === \"ER_NO_REFERENCED_ROW_2\") return \"fk-violation\";\n\tif (c === \"1451\" || c === \"ER_ROW_IS_REFERENCED_2\") return \"fk-violation\";\n\tif (c === \"ECONNRESET\" || c.includes(\"PROTOCOL_CONNECTION_LOST\")) return \"connection-lost\";\n\tif (c === \"ETIMEDOUT\") return \"timeout\";\n\treturn \"internal\";\n}\nfunction mapSqliteCodeToKind(code) {\n\tif (!code) return \"internal\";\n\tconst c = code.toUpperCase();\n\tif (c === \"SQLITE_LOCKED\") return \"deadlock\";\n\tif (c === \"SQLITE_CONSTRAINT_UNIQUE\") return \"unique-violation\";\n\tif (c === \"SQLITE_CONSTRAINT_PRIMARYKEY\") return \"unique-violation\";\n\tif (c === \"SQLITE_CONSTRAINT_FOREIGNKEY\") return \"fk-violation\";\n\tif (c === \"SQLITE_CONSTRAINT_NOTNULL\") return \"not-null-violation\";\n\tif (c === \"SQLITE_INTERRUPT\") return \"timeout\";\n\tif (c === \"SQLITE_ERROR\") return \"syntax\";\n\tif (c.startsWith(\"SQLITE_CONSTRAINT\")) return \"constraint\";\n\treturn \"internal\";\n}\nfunction isLikelyUniqueViolationMessage(dialect, message) {\n\tconst m = message.toLowerCase();\n\tif (dialect === \"mysql\") return m.includes(\"duplicate entry\") || m.includes(\"duplicate key\");\n\tif (dialect === \"sqlite\") return m.includes(\"unique constraint failed\");\n\treturn false;\n}\n// src/errors/error-codes.ts\n/**\n* Canonical NextlyError codes and their HTTP status mappings.\n*\n* Plugin codes outside this enum must always pass an explicit `statusCode`\n* to the NextlyError constructor (no enum lookup happens for unknown codes).\n*/\nconst NEXTLY_ERROR_STATUS = {\n\tVALIDATION_ERROR: 400,\n\tINVALID_INPUT: 400,\n\tAUTH_REQUIRED: 401,\n\tAUTH_INVALID_CREDENTIALS: 401,\n\tTOKEN_EXPIRED: 401,\n\tFORBIDDEN: 403,\n\tEMAIL_NOT_VERIFIED: 403,\n\tBUILDER_DISABLED: 403,\n\tCSRF_FAILED: 403,\n\tSETUP_TOKEN_REQUIRED: 403,\n\tAPI_KEY_ROLE_ABOVE_CREATOR: 403,\n\tNOT_FOUND: 404,\n\tMETHOD_NOT_ALLOWED: 405,\n\tRANGE_NOT_SATISFIABLE: 416,\n\tCONFLICT: 409,\n\tDUPLICATE: 409,\n\tRATE_LIMITED: 429,\n\tPAYLOAD_TOO_LARGE: 413,\n\tUNSUPPORTED_MEDIA_TYPE: 415,\n\tBUSINESS_RULE_VIOLATION: 422,\n\tINTERNAL_ERROR: 500,\n\tDATABASE_ERROR: 500,\n\tDATABASE_BUSY: 503,\n\tEXTERNAL_SERVICE_ERROR: 502,\n\tSERVICE_UNAVAILABLE: 503,\n\tEXTERNAL_URL_BLOCKED: 400,\n\tEXTERNAL_REQUEST_FAILED: 502,\n\tFILENAME_INVALID: 400,\n\tEXTENSION_BLOCKED: 400,\n\tMIME_BLOCKED: 415,\n\tMIME_NOT_ALLOWED: 415,\n\tSIZE_EXCEEDED: 413,\n\tSTORAGE_READ_TOO_LARGE: 413,\n\tSTORAGE_READ_TIMEOUT: 504,\n\tSTORAGE_READ_UNREACHABLE: 502,\n\tMAGIC_BYTE_MISMATCH: 400,\n\tSVG_SANITIZATION_FAILED: 400,\n\tUNSUPPORTED_FOR_BACKEND: 415,\n\tNEXTLY_LEGACY_BOOKKEEPING_DETECTED: 409,\n\tNEXTLY_UPGRADE_TABLE_NAME_COLLISION: 409,\n\tNEXTLY_UPGRADE_IN_PROGRESS: 409,\n\tNEXTLY_MIGRATE_LOCK_BUSY: 409,\n\tNEXTLY_BASELINE_LOCK_NOT_HELD: 409,\n\tNEXTLY_RESOLVE_LOCK_NOT_HELD: 409,\n\tNEXTLY_BOOT_MIGRATIONS_NOT_RUN: 503,\n\tNEXTLY_BOOT_MIGRATIONS_PENDING: 503,\n\tNEXTLY_CORE_DESTRUCTIVE_REFUSED: 409,\n\tNEXTLY_MIGRATION_DRIFT: 409,\n\tNEXTLY_MIGRATION_APPLY_FAILED: 500,\n\tNEXTLY_MIGRATION_FOREIGN_KEY_VIOLATION: 409,\n\tNEXTLY_MIGRATION_PARTIALLY_APPLIED: 500,\n\tNEXTLY_MIGRATION_CONCURRENT_RUN: 409,\n\tNEXTLY_MIGRATION_FILE_MISSING: 404,\n\tNEXTLY_MIGRATION_SNAPSHOT_MISSING: 404,\n\tNEXTLY_MIGRATION_RESOLVE_DRIFT: 409,\n\tNEXTLY_MIGRATION_RESOLVE_PRECONDITION: 409,\n\tNEXTLY_UI_SCHEMA_INVALID: 400,\n\tNEXTLY_SCHEMA_SLUG_COLLISION: 409,\n\tNEXTLY_SCHEMA_RELATION_TARGET_MISSING: 400,\n\tNEXTLY_SCHEMA_RELATION_UNRESOLVED: 400,\n\tNEXTLY_SCHEMA_EXTEND_TARGET_UNKNOWN: 400,\n\tNEXTLY_SCHEMA_EXTEND_FIELD_DUPLICATE: 409,\n\tNEXTLY_SCHEMA_CROSS_PLUGIN_RELATION: 409,\n\tNEXTLY_SCHEMA_RENAME_UNKNOWN_TARGET: 400,\n\tNEXTLY_PLUGIN_CLIENT_CONFIG_INVALID: 500,\n\tNEXTLY_PLUGIN_ADMIN_WIDGET_INVALID: 500,\n\tNEXTLY_ADMIN_COMPONENT_MAP_STALE: 500,\n\tNEXTLY_PLUGIN_DOCUMENT_VIEW_INVALID: 500,\n\tPLUGIN_RESOLUTION_ERROR: 500,\n\tPLUGIN_DEPENDENCY_NOT_INSTALLED: 409,\n\tPLUGIN_HAS_DEPENDENTS: 409,\n\tPLUGIN_UNINSTALL_IRREVERSIBLE: 409,\n\tPLUGIN_UNINSTALL_UNCONFIRMED: 409,\n\tPLUGIN_SCHEMA_BEHIND: 409,\n\tPLUGIN_SCHEMA_UNINSTALLED: 409,\n\tPLUGIN_NOT_INSTALLED: 409,\n\tPLUGIN_DISABLED: 409,\n\tPLUGIN_UNINSTALL_UNFINISHED: 409,\n\tPLUGIN_SCHEMA_VERSION_NOT_ADVANCED: 409,\n\tPLUGIN_MIGRATION_DROPS_CREATED_SCHEMA: 409,\n\tPLUGIN_MIGRATION_ADDS_UNFILLABLE_COLUMN: 409,\n\tPLUGIN_MIGRATION_SQL_MISSING: 409,\n\tPLUGIN_MIGRATIONS_UNAVAILABLE: 409,\n\tDROP_OF_FOREIGN_TABLE: 409,\n\tMIGRATION_CHECKSUM_MISMATCH: 409,\n\tPLUGIN_MIGRATIONS_OUT_OF_ORDER: 409,\n\tPLUGIN_MIGRATION_HISTORY_CHANGED: 409,\n\tNEXTLY_ROUTE_COLLISION: 409,\n\tNEXTLY_ROUTE_INVALID_PATH: 400,\n\tNEXTLY_ROUTE_UNREACHABLE_ROOT: 400,\n\tNEXTLY_ROUTE_INVALID_MOUNT: 400,\n\tNEXTLY_EMAIL_TRANSPORT_UNAVAILABLE: 503,\n\tNEXTLY_CONFIG_TOOLING_UNAVAILABLE: 503,\n\tNEXTLY_POSTGRES_SCHEMA_MISMATCH: 500,\n\tNEXTLY_POSTGRES_SCHEMA_UNSUPPORTED: 500\n};\n/**\n* The codes that REPRESENT their status, when a failure names none.\n*\n* A service that returns `{ success: false, statusCode }` without a code leaves\n* every boundary to infer one, and three boundaries inferring separately is how\n* the same 401 became `AUTH_REQUIRED` through the Direct API and\n* `INTERNAL_ERROR` through the REST dispatcher. This list is the ONE inference,\n* so they cannot disagree.\n*\n* Listed as CODES, not as status numbers: the number for each comes from\n* {@link NEXTLY_ERROR_STATUS} below, so a code whose canonical status changes\n* carries its inference with it instead of leaving a stale literal here.\n*\n* Several codes share a status -- 409 is both `CONFLICT` and `DUPLICATE`, 400\n* is both `VALIDATION_ERROR` and `INVALID_INPUT` -- so this is a choice, not a\n* mechanical inversion. Each entry is the reading that is still safe if the\n* other was meant: `CONFLICT` says \"reload\", which is unhelpful for a name\n* clash, while `DUPLICATE` would say \"already exists\", which is WRONG for a\n* stale write. A producer that knows which it means sets `code` and is\n* believed, and this list is never consulted for it.\n*/\nconst CANONICAL_CODE_FOR_STATUS = [\n\t\"VALIDATION_ERROR\",\n\t\"AUTH_REQUIRED\",\n\t\"FORBIDDEN\",\n\t\"NOT_FOUND\",\n\t\"CONFLICT\",\n\t\"PAYLOAD_TOO_LARGE\",\n\t\"UNSUPPORTED_MEDIA_TYPE\",\n\t\"RATE_LIMITED\",\n\t\"EXTERNAL_SERVICE_ERROR\",\n\t\"SERVICE_UNAVAILABLE\"\n];\n/**\n* 422, which no canonical code claims.\n*\n* `INVALID_INPUT` answers 400 in this system, so it cannot supply this key the\n* way the codes above supply theirs. Legacy envelopes nonetheless use 422 for\n* \"understood but unprocessable\", and reading it as an internal error would\n* report the caller's own mistake as a server fault. Named rather than inlined\n* so it is visibly the one entry that is NOT derived.\n*/\nconst LEGACY_UNPROCESSABLE_STATUS = 422;\nconst STATUS_TO_CODE = {\n\t...Object.fromEntries(CANONICAL_CODE_FOR_STATUS.map((code) => [NEXTLY_ERROR_STATUS[code], code])),\n\t[LEGACY_UNPROCESSABLE_STATUS]: \"INVALID_INPUT\"\n};\n/**\n* The canonical code for a status, for a failure that named none.\n*\n* Anything outside the table is an internal error: an unrecognised status from\n* a legacy envelope says nothing a caller can act on, and inventing a specific\n* code for it would assert a meaning no producer expressed.\n*/\nfunction statusToErrorCode(statusCode) {\n\treturn STATUS_TO_CODE[statusCode] ?? \"INTERNAL_ERROR\";\n}\n/**\n* The sentence a caller reads for a code, when the failure supplied none.\n*\n* Kept beside the status table because they answer the same question together:\n* a code-less envelope's own `message` is NOT usable here. Those envelopes come\n* from legacy converters that store a raw exception's text, so promoting it\n* would put driver output, table names and internal paths on the wire -- the\n* disclosure the public error shape exists to prevent (spec 13.8).\n*\n* Every entry is generic by design. The specific detail stays in `logContext`\n* for the operator, against the same request id.\n*/\nconst GENERIC_PUBLIC_MESSAGE = {\n\tVALIDATION_ERROR: \"Validation failed.\",\n\tINVALID_INPUT: \"The request could not be processed.\",\n\tAUTH_REQUIRED: \"Authentication required.\",\n\tFORBIDDEN: \"You don't have permission to perform this action.\",\n\tNOT_FOUND: \"Not found.\",\n\tMETHOD_NOT_ALLOWED: \"That method is not allowed on this address.\",\n\tRANGE_NOT_SATISFIABLE: \"The requested range is outside the file.\",\n\tCONFLICT: \"The resource has changed since you last loaded it. Please refresh and try again.\",\n\tDUPLICATE: \"Resource already exists.\",\n\tPAYLOAD_TOO_LARGE: \"The request is too large.\",\n\tUNSUPPORTED_MEDIA_TYPE: \"That file type is not supported.\",\n\tRATE_LIMITED: \"Too many requests. Please try again later.\",\n\tEXTERNAL_SERVICE_ERROR: \"An upstream service failed.\",\n\tSERVICE_UNAVAILABLE: \"The service is temporarily unavailable.\",\n\tDATABASE_BUSY: \"The database is busy. Please try again shortly.\",\n\tINTERNAL_ERROR: \"An unexpected error occurred.\"\n};\n/** The generic sentence for a code; the internal one for anything unlisted. */\nfunction genericPublicMessage(code) {\n\treturn GENERIC_PUBLIC_MESSAGE[code] ?? GENERIC_PUBLIC_MESSAGE.INTERNAL_ERROR;\n}\n// src/errors/retry-after.ts\n/**\n* The seconds an error asks its caller to wait before retrying, or\n* `undefined` when it carries no retry hint.\n*\n* Read from the error's public data rather than from its code, so every error\n* that carries a hint is answered with the header, and a code that comes to\n* carry one needs no change here.\n*/\nfunction retryAfterSeconds(error) {\n\tconst data = error.publicData;\n\tif (data && typeof data === \"object\" && \"retryAfterSeconds\" in data && typeof data.retryAfterSeconds === \"number\") return data.retryAfterSeconds;\n}\n/**\n* The Retry-After header for an error: none when it carries no retry hint.\n* Spread into a response's headers by every builder that answers one.\n*/\nfunction retryAfterHeader(error) {\n\tconst seconds = retryAfterSeconds(error);\n\treturn seconds === void 0 ? {} : { \"retry-after\": String(seconds) };\n}\n// src/errors/nextly-error.ts\nvar nextly_error_exports = /* @__PURE__ */ __exportAll({ NextlyError: () => NextlyError });\n/**\n* Default mapping from DbErrorKind to NextlyError contract. Used by\n* `NextlyError.fromDatabaseError`. Public messages are intentionally generic\n* per spec §13.8 — no DB driver text, no constraint names, no field hints.\n*\n* `satisfies Record<DbErrorKind, ...>` makes the mapping exhaustive at\n* compile time: adding a new DbErrorKind without updating this table is a\n* type error.\n*/\nconst DB_ERROR_MAPPING = {\n\t\"unique-violation\": {\n\t\tcode: \"DUPLICATE\",\n\t\tstatusCode: 409,\n\t\tpublicMessage: \"Resource already exists.\"\n\t},\n\t\"fk-violation\": {\n\t\tcode: \"VALIDATION_ERROR\",\n\t\tstatusCode: 400,\n\t\tpublicMessage: \"Referenced record does not exist.\"\n\t},\n\t\"not-null-violation\": {\n\t\tcode: \"VALIDATION_ERROR\",\n\t\tstatusCode: 400,\n\t\tpublicMessage: \"A required field is missing.\"\n\t},\n\tconstraint: {\n\t\tcode: \"VALIDATION_ERROR\",\n\t\tstatusCode: 400,\n\t\tpublicMessage: \"The provided data violates a constraint.\"\n\t},\n\tdeadlock: {\n\t\tcode: \"CONFLICT\",\n\t\tstatusCode: 409,\n\t\tpublicMessage: \"The operation could not be completed. Please retry.\"\n\t},\n\t\"serialization-failure\": {\n\t\tcode: \"CONFLICT\",\n\t\tstatusCode: 409,\n\t\tpublicMessage: \"The operation could not be completed. Please retry.\"\n\t},\n\tbusy: {\n\t\tcode: \"DATABASE_BUSY\",\n\t\tstatusCode: NEXTLY_ERROR_STATUS.DATABASE_BUSY,\n\t\tpublicMessage: genericPublicMessage(\"DATABASE_BUSY\"),\n\t\tpublicData: { retryAfterSeconds: 5 }\n\t},\n\ttimeout: {\n\t\tcode: \"DATABASE_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"The operation timed out. Please try again.\"\n\t},\n\t\"connection-lost\": {\n\t\tcode: \"DATABASE_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"A temporary database error occurred. Please try again.\"\n\t},\n\tsyntax: {\n\t\tcode: \"INTERNAL_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"An unexpected error occurred.\"\n\t},\n\tinternal: {\n\t\tcode: \"INTERNAL_ERROR\",\n\t\tstatusCode: 500,\n\t\tpublicMessage: \"An unexpected error occurred.\"\n\t}\n};\nconst NEXTLY_ERROR_BRAND = Symbol.for(\"nextly/NextlyError\");\nfunction hasBrand(value) {\n\tif (value === null || typeof value !== \"object\" && typeof value !== \"function\") return false;\n\treturn value[NEXTLY_ERROR_BRAND] === true;\n}\n/**\n* Unified error class for Nextly. Used at every throw site across services,\n* direct API, auth, and plugins. Carries two distinct payloads:\n*\n* - Public (`code`, `publicMessage`, `publicData`, `statusCode`, `messageKey`)\n* sent in HTTP responses and Server Action results.\n* - Log (`logMessage`, `logContext`, `cause`, stack trace)\n* written to the server logger; never serialised to the wire.\n*\n* Use the static factories (notFound, forbidden, validation, ...) for the\n* common cases. Use the free-form constructor for plugin codes or one-off\n* shapes.\n*/\nvar NextlyError = class NextlyError extends Error {\n\tcode;\n\tstatusCode;\n\tpublicMessage;\n\tpublicData;\n\tmessageKey;\n\tlogMessage;\n\tlogContext;\n\tcause;\n\ttimestamp;\n\tconstructor(opts) {\n\t\tsuper(opts.publicMessage);\n\t\tthis.name = \"NextlyError\";\n\t\tthis.code = opts.code;\n\t\tthis.publicMessage = opts.publicMessage;\n\t\tthis.publicData = opts.publicData;\n\t\tthis.messageKey = opts.messageKey;\n\t\tthis.logMessage = opts.logMessage;\n\t\tthis.logContext = opts.logContext;\n\t\tthis.cause = opts.cause;\n\t\tthis.timestamp = /* @__PURE__ */ new Date();\n\t\tthis.statusCode = NextlyError.resolveStatusCode(opts);\n\t\tError.captureStackTrace?.(this, NextlyError);\n\t}\n\tstatic {\n\t\tNextlyError.prototype[NEXTLY_ERROR_BRAND] = true;\n\t}\n\tstatic resolveStatusCode(opts) {\n\t\tif (typeof opts.statusCode === \"number\") return opts.statusCode;\n\t\tif (opts.code in NEXTLY_ERROR_STATUS) return NEXTLY_ERROR_STATUS[opts.code];\n\t\treturn 500;\n\t}\n\t/** HTTP-safe JSON. Strips logMessage / logContext / cause / stack. */\n\ttoResponseJSON(requestId) {\n\t\tconst json = {\n\t\t\tcode: String(this.code),\n\t\t\tmessage: this.publicMessage,\n\t\t\trequestId\n\t\t};\n\t\tif (this.messageKey) json.messageKey = this.messageKey;\n\t\tif (this.publicData !== void 0) json.data = this.publicData;\n\t\treturn json;\n\t}\n\t/** Operator-facing JSON for log lines. Includes everything. */\n\ttoLogJSON(requestId) {\n\t\treturn {\n\t\t\tcode: this.code,\n\t\t\tstatusCode: this.statusCode,\n\t\t\tpublicMessage: this.publicMessage,\n\t\t\tmessageKey: this.messageKey,\n\t\t\tlogMessage: this.logMessage,\n\t\t\tlogContext: this.logContext,\n\t\t\tcause: this.cause ? {\n\t\t\t\tname: this.cause.name,\n\t\t\t\tmessage: this.cause.message,\n\t\t\t\tstack: this.cause.stack\n\t\t\t} : void 0,\n\t\t\ttimestamp: this.timestamp.toISOString(),\n\t\t\trequestId\n\t\t};\n\t}\n\tstatic invalidCredentials(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"AUTH_INVALID_CREDENTIALS\",\n\t\t\tpublicMessage: \"Invalid email or password.\",\n\t\t\tlogMessage: \"Login failed\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* The password was correct and the address is unverified. Thrown only once\n\t* the password is proven, so only someone who holds it learns the address\n\t* is unverified; every other refusal stays\n\t* {@link NextlyError.invalidCredentials}.\n\t*/\n\tstatic emailNotVerified(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"EMAIL_NOT_VERIFIED\",\n\t\t\tpublicMessage: \"Verify your email address to sign in. Check your inbox for the link.\",\n\t\t\tlogMessage: \"Login refused: email not verified\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic authRequired(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"AUTH_REQUIRED\",\n\t\t\tpublicMessage: \"Authentication required.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* Distinct from `authRequired`: the caller was authenticated but the\n\t* session token expired. Clients key on the TOKEN_EXPIRED *code* to\n\t* silently refresh and retry rather than redirecting to login; the public\n\t* message stays the generic spec §13.6 string (\"Authentication required.\")\n\t* so the wire never reveals the session state — same as `authRequired`.\n\t*/\n\tstatic tokenExpired(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"TOKEN_EXPIRED\",\n\t\t\tpublicMessage: \"Authentication required.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic notFound(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"NOT_FOUND\",\n\t\t\tpublicMessage: opts?.message ?? \"Not found.\",\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic forbidden(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: \"You don't have permission to perform this action.\",\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* Something only a signed-in person can do, asked by a caller that is not\n\t* one: an API key, or a request acting as no person. Forbidden, and the\n\t* message says so, since it is about what kind of caller asked, not about\n\t* the caller's permissions. `doing` completes \"Only a signed-in person can\".\n\t*/\n\tstatic personOnly(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: `Only a signed-in person can ${opts.doing}.`,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\t/**\n\t* A role or permission built into Nextly, which is never changed or\n\t* deleted. Forbidden, and the message says so: it is a fact about the role,\n\t* not about the caller's permissions.\n\t*/\n\tstatic builtIn(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: `This ${opts.thing} is built in, so it can't be ${opts.change === \"change\" ? \"changed\" : \"deleted\"}.`,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\t/**\n\t* A request from a site not allowed to make it: its own `Origin` names a\n\t* site the installation does not allow. Forbidden, and the message says so;\n\t* the origin is the caller's own, so naming its kind tells them nothing.\n\t*/\n\tstatic originRefused(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: \"This request came from a site that isn't allowed to make it.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A Single deleted without `force`: Singles hold a site's lasting settings,\n\t* so they are not deleted from here, only by an admin or CLI clean-up that\n\t* passes `force`. Forbidden, and the message says so.\n\t*/\n\tstatic singleNotDeletable(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: \"A Single can't be deleted from here.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A collection, Single or component defined in code, which is changed by\n\t* changing its code and not from here. Forbidden, and the message says so:\n\t* it is a fact about the thing, not about the caller's permissions, so it\n\t* names no permission and no policy. The lock's detail goes to the log\n\t* through `logContext`.\n\t*/\n\tstatic definedInCode(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: `This ${opts.thing} is defined in code, so it can't be ${opts.change === \"change\" ? \"changed\" : \"deleted\"} here.`,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\t/**\n\t* An autosave where the collection or Single does not autosave: its owner\n\t* switched autosave off, or it keeps no drafts to autosave into. Forbidden,\n\t* and the message says so, since it is a setting and not a permission.\n\t*/\n\tstatic autosaveOff(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"FORBIDDEN\",\n\t\t\tpublicMessage: `Autosave is turned off for this ${opts.scopeKind === \"single\" ? \"Single\" : \"collection\"}.`,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\t/**\n\t* An API key refused because its role allows more than the person creating\n\t* it may do. The sentence is FORBIDDEN's and names no permission; which one\n\t* exceeded goes to the log through `logContext`. The code is its own, so a\n\t* client can tell \"choose a smaller role\" from plain FORBIDDEN.\n\t*/\n\tstatic apiKeyRoleAboveCreator(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"API_KEY_ROLE_ABOVE_CREATOR\",\n\t\t\tpublicMessage: genericPublicMessage(\"FORBIDDEN\"),\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A cookie-authenticated write refused because its origin or CSRF token did\n\t* not check out. The public message names no detail of which check failed;\n\t* that goes to the log through `logMessage`.\n\t*/\n\tstatic csrfFailed(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"CSRF_FAILED\",\n\t\t\tpublicMessage: \"This request could not be verified. Reload the page and try again.\",\n\t\t\tlogMessage: opts?.logMessage,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A call the caller got wrong, where naming the mistake IS the value of the\n\t* error.\n\t*\n\t* The only factory that takes its public message from the caller. The\n\t* generic messages elsewhere exist so an HTTP response cannot leak internal\n\t* detail; this one is for arguments and configuration a developer controls\n\t* and must be told about — a missing option, an unusable combination — where\n\t* `internal()` would reduce the one useful sentence to \"An unexpected error\n\t* occurred.\" Do not pass user-supplied data through it.\n\t*/\n\tstatic invalidInput(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"INVALID_INPUT\",\n\t\t\tpublicMessage: opts.message,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\tstatic validation(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\tpublicMessage: \"Validation failed.\",\n\t\t\tpublicData: { errors: opts.errors },\n\t\t\tcause: opts.cause,\n\t\t\tlogContext: opts.logContext\n\t\t});\n\t}\n\tstatic conflict(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"CONFLICT\",\n\t\t\tpublicMessage: opts?.message ?? \"The resource has changed since you last loaded it. Please refresh and try again.\",\n\t\t\tpublicData: opts?.data,\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: {\n\t\t\t\treason: opts?.reason,\n\t\t\t\t...opts?.logContext\n\t\t\t}\n\t\t});\n\t}\n\tstatic duplicate(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"DUPLICATE\",\n\t\t\tpublicMessage: \"Resource already exists.\",\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic rateLimited(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"RATE_LIMITED\",\n\t\t\tpublicMessage: \"Too many requests. Please try again later.\",\n\t\t\tpublicData: opts?.retryAfterSeconds !== void 0 ? { retryAfterSeconds: opts.retryAfterSeconds } : void 0,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* A request that waited `pool.connectionTimeoutMs` for a database\n\t* connection and was given none. The statement or transaction that waited\n\t* never ran; work committed before it stays committed. The same error\n\t* `fromDatabaseError` gives a busy DbError, from the same table row.\n\t*/\n\tstatic databaseBusy(opts) {\n\t\tconst busy = DB_ERROR_MAPPING.busy;\n\t\treturn new NextlyError({\n\t\t\tcode: busy.code,\n\t\t\tstatusCode: busy.statusCode,\n\t\t\tpublicMessage: busy.publicMessage,\n\t\t\tpublicData: busy.publicData,\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* What a request boundary answers with for a thrown value that is not a\n\t* NextlyError: \"database busy\" when the request waited out its bound for a\n\t* connection, which is retryable and no fault of the server's code, and an\n\t* internal error for anything else.\n\t*\n\t* The busy case has to be read here because it usually arrives raw:\n\t* `withDbErrors` converts only DbErrors, so a driver's error passes through\n\t* services unconverted to the boundary that answers the request.\n\t*/\n\tstatic fromUnexpected(error) {\n\t\treturn NextlyError.busyOr(error, () => NextlyError.internal({ cause: error instanceof Error ? error : void 0 }));\n\t}\n\t/**\n\t* \"Database busy\" when `error` is a request that waited out its bound for\n\t* a connection, and `otherwise()` for anything else.\n\t*\n\t* For a boundary that answers an unexpected failure with an error of its\n\t* own choosing rather than an internal one (a 503 for a flow that must not\n\t* answer on incomplete data), so that a busy database still answers there\n\t* as it does everywhere else. `fromUnexpected` is this rule with the\n\t* internal error as its fallback.\n\t*/\n\tstatic busyOr(error, otherwise) {\n\t\tif (!isDatabaseBusy(error)) return otherwise();\n\t\treturn NextlyError.databaseBusy({ cause: error instanceof Error ? error : void 0 });\n\t}\n\tstatic internal(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"INTERNAL_ERROR\",\n\t\t\tpublicMessage: \"An unexpected error occurred.\",\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\tstatic serviceUnavailable(opts) {\n\t\treturn new NextlyError({\n\t\t\tcode: \"SERVICE_UNAVAILABLE\",\n\t\t\tpublicMessage: opts?.publicMessage ?? \"Service unavailable. Please try again later.\",\n\t\t\tlogMessage: opts?.logMessage,\n\t\t\tcause: opts?.cause,\n\t\t\tlogContext: opts?.logContext\n\t\t});\n\t}\n\t/**\n\t* Convert a DbError (or arbitrary unknown thrown by the DB layer) to a\n\t* NextlyError with a generic public message and rich logContext. Used by\n\t* `withDbErrors` for auto-conversion (Pattern A) and by services that\n\t* catch DB errors at boundaries (Pattern B). Spec §8.2 mapping table.\n\t*\n\t* Never leaks DB driver text, constraint names, or table names into\n\t* `publicMessage`. All DB context goes into `logContext`. The original\n\t* DbError is preserved as `cause`.\n\t*/\n\tstatic fromDatabaseError(error) {\n\t\tif (isDbError(error)) {\n\t\t\tconst mapping = DB_ERROR_MAPPING[error.kind];\n\t\t\tconst logContext = {\n\t\t\t\tdbKind: error.kind,\n\t\t\t\tdialect: error.dialect\n\t\t\t};\n\t\t\tif (error.code !== void 0) logContext.dbCode = error.code;\n\t\t\tif (error.meta !== void 0) logContext.meta = error.meta;\n\t\t\treturn new NextlyError({\n\t\t\t\tcode: mapping.code,\n\t\t\t\tstatusCode: mapping.statusCode,\n\t\t\t\tpublicMessage: mapping.publicMessage,\n\t\t\t\tpublicData: \"publicData\" in mapping ? mapping.publicData : void 0,\n\t\t\t\tlogMessage: \"Database error\",\n\t\t\t\tlogContext,\n\t\t\t\tcause: error\n\t\t\t});\n\t\t}\n\t\treturn new NextlyError({\n\t\t\tcode: \"INTERNAL_ERROR\",\n\t\t\tstatusCode: 500,\n\t\t\tpublicMessage: \"An unexpected error occurred.\",\n\t\t\tlogMessage: \"Non-DbError passed to fromDatabaseError\",\n\t\t\tcause: error instanceof Error ? error : void 0,\n\t\t\tlogContext: error instanceof Error ? void 0 : { value: String(error) }\n\t\t});\n\t}\n\tstatic is(err) {\n\t\treturn hasBrand(err);\n\t}\n\tstatic isCode(err, code) {\n\t\treturn hasBrand(err) && err.code === code;\n\t}\n\tstatic isNotFound(err) {\n\t\treturn NextlyError.isCode(err, \"NOT_FOUND\");\n\t}\n\tstatic isValidation(err) {\n\t\treturn NextlyError.isCode(err, \"VALIDATION_ERROR\");\n\t}\n\tstatic isAuthRequired(err) {\n\t\treturn NextlyError.isCode(err, \"AUTH_REQUIRED\");\n\t}\n\tstatic isForbidden(err) {\n\t\treturn NextlyError.isCode(err, \"FORBIDDEN\");\n\t}\n\tstatic isConflict(err) {\n\t\treturn NextlyError.isCode(err, \"CONFLICT\");\n\t}\n\tstatic isRateLimited(err) {\n\t\treturn NextlyError.isCode(err, \"RATE_LIMITED\");\n\t}\n};\nexport { NEXTLY_ERROR_STATUS as a, DbError as c, isUniqueViolation as d, safeCode as f, retryAfterSeconds as i, isDatabaseBusy as l, nextly_error_exports as n, genericPublicMessage as o, toDbError as p, retryAfterHeader as r, statusToErrorCode as s, NextlyError as t, isDbError as u };\n","import { t as __exportAll } from \"./rolldown-runtime-BJohB4LM.mjs\";\n// src/utils/get-trusted-client-ip.ts\nvar get_trusted_client_ip_exports = /* @__PURE__ */ __exportAll({\n\tCLIENT_IP_HEADERS: () => CLIENT_IP_HEADERS,\n\tcarriesClientIpHeader: () => carriesClientIpHeader,\n\tgetTrustedClientIp: () => getTrustedClientIp,\n\tipv4ToInt: () => ipv4ToInt,\n\tparseTrustedProxyIpsEnv: () => parseTrustedProxyIpsEnv\n});\n/**\n* Trusted client-IP resolution for Web `Request` objects.\n*\n* The previous `getClientIp` helpers parsed\n* `X-Forwarded-For` unconditionally and returned the *leftmost* hop —\n* which a direct attacker can forge to defeat per-IP rate limits,\n* brute-force lockouts, and refresh-token IP binding.\n*\n* This helper applies the standard \"rightmost-untrusted-hop\" algorithm:\n*\n* - When `trustProxy` is `false` (default), proxy headers are\n* ignored entirely. Returns `null` because Web `Request` does not\n* expose the immediate-peer IP.\n*\n* - When `trustProxy` is `true`, walk `X-Forwarded-For` from the\n* rightmost hop, skipping any value that matches `trustedProxyIps`\n* (CIDR list). Return the first hop that is not in the trust list\n* — that is the closest *untrusted* IP in the chain, i.e. the real\n* client (or the closest claim of one).\n*\n* If no `X-Forwarded-For` is present, fall back to `cf-connecting-ip`\n* (Cloudflare) and `x-real-ip` (Nginx convention).\n*\n* If every hop in the chain is in the trust list, return `null`\n* rather than picking a trusted proxy as \"the client\".\n*\n* Implementation note: this module deliberately avoids `node:net` so\n* downstream packages that bundle for the browser (e.g. `@nextlyhq/admin`)\n* don't fail at build time. IP-family classification is done with\n* regex.\n*\n* @module utils/get-trusted-client-ip\n*/\nconst IPV4_RE = /^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/;\nconst IPV6_CHAR_RE = /^[0-9a-fA-F:.]+$/;\n/** Returns 4 / 6 / 0 (mirrors `net.isIP()` without the Node import). */\nfunction classifyIp(addr) {\n\tif (IPV4_RE.test(addr)) return 4;\n\tif (addr.includes(\":\") && IPV6_CHAR_RE.test(addr) && addr.length <= 45) return 6;\n\treturn 0;\n}\n/**\n* The headers a proxy names the client address in, and the only ones\n* {@link getTrustedClientIp} reads. Exported so a check for \"did this request\n* come through a proxy?\" asks about exactly the headers resolution would use.\n*/\nconst CLIENT_IP_HEADERS = [\n\t\"x-forwarded-for\",\n\t\"cf-connecting-ip\",\n\t\"x-real-ip\"\n];\n/** Whether `request` carries any header a proxy names the client in. */\nfunction carriesClientIpHeader(request) {\n\treturn CLIENT_IP_HEADERS.some((name) => request.headers.has(name));\n}\n/**\n* Resolve the client IP for a Web `Request`, applying the trust-proxy\n* gate described above. Returns `null` when no trusted IP can be\n* identified — callers should treat that as \"unknown\" rather than\n* picking a fallback like `127.0.0.1` (which would collapse all\n* unknown clients into one rate-limit bucket).\n*/\nfunction getTrustedClientIp(request, options) {\n\tif (!options.trustProxy) return null;\n\tconst trustedCidrs = (options.trustedProxyIps ?? []).map(parseCidr).filter((c) => c !== null);\n\tconst xff = request.headers.get(CLIENT_IP_HEADERS[0]);\n\tif (xff) {\n\t\tconst hops = xff.split(\",\").map((h) => h.trim()).filter(Boolean);\n\t\tfor (let i = hops.length - 1; i >= 0; i--) {\n\t\t\tconst hop = stripIpv6Brackets(hops[i]);\n\t\t\tif (!classifyIp(hop)) continue;\n\t\t\tif (!isIpInAnyCidr(hop, trustedCidrs)) return hop;\n\t\t}\n\t\treturn null;\n\t}\n\tconst cfIp = request.headers.get(CLIENT_IP_HEADERS[1])?.trim();\n\tif (cfIp && classifyIp(cfIp)) return cfIp;\n\tconst realIp = request.headers.get(CLIENT_IP_HEADERS[2])?.trim();\n\tif (realIp && classifyIp(realIp)) return realIp;\n\treturn null;\n}\n/**\n* Parse `TRUSTED_PROXY_IPS` env-var format: comma-separated CIDR list\n* with optional whitespace. Empty / unset → empty array.\n*/\nfunction parseTrustedProxyIpsEnv(raw) {\n\tif (!raw) return [];\n\treturn raw.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\nfunction stripIpv6Brackets(ip) {\n\treturn ip.startsWith(\"[\") && ip.endsWith(\"]\") ? ip.slice(1, -1) : ip;\n}\nfunction parseCidr(entry) {\n\tconst [addr, prefixRaw] = entry.split(\"/\");\n\tconst stripped = stripIpv6Brackets(addr);\n\tconst family = classifyIp(stripped);\n\tif (family === 4) {\n\t\tconst prefix = prefixRaw === void 0 ? 32 : Number(prefixRaw);\n\t\tif (!Number.isInteger(prefix) || prefix < 0 || prefix > 32) return null;\n\t\tconst intAddr = ipv4ToInt(stripped);\n\t\tif (intAddr === null) return null;\n\t\treturn {\n\t\t\tfamily: \"ipv4\",\n\t\t\tnetwork: intAddr & (prefix === 0 ? 0 : -1 >>> 32 - prefix << 32 - prefix),\n\t\t\tprefix\n\t\t};\n\t}\n\tif (family === 6) {\n\t\tif (prefixRaw !== void 0 && prefixRaw !== \"128\") return null;\n\t\treturn {\n\t\t\tfamily: \"ipv6\",\n\t\t\tnetwork: stripped.toLowerCase(),\n\t\t\tprefix: 128\n\t\t};\n\t}\n\treturn null;\n}\n/**\n* A dotted-quad IPv4 address as an unsigned 32-bit integer, or null when it is\n* not one. Shared by the client-address, refresh-binding and outbound-URL\n* prefix checks.\n*/\nfunction ipv4ToInt(ip) {\n\tconst parts = ip.split(\".\");\n\tif (parts.length !== 4) return null;\n\tlet acc = 0;\n\tfor (const p of parts) {\n\t\tconst n = Number(p);\n\t\tif (!Number.isInteger(n) || n < 0 || n > 255) return null;\n\t\tacc = acc << 8 | n;\n\t}\n\treturn acc >>> 0;\n}\nfunction isIpInAnyCidr(ip, cidrs) {\n\tif (cidrs.length === 0) return false;\n\tconst family = classifyIp(ip);\n\tif (family === 4) {\n\t\tconst intIp = ipv4ToInt(ip);\n\t\tif (intIp === null) return false;\n\t\tfor (const c of cidrs) {\n\t\t\tif (c.family !== \"ipv4\") continue;\n\t\t\tconst mask = c.prefix === 0 ? 0 : -1 >>> 32 - c.prefix << 32 - c.prefix;\n\t\t\tif ((intIp & mask) >>> 0 === (c.network & mask) >>> 0) return true;\n\t\t}\n\t\treturn false;\n\t}\n\tif (family === 6) {\n\t\tconst lower = ip.toLowerCase();\n\t\tfor (const c of cidrs) if (c.family === \"ipv6\" && c.network === lower) return true;\n\t\treturn false;\n\t}\n\treturn false;\n}\nexport { parseTrustedProxyIpsEnv as a, ipv4ToInt as i, getTrustedClientIp as n, get_trusted_client_ip_exports as r, carriesClientIpHeader as t };\n","import { t as NextlyError } from \"./nextly-error-DetCjZnO.mjs\";\nimport { i as ipv4ToInt } from \"./get-trusted-client-ip-CYEbmLA3.mjs\";\n// src/utils/validate-external-url.ts\nconst IPV4_RE = /^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/;\n/**\n* IPv4 CIDR ranges that must NEVER be the destination of an outbound\n* fetch sourced from a user-controllable URL. Listed roughly by RFC.\n*/\nconst PRIVATE_IPV4_CIDRS = [\n\t\"0.0.0.0/8\",\n\t\"10.0.0.0/8\",\n\t\"100.64.0.0/10\",\n\t\"127.0.0.0/8\",\n\t\"169.254.0.0/16\",\n\t\"172.16.0.0/12\",\n\t\"192.0.0.0/24\",\n\t\"192.0.2.0/24\",\n\t\"192.168.0.0/16\",\n\t\"198.18.0.0/15\",\n\t\"198.51.100.0/24\",\n\t\"203.0.113.0/24\",\n\t\"224.0.0.0/4\",\n\t\"240.0.0.0/4\"\n];\n/**\n* Cloud-metadata hostnames. These often resolve to private IPs and the\n* private-IP block catches them, but we reject by hostname first so the\n* error message is clear.\n*/\nconst CLOUD_METADATA_HOSTS = /* @__PURE__ */ new Set([\n\t\"metadata.google.internal\",\n\t\"metadata.googleapis.com\",\n\t\"metadata\"\n]);\n/**\n* An outbound URL refused for SSRF safety. Extends `NextlyError` (the package's\n* canonical error) so throw sites honor the error contract, while remaining a\n* distinct class the callers (e.g. the form-builder webhook handler) match with\n* `instanceof`.\n*/\nvar ExternalUrlError = class extends NextlyError {\n\turl;\n\tconstructor(message, url) {\n\t\tsuper({\n\t\t\tcode: \"EXTERNAL_URL_BLOCKED\",\n\t\t\tpublicMessage: message,\n\t\t\tlogContext: { url }\n\t\t});\n\t\tthis.url = url;\n\t\tthis.name = \"ExternalUrlError\";\n\t}\n};\n/** Validate a URL for outbound fetch. Throws `ExternalUrlError` on rejection. */\nasync function validateExternalUrl(rawUrl, options = {}) {\n\tlet parsed;\n\ttry {\n\t\tparsed = new URL(rawUrl);\n\t} catch {\n\t\tthrow new ExternalUrlError(\"Invalid URL\", rawUrl);\n\t}\n\tconst hostname = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n\tconst isLocalhostHostname = hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\";\n\tconst baseProtocols = options.allowedProtocols ?? [\"https:\"];\n\tconst protocols = options.allowLocalhost && isLocalhostHostname ? [...baseProtocols, \"http:\"] : baseProtocols;\n\tif (!protocols.includes(parsed.protocol)) throw new ExternalUrlError(`Protocol ${parsed.protocol} not allowed (allowed: ${protocols.join(\", \")})`, rawUrl);\n\tif (CLOUD_METADATA_HOSTS.has(hostname)) throw new ExternalUrlError(`Cloud-metadata hostname rejected: ${parsed.hostname}`, rawUrl);\n\tif (IPV4_RE.test(hostname)) {\n\t\tif (!isPublicIpv4(hostname, options.allowLocalhost === true && hostname === \"127.0.0.1\")) throw new ExternalUrlError(`Resolved to non-public IP: ${hostname}`, rawUrl);\n\t\treturn {\n\t\t\turl: parsed,\n\t\t\tpinnedIp: hostname,\n\t\t\tfamily: 4\n\t\t};\n\t}\n\tif (hostname.includes(\":\")) {\n\t\tif (!isPublicIpv6(hostname, options.allowLocalhost === true && hostname === \"::1\")) throw new ExternalUrlError(`Resolved to non-public IP: ${hostname}`, rawUrl);\n\t\treturn {\n\t\t\turl: parsed,\n\t\t\tpinnedIp: hostname,\n\t\t\tfamily: 6\n\t\t};\n\t}\n\tconst { lookup } = await import(\"node:dns/promises\");\n\tlet addresses;\n\ttry {\n\t\taddresses = await lookup(hostname, { all: true });\n\t} catch (err) {\n\t\tthrow new ExternalUrlError(`DNS lookup failed: ${err.message}`, rawUrl);\n\t}\n\tif (addresses.length === 0) throw new ExternalUrlError(\"No IPs returned for host\", rawUrl);\n\tfor (const { address, family } of addresses) {\n\t\tconst allow = options.allowLocalhost === true && isLocalhostHostname && family === 4;\n\t\tif (!(family === 4 ? isPublicIpv4(address, allow) : isPublicIpv6(address, allow))) throw new ExternalUrlError(`Resolved to non-public IP: ${address}`, rawUrl);\n\t}\n\tconst first = addresses[0];\n\treturn {\n\t\turl: parsed,\n\t\tpinnedIp: first.address,\n\t\tfamily: first.family === 6 ? 6 : 4\n\t};\n}\n/** Default response body cap: reject anything larger before buffering it all. */\n/**\n* How many bytes a bounded external read may buffer, absent a caller's own cap.\n*\n* Exported for the same reason as the deadline below: an adapter that never\n* touches `safeFetch` still owes callers this default, and restating the number\n* gives the tree two that drift.\n*/\nconst DEFAULT_MAX_RESPONSE_BYTES = 10485760;\n/** Default overall deadline covering DNS + connect + TLS + response. */\n/**\n* How long a bounded external read may take, absent a caller's own limit.\n*\n* Exported so a caller that must begin the clock EARLIER — a storage adapter\n* bounding a metadata lookup as well as the fetch that follows — uses this\n* number rather than restating it. Two spellings of one default agree today and\n* drift the first time either is tuned.\n*/\nconst DEFAULT_TIMEOUT_MS = 3e4;\n/**\n* Raised for fetch-phase failures that are NOT SSRF rejections: an over-large\n* response body, the overall deadline elapsing, or an undecodable content\n* encoding. Extends `NextlyError` (the canonical error contract) while staying a\n* distinct class, so a caller can tell \"URL refused for safety\"\n* (`ExternalUrlError`) apart from \"the request itself failed\".\n*/\nvar SafeFetchError = class extends NextlyError {\n\turl;\n\treason;\n\tstatus;\n\tconstructor(message, url, reason, status) {\n\t\tsuper({\n\t\t\tcode: \"EXTERNAL_REQUEST_FAILED\",\n\t\t\tpublicMessage: message,\n\t\t\tlogContext: {\n\t\t\t\turl,\n\t\t\t\treason\n\t\t\t}\n\t\t});\n\t\tthis.url = url;\n\t\tthis.reason = reason;\n\t\tthis.status = status;\n\t\tthis.name = \"SafeFetchError\";\n\t}\n};\n/**\n* Build a `dns.lookup`-compatible function that ignores the hostname and\n* always resolves to `ip`/`family`. Handing this to `http(s).request` forces\n* the socket to dial the exact address `validateExternalUrl` already vetted,\n* closing the DNS-rebinding window where a second resolution at connect time\n* could return a private IP. Not re-exported from the package barrel; exported\n* for the plugin `ctx.fetch` transport, which pins its vetted address the same\n* way, and so the rebinding invariant can be unit-tested directly.\n*/\nfunction createPinnedLookup(ip, family) {\n\treturn (_hostname, options, callback) => {\n\t\tif (options && options.all) callback(null, [{\n\t\t\taddress: ip,\n\t\t\tfamily\n\t\t}]);\n\t\telse callback(null, ip, family);\n\t};\n}\n/**\n* Validate `rawUrl` then fetch it with the validated IP pinned at the socket.\n* The convenience wrapper for the common case (webhook delivery, email\n* attachment fetch). Node-runtime only.\n*\n* DNS is resolved once by `validateExternalUrl`; `createPinnedLookup` forces\n* the connection to that same address, so an attacker's DNS cannot rebind the\n* request to a private host between validation and connect. Redirects are not\n* followed, the body is capped at `maxResponseBytes`, and the request is\n* bounded by `timeoutMs`.\n*/\nasync function safeFetch(rawUrl, options = {}) {\n\tconst { allowLocalhost, allowedProtocols, method, headers, body, signal, maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES, timeoutMs = DEFAULT_TIMEOUT_MS } = options;\n\tconst controller = new AbortController();\n\tconst forwardAbort = () => controller.abort(signal?.reason);\n\tif (signal) {\n\t\tif (signal.aborted) controller.abort(signal.reason);\n\t\telse signal.addEventListener(\"abort\", forwardAbort, { once: true });\n\t}\n\tconst timer = setTimeout(() => controller.abort(new SafeFetchError(`Request exceeded ${timeoutMs}ms`, rawUrl, \"timeout\")), timeoutMs);\n\ttry {\n\t\treturn await pinnedFetch(await abortable(validateExternalUrl(rawUrl, {\n\t\t\tallowLocalhost,\n\t\t\tallowedProtocols\n\t\t}), controller.signal), {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody,\n\t\t\tsignal: controller.signal,\n\t\t\tmaxResponseBytes\n\t\t});\n\t} finally {\n\t\tclearTimeout(timer);\n\t\tif (signal) signal.removeEventListener(\"abort\", forwardAbort);\n\t}\n}\n/**\n* The signal's abort reason as an `Error`. Our own aborts carry a\n* `SafeFetchError` (timeout); a caller's `AbortController.abort()` carries a\n* DOMException `AbortError`; anything else (a non-Error reason) is surfaced as\n* a standard `AbortError` so downstream `name === \"AbortError\"` checks hold.\n*/\nfunction abortError(signal) {\n\tconst reason = signal.reason;\n\tif (reason instanceof Error) return reason;\n\treturn new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n/**\n* Resolve `promise`, but reject with the signal's reason if it aborts first.\n* Lets a phase that runs before the request (DNS validation) share the overall\n* deadline and caller cancellation.\n*/\nfunction abortable(promise, signal) {\n\tif (signal.aborted) return Promise.reject(abortError(signal));\n\tlet onAbort;\n\tconst aborted = new Promise((_resolve, reject) => {\n\t\tonAbort = () => reject(abortError(signal));\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n\treturn Promise.race([promise, aborted]).finally(() => signal.removeEventListener(\"abort\", onAbort));\n}\n/**\n* Issue the request over `node:http`/`node:https` with the validated IP pinned\n* via a custom `lookup`, then adapt the Node response into a WHATWG `Response`.\n* `agent: false` forces a fresh socket per call so no pooled connection can\n* reuse a differently-resolved address. The overall deadline is enforced by the\n* caller through `init.signal`, so there is no separate timer here.\n*/\nasync function pinnedFetch(validated, init) {\n\tconst { url, pinnedIp, family } = validated;\n\tconst httpMod = url.protocol === \"https:\" ? await import(\"node:https\") : await import(\"node:http\");\n\tconst zlib = await import(\"node:zlib\");\n\tconst lookup = createPinnedLookup(pinnedIp, family);\n\tconst outHeaders = toOutgoingHeaders(init.headers);\n\tif (init.body != null) {\n\t\tdelete outHeaders[\"transfer-encoding\"];\n\t\toutHeaders[\"content-length\"] = String(typeof init.body === \"string\" ? Buffer.byteLength(init.body) : init.body.byteLength);\n\t}\n\treturn new Promise((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst settle = (fn) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tfn();\n\t\t};\n\t\tconst failure = (err) => init.signal.aborted ? abortError(init.signal) : err;\n\t\tconst req = httpMod.request(url, {\n\t\t\tmethod: init.method ?? \"GET\",\n\t\t\theaders: outHeaders,\n\t\t\tlookup,\n\t\t\tagent: false,\n\t\t\tsignal: init.signal\n\t\t}, (res) => {\n\t\t\tconst chunks = [];\n\t\t\tlet received = 0;\n\t\t\tres.on(\"data\", (chunk) => {\n\t\t\t\treceived += chunk.length;\n\t\t\t\tif (received > init.maxResponseBytes) {\n\t\t\t\t\tres.destroy();\n\t\t\t\t\treq.destroy();\n\t\t\t\t\tsettle(() => reject(new SafeFetchError(`Response body exceeded ${init.maxResponseBytes} bytes`, url.href, \"response-too-large\", res.statusCode)));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tchunks.push(chunk);\n\t\t\t});\n\t\t\tres.on(\"end\", () => {\n\t\t\t\tconst decoded = decodeBody(Buffer.concat(chunks), res.headers[\"content-encoding\"], zlib, init.maxResponseBytes, url.href, res.statusCode);\n\t\t\t\tif (decoded instanceof SafeFetchError) {\n\t\t\t\t\tsettle(() => reject(decoded));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsettle(() => resolve(toWhatwgResponse(res, decoded.body, decoded.decoded)));\n\t\t\t});\n\t\t\tres.on(\"error\", (err) => settle(() => reject(failure(err))));\n\t\t});\n\t\treq.on(\"error\", (err) => settle(() => reject(failure(err))));\n\t\tif (!req.destroyed) {\n\t\t\tif (init.body != null) req.write(init.body);\n\t\t\treq.end();\n\t\t}\n\t});\n}\n/**\n* Normalize a `HeadersInit` into Node's outgoing-header shape. Header names are\n* lowercased (they are case-insensitive) so later framing checks\n* (`content-length`) and the Host strip are reliable regardless of caller\n* casing. A caller-supplied `Host` is dropped: it is derived from the validated\n* URL, and honoring an override would let Host-based routing reach an internal\n* vhost behind a validated public IP, defeating the SSRF pin.\n*/\nfunction toOutgoingHeaders(headers) {\n\tconst out = {};\n\tif (!headers) return out;\n\tconst add = (rawKey, value) => {\n\t\tconst key = rawKey.toLowerCase();\n\t\tif (key === \"host\") return;\n\t\tconst existing = out[key];\n\t\tout[key] = existing === void 0 ? value : [].concat(existing, value);\n\t};\n\tif (headers instanceof Headers) headers.forEach((value, key) => add(key, value));\n\telse if (Array.isArray(headers)) for (const [key, value] of headers) add(key, value);\n\telse for (const [key, value] of Object.entries(headers)) add(key, value);\n\treturn out;\n}\n/**\n* Adapt a Node `IncomingMessage` + buffered body into a WHATWG `Response`.\n* Total by construction: a header the WHATWG layer rejects is skipped and the\n* status is clamped to a constructible range, so this never throws (a throw\n* would otherwise escape the `end` handler as an uncaught error).\n*/\nfunction toWhatwgResponse(res, body, stripContentHeaders) {\n\tconst headers = new Headers();\n\tfor (const [key, value] of Object.entries(res.headers)) {\n\t\tif (value == null) continue;\n\t\tconst lower = key.toLowerCase();\n\t\tif (stripContentHeaders && (lower === \"content-encoding\" || lower === \"content-length\")) continue;\n\t\tconst values = Array.isArray(value) ? value : [value];\n\t\tfor (const v of values) try {\n\t\t\theaders.append(key, v);\n\t\t} catch {}\n\t}\n\tconst raw = res.statusCode ?? 502;\n\tconst status = raw >= 200 && raw <= 599 ? raw : 502;\n\tconst nullBody = status === 204 || status === 205 || status === 304;\n\tconst bytes = new Uint8Array(body.byteLength);\n\tbytes.set(body);\n\treturn new Response(nullBody ? null : bytes, {\n\t\tstatus,\n\t\tstatusText: res.statusMessage ?? \"\",\n\t\theaders\n\t});\n}\n/**\n* Content-decode a response body per its `Content-Encoding`. node:http returns\n* raw wire bytes (unlike global fetch), so gzip/deflate/br bodies are inflated\n* here to preserve the previous behavior. `maxOutputLength` bounds the inflated\n* size, turning a decompression bomb into a `SafeFetchError` rather than an OOM.\n* Returns the (possibly decoded) buffer, or a `SafeFetchError` on failure.\n*/\nfunction decodeBody(buf, encoding, zlib, cap, url, status) {\n\tif (!encoding) return {\n\t\tbody: buf,\n\t\tdecoded: false\n\t};\n\tif (buf.length === 0) return {\n\t\tbody: buf,\n\t\tdecoded: true\n\t};\n\tconst layers = encoding.split(\",\").map((e) => e.trim().toLowerCase()).filter(Boolean);\n\tconst opts = { maxOutputLength: cap };\n\tlet current = buf;\n\tlet decoded = false;\n\ttry {\n\t\tfor (let i = layers.length - 1; i >= 0; i--) {\n\t\t\tconst enc = layers[i];\n\t\t\tif (enc === \"identity\") continue;\n\t\t\tif (enc === \"gzip\" || enc === \"x-gzip\") current = zlib.gunzipSync(current, opts);\n\t\t\telse if (enc === \"br\") current = zlib.brotliDecompressSync(current, opts);\n\t\t\telse if (enc === \"deflate\") try {\n\t\t\t\tcurrent = zlib.inflateSync(current, opts);\n\t\t\t} catch (inflateErr) {\n\t\t\t\tif (errorCode(inflateErr) === \"ERR_BUFFER_TOO_LARGE\") throw inflateErr;\n\t\t\t\tcurrent = zlib.inflateRawSync(current, opts);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (decoded) return new SafeFetchError(`Cannot fully decode content-encoding \"${encoding}\"`, url, \"decode-failed\", status);\n\t\t\t\treturn {\n\t\t\t\t\tbody: buf,\n\t\t\t\t\tdecoded: false\n\t\t\t\t};\n\t\t\t}\n\t\t\tdecoded = true;\n\t\t}\n\t\treturn {\n\t\t\tbody: current,\n\t\t\tdecoded\n\t\t};\n\t} catch (err) {\n\t\tconst tooLarge = errorCode(err) === \"ERR_BUFFER_TOO_LARGE\";\n\t\treturn new SafeFetchError(tooLarge ? `Decoded ${encoding} response body exceeded the size cap` : `Failed to decode ${encoding} response body`, url, tooLarge ? \"response-too-large\" : \"decode-failed\", status);\n\t}\n}\n/** The `.code` of a Node system error, if present. */\nfunction errorCode(err) {\n\tif (err != null && typeof err === \"object\" && \"code\" in err) {\n\t\tconst code = err.code;\n\t\treturn typeof code === \"string\" ? code : void 0;\n\t}\n}\nfunction isIpv4InCidr(intIp, cidr) {\n\tconst [addr, prefixRaw] = cidr.split(\"/\");\n\tconst intCidr = ipv4ToInt(addr);\n\tif (intCidr === null) return false;\n\tconst prefix = Number(prefixRaw);\n\tif (!Number.isInteger(prefix) || prefix < 0 || prefix > 32) return false;\n\tconst mask = prefix === 0 ? 0 : -1 >>> 32 - prefix << 32 - prefix;\n\treturn (intIp & mask) >>> 0 === (intCidr & mask) >>> 0;\n}\nfunction isPublicIpv4(addr, allowLoopback) {\n\tconst intIp = ipv4ToInt(addr);\n\tif (intIp === null) return false;\n\tif (allowLoopback && addr === \"127.0.0.1\") return true;\n\tfor (const cidr of PRIVATE_IPV4_CIDRS) if (isIpv4InCidr(intIp, cidr)) return false;\n\treturn true;\n}\n/**\n* Extract the embedded IPv4 of an IPv4-mapped IPv6 address, or null. Handles\n* both the dotted form (`::ffff:1.2.3.4`) and the hex form (`::ffff:7f00:1`)\n* that `URL.hostname` normalizes the dotted literal to — the latter would\n* otherwise skip the IPv4 denylist and pin, e.g., loopback as public.\n*/\nfunction mappedIpv4(lower) {\n\tconst dotted = lower.match(/^::ffff:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/);\n\tif (dotted) return dotted[1];\n\tconst hex = lower.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);\n\tif (hex) {\n\t\tconst hi = parseInt(hex[1], 16);\n\t\tconst lo = parseInt(hex[2], 16);\n\t\treturn [\n\t\t\thi >> 8,\n\t\t\thi & 255,\n\t\t\tlo >> 8,\n\t\t\tlo & 255\n\t\t].join(\".\");\n\t}\n\treturn null;\n}\nfunction isPublicIpv6(addr, allowLoopback) {\n\tconst lower = addr.toLowerCase();\n\tif (allowLoopback && lower === \"::1\") return true;\n\tconst mapped = mappedIpv4(lower);\n\tif (mapped) return isPublicIpv4(mapped, allowLoopback);\n\tif (lower === \"::\" || lower === \"::1\") return false;\n\tconst firstHextet = lower.split(\":\")[0] || \"\";\n\tif (firstHextet.startsWith(\"fc\") || firstHextet.startsWith(\"fd\")) return false;\n\tif (firstHextet.startsWith(\"fe8\") || firstHextet.startsWith(\"fe9\")) return false;\n\tif (firstHextet.startsWith(\"fea\") || firstHextet.startsWith(\"feb\")) return false;\n\tif (firstHextet.startsWith(\"ff\")) return false;\n\treturn true;\n}\nexport { createPinnedLookup as a, SafeFetchError as i, DEFAULT_TIMEOUT_MS as n, safeFetch as o, ExternalUrlError as r, validateExternalUrl as s, DEFAULT_MAX_RESPONSE_BYTES as t };\n","import { t as NextlyError } from \"../nextly-error-DetCjZnO.mjs\";\n// src/storage/read-errors.ts\n/**\n* The one way the storage layer says a read exceeded the caller's cap.\n*\n* `StorageReadOptions.maxBytes` is part of the adapter contract, so what happens\n* when it is exceeded belongs to the contract too. Without this each backend\n* refuses in its own vocabulary — the URL-addressed ones through a fetch error\n* carrying a `reason`, S3 through whatever its own code threw — and a caller\n* wanting to tell \"too large\" from \"could not read\" has to know which adapter it\n* is talking to. That is the thing an adapter contract exists to stop.\n*\n* Distinct from a generic internal failure because callers ACT on the\n* difference. The email attachment path answers an over-cap read with\n* `ATTACHMENT_SIZE_EXCEEDED`, which tells an author to attach something smaller;\n* a storage failure tells them nothing they can act on. Collapsing the two turns\n* a fixable refusal into an opaque error, which is the same conflation this\n* contract already draws between a missing key and an unreachable store.\n*\n* @module storage/read-errors\n*/\n/**\n* A read refused because the object is larger than the caller allowed.\n*\n* Carries the numbers rather than only a message, so a caller can say what the\n* limit was without parsing prose — and so the message itself stays free of the\n* key, which should not travel to whoever asked for the file.\n*/\nvar StorageReadTooLargeError = class extends NextlyError {\n\tpath;\n\tmaxBytes;\n\tsize;\n\tconstructor(path, maxBytes, size) {\n\t\tsuper({\n\t\t\tcode: \"STORAGE_READ_TOO_LARGE\",\n\t\t\tpublicMessage: \"The stored file is larger than the limit for this read.\",\n\t\t\tlogContext: {\n\t\t\t\tpath,\n\t\t\t\tmaxBytes,\n\t\t\t\t...size === void 0 ? {} : { size }\n\t\t\t}\n\t\t});\n\t\tthis.path = path;\n\t\tthis.maxBytes = maxBytes;\n\t\tthis.size = size;\n\t}\n};\n/**\n* Whether a thrown value is the over-cap refusal.\n*\n* A predicate rather than leaving every caller to write `instanceof`, because\n* this module can be loaded twice — a narrow entry point and a barrel are\n* different module instances, and `instanceof` across them is false for objects\n* that are otherwise identical. Callers that ask here cannot be caught by that.\n*/\nfunction isStorageReadTooLarge(error) {\n\treturn NextlyError.is(error) && error.code === \"STORAGE_READ_TOO_LARGE\";\n}\n/**\n* A read abandoned because the backend did not answer in time.\n*\n* Carried as the abort REASON rather than raised afterwards, which is what\n* makes it reach the caller at all: `AbortSignal.timeout` rejects with a\n* platform `DOMException`, and product code in this package answers in\n* `NextlyError` so a caller can classify what it caught without matching on a\n* name the runtime chose. `safeFetch` already aborts this way for the same\n* reason.\n*\n* Distinct from the over-cap refusal above by what each one KNOWS. The over-cap\n* refusal has measured the object and found it larger than the caller allowed.\n* This one knows only that the read did not finish in time: it may never have\n* opened the object, or may have taken some of it and been cut off part way, so\n* neither the object's size nor its existence follows from this error.\n*/\nvar StorageReadTimeoutError = class extends NextlyError {\n\tpath;\n\ttimeoutMs;\n\tconstructor(path, timeoutMs) {\n\t\tsuper({\n\t\t\tcode: \"STORAGE_READ_TIMEOUT\",\n\t\t\tpublicMessage: \"The stored file could not be read in time.\",\n\t\t\tlogContext: {\n\t\t\t\tpath,\n\t\t\t\ttimeoutMs\n\t\t\t}\n\t\t});\n\t\tthis.path = path;\n\t\tthis.timeoutMs = timeoutMs;\n\t}\n};\n/**\n* Whether a thrown value is the deadline refusal.\n*\n* A predicate for the same reason as `isStorageReadTooLarge`: a narrow entry\n* point and a barrel are different module instances, and `instanceof` across\n* them is false for objects that are otherwise identical.\n*/\nfunction isStorageReadTimeout(error) {\n\treturn NextlyError.is(error) && error.code === \"STORAGE_READ_TIMEOUT\";\n}\nexport { StorageReadTimeoutError, StorageReadTooLargeError, isStorageReadTimeout, isStorageReadTooLarge };\n","import { t as NextlyError } from \"../nextly-error-DetCjZnO.mjs\";\nimport { i as SafeFetchError, n as DEFAULT_TIMEOUT_MS, o as safeFetch, t as DEFAULT_MAX_RESPONSE_BYTES } from \"../validate-external-url-CfT2WjgH.mjs\";\nimport { StorageReadTimeoutError, StorageReadTooLargeError } from \"./read-errors.mjs\";\n// src/storage/fetch-stored-bytes.ts\n/**\n* Reading bytes back from a storage service that only exposes them over HTTP.\n*\n* The local adapter reads from disk and S3 reads through its own SDK, so\n* neither needs this. The services that address a file by URL — Vercel Blob,\n* UploadThing — all end up doing the same three things, and doing them the same\n* way matters more than it looks: each step below is a place where the obvious\n* shortcut reports the wrong thing to a caller who may act on it.\n*\n* Built on {@link safeFetch} rather than on a bare `fetch`, because \"read a\n* remote object into memory\" already has an implementation here that caps the\n* body, bounds the request and refuses an address that resolves somewhere\n* private. A second capped fetch beside it would be two answers to one\n* question, and the two would drift the first time either learned something.\n* Measured: it costs an adapter package about 80K, against the 1MB the whole\n* storage barrel costs.\n*\n* @module storage/fetch-stored-bytes\n*/\n/**\n* Fetch a stored object's bytes from the URL its service issued.\n*\n* Separates the two answers a read can have, which is the whole reason this is\n* a function rather than three lines inlined twice.\n*\n* `null` means the object is NOT THERE — an ordinary fact about the store. A\n* 404 is that answer even when the lookup just succeeded: these stores are\n* remote and concurrent, so an object can be deleted between resolving its\n* address and fetching it. Reporting that ordinary race as a server failure\n* would make a caller handle an error for something its own contract already\n* has a value for.\n*\n* Anything else THROWS. A dropped connection, a 5xx or a refused request says\n* nothing about whether the object exists, and reporting it as absence invites\n* a caller to treat a live file as deleted and write a replacement over it. The\n* two are easy to state apart and easy to lose when the fetch sits inside the\n* same `try` that catches the lookup.\n*\n* The URL is always one the SERVICE issued, never one assembled from a key.\n* These stores mint addresses carrying suffixes the adapter never chose, so a\n* derived URL is a guess at a string another system owns.\n*\n* @param url - The address the storage service reported for this object\n* @param context - What is being read, for the error message: usually the key\n* @param label - The service's name, so a failure says which store answered\n* @param options - Bounds for the read; see {@link StorageReadOptions}\n* @param signal - A deadline ALREADY RUNNING, covering an earlier phase too\n* @returns The object's bytes, or `null` when the store answers 404\n*/\nasync function fetchStoredBytes(url, context, label, options, signal) {\n\tlet response;\n\ttry {\n\t\tresponse = await safeFetch(url, {\n\t\t\t...options?.maxBytes === void 0 ? {} : { maxResponseBytes: options.maxBytes },\n\t\t\t...signal !== void 0 ? { signal } : options?.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }\n\t\t});\n\t} catch (error) {\n\t\tconst verdict = classifyFetchFailure(error);\n\t\tif (verdict === \"absent\") return null;\n\t\tif (verdict === \"oversized\") throw new StorageReadTooLargeError(context, resolveReadBounds(options).maxBytes);\n\t\tthrow error;\n\t}\n\tif (response.status === 404) return null;\n\tif (!response.ok) throw NextlyError.internal({ logContext: {\n\t\tservice: label,\n\t\tpath: context,\n\t\tstatus: response.status,\n\t\tstatusText: response.statusText\n\t} });\n\treturn Buffer.from(await response.arrayBuffer());\n}\n/**\n* What a failed fetch actually says about the object.\n*\n* Its own function because the three answers are the whole point of this module\n* and they are easy to collapse into each other — each collapse having been a\n* real defect here rather than a hypothetical:\n*\n* - ABSENT. A 404 is absence whatever size its body was. `safeFetch` caps while\n* buffering, so a verbose CDN error page raises before a `Response` exists\n* and the status check further down is never reached; the object is still\n* gone, and must not become an error because the page explaining it was long.\n* - OVERSIZED. Only a SUCCESSFUL response that blew the cap. A failed response\n* can exceed it too, and translating on the reason alone reported a backend\n* outage as \"your file is too big\" — a cause the author would act on, wrongly.\n* - UNKNOWN. Everything else, including a too-large refusal carrying NO status:\n* that means the failure arrived before any status did, which says nothing\n* about whether the object was oversized.\n*/\nfunction classifyFetchFailure(error) {\n\tif (!(error instanceof SafeFetchError)) return \"unknown\";\n\tif (error.status === 404) return \"absent\";\n\tconst successful = error.status !== void 0 && error.status >= 200 && error.status < 300;\n\treturn error.reason === \"response-too-large\" && successful ? \"oversized\" : \"unknown\";\n}\n/** The deadline a stored read runs under when the caller names none. */\nconst DEFAULT_READ_TIMEOUT_MS = DEFAULT_TIMEOUT_MS;\n/** The byte cap a stored read runs under when the caller names none. */\nconst DEFAULT_READ_MAX_BYTES = DEFAULT_MAX_RESPONSE_BYTES;\n/**\n* The bounds a read actually runs under, defaults filled in.\n*\n* ONE place, because every adapter needs the same answer and the ones that\n* derived it themselves diverged: the URL-backed pair inherited `safeFetch`'s\n* cap and deadline for free, while the local and S3 adapters — which never\n* touch `safeFetch` — applied NO bound at all when the caller named none.\n* `StorageReadOptions` promises the default either way, and a production caller\n* reading media without options got it from two of four backends.\n*\n* Filling the defaults here rather than per adapter is what makes the promise\n* true by construction rather than by four implementations agreeing.\n*/\nfunction resolveReadBounds(options) {\n\treturn {\n\t\tmaxBytes: options?.maxBytes ?? DEFAULT_READ_MAX_BYTES,\n\t\ttimeoutMs: options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS\n\t};\n}\n/**\n* A deadline that aborts with a NextlyError rather than a platform exception.\n*\n* `AbortSignal.timeout` rejects with a `DOMException` named `TimeoutError`, and\n* product code in this package answers in `NextlyError` — so a caller can\n* classify what it caught rather than matching a name the runtime chose. Built\n* here rather than per adapter so every storage deadline says the same thing.\n*\n* The timer is unreferenced so a pending deadline is never a reason the process\n* stays alive, and the returned `cancel` clears it once the read settles — the\n* unref alone would leave one scheduled per read for the whole timeout.\n*\n* @param timeoutMs - How long the read may take\n* @param context - What is being read, carried into the refusal's log side\n*/\nfunction deadlineSignal(timeoutMs, context) {\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => {\n\t\tcontroller.abort(new StorageReadTimeoutError(context, timeoutMs));\n\t}, timeoutMs);\n\ttimer.unref?.();\n\treturn {\n\t\tsignal: controller.signal,\n\t\tcancel: () => {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t};\n}\n/**\n* Stop waiting on a promise once the deadline fires.\n*\n* For a lookup whose SDK cannot be cancelled. UploadThing 7.7.4's\n* `getFileUrls` reads only `keyType` and forwards no signal, so handing it one\n* bounds nothing — the option is accepted and ignored, which reads as covered\n* and behaves as absent.\n*\n* This RACES rather than cancels, and the difference is worth stating plainly:\n* the underlying request keeps running to completion in the background. What it\n* buys is that `read` returns within the deadline it advertised, instead of\n* holding its caller for as long as a stalled backend feels like. That is the\n* promise the contract actually makes; genuinely cancelling the work needs an\n* SDK that accepts cancellation, and this one does not.\n*/\nasync function withDeadline(work, signal) {\n\tif (signal === void 0) return await work;\n\treturn await Promise.race([work, new Promise((_, reject) => {\n\t\tif (signal.aborted) {\n\t\t\treject(signal.reason);\n\t\t\treturn;\n\t\t}\n\t\tsignal.addEventListener(\"abort\", () => reject(signal.reason), { once: true });\n\t})]);\n}\nexport { DEFAULT_READ_MAX_BYTES, DEFAULT_READ_TIMEOUT_MS, classifyFetchFailure, deadlineSignal, fetchStoredBytes, resolveReadBounds, withDeadline };\n","/**\n * Vercel Blob Storage Adapter\n *\n * Stores files on Vercel Blob Storage, a globally distributed object storage\n * service powered by Cloudflare R2. Optimized for Vercel deployments with\n * built-in CDN distribution.\n *\n * Features:\n * - Globally distributed CDN-backed storage\n * - Automatic file management with unique filenames\n * - Token-based authentication\n * - Client-side upload support (via handleUpload API)\n * - Serverless-friendly (no filesystem access required)\n *\n * @example Basic usage\n * ```typescript\n * const adapter = new VercelBlobStorageAdapter({\n * token: process.env.BLOB_READ_WRITE_TOKEN,\n * collections: { media: true }\n * });\n *\n * const result = await adapter.upload(buffer, {\n * filename: 'photo.jpg',\n * mimeType: 'image/jpeg'\n * });\n * // result.url: \"https://abc123.public.blob.vercel-storage.com/photo-xyz.jpg\"\n * ```\n */\n\nimport { put, del, head, list, BlobNotFoundError } from \"@vercel/blob\";\nimport { NextlyError } from \"nextly/errors\";\nimport type {\n IStorageAdapter,\n UploadOptions,\n UploadResult,\n StorageAdapterInfo,\n ClientUploadData,\n FileMetadata,\n BulkDeleteResult,\n StorageReadOptions,\n StoredFileEntry,\n} from \"nextly/storage\";\nimport {\n fetchStoredBytes,\n DEFAULT_READ_TIMEOUT_MS,\n} from \"nextly/storage/fetch-stored-bytes\";\n\nimport type {\n VercelBlobStorageConfig,\n ResolvedVercelBlobConfig,\n} from \"./types\";\n\n// ============================================================\n// Vercel Blob Storage Adapter\n// ============================================================\n\n/**\n * Vercel Blob Storage Adapter\n *\n * Implements the IStorageAdapter interface for Vercel Blob Storage.\n * Provides file upload, deletion, existence checks, and metadata retrieval.\n */\nexport class VercelBlobStorageAdapter implements IStorageAdapter {\n private resolvedConfig: ResolvedVercelBlobConfig;\n\n /**\n * Create a new Vercel Blob storage adapter.\n *\n * @param config - Vercel Blob storage configuration\n * @throws Error if token is not provided\n */\n constructor(private config: VercelBlobStorageConfig) {\n // Resolve token from config or environment\n const token = config.token || process.env.BLOB_READ_WRITE_TOKEN || \"\";\n\n if (!token) {\n throw new Error(\n \"@nextly/storage-vercel-blob: token is required.\\n\\n\" +\n \"Either set the BLOB_READ_WRITE_TOKEN environment variable or pass token in config.\\n\" +\n \"Get your token from: Vercel Dashboard > Storage > Blob > Tokens\"\n );\n }\n\n // Resolve config with defaults\n this.resolvedConfig = {\n token,\n addRandomSuffix: config.addRandomSuffix ?? true,\n cacheControlMaxAge: config.cacheControlMaxAge ?? 31536000,\n access: config.access ?? \"public\",\n storeId: config.storeId,\n allowOverwrite: config.allowOverwrite ?? false,\n multipartThreshold: config.multipartThreshold ?? 5 * 1024 * 1024, // 5MB\n };\n }\n\n // ============================================================\n // Core IStorageAdapter Methods\n // ============================================================\n\n /**\n * Upload file to Vercel Blob.\n *\n * Files are stored with globally distributed CDN backing.\n * By default, a random suffix is added to prevent filename collisions.\n *\n * @param buffer - File content as Buffer\n * @param options - Upload options (filename, mimeType, folder, collection)\n * @returns Upload result with URL and storage path\n */\n async upload(buffer: Buffer, options: UploadOptions): Promise<UploadResult> {\n const mimeType = (options.contentType || options.mimeType || \"\")\n .toLowerCase()\n .trim();\n const filename = (options.filename || \"\").toLowerCase();\n const ext = filename.includes(\".\")\n ? filename.slice(filename.lastIndexOf(\".\") + 1)\n : \"\";\n const isHtml =\n mimeType === \"text/html\" ||\n mimeType === \"application/xhtml+xml\" ||\n ext === \"html\" ||\n ext === \"htm\" ||\n ext === \"xhtml\";\n // HTML stays unconditionally rejected. The `downloadUrl` trick that\n // makes SVG safe (see below) doesn't help HTML — a downloaded HTML\n // file is still a usable XSS vector when opened from disk, and\n // Vercel Blob has no equivalent of `Content-Security-Policy` to\n // defang it.\n if (isHtml) {\n throw NextlyError.validation({\n errors: [\n {\n path: \"file\",\n code: \"UNSUPPORTED_FOR_BACKEND\",\n message:\n \"HTML files cannot be hosted on Vercel Blob. Use the S3 or R2 adapter, or upload as another format.\",\n },\n ],\n logContext: {\n adapter: \"vercel-blob\",\n claimedMimeType: options.mimeType,\n reason: \"vercel-blob-rejects-html\",\n filename: options.filename,\n },\n });\n }\n\n const isSvg =\n mimeType === \"image/svg+xml\" || ext === \"svg\" || ext === \"svgz\";\n\n const pathname = this.buildPathname(options.filename, options.folder);\n\n const result = await put(pathname, buffer, {\n access: this.resolvedConfig.access,\n token: this.resolvedConfig.token,\n contentType: options.contentType || options.mimeType,\n addRandomSuffix: this.resolvedConfig.addRandomSuffix,\n cacheControlMaxAge: this.resolvedConfig.cacheControlMaxAge,\n });\n\n // SVGs are served via Vercel Blob's `downloadUrl` (the same URL with\n // `?download=1` appended) so direct top-level navigation forces an\n // attachment download instead of rendering. `<img src>` ignores the\n // `Content-Disposition` header, so legitimate inline rendering still\n // works. The `@vercel/blob` SDK has no `contentDisposition` input\n // option on `put()`, so this query-param-driven approach is the\n // supported mechanism. Caller is responsible for sanitizing SVG\n // contents upstream (handled by `upload-validation`).\n const url =\n isSvg && options.contentDisposition === \"attachment\"\n ? result.downloadUrl\n : result.url;\n\n return {\n url,\n path: result.url,\n };\n }\n\n /**\n * Delete file from Vercel Blob.\n *\n * @param filePath - Full blob URL to delete\n */\n async delete(filePath: string): Promise<void> {\n await del(filePath, {\n token: this.resolvedConfig.token,\n });\n }\n\n /**\n * Delete multiple files from Vercel Blob in chunked batches.\n *\n * Processes deletions in chunks of 10 concurrent calls using Promise.allSettled,\n * collecting successes and failures without short-circuiting.\n *\n * @param filePaths - Array of full blob URLs to delete\n * @returns BulkDeleteResult with successful and failed arrays\n */\n async bulkDelete(filePaths: string[]): Promise<BulkDeleteResult> {\n const successful: string[] = [];\n const failed: Array<{ filePath: string; error: string }> = [];\n const chunkSize = 10;\n\n for (let i = 0; i < filePaths.length; i += chunkSize) {\n const chunk = filePaths.slice(i, i + chunkSize);\n const results = await Promise.allSettled(\n chunk.map(fp => del(fp, { token: this.resolvedConfig.token }))\n );\n\n results.forEach((result, idx) => {\n const fp = chunk[idx];\n if (result.status === \"fulfilled\") {\n successful.push(fp);\n } else {\n failed.push({\n filePath: fp,\n error:\n result.reason instanceof Error\n ? result.reason.message\n : String(result.reason),\n });\n }\n });\n }\n\n return { successful, failed };\n }\n\n /**\n * Check if file exists in Vercel Blob.\n *\n * Uses the head() function which is efficient for existence checks.\n *\n * @param filePath - Full blob URL to check\n * @returns true if file exists, false otherwise\n */\n async exists(filePath: string): Promise<boolean> {\n try {\n await head(filePath, {\n token: this.resolvedConfig.token,\n });\n return true;\n } catch {\n // Vercel Blob throws an error if the blob doesn't exist\n return false;\n }\n }\n\n /**\n * Read a stored blob back as bytes, or `null` when it is not there.\n *\n * A NETWORK round trip, unlike the local adapter's disk read, because the\n * bytes live on Vercel's CDN and there is no other way to reach them. That\n * cost is the reason a caller serving these from its own origin has to cache:\n * the privacy rule that forces same-origin serving does not also make the\n * fetch free, and an uncached proxy pays it on every request.\n *\n * The URL is taken from `head` rather than assembled from `filePath`,\n * because a blob's address is issued by the service — it carries a random\n * suffix this adapter never chose — so deriving one here would be guessing at\n * a string another system owns.\n *\n * `null` for a missing blob rather than a throw, matching {@link exists}.\n *\n * @param filePath - Blob path/key\n * @returns The blob's bytes, or `null` when it does not exist\n */\n async read(\n filePath: string,\n options?: StorageReadOptions\n ): Promise<Buffer | null> {\n /*\n * ONE deadline for both phases, started before the lookup.\n *\n * `head` can stall exactly as the fetch can, and it runs first — so a\n * deadline that begins only at the fetch leaves the lookup unbounded and\n * the read can outlive what the caller was promised. Created here and\n * handed to both.\n *\n * ALWAYS, not only when the caller named a timeout. `safeFetch` applies a\n * default deadline of its own, so a caller stating none was still bounded\n * for the fetch and unbounded for the lookup — which is the commonest call,\n * the email path among them, since it supplies only a byte cap. The default\n * comes from the same constant `safeFetch` uses rather than being restated.\n */\n const deadline = AbortSignal.timeout(\n options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS\n );\n\n let target: string;\n try {\n const meta = await head(filePath, {\n token: this.resolvedConfig.token,\n abortSignal: deadline,\n });\n target = meta.downloadUrl ?? meta.url;\n } catch (error: unknown) {\n /*\n * ONLY the not-found class becomes `null`. `head` also rejects for an\n * expired token, a suspended or missing store, an aborted request and a\n * plain network failure, and every one of those says nothing about\n * whether the blob exists. Catching them all reports an outage as a\n * deletion, which a caller may act on by writing a replacement over a\n * file that is still there.\n *\n * Identified by the CLASS the SDK exports rather than by matching the\n * message, because the message is prose this package does not own.\n */\n if (error instanceof BlobNotFoundError) return null;\n throw error;\n }\n\n /*\n * OUTSIDE the catch above, deliberately, and through the shared helper so\n * that separation is stated once rather than in each adapter. A failed\n * fetch of a blob whose metadata just resolved is a transport failure\n * rather than an absence, and folding it into `null` would report a\n * network outage as a deleted file.\n */\n return await fetchStoredBytes(\n target,\n filePath,\n \"Vercel Blob\",\n options,\n deadline\n );\n }\n\n /**\n * Get public URL for Vercel Blob file.\n *\n * Vercel Blob paths ARE the public URLs - they're already full HTTPS URLs\n * with CDN distribution.\n *\n * @param filePath - Full blob URL\n * @returns The same URL (Vercel Blob paths are already public URLs)\n */\n /**\n * Every blob in the store, by its URL (which is its stored path here), with\n * when it was uploaded, a page at a time.\n */\n async *list(): AsyncIterable<StoredFileEntry> {\n let cursor: string | undefined;\n do {\n const page = await this.listBlobs(undefined, { cursor });\n for (const blob of page.blobs) {\n yield { path: blob.url, lastModified: blob.uploadedAt };\n }\n cursor = page.hasMore ? page.cursor : undefined;\n } while (cursor);\n }\n\n getPublicUrl(filePath: string): string {\n // Vercel Blob paths are already full URLs\n return filePath;\n }\n\n /**\n * Get storage type identifier.\n */\n getType(): \"vercel-blob\" {\n return \"vercel-blob\";\n }\n\n // ============================================================\n // Optional IStorageAdapter Methods\n // ============================================================\n\n /**\n * Get adapter info including capabilities.\n *\n * @returns Adapter info with type, name, and capability flags\n */\n getInfo(): StorageAdapterInfo {\n return {\n type: \"vercel-blob\",\n name: \"VercelBlobStorageAdapter\",\n supportsSignedUrls: false, // Vercel Blob URLs are public by default\n supportsClientUploads: true, // Via handleUpload API\n };\n }\n\n /**\n * Get file metadata from Vercel Blob.\n *\n * Retrieves file information including size, content type, and upload date.\n *\n * @param filePath - Full blob URL\n * @returns File metadata or null if file not found\n */\n async getMetadata(filePath: string): Promise<FileMetadata | null> {\n try {\n const result = await head(filePath, {\n token: this.resolvedConfig.token,\n });\n\n // Extract filename from pathname\n const filename = result.pathname.split(\"/\").pop() || result.pathname;\n\n return {\n id: filePath,\n filename,\n originalFilename: filename,\n mimeType: result.contentType,\n size: result.size,\n url: result.url,\n createdAt: result.uploadedAt.toISOString(),\n };\n } catch {\n // File not found\n return null;\n }\n }\n\n /**\n * Generate pre-signed URL for client-side uploads.\n *\n * Vercel Blob uses a different pattern for client uploads - they require\n * the handleUpload API which handles token generation server-side.\n *\n * This method is not implemented because Vercel Blob's client upload flow\n * requires server-side route handlers with handleUpload().\n *\n * @see https://vercel.com/docs/storage/vercel-blob/client-upload\n * @throws Error always - client uploads require handleUpload API\n */\n getPresignedUploadUrl(\n _key: string,\n _mimeType: string,\n _expiresIn?: number\n ): Promise<ClientUploadData> {\n return Promise.reject(\n new Error(\n \"@nextly/storage-vercel-blob: Client uploads require the handleUpload API.\\n\\n\" +\n \"Vercel Blob uses a different pattern for client-side uploads that involves:\\n\" +\n \"1. A server-side route handler with handleUpload()\\n\" +\n \"2. The @vercel/blob/client upload() function\\n\\n\" +\n \"See: https://vercel.com/docs/storage/vercel-blob/client-upload\\n\\n\" +\n \"For server-side uploads, use the standard upload() method instead.\"\n )\n );\n }\n\n // ============================================================\n // Additional Methods\n // ============================================================\n\n /**\n * List blobs with optional prefix filter.\n *\n * Useful for browsing or batch operations on stored files.\n *\n * @param prefix - Optional prefix to filter results\n * @param options - List options (limit, cursor)\n * @returns List of blob metadata\n */\n async listBlobs(\n prefix?: string,\n options?: { limit?: number; cursor?: string }\n ): Promise<{\n blobs: Array<{\n url: string;\n pathname: string;\n size: number;\n uploadedAt: Date;\n }>;\n hasMore: boolean;\n cursor?: string;\n }> {\n const result = await list({\n token: this.resolvedConfig.token,\n prefix,\n limit: options?.limit,\n cursor: options?.cursor,\n });\n\n return {\n blobs: result.blobs.map(blob => ({\n url: blob.url,\n pathname: blob.pathname,\n size: blob.size,\n uploadedAt: blob.uploadedAt,\n })),\n hasMore: result.hasMore,\n cursor: result.cursor,\n };\n }\n\n // ============================================================\n // Helper Methods\n // ============================================================\n\n /**\n * Build pathname for Vercel Blob upload.\n *\n * Creates pathname in format: {folder}/{filename}\n * If no folder is provided, uses the filename directly.\n *\n * @param filename - Original filename (will be sanitized)\n * @param folder - Optional folder/prefix for organizing uploads\n * @returns Generated pathname\n * @throws Error if folder fails sanitization\n */\n private buildPathname(filename: string, folder?: string): string {\n const sanitized = this.sanitizeFilename(filename);\n if (!folder) return sanitized;\n return `${this.sanitizeFolder(folder)}/${sanitized}`;\n }\n\n /**\n * Sanitize filename to prevent path traversal issues.\n *\n * @param filename - Original filename\n * @returns Sanitized filename\n */\n private sanitizeFilename(filename: string): string {\n const basename = filename.split(/[/\\\\]/).pop() || filename;\n return basename.replace(/[^a-zA-Z0-9._-]/g, \"-\");\n }\n\n /**\n * Reject folder values that would let a caller\n * escape the configured prefix via path traversal or weird\n * separators. Vercel Blob is flat-keyed so `/` is just part of the\n * pathname, but an attacker who controls `folder` could still:\n *\n * - Use `..` to chain a relative-traversal-style key.\n * - Use `\\` (Windows separator) to confuse downstream tooling.\n * - Use control chars / null bytes to truncate the key.\n * - Use a leading `/` to look like an absolute path.\n *\n * Internal `/` segments stay allowed because callers legitimately\n * use nested folders (`docs/2026/...`); a leading `/`, empty\n * segments (`docs//x`), or `..` segments are rejected.\n *\n * @throws Error with a stable message so the storage facade can\n * surface a 400 instead of a 500.\n */\n private sanitizeFolder(folder: string): string {\n const trimmed = folder.replace(/\\/+$/, \"\"); // tolerate one trailing `/`\n if (!trimmed) {\n throw new Error(\"Folder must be a non-empty string.\");\n }\n // eslint-disable-next-line no-control-regex -- the whole point is to reject control chars\n if (/[\\\\\\0\\x01-\\x1f\\x7f]/.test(trimmed)) {\n throw new Error(\n \"Folder contains forbidden characters (backslash, control chars, or null bytes).\"\n );\n }\n if (trimmed.startsWith(\"/\")) {\n throw new Error(\"Folder must not start with `/`.\");\n }\n const segments = trimmed.split(\"/\");\n for (const segment of segments) {\n if (segment === \"\") {\n throw new Error(\"Folder must not contain empty segments (`//`).\");\n }\n if (segment === \"..\") {\n throw new Error(\"Folder must not contain `..` segments.\");\n }\n }\n return trimmed;\n }\n\n // ============================================================\n // Public Accessors\n // ============================================================\n\n /**\n * Get the configured token (masked for logging).\n */\n getTokenMasked(): string {\n const token = this.resolvedConfig.token;\n if (token.length <= 8) return \"****\";\n return `${token.slice(0, 4)}...${token.slice(-4)}`;\n }\n\n /**\n * Check if random suffix is enabled.\n */\n hasRandomSuffix(): boolean {\n return this.resolvedConfig.addRandomSuffix;\n }\n\n /**\n * Get configured cache control max age.\n */\n getCacheControlMaxAge(): number {\n return this.resolvedConfig.cacheControlMaxAge;\n }\n}\n","/**\n * Vercel Blob Storage Plugin\n *\n * Factory function that creates a storage plugin for Vercel Blob Storage.\n * Returns a StoragePlugin that can be registered with MediaStorage.\n *\n * @example Basic usage\n * ```typescript\n * import { vercelBlobStorage } from '@nextly/storage-vercel-blob'\n * import { defineConfig } from 'nextly/config'\n *\n * export default defineConfig({\n * storage: [\n * vercelBlobStorage({\n * token: process.env.BLOB_READ_WRITE_TOKEN,\n * collections: {\n * media: true\n * }\n * })\n * ]\n * })\n * ```\n *\n * @example With client uploads (recommended for Vercel)\n * ```typescript\n * vercelBlobStorage({\n * collections: {\n * media: {\n * clientUploads: true // Bypass 4.5MB serverless limit\n * }\n * }\n * })\n * ```\n *\n * @example With collection-specific configuration\n * ```typescript\n * vercelBlobStorage({\n * addRandomSuffix: true,\n * cacheControlMaxAge: 86400, // 1 day\n * collections: {\n * // Simple enable with defaults\n * media: true,\n *\n * // Full configuration\n * documents: {\n * prefix: 'docs/',\n * addRandomSuffix: false,\n * allowOverwrite: true\n * }\n * }\n * })\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { StoragePlugin, ClientUploadData } from \"nextly/storage\";\n\nimport { VercelBlobStorageAdapter } from \"./adapter\";\nimport type { VercelBlobStorageConfig } from \"./types\";\n\n// ============================================================\n// Plugin Factory Function\n// ============================================================\n\n/**\n * Create a Vercel Blob storage plugin for Nextly.\n *\n * This factory function creates a StoragePlugin that can be added to\n * the `storage` array in `nextly.config.ts`. Vercel Blob is optimized\n * for Vercel deployments with:\n *\n * - Global CDN distribution\n * - Simple token-based authentication\n * - Client-side upload support (via handleUpload API)\n * - Automatic file management\n *\n * @param config - Vercel Blob storage configuration\n * @returns A StoragePlugin that MediaStorage can register\n *\n * @throws Error if token is not provided (via adapter)\n */\nexport function vercelBlobStorage(\n config: VercelBlobStorageConfig\n): StoragePlugin {\n // Handle disabled plugin\n // When disabled, return a plugin with no collections and null adapter\n // MediaStorage.registerPlugin() checks for null adapter and skips registration\n if (config.enabled === false) {\n return {\n name: \"vercel-blob-storage\",\n type: \"vercel-blob\",\n collections: {},\n adapter: null as unknown as StoragePlugin[\"adapter\"],\n };\n }\n\n // Create the Vercel Blob adapter\n // Adapter constructor validates required config (token)\n const adapter = new VercelBlobStorageAdapter(config);\n\n // Build and return the plugin\n const plugin: StoragePlugin = {\n name: \"vercel-blob-storage\",\n type: \"vercel-blob\",\n collections: config.collections,\n adapter,\n\n /**\n * Generate upload URL for client-side uploads.\n *\n * Note: Vercel Blob uses a different pattern for client uploads.\n * Instead of pre-signed URLs, it uses the handleUpload() API which\n * requires server-side route handlers.\n *\n * This method throws an error explaining the correct approach.\n *\n * @see https://vercel.com/docs/storage/vercel-blob/client-upload\n */\n getClientUploadUrl(\n _filename: string,\n _mimeType: string,\n _collection: string\n ): Promise<ClientUploadData> {\n // Vercel Blob doesn't use pre-signed URLs like S3\n // Instead, it requires using the handleUpload API with @vercel/blob/client\n return Promise.reject(\n new Error(\n \"@nextly/storage-vercel-blob: Client uploads require the handleUpload API.\\n\\n\" +\n \"Vercel Blob uses a different pattern than S3 for client-side uploads:\\n\\n\" +\n \"1. Create a server-side route handler with handleUpload()\\n\" +\n \"2. Use upload() from @vercel/blob/client on the frontend\\n\\n\" +\n \"See: https://vercel.com/docs/storage/vercel-blob/client-upload\"\n )\n );\n },\n\n /**\n * Get signed download URL for file access.\n *\n * Note: Vercel Blob URLs are public by default and do not support\n * signed/temporary URLs. All uploaded blobs are accessible via their\n * public URL.\n *\n * @param path - Storage path (full blob URL)\n * @returns The same URL (Vercel Blob URLs are public)\n */\n getSignedDownloadUrl(path: string): Promise<string> {\n // Vercel Blob URLs are public by default\n // No signed URL support - just return the public URL\n return Promise.resolve(path);\n },\n };\n\n return plugin;\n}\n","/**\n * @nextly/storage-vercel-blob\n *\n * Vercel Blob storage adapter for Nextly CMS.\n * Optimized for Vercel deployments with client-side upload support\n * to bypass serverless function size limits (4.5MB).\n *\n * @example Basic usage\n * ```typescript\n * import { vercelBlobStorage } from '@nextly/storage-vercel-blob'\n * import { defineConfig } from 'nextly/config'\n *\n * export default defineConfig({\n * storage: [\n * vercelBlobStorage({\n * token: process.env.BLOB_READ_WRITE_TOKEN,\n * collections: {\n * media: true\n * }\n * })\n * ]\n * })\n * ```\n *\n * @example With client uploads (recommended for Vercel)\n * ```typescript\n * vercelBlobStorage({\n * collections: {\n * media: {\n * clientUploads: true // Bypass 4.5MB serverless limit\n * }\n * }\n * })\n * ```\n *\n * @packageDocumentation\n */\n\n// ============================================================\n// Vercel Blob Storage Plugin Export (Primary API)\n// ============================================================\n\nexport { vercelBlobStorage } from \"./plugin\";\n\n// ============================================================\n// Vercel Blob Storage Adapter Export\n// ============================================================\n\nexport { VercelBlobStorageAdapter } from \"./adapter\";\n\n// ============================================================\n// Vercel Blob Types Export\n// ============================================================\n\nexport type {\n VercelBlobStorageConfig,\n VercelBlobCollectionConfig,\n VercelBlobCollectionStorageMap,\n ResolvedVercelBlobConfig,\n} from \"./types\";\n\n// ============================================================\n// Package Metadata\n// ============================================================\n\nexport const PACKAGE_NAME = \"@nextly/storage-vercel-blob\";\nexport const PACKAGE_VERSION = \"0.1.0\";\n"],"mappings":"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"}