@prisma/composer-prisma-cloud 0.1.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +201 -0
  2. package/dist/control.d.mts +53 -0
  3. package/dist/control.mjs +2031 -0
  4. package/dist/control.mjs.map +1 -0
  5. package/dist/cron/index.d.mts +99 -0
  6. package/dist/cron/index.mjs +392 -0
  7. package/dist/cron/index.mjs.map +1 -0
  8. package/dist/cron/scheduler-entrypoint.mjs +7769 -0
  9. package/dist/cron/scheduler-entrypoint.mjs.map +1 -0
  10. package/dist/cron/scheduler-service.mjs +318 -0
  11. package/dist/cron/scheduler-service.mjs.map +1 -0
  12. package/dist/index.d.mts +205 -0
  13. package/dist/index.mjs +182 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/dist/param-DB0B8m15-IvzNq9BM.mjs +92 -0
  16. package/dist/param-DB0B8m15-IvzNq9BM.mjs.map +1 -0
  17. package/dist/prisma-next-COrwlg3N.mjs +176 -0
  18. package/dist/prisma-next-COrwlg3N.mjs.map +1 -0
  19. package/dist/prisma-next.d.mts +71 -0
  20. package/dist/prisma-next.mjs +2 -0
  21. package/dist/serializer-DAEWRfnm-D3GW9dOZ.mjs +235 -0
  22. package/dist/serializer-DAEWRfnm-D3GW9dOZ.mjs.map +1 -0
  23. package/dist/storage/index.d.mts +55 -0
  24. package/dist/storage/index.mjs +411 -0
  25. package/dist/storage/index.mjs.map +1 -0
  26. package/dist/storage/storage-entrypoint.mjs +1173 -0
  27. package/dist/storage/storage-entrypoint.mjs.map +1 -0
  28. package/dist/storage/storage-service.mjs +377 -0
  29. package/dist/storage/storage-service.mjs.map +1 -0
  30. package/dist/storage/testing.d.mts +85 -0
  31. package/dist/storage/testing.mjs +531 -0
  32. package/dist/storage/testing.mjs.map +1 -0
  33. package/dist/streams/index.d.mts +47 -0
  34. package/dist/streams/index.mjs +450 -0
  35. package/dist/streams/index.mjs.map +1 -0
  36. package/dist/streams/streams-entrypoint.mjs +40575 -0
  37. package/dist/streams/streams-entrypoint.mjs.map +1 -0
  38. package/dist/streams/streams-service.mjs +424 -0
  39. package/dist/streams/streams-service.mjs.map +1 -0
  40. package/dist/streams/testing.d.mts +33 -0
  41. package/dist/streams/testing.mjs +31335 -0
  42. package/dist/streams/testing.mjs.map +1 -0
  43. package/dist/testing.d.mts +25 -0
  44. package/dist/testing.mjs +32 -0
  45. package/dist/testing.mjs.map +1 -0
  46. package/package.json +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.mjs","names":[],"sources":["../../../../1-prisma-cloud/2-shared-modules/storage/dist/testing.mjs"],"sourcesContent":["import { createHash, createHmac, timingSafeEqual } from \"node:crypto\";\nimport { SQL } from \"bun\";\n//#region ../../1-extensions/target/dist/pg-connection.mjs\n/** Connection resilience helpers for Prisma Postgres cold-starts (FT-5226); no heavy imports (no `effect`/`alchemy`/`pg`), so the deploy lowerings, the pnPostgres runtime client, and bun-runnable services (the storage store, via the pure `@internal/prisma-cloud/connection` subpath) all share one implementation. */\n/** Network-level socket failures node-postgres surfaces as `err.code`. */\nconst TRANSIENT_CODES = /* @__PURE__ */ new Set([\n\t\"ECONNREFUSED\",\n\t\"ECONNRESET\",\n\t\"ETIMEDOUT\",\n\t\"EPIPE\",\n\t\"ENOTFOUND\",\n\t\"EAI_AGAIN\"\n]);\n/** Connection-establishment failure messages (no useful `err.code`). */\nconst TRANSIENT_MESSAGE_FRAGMENTS = [\n\t\"upstream database\",\n\t\"connection terminated\",\n\t\"connection refused\",\n\t\"terminating connection\",\n\t\"server closed the connection\",\n\t\"connection timeout\",\n\t\"timeout expired\"\n];\n/** Whether an error is a transient connection failure worth retrying, as opposed to a real query error that must surface at once. */\nfunction isTransientConnectionError(error) {\n\tif (typeof error !== \"object\" || error === null) return false;\n\tconst code = \"code\" in error && typeof error.code === \"string\" ? error.code : void 0;\n\tif (code !== void 0 && TRANSIENT_CODES.has(code)) return true;\n\tconst message = \"message\" in error && typeof error.message === \"string\" ? error.message.toLowerCase() : \"\";\n\treturn TRANSIENT_MESSAGE_FRAGMENTS.some((fragment) => message.includes(fragment));\n}\n/**\n* Retries an operation past a transient connection failure, bounded (default\n* ~1 min). `shouldRetry` decides what's transient — defaults to retrying\n* everything; the runtime client passes {@link isTransientConnectionError}.\n*/\nasync function withConnectionRetry(operation, opts = {}) {\n\tconst attempts = opts.attempts ?? 12;\n\tconst delayMs = opts.delayMs ?? 5e3;\n\tconst sleep = opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n\tconst shouldRetry = opts.shouldRetry ?? (() => true);\n\tlet lastError;\n\tfor (let attempt = 1; attempt <= attempts; attempt++) try {\n\t\treturn await operation();\n\t} catch (error) {\n\t\tif (!shouldRetry(error)) throw error;\n\t\tlastError = error;\n\t\tif (attempt < attempts) await sleep(delayMs);\n\t}\n\tthrow lastError;\n}\n/** Retries acquiring a connection past a transient cold-start; {@link withConnectionRetry} with {@link isTransientConnectionError} fixed as the predicate. */\nfunction retryTransientConnect(acquire, opts = {}) {\n\treturn withConnectionRetry(acquire, {\n\t\t...opts,\n\t\tshouldRetry: isTransientConnectionError\n\t});\n}\n//#endregion\n//#region src/pg-store.ts\n/**\n* The `ObjectStore` over Postgres `bytea` (spec § 3): one `objects` table,\n* single-row-per-object. Ranged reads use SQL `substring` so a range request\n* never detoasts the whole object. The schema is applied idempotently at init\n* behind a bounded connection retry — the first connect to a freshly\n* provisioned Postgres is rejected while the upstream is cold (FT-5226).\n*\n* Runtime engine code (`bun` SQL + `node:crypto`); NOT re-exported from the\n* authoring barrel.\n*/\nconst DEFAULT_MAX_KEYS$1 = 1e3;\nfunction etagOf(bytes) {\n\treturn `\"${createHash(\"sha256\").update(bytes).digest(\"hex\")}\"`;\n}\n/** bytea comes back as a Node Buffer (a Uint8Array). Fail closed on anything else rather than returning wrong bytes. */\nfunction toBytes(value) {\n\tif (value instanceof Uint8Array) return value;\n\tthrow new TypeError(`expected bytea to decode as Uint8Array, got ${typeof value}`);\n}\n/** One row → GetResult (both the whole-object and ranged queries alias the payload as `bytes`; `size` is the bigint total). */\nfunction toGetResult(row) {\n\treturn {\n\t\tbytes: toBytes(row.bytes),\n\t\tetag: row.etag,\n\t\tcontentType: row.content_type,\n\t\tsize: Number(row.size)\n\t};\n}\nvar PgObjectStore = class {\n\tsql;\n\tconstructor(sql) {\n\t\tthis.sql = sql;\n\t}\n\tasync put(bucket, key, bytes, opts = {}) {\n\t\tconst etag = etagOf(bytes);\n\t\tconst contentType = opts.contentType ?? \"application/octet-stream\";\n\t\tawait this.sql`\n insert into objects (bucket, key, bytes, size, etag, content_type)\n values (${bucket}, ${key}, ${bytes}, ${bytes.byteLength}, ${etag}, ${contentType})\n on conflict (bucket, key) do update set\n bytes = excluded.bytes, size = excluded.size,\n etag = excluded.etag, content_type = excluded.content_type`;\n\t\treturn { etag };\n\t}\n\tasync get(bucket, key, opts = {}) {\n\t\tconst range = opts.range;\n\t\tif (range) {\n\t\t\tconst from = range.start + 1;\n\t\t\tconst row = (range.end === void 0 ? await this.sql`select substring(bytes from ${from}) as bytes, size, etag, content_type\n from objects where bucket = ${bucket} and key = ${key}` : await this.sql`select substring(bytes from ${from} for ${range.end - range.start + 1}) as bytes,\n size, etag, content_type\n from objects where bucket = ${bucket} and key = ${key}`)[0];\n\t\t\treturn row === void 0 ? null : toGetResult(row);\n\t\t}\n\t\tconst row = (await this.sql`select bytes, size, etag, content_type\n from objects where bucket = ${bucket} and key = ${key}`)[0];\n\t\treturn row === void 0 ? null : toGetResult(row);\n\t}\n\tasync head(bucket, key) {\n\t\tconst row = (await this.sql`select size, etag, content_type\n from objects where bucket = ${bucket} and key = ${key}`)[0];\n\t\tif (row === void 0) return null;\n\t\treturn {\n\t\t\tetag: row.etag,\n\t\t\tsize: Number(row.size),\n\t\t\tcontentType: row.content_type\n\t\t};\n\t}\n\tasync delete(bucket, key) {\n\t\tawait this.sql`delete from objects where bucket = ${bucket} and key = ${key}`;\n\t}\n\tasync list(bucket, opts = {}) {\n\t\tconst prefix = opts.prefix ?? \"\";\n\t\tconst maxKeys = opts.maxKeys ?? DEFAULT_MAX_KEYS$1;\n\t\tconst token = opts.continuationToken;\n\t\tconst limit = maxKeys + 1;\n\t\tconst keys = (token === void 0 ? await this.sql`select key from objects\n where bucket = ${bucket} and starts_with(key, ${prefix})\n order by key limit ${limit}` : await this.sql`select key from objects\n where bucket = ${bucket} and starts_with(key, ${prefix}) and key > ${token}\n order by key limit ${limit}`).map((r) => r.key);\n\t\tconst isTruncated = keys.length > maxKeys;\n\t\tconst page = isTruncated ? keys.slice(0, maxKeys) : keys;\n\t\tconst last = page.at(-1);\n\t\treturn {\n\t\t\tkeys: page,\n\t\t\tisTruncated,\n\t\t\t...isTruncated && last !== void 0 ? { nextContinuationToken: last } : {}\n\t\t};\n\t}\n};\n/**\n* Connect (FT-5219 posture: `max: 1`, short `idleTimeout`), apply the schema\n* idempotently behind the cold-start retry, and return the store.\n*/\nasync function createPgStore(url) {\n\tconst sql = new SQL({\n\t\turl,\n\t\tmax: 1,\n\t\tidleTimeout: 10\n\t});\n\tawait retryTransientConnect(() => sql`\n create table if not exists objects (\n bucket text not null,\n key text not null,\n bytes bytea not null,\n size bigint not null,\n etag text not null,\n content_type text not null,\n created_at timestamptz not null default now(),\n primary key (bucket, key)\n )`);\n\treturn new PgObjectStore(sql);\n}\n//#endregion\n//#region src/sigv4.ts\n/**\n* AWS SigV4 verification for the S3 wire protocol (spec § 2 auth). The payload\n* hash comes from the client — `x-amz-content-sha256` (a real hash or\n* `UNSIGNED-PAYLOAD`) for header auth, `UNSIGNED-PAYLOAD` for presign — and is\n* never re-hashed; the verifier trusts what was signed, like a real S3 endpoint.\n* Runtime engine code (`node:crypto`); not re-exported from the authoring barrel.\n*/\nconst ALGORITHM = \"AWS4-HMAC-SHA256\";\nconst UNSIGNED_PAYLOAD = \"UNSIGNED-PAYLOAD\";\nfunction sha256Hex(data) {\n\treturn createHash(\"sha256\").update(data).digest(\"hex\");\n}\nfunction hmac(key, data) {\n\treturn createHmac(\"sha256\", key).update(data).digest();\n}\n/** AWS canonical URI encoding: every byte except the unreserved set is %XX. */\nfunction awsUriEncode(value) {\n\treturn encodeURIComponent(value).replace(/[!'()*]/g, (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%7E/g, \"~\");\n}\nfunction parseCredential(credential) {\n\tconst parts = credential.split(\"/\");\n\tif (parts.length !== 5 || parts[4] !== \"aws4_request\") return null;\n\tconst [accessKeyId, date, region, service] = parts;\n\tif (!accessKeyId || !date || !region || !service) return null;\n\treturn {\n\t\taccessKeyId,\n\t\tdate,\n\t\tregion,\n\t\tservice\n\t};\n}\nfunction signingKey(secret, scope) {\n\treturn hmac(hmac(hmac(hmac(`AWS4${secret}`, scope.date), scope.region), scope.service), \"aws4_request\");\n}\nfunction canonicalHeaders(url, req, signedHeaders) {\n\treturn signedHeaders.map((name) => {\n\t\treturn `${name}:${(name === \"host\" ? url.host : req.headers.get(name) ?? \"\").trim().replace(/\\s+/g, \" \")}\\n`;\n\t}).join(\"\");\n}\nfunction canonicalQuery(url, exclude) {\n\tconst entries = [];\n\tfor (const [key, value] of url.searchParams.entries()) {\n\t\tif (exclude !== void 0 && key === exclude) continue;\n\t\tentries.push([awsUriEncode(key), awsUriEncode(value)]);\n\t}\n\tconst cmp = (a, b) => a < b ? -1 : a > b ? 1 : 0;\n\tentries.sort(([ak, av], [bk, bv]) => cmp(ak, bk) || cmp(av, bv));\n\treturn entries.map(([k, v]) => `${k}=${v}`).join(\"&\");\n}\nfunction stringToSign(amzDate, scope, canonicalRequest) {\n\tconst scopeString = `${scope.date}/${scope.region}/${scope.service}/aws4_request`;\n\treturn [\n\t\tALGORITHM,\n\t\tamzDate,\n\t\tscopeString,\n\t\tsha256Hex(canonicalRequest)\n\t].join(\"\\n\");\n}\nfunction signatureMatches(expected, provided) {\n\tconst a = Buffer.from(expected, \"hex\");\n\tconst b = Buffer.from(provided, \"hex\");\n\treturn a.length === b.length && a.length > 0 && timingSafeEqual(a, b);\n}\n/** `YYYYMMDDTHHMMSSZ` → epoch ms, or null when malformed. */\nfunction parseAmzDate(amzDate) {\n\tconst match = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(amzDate);\n\tif (!match) return null;\n\tconst [, y, mo, d, h, mi, s] = match;\n\treturn Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s));\n}\nfunction parseAuthorizationHeader(header) {\n\tif (!header.startsWith(`${ALGORITHM} `)) return null;\n\tconst rest = header.slice(17);\n\tconst fields = /* @__PURE__ */ new Map();\n\tfor (const part of rest.split(\",\")) {\n\t\tconst eq = part.indexOf(\"=\");\n\t\tif (eq === -1) continue;\n\t\tfields.set(part.slice(0, eq).trim(), part.slice(eq + 1).trim());\n\t}\n\tconst credential = fields.get(\"Credential\");\n\tconst signedHeaders = fields.get(\"SignedHeaders\");\n\tconst signature = fields.get(\"Signature\");\n\tif (!credential || !signedHeaders || !signature) return null;\n\treturn {\n\t\tcredential,\n\t\tsignedHeaders: signedHeaders.split(\";\"),\n\t\tsignature\n\t};\n}\n/** The one signing core both auth forms share: check the access key, rebuild the canonical request, derive the key, compare in constant time. */\nfunction verifySignature(req, url, credentials, params) {\n\tif (params.scope.accessKeyId !== credentials.accessKeyId) return {\n\t\tok: false,\n\t\treason: \"unknown access key\"\n\t};\n\tconst canonicalRequest = [\n\t\treq.method,\n\t\turl.pathname,\n\t\tcanonicalQuery(url, params.excludeQuery),\n\t\tcanonicalHeaders(url, req, params.signedHeaders),\n\t\tparams.signedHeaders.join(\";\"),\n\t\tparams.payloadHash\n\t].join(\"\\n\");\n\treturn signatureMatches(hmac(signingKey(credentials.secretAccessKey, params.scope), stringToSign(params.amzDate, params.scope, canonicalRequest)).toString(\"hex\"), params.signature) ? { ok: true } : {\n\t\tok: false,\n\t\treason: \"signature mismatch\"\n\t};\n}\nfunction verifyHeader(req, url, credentials) {\n\tconst auth = parseAuthorizationHeader(req.headers.get(\"authorization\") ?? \"\");\n\tif (!auth) return {\n\t\tok: false,\n\t\treason: \"malformed Authorization header\"\n\t};\n\tconst scope = parseCredential(auth.credential);\n\tif (!scope) return {\n\t\tok: false,\n\t\treason: \"malformed credential scope\"\n\t};\n\tconst amzDate = req.headers.get(\"x-amz-date\");\n\tif (!amzDate) return {\n\t\tok: false,\n\t\treason: \"missing x-amz-date\"\n\t};\n\tconst payloadHash = req.headers.get(\"x-amz-content-sha256\");\n\tif (!payloadHash) return {\n\t\tok: false,\n\t\treason: \"missing x-amz-content-sha256\"\n\t};\n\treturn verifySignature(req, url, credentials, {\n\t\tscope,\n\t\tamzDate,\n\t\tsignedHeaders: auth.signedHeaders,\n\t\tpayloadHash,\n\t\tsignature: auth.signature\n\t});\n}\nfunction verifyPresigned(req, url, credentials, now) {\n\tconst q = url.searchParams;\n\tif (q.get(\"X-Amz-Algorithm\") !== ALGORITHM) return {\n\t\tok: false,\n\t\treason: \"unsupported presign algorithm\"\n\t};\n\tconst credentialRaw = q.get(\"X-Amz-Credential\");\n\tconst amzDate = q.get(\"X-Amz-Date\");\n\tconst expiresRaw = q.get(\"X-Amz-Expires\");\n\tconst signedHeadersRaw = q.get(\"X-Amz-SignedHeaders\");\n\tconst signature = q.get(\"X-Amz-Signature\");\n\tif (!credentialRaw || !amzDate || !expiresRaw || !signedHeadersRaw || !signature) return {\n\t\tok: false,\n\t\treason: \"incomplete presign parameters\"\n\t};\n\tconst scope = parseCredential(credentialRaw);\n\tif (!scope) return {\n\t\tok: false,\n\t\treason: \"malformed credential scope\"\n\t};\n\tconst signedAt = parseAmzDate(amzDate);\n\tconst expires = Number(expiresRaw);\n\tif (signedAt === null || !Number.isFinite(expires)) return {\n\t\tok: false,\n\t\treason: \"malformed presign date\"\n\t};\n\tif (now.getTime() > signedAt + expires * 1e3) return {\n\t\tok: false,\n\t\treason: \"presign expired\"\n\t};\n\treturn verifySignature(req, url, credentials, {\n\t\tscope,\n\t\tamzDate,\n\t\tsignedHeaders: signedHeadersRaw.split(\";\"),\n\t\tpayloadHash: UNSIGNED_PAYLOAD,\n\t\tsignature,\n\t\texcludeQuery: \"X-Amz-Signature\"\n\t});\n}\n/**\n* Verify a request's SigV4 signature against a single credential pair. Picks\n* the presigned form when `X-Amz-Signature` is present, otherwise the\n* `Authorization`-header form. `now` is injectable for deterministic\n* expiry tests.\n*/\nfunction verifyRequest(req, credentials, now = /* @__PURE__ */ new Date()) {\n\tconst url = new URL(req.url);\n\tif (url.searchParams.has(\"X-Amz-Signature\")) return verifyPresigned(req, url, credentials, now);\n\tif (req.headers.has(\"authorization\")) return verifyHeader(req, url, credentials);\n\treturn {\n\t\tok: false,\n\t\treason: \"unsigned request\"\n\t};\n}\n//#endregion\n//#region src/handler.ts\nconst DEFAULT_CONTENT_TYPE = \"application/octet-stream\";\n/** Path-style: `/{bucket}/{key…}`. Each segment is percent-decoded. */\nfunction parseTarget(url) {\n\tconst segments = url.pathname.split(\"/\").filter((s) => s.length > 0);\n\tif (segments.length === 0) return null;\n\tconst [bucket, ...keyParts] = segments;\n\treturn {\n\t\tbucket: decodeURIComponent(bucket ?? \"\"),\n\t\tkey: keyParts.map(decodeURIComponent).join(\"/\")\n\t};\n}\n/** `bytes=a-b` (inclusive) or `bytes=a-` (open-ended). Null when absent/malformed. */\nfunction parseRange(header) {\n\tif (!header) return null;\n\tconst match = /^bytes=(\\d+)-(\\d*)$/.exec(header.trim());\n\tif (!match) return null;\n\tconst start = Number(match[1]);\n\treturn match[2] ? {\n\t\tstart,\n\t\tend: Number(match[2])\n\t} : { start };\n}\nfunction xmlEscape(value) {\n\treturn value.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&apos;\");\n}\nfunction listXml(bucket, prefix, maxKeys, result) {\n\tconst contents = result.keys.map((k) => `<Contents><Key>${xmlEscape(k)}</Key></Contents>`).join(\"\");\n\tconst next = result.isTruncated && result.nextContinuationToken !== void 0 ? `<NextContinuationToken>${xmlEscape(result.nextContinuationToken)}</NextContinuationToken>` : \"\";\n\treturn `<?xml version=\"1.0\" encoding=\"UTF-8\"?><ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>${xmlEscape(bucket)}</Name><Prefix>${xmlEscape(prefix)}</Prefix><KeyCount>${result.keys.length}</KeyCount><MaxKeys>${maxKeys}</MaxKeys><IsTruncated>${result.isTruncated}</IsTruncated>` + contents + next + \"</ListBucketResult>\";\n}\nconst DEFAULT_MAX_KEYS = 1e3;\nasync function handleList(store, bucket, url) {\n\tconst prefix = url.searchParams.get(\"prefix\") ?? \"\";\n\tconst continuationToken = url.searchParams.get(\"continuation-token\");\n\tconst maxKeysRaw = url.searchParams.get(\"max-keys\");\n\tconst maxKeys = maxKeysRaw !== null && Number.isFinite(Number(maxKeysRaw)) ? Number(maxKeysRaw) : DEFAULT_MAX_KEYS;\n\tconst result = await store.list(bucket, {\n\t\tprefix,\n\t\tmaxKeys,\n\t\t...continuationToken !== null ? { continuationToken } : {}\n\t});\n\treturn new Response(listXml(bucket, prefix, maxKeys, result), {\n\t\tstatus: 200,\n\t\theaders: { \"content-type\": \"application/xml\" }\n\t});\n}\n/** aws-chunked / flexible-checksum PUTs frame the body as chunks + a trailer (signalled by `x-amz-content-sha256: STREAMING-…` or `content-encoding: aws-chunked`); the seed signature still verifies, so reject them (501) rather than store the raw framing as the object bytes. Decoding is out of scope. */\nfunction isStreamingPut(req) {\n\tconst contentSha = req.headers.get(\"x-amz-content-sha256\") ?? \"\";\n\tconst contentEncoding = req.headers.get(\"content-encoding\") ?? \"\";\n\treturn contentSha.startsWith(\"STREAMING-\") || contentEncoding.split(\",\").some((e) => e.trim() === \"aws-chunked\");\n}\nasync function handlePut(store, t, req) {\n\tif (isStreamingPut(req)) return new Response(\"aws-chunked / flexible checksums not supported; set requestChecksumCalculation: 'WHEN_REQUIRED'\", { status: 501 });\n\tconst body = new Uint8Array(await req.arrayBuffer());\n\tconst contentType = req.headers.get(\"content-type\") ?? DEFAULT_CONTENT_TYPE;\n\tconst { etag } = await store.put(t.bucket, t.key, body, { contentType });\n\treturn new Response(null, {\n\t\tstatus: 200,\n\t\theaders: { etag }\n\t});\n}\n/** The etag/content-type/content-length/accept-ranges headers GET and HEAD share — `contentLength` is the slice length for GET, the total object size for HEAD. */\nfunction metaHeaders(meta) {\n\treturn new Headers({\n\t\tetag: meta.etag,\n\t\t\"content-type\": meta.contentType,\n\t\t\"content-length\": String(meta.contentLength),\n\t\t\"accept-ranges\": \"bytes\"\n\t});\n}\nasync function handleGet(store, t, req) {\n\tconst range = parseRange(req.headers.get(\"range\"));\n\tconst object = await store.get(t.bucket, t.key, range ? { range } : void 0);\n\tif (!object) return new Response(null, { status: 404 });\n\tconst headers = metaHeaders({\n\t\tetag: object.etag,\n\t\tcontentType: object.contentType,\n\t\tcontentLength: object.bytes.byteLength\n\t});\n\tif (!range) return new Response(object.bytes, {\n\t\tstatus: 200,\n\t\theaders\n\t});\n\tif (range.start >= object.size && object.size > 0) return new Response(null, {\n\t\tstatus: 416,\n\t\theaders: { \"content-range\": `bytes */${object.size}` }\n\t});\n\tconst end = range.end === void 0 ? object.size - 1 : Math.min(range.end, object.size - 1);\n\theaders.set(\"content-range\", `bytes ${range.start}-${end}/${object.size}`);\n\treturn new Response(object.bytes, {\n\t\tstatus: 206,\n\t\theaders\n\t});\n}\nasync function handleHead(store, t) {\n\tconst meta = await store.head(t.bucket, t.key);\n\tif (!meta) return new Response(null, { status: 404 });\n\treturn new Response(null, {\n\t\tstatus: 200,\n\t\theaders: metaHeaders({\n\t\t\tetag: meta.etag,\n\t\t\tcontentType: meta.contentType,\n\t\t\tcontentLength: meta.size\n\t\t})\n\t});\n}\nasync function handleDelete(store, t) {\n\tawait store.delete(t.bucket, t.key);\n\treturn new Response(null, { status: 204 });\n}\nfunction createS3Handler(opts) {\n\tconst { store, credentials } = opts;\n\treturn async (req) => {\n\t\tif (!verifyRequest(req, credentials).ok) return new Response(null, { status: 403 });\n\t\tconst url = new URL(req.url);\n\t\tconst target = parseTarget(url);\n\t\tif (!target) return new Response(null, { status: 400 });\n\t\tif (req.method === \"GET\" && url.searchParams.get(\"list-type\") === \"2\" && target.key === \"\") return handleList(store, target.bucket, url);\n\t\tif (target.key === \"\") return new Response(null, { status: 400 });\n\t\tswitch (req.method) {\n\t\t\tcase \"PUT\": return handlePut(store, target, req);\n\t\t\tcase \"GET\": return handleGet(store, target, req);\n\t\t\tcase \"HEAD\": return handleHead(store, target);\n\t\t\tcase \"DELETE\": return handleDelete(store, target);\n\t\t\tdefault: return new Response(null, { status: 405 });\n\t\t}\n\t};\n}\n//#endregion\n//#region src/storage-server.ts\n/**\n* Boots the S3 wire protocol on `Bun.serve` — the D2 handler over any\n* `ObjectStore`. Binds all interfaces (Compute routes external HTTP to the VM,\n* so a loopback-only listener would be unreachable). Installs the FT-5219\n* process guards so an idle Bun.SQL connection close surfaces as a logged\n* error instead of crash-looping the process on scale-to-zero.\n*\n* Runtime engine code; NOT re-exported from the authoring barrel. The D4\n* entrypoint reads deps via `load()` and calls this.\n*/\nlet guardsInstalled = false;\n/** FT-5219: keep the process alive when Bun.SQL surfaces an idle-close as an unawaited async error. Installed once. */\nfunction installProcessGuards() {\n\tif (guardsInstalled) return;\n\tguardsInstalled = true;\n\tprocess.on(\"uncaughtException\", (err) => console.error(\"uncaughtException\", err));\n\tprocess.on(\"unhandledRejection\", (err) => console.error(\"unhandledRejection\", err));\n}\nfunction startStorageServer(opts) {\n\tinstallProcessGuards();\n\tconst handler = createS3Handler({\n\t\tstore: opts.store,\n\t\tcredentials: opts.credentials\n\t});\n\tconst hostname = opts.hostname ?? \"0.0.0.0\";\n\tconst server = Bun.serve({\n\t\tport: opts.port,\n\t\thostname,\n\t\tfetch: (req) => handler(req)\n\t});\n\treturn {\n\t\turl: `http://${hostname === \"0.0.0.0\" ? \"127.0.0.1\" : hostname}:${server.port}`,\n\t\tstop: () => server.stop(true)\n\t};\n}\n//#endregion\nexport { createPgStore, startStorageServer };\n\n//# sourceMappingURL=testing.mjs.map"],"mappings":";;;;;AAKA,MAAM,kCAAkC,IAAI,IAAI;CAC/C;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;;AAED,MAAM,8BAA8B;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;AAEA,SAAS,2BAA2B,OAAO;CAC1C,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,OAAO,UAAU,SAAS,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,KAAK;CACnF,IAAI,SAAS,KAAK,KAAK,gBAAgB,IAAI,IAAI,GAAG,OAAO;CACzD,MAAM,UAAU,aAAa,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,QAAQ,YAAY,IAAI;CACxG,OAAO,4BAA4B,MAAM,aAAa,QAAQ,SAAS,QAAQ,CAAC;AACjF;;;;;;AAMA,eAAe,oBAAoB,WAAW,OAAO,CAAC,GAAG;CACxD,MAAM,WAAW,KAAK,YAAY;CAClC,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,QAAQ,KAAK,WAAW,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;CACrF,MAAM,cAAc,KAAK,sBAAsB;CAC/C,IAAI;CACJ,KAAK,IAAI,UAAU,GAAG,WAAW,UAAU,WAAW,IAAI;EACzD,OAAO,MAAM,UAAU;CACxB,SAAS,OAAO;EACf,IAAI,CAAC,YAAY,KAAK,GAAG,MAAM;EAC/B,YAAY;EACZ,IAAI,UAAU,UAAU,MAAM,MAAM,OAAO;CAC5C;CACA,MAAM;AACP;;AAEA,SAAS,sBAAsB,SAAS,OAAO,CAAC,GAAG;CAClD,OAAO,oBAAoB,SAAS;EACnC,GAAG;EACH,aAAa;CACd,CAAC;AACF;;;;;;;;;;;AAaA,MAAM,qBAAqB;AAC3B,SAAS,OAAO,OAAO;CACtB,OAAO,IAAI,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,EAAE;AAC7D;;AAEA,SAAS,QAAQ,OAAO;CACvB,IAAI,iBAAiB,YAAY,OAAO;CACxC,MAAM,IAAI,UAAU,+CAA+C,OAAO,OAAO;AAClF;;AAEA,SAAS,YAAY,KAAK;CACzB,OAAO;EACN,OAAO,QAAQ,IAAI,KAAK;EACxB,MAAM,IAAI;EACV,aAAa,IAAI;EACjB,MAAM,OAAO,IAAI,IAAI;CACtB;AACD;AACA,IAAI,gBAAgB,MAAM;CACzB;CACA,YAAY,KAAK;EAChB,KAAK,MAAM;CACZ;CACA,MAAM,IAAI,QAAQ,KAAK,OAAO,OAAO,CAAC,GAAG;EACxC,MAAM,OAAO,OAAO,KAAK;EACzB,MAAM,cAAc,KAAK,eAAe;EACxC,MAAM,KAAK,GAAG;;gBAEA,OAAO,IAAI,IAAI,IAAI,MAAM,IAAI,MAAM,WAAW,IAAI,KAAK,IAAI,YAAY;;;;EAIrF,OAAO,EAAE,KAAK;CACf;CACA,MAAM,IAAI,QAAQ,KAAK,OAAO,CAAC,GAAG;EACjC,MAAM,QAAQ,KAAK;EACnB,IAAI,OAAO;GACV,MAAM,OAAO,MAAM,QAAQ;GAC3B,MAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,GAAG,+BAA+B,KAAK;yDAChC,OAAO,aAAa,QAAQ,MAAM,KAAK,GAAG,+BAA+B,KAAK,OAAO,MAAM,MAAM,MAAM,QAAQ,EAAE;;yDAEjH,OAAO,aAAa,MAAA,CAAO;GACjF,OAAO,QAAQ,KAAK,IAAI,OAAO,YAAY,GAAG;EAC/C;EACA,MAAM,OAAO,MAAM,KAAK,GAAG;8DACiC,OAAO,aAAa,MAAA,CAAO;EACvF,OAAO,QAAQ,KAAK,IAAI,OAAO,YAAY,GAAG;CAC/C;CACA,MAAM,KAAK,QAAQ,KAAK;EACvB,MAAM,OAAO,MAAM,KAAK,GAAG;8DACiC,OAAO,aAAa,MAAA,CAAO;EACvF,IAAI,QAAQ,KAAK,GAAG,OAAO;EAC3B,OAAO;GACN,MAAM,IAAI;GACV,MAAM,OAAO,IAAI,IAAI;GACrB,aAAa,IAAI;EAClB;CACD;CACA,MAAM,OAAO,QAAQ,KAAK;EACzB,MAAM,KAAK,GAAG,sCAAsC,OAAO,aAAa;CACzE;CACA,MAAM,KAAK,QAAQ,OAAO,CAAC,GAAG;EAC7B,MAAM,SAAS,KAAK,UAAU;EAC9B,MAAM,UAAU,KAAK,WAAW;EAChC,MAAM,QAAQ,KAAK;EACnB,MAAM,QAAQ,UAAU;EACxB,MAAM,QAAQ,UAAU,KAAK,IAAI,MAAM,KAAK,GAAG;0CACP,OAAO,wBAAwB,OAAO;8CAClC,UAAU,MAAM,KAAK,GAAG;0CAC5B,OAAO,wBAAwB,OAAO,cAAc,MAAM;8CACtD,QAAA,CAAS,KAAK,MAAM,EAAE,GAAG;EACrE,MAAM,cAAc,KAAK,SAAS;EAClC,MAAM,OAAO,cAAc,KAAK,MAAM,GAAG,OAAO,IAAI;EACpD,MAAM,OAAO,KAAK,GAAG,EAAE;EACvB,OAAO;GACN,MAAM;GACN;GACA,GAAG,eAAe,SAAS,KAAK,IAAI,EAAE,uBAAuB,KAAK,IAAI,CAAC;EACxE;CACD;AACD;;;;;AAKA,eAAe,cAAc,KAAK;CACjC,MAAM,MAAM,IAAI,IAAI;EACnB;EACA,KAAK;EACL,aAAa;CACd,CAAC;CACD,MAAM,4BAA4B,GAAG;;;;;;;;;;QAU9B;CACP,OAAO,IAAI,cAAc,GAAG;AAC7B;;;;;;;;AAUA,MAAM,YAAY;AAClB,MAAM,mBAAmB;AACzB,SAAS,UAAU,MAAM;CACxB,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK;AACtD;AACA,SAAS,KAAK,KAAK,MAAM;CACxB,OAAO,WAAW,UAAU,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO;AACtD;;AAEA,SAAS,aAAa,OAAO;CAC5B,OAAO,mBAAmB,KAAK,CAAC,CAAC,QAAQ,aAAa,OAAO,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,QAAQ,QAAQ,GAAG;AACpI;AACA,SAAS,gBAAgB,YAAY;CACpC,MAAM,QAAQ,WAAW,MAAM,GAAG;CAClC,IAAI,MAAM,WAAW,KAAK,MAAM,OAAO,gBAAgB,OAAO;CAC9D,MAAM,CAAC,aAAa,MAAM,QAAQ,WAAW;CAC7C,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,OAAO;CACzD,OAAO;EACN;EACA;EACA;EACA;CACD;AACD;AACA,SAAS,WAAW,QAAQ,OAAO;CAClC,OAAO,KAAK,KAAK,KAAK,KAAK,OAAO,UAAU,MAAM,IAAI,GAAG,MAAM,MAAM,GAAG,MAAM,OAAO,GAAG,cAAc;AACvG;AACA,SAAS,iBAAiB,KAAK,KAAK,eAAe;CAClD,OAAO,cAAc,KAAK,SAAS;EAClC,OAAO,GAAG,KAAK,IAAI,SAAS,SAAS,IAAI,OAAO,IAAI,QAAQ,IAAI,IAAI,KAAK,GAAA,CAAI,KAAK,CAAC,CAAC,QAAQ,QAAQ,GAAG,EAAE;CAC1G,CAAC,CAAC,CAAC,KAAK,EAAE;AACX;AACA,SAAS,eAAe,KAAK,SAAS;CACrC,MAAM,UAAU,CAAC;CACjB,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,aAAa,QAAQ,GAAG;EACtD,IAAI,YAAY,KAAK,KAAK,QAAQ,SAAS;EAC3C,QAAQ,KAAK,CAAC,aAAa,GAAG,GAAG,aAAa,KAAK,CAAC,CAAC;CACtD;CACA,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;CAC/C,QAAQ,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,QAAQ,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC;CAC/D,OAAO,QAAQ,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG;AACrD;AACA,SAAS,aAAa,SAAS,OAAO,kBAAkB;CACvD,MAAM,cAAc,GAAG,MAAM,KAAK,GAAG,MAAM,OAAO,GAAG,MAAM,QAAQ;CACnE,OAAO;EACN;EACA;EACA;EACA,UAAU,gBAAgB;CAC3B,CAAC,CAAC,KAAK,IAAI;AACZ;AACA,SAAS,iBAAiB,UAAU,UAAU;CAC7C,MAAM,IAAI,OAAO,KAAK,UAAU,KAAK;CACrC,MAAM,IAAI,OAAO,KAAK,UAAU,KAAK;CACrC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,KAAK,gBAAgB,GAAG,CAAC;AACrE;;AAEA,SAAS,aAAa,SAAS;CAC9B,MAAM,QAAQ,iDAAiD,KAAK,OAAO;CAC3E,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK;CAC/B,OAAO,KAAK,IAAI,OAAO,CAAC,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC;AACvF;AACA,SAAS,yBAAyB,QAAQ;CACzC,IAAI,CAAC,OAAO,WAAW,GAAG,UAAU,EAAE,GAAG,OAAO;CAChD,MAAM,OAAO,OAAO,MAAM,EAAE;CAC5B,MAAM,yBAAyB,IAAI,IAAI;CACvC,KAAK,MAAM,QAAQ,KAAK,MAAM,GAAG,GAAG;EACnC,MAAM,KAAK,KAAK,QAAQ,GAAG;EAC3B,IAAI,OAAO,IAAI;EACf,OAAO,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;CAC/D;CACA,MAAM,aAAa,OAAO,IAAI,YAAY;CAC1C,MAAM,gBAAgB,OAAO,IAAI,eAAe;CAChD,MAAM,YAAY,OAAO,IAAI,WAAW;CACxC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,WAAW,OAAO;CACxD,OAAO;EACN;EACA,eAAe,cAAc,MAAM,GAAG;EACtC;CACD;AACD;;AAEA,SAAS,gBAAgB,KAAK,KAAK,aAAa,QAAQ;CACvD,IAAI,OAAO,MAAM,gBAAgB,YAAY,aAAa,OAAO;EAChE,IAAI;EACJ,QAAQ;CACT;CACA,MAAM,mBAAmB;EACxB,IAAI;EACJ,IAAI;EACJ,eAAe,KAAK,OAAO,YAAY;EACvC,iBAAiB,KAAK,KAAK,OAAO,aAAa;EAC/C,OAAO,cAAc,KAAK,GAAG;EAC7B,OAAO;CACR,CAAC,CAAC,KAAK,IAAI;CACX,OAAO,iBAAiB,KAAK,WAAW,YAAY,iBAAiB,OAAO,KAAK,GAAG,aAAa,OAAO,SAAS,OAAO,OAAO,gBAAgB,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,OAAO,SAAS,IAAI,EAAE,IAAI,KAAK,IAAI;EACrM,IAAI;EACJ,QAAQ;CACT;AACD;AACA,SAAS,aAAa,KAAK,KAAK,aAAa;CAC5C,MAAM,OAAO,yBAAyB,IAAI,QAAQ,IAAI,eAAe,KAAK,EAAE;CAC5E,IAAI,CAAC,MAAM,OAAO;EACjB,IAAI;EACJ,QAAQ;CACT;CACA,MAAM,QAAQ,gBAAgB,KAAK,UAAU;CAC7C,IAAI,CAAC,OAAO,OAAO;EAClB,IAAI;EACJ,QAAQ;CACT;CACA,MAAM,UAAU,IAAI,QAAQ,IAAI,YAAY;CAC5C,IAAI,CAAC,SAAS,OAAO;EACpB,IAAI;EACJ,QAAQ;CACT;CACA,MAAM,cAAc,IAAI,QAAQ,IAAI,sBAAsB;CAC1D,IAAI,CAAC,aAAa,OAAO;EACxB,IAAI;EACJ,QAAQ;CACT;CACA,OAAO,gBAAgB,KAAK,KAAK,aAAa;EAC7C;EACA;EACA,eAAe,KAAK;EACpB;EACA,WAAW,KAAK;CACjB,CAAC;AACF;AACA,SAAS,gBAAgB,KAAK,KAAK,aAAa,KAAK;CACpD,MAAM,IAAI,IAAI;CACd,IAAI,EAAE,IAAI,iBAAiB,MAAM,WAAW,OAAO;EAClD,IAAI;EACJ,QAAQ;CACT;CACA,MAAM,gBAAgB,EAAE,IAAI,kBAAkB;CAC9C,MAAM,UAAU,EAAE,IAAI,YAAY;CAClC,MAAM,aAAa,EAAE,IAAI,eAAe;CACxC,MAAM,mBAAmB,EAAE,IAAI,qBAAqB;CACpD,MAAM,YAAY,EAAE,IAAI,iBAAiB;CACzC,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,cAAc,CAAC,oBAAoB,CAAC,WAAW,OAAO;EACxF,IAAI;EACJ,QAAQ;CACT;CACA,MAAM,QAAQ,gBAAgB,aAAa;CAC3C,IAAI,CAAC,OAAO,OAAO;EAClB,IAAI;EACJ,QAAQ;CACT;CACA,MAAM,WAAW,aAAa,OAAO;CACrC,MAAM,UAAU,OAAO,UAAU;CACjC,IAAI,aAAa,QAAQ,CAAC,OAAO,SAAS,OAAO,GAAG,OAAO;EAC1D,IAAI;EACJ,QAAQ;CACT;CACA,IAAI,IAAI,QAAQ,IAAI,WAAW,UAAU,KAAK,OAAO;EACpD,IAAI;EACJ,QAAQ;CACT;CACA,OAAO,gBAAgB,KAAK,KAAK,aAAa;EAC7C;EACA;EACA,eAAe,iBAAiB,MAAM,GAAG;EACzC,aAAa;EACb;EACA,cAAc;CACf,CAAC;AACF;;;;;;;AAOA,SAAS,cAAc,KAAK,aAAa,sBAAsB,IAAI,KAAK,GAAG;CAC1E,MAAM,MAAM,IAAI,IAAI,IAAI,GAAG;CAC3B,IAAI,IAAI,aAAa,IAAI,iBAAiB,GAAG,OAAO,gBAAgB,KAAK,KAAK,aAAa,GAAG;CAC9F,IAAI,IAAI,QAAQ,IAAI,eAAe,GAAG,OAAO,aAAa,KAAK,KAAK,WAAW;CAC/E,OAAO;EACN,IAAI;EACJ,QAAQ;CACT;AACD;AAGA,MAAM,uBAAuB;;AAE7B,SAAS,YAAY,KAAK;CACzB,MAAM,WAAW,IAAI,SAAS,MAAM,GAAG,CAAC,CAAC,QAAQ,MAAM,EAAE,SAAS,CAAC;CACnE,IAAI,SAAS,WAAW,GAAG,OAAO;CAClC,MAAM,CAAC,QAAQ,GAAG,YAAY;CAC9B,OAAO;EACN,QAAQ,mBAAmB,UAAU,EAAE;EACvC,KAAK,SAAS,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;CAC/C;AACD;;AAEA,SAAS,WAAW,QAAQ;CAC3B,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,QAAQ,sBAAsB,KAAK,OAAO,KAAK,CAAC;CACtD,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,QAAQ,OAAO,MAAM,EAAE;CAC7B,OAAO,MAAM,KAAK;EACjB;EACA,KAAK,OAAO,MAAM,EAAE;CACrB,IAAI,EAAE,MAAM;AACb;AACA,SAAS,UAAU,OAAO;CACzB,OAAO,MAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,QAAQ,CAAC,CAAC,QAAQ,MAAM,QAAQ;AAC/H;AACA,SAAS,QAAQ,QAAQ,QAAQ,SAAS,QAAQ;CACjD,MAAM,WAAW,OAAO,KAAK,KAAK,MAAM,kBAAkB,UAAU,CAAC,EAAE,kBAAkB,CAAC,CAAC,KAAK,EAAE;CAClG,MAAM,OAAO,OAAO,eAAe,OAAO,0BAA0B,KAAK,IAAI,0BAA0B,UAAU,OAAO,qBAAqB,EAAE,4BAA4B;CAC3K,OAAO,iHAAiH,UAAU,MAAM,EAAE,iBAAiB,UAAU,MAAM,EAAE,qBAAqB,OAAO,KAAK,OAAO,sBAAsB,QAAQ,yBAAyB,OAAO,YAAY,kBAAkB,WAAW,OAAO;AACpU;AACA,MAAM,mBAAmB;AACzB,eAAe,WAAW,OAAO,QAAQ,KAAK;CAC7C,MAAM,SAAS,IAAI,aAAa,IAAI,QAAQ,KAAK;CACjD,MAAM,oBAAoB,IAAI,aAAa,IAAI,oBAAoB;CACnE,MAAM,aAAa,IAAI,aAAa,IAAI,UAAU;CAClD,MAAM,UAAU,eAAe,QAAQ,OAAO,SAAS,OAAO,UAAU,CAAC,IAAI,OAAO,UAAU,IAAI;CAClG,MAAM,SAAS,MAAM,MAAM,KAAK,QAAQ;EACvC;EACA;EACA,GAAG,sBAAsB,OAAO,EAAE,kBAAkB,IAAI,CAAC;CAC1D,CAAC;CACD,OAAO,IAAI,SAAS,QAAQ,QAAQ,QAAQ,SAAS,MAAM,GAAG;EAC7D,QAAQ;EACR,SAAS,EAAE,gBAAgB,kBAAkB;CAC9C,CAAC;AACF;;AAEA,SAAS,eAAe,KAAK;CAC5B,MAAM,aAAa,IAAI,QAAQ,IAAI,sBAAsB,KAAK;CAC9D,MAAM,kBAAkB,IAAI,QAAQ,IAAI,kBAAkB,KAAK;CAC/D,OAAO,WAAW,WAAW,YAAY,KAAK,gBAAgB,MAAM,GAAG,CAAC,CAAC,MAAM,MAAM,EAAE,KAAK,MAAM,aAAa;AAChH;AACA,eAAe,UAAU,OAAO,GAAG,KAAK;CACvC,IAAI,eAAe,GAAG,GAAG,OAAO,IAAI,SAAS,mGAAmG,EAAE,QAAQ,IAAI,CAAC;CAC/J,MAAM,OAAO,IAAI,WAAW,MAAM,IAAI,YAAY,CAAC;CACnD,MAAM,cAAc,IAAI,QAAQ,IAAI,cAAc,KAAK;CACvD,MAAM,EAAE,SAAS,MAAM,MAAM,IAAI,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,YAAY,CAAC;CACvE,OAAO,IAAI,SAAS,MAAM;EACzB,QAAQ;EACR,SAAS,EAAE,KAAK;CACjB,CAAC;AACF;;AAEA,SAAS,YAAY,MAAM;CAC1B,OAAO,IAAI,QAAQ;EAClB,MAAM,KAAK;EACX,gBAAgB,KAAK;EACrB,kBAAkB,OAAO,KAAK,aAAa;EAC3C,iBAAiB;CAClB,CAAC;AACF;AACA,eAAe,UAAU,OAAO,GAAG,KAAK;CACvC,MAAM,QAAQ,WAAW,IAAI,QAAQ,IAAI,OAAO,CAAC;CACjD,MAAM,SAAS,MAAM,MAAM,IAAI,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,IAAI,KAAK,CAAC;CAC1E,IAAI,CAAC,QAAQ,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;CACtD,MAAM,UAAU,YAAY;EAC3B,MAAM,OAAO;EACb,aAAa,OAAO;EACpB,eAAe,OAAO,MAAM;CAC7B,CAAC;CACD,IAAI,CAAC,OAAO,OAAO,IAAI,SAAS,OAAO,OAAO;EAC7C,QAAQ;EACR;CACD,CAAC;CACD,IAAI,MAAM,SAAS,OAAO,QAAQ,OAAO,OAAO,GAAG,OAAO,IAAI,SAAS,MAAM;EAC5E,QAAQ;EACR,SAAS,EAAE,iBAAiB,WAAW,OAAO,OAAO;CACtD,CAAC;CACD,MAAM,MAAM,MAAM,QAAQ,KAAK,IAAI,OAAO,OAAO,IAAI,KAAK,IAAI,MAAM,KAAK,OAAO,OAAO,CAAC;CACxF,QAAQ,IAAI,iBAAiB,SAAS,MAAM,MAAM,GAAG,IAAI,GAAG,OAAO,MAAM;CACzE,OAAO,IAAI,SAAS,OAAO,OAAO;EACjC,QAAQ;EACR;CACD,CAAC;AACF;AACA,eAAe,WAAW,OAAO,GAAG;CACnC,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG;CAC7C,IAAI,CAAC,MAAM,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;CACpD,OAAO,IAAI,SAAS,MAAM;EACzB,QAAQ;EACR,SAAS,YAAY;GACpB,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,eAAe,KAAK;EACrB,CAAC;CACF,CAAC;AACF;AACA,eAAe,aAAa,OAAO,GAAG;CACrC,MAAM,MAAM,OAAO,EAAE,QAAQ,EAAE,GAAG;CAClC,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAC1C;AACA,SAAS,gBAAgB,MAAM;CAC9B,MAAM,EAAE,OAAO,gBAAgB;CAC/B,OAAO,OAAO,QAAQ;EACrB,IAAI,CAAC,cAAc,KAAK,WAAW,CAAC,CAAC,IAAI,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;EAClF,MAAM,MAAM,IAAI,IAAI,IAAI,GAAG;EAC3B,MAAM,SAAS,YAAY,GAAG;EAC9B,IAAI,CAAC,QAAQ,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;EACtD,IAAI,IAAI,WAAW,SAAS,IAAI,aAAa,IAAI,WAAW,MAAM,OAAO,OAAO,QAAQ,IAAI,OAAO,WAAW,OAAO,OAAO,QAAQ,GAAG;EACvI,IAAI,OAAO,QAAQ,IAAI,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;EAChE,QAAQ,IAAI,QAAZ;GACC,KAAK,OAAO,OAAO,UAAU,OAAO,QAAQ,GAAG;GAC/C,KAAK,OAAO,OAAO,UAAU,OAAO,QAAQ,GAAG;GAC/C,KAAK,QAAQ,OAAO,WAAW,OAAO,MAAM;GAC5C,KAAK,UAAU,OAAO,aAAa,OAAO,MAAM;GAChD,SAAS,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;EACnD;CACD;AACD;;;;;;;;;;;AAaA,IAAI,kBAAkB;;AAEtB,SAAS,uBAAuB;CAC/B,IAAI,iBAAiB;CACrB,kBAAkB;CAClB,QAAQ,GAAG,sBAAsB,QAAQ,QAAQ,MAAM,qBAAqB,GAAG,CAAC;CAChF,QAAQ,GAAG,uBAAuB,QAAQ,QAAQ,MAAM,sBAAsB,GAAG,CAAC;AACnF;AACA,SAAS,mBAAmB,MAAM;CACjC,qBAAqB;CACrB,MAAM,UAAU,gBAAgB;EAC/B,OAAO,KAAK;EACZ,aAAa,KAAK;CACnB,CAAC;CACD,MAAM,WAAW,KAAK,YAAY;CAClC,MAAM,SAAS,IAAI,MAAM;EACxB,MAAM,KAAK;EACX;EACA,QAAQ,QAAQ,QAAQ,GAAG;CAC5B,CAAC;CACD,OAAO;EACN,KAAK,UAAU,aAAa,YAAY,cAAc,SAAS,GAAG,OAAO;EACzE,YAAY,OAAO,KAAK,IAAI;CAC7B;AACD"}
@@ -0,0 +1,47 @@
1
+ import { Contract, DependencyEnd, ModuleNode, SecretNeed } from "@prisma/composer";
2
+ //#region ../../1-prisma-cloud/2-shared-modules/storage/dist/storage-service-CTRaaF2H.d.mts
3
+ //#region src/contract.d.ts
4
+ interface S3Config {
5
+ readonly url: string;
6
+ readonly bucket: string;
7
+ readonly accessKeyId: string;
8
+ readonly secretAccessKey: string;
9
+ }
10
+ declare const s3Contract: Contract<'s3', S3Config>;
11
+ type S3Contract = typeof s3Contract;
12
+ //#endregion
13
+ //#region ../../1-prisma-cloud/2-shared-modules/streams/dist/streams-service-CBgfFpQj.d.mts
14
+ //#region src/contract.d.ts
15
+ interface StreamsConfig {
16
+ readonly url: string;
17
+ }
18
+ declare const streamsContract: Contract<'streams', StreamsConfig>;
19
+ type StreamsContract = typeof streamsContract;
20
+ /** A consumer's dependency on a durable-streams server. */
21
+ declare function durableStreams(): DependencyEnd<StreamsConfig, typeof streamsContract>;
22
+ //#endregion
23
+ //#region src/streams-service.d.ts
24
+ declare function streamsService(): import("@prisma/composer").RunnableServiceNode<{
25
+ store: import("@prisma/composer").DependencyEnd<S3Config, import("@prisma/composer").Contract<"s3", S3Config>>;
26
+ }, Record<never, never> & {
27
+ readonly port: import("@prisma/composer").ConfigParam<import("@standard-schema/spec").StandardSchemaV1<number, number>>;
28
+ }, {
29
+ streams: import("@prisma/composer").Contract<"streams", StreamsConfig>;
30
+ }, {
31
+ apiKey: import("@prisma/composer").SecretNeed;
32
+ }>;
33
+ //#endregion
34
+ //#region ../../1-prisma-cloud/2-shared-modules/streams/dist/index.d.mts
35
+ //#region src/streams-module.d.ts
36
+ declare function streams(opts?: {
37
+ name?: string;
38
+ }): ModuleNode<{
39
+ store: DependencyEnd<S3Config, S3Contract>;
40
+ }, {
41
+ streams: typeof streamsContract;
42
+ }, {
43
+ apiKey: SecretNeed;
44
+ }>;
45
+ //#endregion
46
+ export { type StreamsConfig, type StreamsContract, durableStreams, streams, streamsContract, streamsService };
47
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,450 @@
1
+ import { dependency, hydrateSecrets, hydrateSync, module, number, resource, secret, service, string } from "@prisma/composer";
2
+ import { blindCast } from "@prisma/composer/casts";
3
+ import "@prisma/composer/rpc";
4
+ import node from "@prisma/composer/node";
5
+ blindCast(Symbol.for("prisma:prisma-cloud-secret-source"));
6
+ /**
7
+ * Walks a node's own params, then each dependency input's connection params —
8
+ * the same enumeration order `configOf` uses, but carrying the raw
9
+ * `ConfigParam` (with its `serialize`/`deserialize`) instead of a pure-data
10
+ * projection.
11
+ */
12
+ function paramEntries(node) {
13
+ const entries = [];
14
+ for (const [input, value] of Object.entries(node.inputs)) {
15
+ if (typeof value !== "object" || value === null) continue;
16
+ const params = blindCast(value).connection.params;
17
+ for (const [name, param] of Object.entries(params)) entries.push({
18
+ owner: { input },
19
+ name,
20
+ param
21
+ });
22
+ }
23
+ for (const [name, param] of Object.entries(node.params)) entries.push({
24
+ owner: "service",
25
+ name,
26
+ param
27
+ });
28
+ return entries;
29
+ }
30
+ const configKey = (address, d) => {
31
+ const segments = address.split(".").filter((s) => s.length > 0);
32
+ const owner = d.owner === "service" ? [] : [d.owner.input];
33
+ return [
34
+ "COMPOSER",
35
+ ...segments,
36
+ ...owner,
37
+ d.name
38
+ ].join("_").toUpperCase();
39
+ };
40
+ /**
41
+ * Typed value → its stored string. Service-own literals are JSON-encoded; a
42
+ * dependency-input value is a provisioning ref at deploy (and a resolved
43
+ * string at boot) and passes through untouched — LANDMINE: JSON-encoding it
44
+ * would break the ordering edge Alchemy resolves through it.
45
+ */
46
+ function encode(owner, value) {
47
+ return owner === "service" ? JSON.stringify(value) : blindCast(value);
48
+ }
49
+ /** Reverses `encode`: JSON-parse a service-own value, take a dependency-input value raw. */
50
+ function decode(owner, raw) {
51
+ return owner === "service" ? JSON.parse(raw) : raw;
52
+ }
53
+ const PARAM_POINTER_PREFIX = "@composer-param-pointer:";
54
+ /** True iff `raw` is a param pointer row (as opposed to a JSON-encoded literal). */
55
+ const isParamPointerRow = (raw) => raw.startsWith(PARAM_POINTER_PREFIX);
56
+ /** Reverses `encodeParamPointer`: the platform var NAME a pointer row points to. */
57
+ const decodeParamPointer = (raw) => raw.slice(24);
58
+ function coerce(raw, d, key) {
59
+ if (!(raw !== void 0 && raw !== "")) {
60
+ if (d.param.default !== void 0) return d.param.default;
61
+ if (d.param.optional === true) return void 0;
62
+ throw new Error(`missing required config param "${d.name}" (env ${key})`);
63
+ }
64
+ if (d.owner === "service" && isParamPointerRow(raw)) return coerceEnvSourcedParam(raw, d, key);
65
+ try {
66
+ return standardValidateSync(d.param.schema, decode(d.owner, raw));
67
+ } catch (cause) {
68
+ const message = cause instanceof Error ? cause.message : String(cause);
69
+ throw new Error(`invalid value for config param "${d.name}" (env ${key}): ${message}`);
70
+ }
71
+ }
72
+ /**
73
+ * Boot resolution for an env-sourced param: double-lookup (pointer → platform
74
+ * var), then the param's own schema on the raw string — no JSON decode, and
75
+ * no redaction (it's config, not a secret). An UNSET platform var is a loud
76
+ * boot failure naming both the param and the platform var; an EMPTY string is
77
+ * not special-cased here — it reaches the schema like any other value, so it
78
+ * passes iff the schema accepts it (deliberately unlike a literal param's own
79
+ * ""-means-absent rule, and unlike a secret's non-empty requirement).
80
+ */
81
+ function coerceEnvSourcedParam(raw, d, key) {
82
+ const platformVar = decodeParamPointer(raw);
83
+ const value = process.env[platformVar];
84
+ if (value === void 0) throw new Error(`env-sourced config param "${d.name}" (env ${key} → ${platformVar}) is unset: the platform variable "${platformVar}" was not injected — the deploy did not provision it.`);
85
+ try {
86
+ return standardValidateSync(d.param.schema, value);
87
+ } catch (cause) {
88
+ const message = cause instanceof Error ? cause.message : String(cause);
89
+ throw new Error(`invalid value for env-sourced config param "${d.name}" (env ${key} → ${platformVar}): ${message}`);
90
+ }
91
+ }
92
+ /**
93
+ * Boot: read each declared param from env by its key, reverse the param's own
94
+ * serialization (missing/invalid fails loudly), assemble the typed Config.
95
+ * Secrets ride a separate channel (deserializeSecrets), not this one.
96
+ */
97
+ const deserialize = (node, address) => {
98
+ const service = {};
99
+ const inputs = {};
100
+ for (const d of paramEntries(node)) {
101
+ const key = configKey(address, d);
102
+ const value = coerce(process.env[key], d, key);
103
+ if (d.owner === "service") service[d.name] = value;
104
+ else {
105
+ let bucket = inputs[d.owner.input];
106
+ if (bucket === void 0) {
107
+ bucket = {};
108
+ inputs[d.owner.input] = bucket;
109
+ }
110
+ bucket[d.name] = value;
111
+ }
112
+ }
113
+ return {
114
+ service,
115
+ inputs
116
+ };
117
+ };
118
+ /**
119
+ * run()'s setup step: write the resolved config to the environment under
120
+ * address-free keys (configKey("", d) + each serialize suffix), which load()
121
+ * reads back with no address. Uses env, not a module variable, because a
122
+ * framework may fork worker processes that inherit env but not memory.
123
+ * Writes only these keys; nothing else is touched.
124
+ */
125
+ const stash = (node, config) => {
126
+ for (const d of paramEntries(node)) {
127
+ const value = d.owner === "service" ? config.service[d.name] : config.inputs[d.owner.input]?.[d.name];
128
+ if (value === void 0) continue;
129
+ process.env[configKey("", d)] = encode(d.owner, value);
130
+ }
131
+ };
132
+ /** The pointer-row key for a secret slot: COMPOSER_<addr>_<slot> (secrets are service-level). */
133
+ const secretKey = (address, slot) => configKey(address, {
134
+ owner: "service",
135
+ name: slot
136
+ });
137
+ /**
138
+ * Boot: resolve every secret slot to its value by double-lookup — read the
139
+ * pointer key (the platform NAME), then read that platform var. A missing
140
+ * pointer or a missing/empty platform value is a loud failure naming both keys.
141
+ * Returns a plain Record for core's `hydrateSecrets` to box.
142
+ */
143
+ const deserializeSecrets = (node, address) => {
144
+ const values = {};
145
+ for (const slot of Object.keys(node.secretSlots)) {
146
+ const key = secretKey(address, slot);
147
+ const name = process.env[key];
148
+ if (name === void 0 || name === "") throw new Error(`missing secret pointer for slot "${slot}" (env ${key}) — the deploy did not write it.`);
149
+ const value = process.env[name];
150
+ if (value === void 0 || value === "") throw new Error(`secret "${slot}" is not provisioned (env ${key} → ${name}): the platform var "${name}" is unset or empty.`);
151
+ values[slot] = value;
152
+ }
153
+ return values;
154
+ };
155
+ /**
156
+ * run()'s setup step for secrets: re-emit each slot's pointer NAME under its
157
+ * address-free key, so the address-free `deserializeSecrets` double-looks-up
158
+ * identically. Never the value — the value stays only in the platform var.
159
+ */
160
+ const stashSecrets = (node, address) => {
161
+ for (const slot of Object.keys(node.secretSlots)) {
162
+ const name = process.env[secretKey(address, slot)];
163
+ if (name === void 0) continue;
164
+ process.env[secretKey("", slot)] = name;
165
+ }
166
+ };
167
+ /** Synchronous Standard Schema validation — see the matching note in core's `config.ts`. */
168
+ function standardValidateSync(schema, value) {
169
+ const result = schema["~standard"].validate(value);
170
+ if (result instanceof Promise) throw new Error("config param schema validation must be synchronous — async Standard Schema validators are not supported for config params");
171
+ if (result.issues !== void 0) throw new Error(`config param validation failed: ${result.issues.map((issue) => issue.message).join("; ")}`);
172
+ return result.value;
173
+ }
174
+ //#endregion
175
+ //#region ../../1-prisma-cloud/1-extensions/target/dist/param-DB0B8m15.mjs
176
+ /** The reserved accepted-keys env var: COMPOSER_<addr>_RPC_ACCEPTED_KEYS ("" ↦ @internal/rpc's RPC_ACCEPTED_KEYS_ENV). */
177
+ const serviceKeyEnvName = (address) => configKey(address, {
178
+ owner: "service",
179
+ name: "RPC_ACCEPTED_KEYS"
180
+ });
181
+ blindCast(Symbol.for("prisma:prisma-cloud-param-source"));
182
+ //#endregion
183
+ //#region ../../1-prisma-cloud/1-extensions/target/dist/index.mjs
184
+ const reservedParams = { port: number({ default: 3e3 }) };
185
+ /**
186
+ * A Prisma Compute service — declarations only (deps + params + build + the
187
+ * ports it exposes), no descriptor. `params` merges with the reserved
188
+ * `ReservedParams` (`port`); a user param whose name collides with a reserved
189
+ * one fails at authoring, the same way a colliding dependency name does.
190
+ * Returns the extension's runnable/loadable node:
191
+ * · run(address, boot) — the process controller: deserialize the platform
192
+ * environment (keyed off `address`, the extension's ONE env read) into a
193
+ * typed Config, re-emit it under address-free process-local stash keys,
194
+ * then call boot() to start the app's entry.
195
+ * · load() / config() — called from inside the app's entry: read the stash;
196
+ * load() hydrates + memoizes the deps, config() returns the typed params.
197
+ * Separate accessors so a dep and a param never share a namespace (ADR-0021).
198
+ *
199
+ * `service()`'s underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
200
+ * the control-plane registry key `prisma-composer deploy` resolves through the
201
+ * app's `prisma-composer.config.ts` (ADR-0017). This module loads nothing at
202
+ * deploy time; nodes are pure data.
203
+ */
204
+ const compute = (def) => {
205
+ const userParams = def.params ?? blindCast({});
206
+ for (const reserved of Object.keys(reservedParams)) {
207
+ if (reserved in def.deps) throw new Error(`compute(): dependency "${reserved}" collides with the reserved service param of the same name — rename the dependency.`);
208
+ if (reserved in userParams) throw new Error(`compute(): param "${reserved}" collides with the reserved service param of the same name — rename the param.`);
209
+ }
210
+ const params = blindCast({
211
+ ...userParams,
212
+ ...reservedParams
213
+ });
214
+ const node = service({
215
+ name: def.name,
216
+ extension: "@prisma/composer-prisma-cloud",
217
+ type: "compute",
218
+ inputs: def.deps,
219
+ params,
220
+ ...def.secrets !== void 0 ? { secrets: def.secrets } : {},
221
+ build: def.build,
222
+ ...def.expose !== void 0 ? { expose: def.expose } : {}
223
+ });
224
+ let resolved;
225
+ let loadedDeps;
226
+ let loadedParams;
227
+ let loadedSecrets;
228
+ function processConfig() {
229
+ if (resolved === void 0) resolved = deserialize(node, "");
230
+ return resolved;
231
+ }
232
+ const runnable = {
233
+ ...node,
234
+ async run(address, boot) {
235
+ const config = deserialize(node, address);
236
+ stash(node, config);
237
+ stashSecrets(node, address);
238
+ const accepted = process.env[serviceKeyEnvName(address)];
239
+ if (accepted !== void 0) process.env[serviceKeyEnvName("")] = accepted;
240
+ const port = config.service["port"];
241
+ if (typeof port === "number") process.env["PORT"] = String(port);
242
+ return boot();
243
+ },
244
+ load() {
245
+ if (loadedDeps === void 0) loadedDeps = blindCast(hydrateSync(node, processConfig()));
246
+ return loadedDeps;
247
+ },
248
+ config() {
249
+ if (loadedParams === void 0) loadedParams = blindCast(processConfig().service);
250
+ return loadedParams;
251
+ },
252
+ secrets() {
253
+ if (loadedSecrets === void 0) loadedSecrets = blindCast(hydrateSecrets(node, deserializeSecrets(node, "")));
254
+ return loadedSecrets;
255
+ }
256
+ };
257
+ return Object.freeze(blindCast(runnable));
258
+ };
259
+ /**
260
+ * The contract a Postgres provides — and the contract its consumers require.
261
+ * `satisfies` compares KIND, not identity: an extension module can be duplicated
262
+ * across a workspace (same rationale as the Symbol.for node brand), and every
263
+ * duplicate's contract must still satisfy. `__cmp` is the connection config a
264
+ * postgres offers; core never inspects it.
265
+ */
266
+ const postgresContract = Object.freeze({
267
+ kind: "postgres",
268
+ __cmp: { url: "" },
269
+ satisfies: (required) => required.kind === "postgres"
270
+ });
271
+ function postgres(opts) {
272
+ if (opts?.name !== void 0) return resource({
273
+ name: opts.name,
274
+ extension: "@prisma/composer-prisma-cloud",
275
+ provides: postgresContract
276
+ });
277
+ return dependency({
278
+ type: "postgres",
279
+ connection: {
280
+ params: { url: string() },
281
+ hydrate: (v) => v
282
+ },
283
+ required: postgresContract
284
+ });
285
+ }
286
+ /**
287
+ * The contract the `s3-credentials` resource provides — a minted SigV4 key
288
+ * pair. `satisfies` compares KIND only (mirrors `postgresContract`); `__cmp` is
289
+ * the config the resource offers, which core never inspects.
290
+ */
291
+ const credentialsContract = Object.freeze({
292
+ kind: "credentials",
293
+ __cmp: {
294
+ accessKeyId: "",
295
+ secretAccessKey: ""
296
+ },
297
+ satisfies: (required) => required.kind === "credentials"
298
+ });
299
+ function s3Credentials(opts) {
300
+ if (opts?.name !== void 0) return resource({
301
+ name: opts.name,
302
+ extension: "@prisma/composer-prisma-cloud",
303
+ provides: credentialsContract
304
+ });
305
+ return dependency({
306
+ type: "credentials",
307
+ connection: {
308
+ params: {
309
+ accessKeyId: string(),
310
+ secretAccessKey: string()
311
+ },
312
+ hydrate: (v) => v
313
+ },
314
+ required: credentialsContract
315
+ });
316
+ }
317
+ /**
318
+ * The storage service authoring factory — a `compute` service routed to the
319
+ * `s3-store` lowering instead of `compute`'s. It is exactly `compute`'s
320
+ * runnable (run/load/config, deps, params, build, expose) with the routing
321
+ * `type` overridden to `'s3-store'`: nothing at runtime keys off `type` (the
322
+ * serializer keys off the deployment address and each param's owner/name, and
323
+ * `load`/`config` off deps/params), so only the deploy-time descriptor lookup
324
+ * sees the override and routes to the extended-output lowering (§ 5). The
325
+ * return type is compute's exactly (including the reserved `port` param). The
326
+ * storage module (D4b) calls this with its `db`/`credentials` deps, a `bucket`
327
+ * param, and `expose: { store: s3Contract }`.
328
+ */
329
+ function s3StoreService(def) {
330
+ const node = compute(def);
331
+ return Object.freeze(blindCast({
332
+ ...node,
333
+ type: "s3-store"
334
+ }));
335
+ }
336
+ //#endregion
337
+ //#region ../../1-prisma-cloud/2-shared-modules/storage/dist/storage-service-DSaZsAC4.mjs
338
+ const s3Contract = Object.freeze({
339
+ kind: "s3",
340
+ __cmp: {
341
+ url: "",
342
+ bucket: "",
343
+ accessKeyId: "",
344
+ secretAccessKey: ""
345
+ },
346
+ satisfies: (required) => required.kind === "s3"
347
+ });
348
+ /**
349
+ * A consumer's dependency on an S3-compatible store. No `region` in the
350
+ * binding — the server accepts whatever region string the client signed.
351
+ */
352
+ function s3() {
353
+ return dependency({
354
+ type: "s3",
355
+ connection: {
356
+ params: {
357
+ url: string(),
358
+ bucket: string(),
359
+ accessKeyId: string(),
360
+ secretAccessKey: string()
361
+ },
362
+ hydrate: (v) => v
363
+ },
364
+ required: s3Contract
365
+ });
366
+ }
367
+ /**
368
+ * The storage service node (like cron's `scheduler.ts` + `scheduler-service.ts`
369
+ * combined): `storageService` builds the `s3-store` service — a Postgres `db`
370
+ * dependency, a minted `credentials` dependency, a `bucket` param, and the
371
+ * `store` port exposing `s3Contract`. The deploy bootstrap runs the
372
+ * default-exported bare node (`main.run(address, boot)`); the real bucket comes
373
+ * from serialized config at runtime, so the default's `bucket` is only a
374
+ * placeholder — exactly like `scheduler-service.ts` default-exports
375
+ * `cronScheduler({ jobs: [] })`.
376
+ */
377
+ function storageService(opts) {
378
+ return s3StoreService({
379
+ name: "storage",
380
+ deps: {
381
+ db: postgres(),
382
+ credentials: s3Credentials()
383
+ },
384
+ params: { bucket: string({ default: opts.bucket }) },
385
+ build: node({
386
+ module: new URL("./storage-service.mjs", import.meta.url).href,
387
+ entry: "./storage-entrypoint.mjs"
388
+ }),
389
+ expose: { store: s3Contract }
390
+ });
391
+ }
392
+ storageService({ bucket: "storage" });
393
+ //#endregion
394
+ //#region ../../1-prisma-cloud/2-shared-modules/streams/dist/streams-service-Dx0z-whA.mjs
395
+ const streamsContract = Object.freeze({
396
+ kind: "streams",
397
+ __cmp: { url: "" },
398
+ satisfies: (required) => required.kind === "streams"
399
+ });
400
+ /** A consumer's dependency on a durable-streams server. */
401
+ function durableStreams() {
402
+ return dependency({
403
+ type: "streams",
404
+ connection: {
405
+ params: { url: string() },
406
+ hydrate: (v) => v
407
+ },
408
+ required: streamsContract
409
+ });
410
+ }
411
+ /**
412
+ * The streams service node: a plain `compute` service (no lowering extension —
413
+ * the contract binding is `{ url }`, which compute's deploy outputs already
414
+ * carry). It declares the `store` dependency (`s3()`, the storage module's
415
+ * port), the `apiKey` secret slot, and the `streams` expose. The deploy
416
+ * bootstrap runs the default-exported bare node; the real wiring arrives
417
+ * through serialized config at runtime — exactly like `storage-service.ts`.
418
+ */
419
+ function streamsService() {
420
+ return compute({
421
+ name: "streams",
422
+ deps: { store: s3() },
423
+ secrets: { apiKey: secret() },
424
+ build: node({
425
+ module: new URL("./streams-service.mjs", import.meta.url).href,
426
+ entry: "./streams-entrypoint.mjs"
427
+ }),
428
+ expose: { streams: streamsContract }
429
+ });
430
+ }
431
+ streamsService();
432
+ //#endregion
433
+ //#region ../../1-prisma-cloud/2-shared-modules/streams/dist/index.mjs
434
+ function streams(opts) {
435
+ return module(opts?.name ?? "streams", {
436
+ deps: { store: s3() },
437
+ secrets: { apiKey: secret() },
438
+ expose: { streams: streamsContract }
439
+ }, ({ inputs, secrets, provision }) => {
440
+ return { streams: provision(streamsService(), {
441
+ id: "service",
442
+ deps: { store: inputs.store },
443
+ secrets: { apiKey: secrets.apiKey }
444
+ }).streams };
445
+ });
446
+ }
447
+ //#endregion
448
+ export { durableStreams, streams, streamsContract, streamsService };
449
+
450
+ //# sourceMappingURL=index.mjs.map