@prisma/composer-prisma-cloud 0.1.0-dev.9 → 0.2.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.
- package/dist/control.d.mts +40 -34
- package/dist/control.mjs +512 -105
- package/dist/control.mjs.map +1 -1
- package/dist/cron/index.d.mts +54 -4
- package/dist/cron/index.mjs +154 -42
- package/dist/cron/index.mjs.map +1 -1
- package/dist/cron/scheduler-entrypoint.mjs +459 -306
- package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
- package/dist/cron/scheduler-service.mjs +154 -42
- package/dist/cron/scheduler-service.mjs.map +1 -1
- package/dist/index.d.mts +76 -6
- package/dist/index.mjs +108 -45
- package/dist/index.mjs.map +1 -1
- package/dist/{prisma-next-qPB8_Az6.mjs → prisma-next-DlU01kXJ-2sP5mQb6.mjs} +3 -3
- package/dist/prisma-next-DlU01kXJ-2sP5mQb6.mjs.map +1 -0
- package/dist/prisma-next.d.mts +1 -1
- package/dist/prisma-next.mjs +1 -1
- package/dist/{provisioned-edges-DIQAR4q4-Bn9op-JG.mjs → provisioned-edges-B_XS1Mz--NFJgcXK7.mjs} +66 -6
- package/dist/provisioned-edges-B_XS1Mz--NFJgcXK7.mjs.map +1 -0
- package/dist/{serializer-CX4VYdf_-KKGoAxfx.mjs → serializer-D8_84XWO-DA2B6YbX.mjs} +33 -3
- package/dist/serializer-D8_84XWO-DA2B6YbX.mjs.map +1 -0
- package/dist/storage/index.d.mts +62 -14
- package/dist/storage/index.mjs +168 -48
- package/dist/storage/index.mjs.map +1 -1
- package/dist/storage/storage-entrypoint.mjs +361 -239
- package/dist/storage/storage-entrypoint.mjs.map +1 -1
- package/dist/storage/storage-service.mjs +168 -48
- package/dist/storage/storage-service.mjs.map +1 -1
- package/dist/storage/testing.mjs.map +1 -1
- package/dist/streams/index.d.mts +62 -89
- package/dist/streams/index.mjs +169 -49
- package/dist/streams/index.mjs.map +1 -1
- package/dist/streams/streams-entrypoint.mjs +361 -239
- package/dist/streams/streams-entrypoint.mjs.map +1 -1
- package/dist/streams/streams-service.mjs +168 -48
- package/dist/streams/streams-service.mjs.map +1 -1
- package/dist/streams/testing.d.mts +1 -1
- package/dist/streams/testing.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/testing.mjs.map +1 -1
- package/package.json +14 -14
- package/dist/prisma-next-qPB8_Az6.mjs.map +0 -1
- package/dist/provisioned-edges-DIQAR4q4-Bn9op-JG.mjs.map +0 -1
- package/dist/serializer-CX4VYdf_-KKGoAxfx.mjs.map +0 -1
|
@@ -1 +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/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, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\").replace(/'/g, \"'\");\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":"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"}
|
|
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-CadPZuEK.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, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\").replace(/'/g, \"'\");\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":"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"}
|
package/dist/streams/index.d.mts
CHANGED
|
@@ -1,6 +1,57 @@
|
|
|
1
|
-
import { Contract, DependencyEnd, ModuleNode } from "@prisma/composer";
|
|
1
|
+
import { BuildAdapter, Contract, DependencyEnd, Deps, Expose, HydratedDeps, ModuleNode, NODE, Params, RunnableServiceNode, SecretValues, Secrets, ServiceNode, Values } from "@prisma/composer";
|
|
2
2
|
import "@standard-schema/spec";
|
|
3
|
-
//#region ../../1-prisma-cloud/
|
|
3
|
+
//#region ../../1-prisma-cloud/1-extensions/target/dist/index.d.mts
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/compute.d.ts
|
|
6
|
+
declare const reservedParams: {
|
|
7
|
+
readonly port: import("@prisma/composer").ConfigParam<import("@standard-schema/spec").StandardSchemaV1<number, number>>;
|
|
8
|
+
};
|
|
9
|
+
type ReservedParams = typeof reservedParams;
|
|
10
|
+
/**
|
|
11
|
+
* A Prisma Compute service — declarations only (deps + params + build + the
|
|
12
|
+
* ports it exposes), no descriptor. `params` merges with the reserved
|
|
13
|
+
* `ReservedParams` (`port`); a user param whose name collides with a reserved
|
|
14
|
+
* one fails at authoring, the same way a colliding dependency name does.
|
|
15
|
+
*
|
|
16
|
+
* · run(address, boot) — the process controller: deserialize the platform
|
|
17
|
+
* environment (keyed off `address`, the extension's ONE env read) into a
|
|
18
|
+
* typed Config, re-emit it under address-free process-local stash keys,
|
|
19
|
+
* then call boot() to start the app's entry.
|
|
20
|
+
* · load() / config() — called from inside the app's entry: read the stash;
|
|
21
|
+
* load() hydrates + memoizes the deps, config() returns the typed params.
|
|
22
|
+
* Separate accessors so a dep and a param never share a namespace (ADR-0021).
|
|
23
|
+
* · origin() — this service's platform-assigned public origin, read from the
|
|
24
|
+
* stash `run()` populates; memoized per process.
|
|
25
|
+
*
|
|
26
|
+
* The underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
|
|
27
|
+
* the control-plane registry key `prisma-composer deploy` resolves through the
|
|
28
|
+
* app's `prisma-composer.config.ts` (ADR-0017). This module loads nothing at
|
|
29
|
+
* deploy time; nodes are pure data until run() or load() is called.
|
|
30
|
+
*/
|
|
31
|
+
declare class ComputeService<D extends Deps, P extends Params, E extends Expose, S extends Secrets> implements RunnableServiceNode<D, P & ReservedParams, E, S> {
|
|
32
|
+
#private;
|
|
33
|
+
readonly [NODE]: true;
|
|
34
|
+
readonly kind: 'service';
|
|
35
|
+
readonly name: string;
|
|
36
|
+
readonly extension: string;
|
|
37
|
+
readonly type: string;
|
|
38
|
+
readonly inputs: D;
|
|
39
|
+
readonly params: P & ReservedParams;
|
|
40
|
+
readonly secretSlots: S;
|
|
41
|
+
readonly build: BuildAdapter;
|
|
42
|
+
readonly expose: E | undefined;
|
|
43
|
+
constructor(node: ServiceNode<D, P & ReservedParams, E, S>);
|
|
44
|
+
run(address: string, boot: () => Promise<unknown>): Promise<unknown>;
|
|
45
|
+
load(): HydratedDeps<D>;
|
|
46
|
+
config(): Values<P & ReservedParams>;
|
|
47
|
+
secrets(): SecretValues<S>;
|
|
48
|
+
/** This service's platform-assigned public origin — read from the stash
|
|
49
|
+
* run() populates and memoized per process. Throws if called before run()
|
|
50
|
+
* has stashed it (readOrigin's pinned message). */
|
|
51
|
+
origin(): string;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region ../../1-prisma-cloud/2-shared-modules/storage/dist/storage-service-CVf6j3HC.d.mts
|
|
4
55
|
//#region src/contract.d.ts
|
|
5
56
|
interface S3Config {
|
|
6
57
|
readonly url: string;
|
|
@@ -11,7 +62,7 @@ interface S3Config {
|
|
|
11
62
|
declare const s3Contract: Contract<'s3', S3Config>;
|
|
12
63
|
type S3Contract = typeof s3Contract;
|
|
13
64
|
//#endregion
|
|
14
|
-
//#region ../../1-prisma-cloud/2-shared-modules/streams/dist/
|
|
65
|
+
//#region ../../1-prisma-cloud/2-shared-modules/streams/dist/streams-service-DjbzOToP.d.mts
|
|
15
66
|
//#region src/contract.d.ts
|
|
16
67
|
interface StreamsConfig {
|
|
17
68
|
readonly url: string;
|
|
@@ -150,6 +201,14 @@ declare class StreamHandle {
|
|
|
150
201
|
}): Promise<StreamsTailResult<T>>;
|
|
151
202
|
}
|
|
152
203
|
//#endregion
|
|
204
|
+
//#region src/streams-service.d.ts
|
|
205
|
+
declare function streamsService(): ComputeService<{
|
|
206
|
+
store: import("@prisma/composer").DependencyEnd<S3Config, import("@prisma/composer").Contract<"s3", S3Config>>;
|
|
207
|
+
}, Record<never, never>, {
|
|
208
|
+
streams: import("@prisma/composer").Contract<"streams", StreamDefs>;
|
|
209
|
+
}, Record<never, never>>;
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region ../../1-prisma-cloud/2-shared-modules/streams/dist/index.d.mts
|
|
153
212
|
//#region src/streams-module.d.ts
|
|
154
213
|
declare function streams(opts?: {
|
|
155
214
|
name?: string;
|
|
@@ -159,91 +218,5 @@ declare function streams(opts?: {
|
|
|
159
218
|
streams: Contract<'streams', StreamDefs>;
|
|
160
219
|
}, Record<never, never>>;
|
|
161
220
|
//#endregion
|
|
162
|
-
//#region ../../../../node_modules/@standard-schema/spec/dist/index.d.ts
|
|
163
|
-
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
164
|
-
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
165
|
-
/** The Standard properties. */
|
|
166
|
-
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
167
|
-
}
|
|
168
|
-
declare namespace StandardTypedV1 {
|
|
169
|
-
/** The Standard Typed properties interface. */
|
|
170
|
-
interface Props<Input = unknown, Output = Input> {
|
|
171
|
-
/** The version number of the standard. */
|
|
172
|
-
readonly version: 1;
|
|
173
|
-
/** The vendor name of the schema library. */
|
|
174
|
-
readonly vendor: string;
|
|
175
|
-
/** Inferred types associated with the schema. */
|
|
176
|
-
readonly types?: Types<Input, Output> | undefined;
|
|
177
|
-
}
|
|
178
|
-
/** The Standard Typed types interface. */
|
|
179
|
-
interface Types<Input = unknown, Output = Input> {
|
|
180
|
-
/** The input type of the schema. */
|
|
181
|
-
readonly input: Input;
|
|
182
|
-
/** The output type of the schema. */
|
|
183
|
-
readonly output: Output;
|
|
184
|
-
}
|
|
185
|
-
/** Infers the input type of a Standard Typed. */
|
|
186
|
-
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
187
|
-
/** Infers the output type of a Standard Typed. */
|
|
188
|
-
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
189
|
-
}
|
|
190
|
-
/** The Standard Schema interface. */
|
|
191
|
-
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
192
|
-
/** The Standard Schema properties. */
|
|
193
|
-
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
194
|
-
}
|
|
195
|
-
declare namespace StandardSchemaV1 {
|
|
196
|
-
/** The Standard Schema properties interface. */
|
|
197
|
-
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
198
|
-
/** Validates unknown input values. */
|
|
199
|
-
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
|
|
200
|
-
}
|
|
201
|
-
/** The result interface of the validate function. */
|
|
202
|
-
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
203
|
-
/** The result interface if validation succeeds. */
|
|
204
|
-
interface SuccessResult<Output> {
|
|
205
|
-
/** The typed output value. */
|
|
206
|
-
readonly value: Output;
|
|
207
|
-
/** A falsy value for `issues` indicates success. */
|
|
208
|
-
readonly issues?: undefined;
|
|
209
|
-
}
|
|
210
|
-
interface Options {
|
|
211
|
-
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
212
|
-
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
213
|
-
}
|
|
214
|
-
/** The result interface if validation fails. */
|
|
215
|
-
interface FailureResult {
|
|
216
|
-
/** The issues of failed validation. */
|
|
217
|
-
readonly issues: ReadonlyArray<Issue>;
|
|
218
|
-
}
|
|
219
|
-
/** The issue interface of the failure output. */
|
|
220
|
-
interface Issue {
|
|
221
|
-
/** The error message of the issue. */
|
|
222
|
-
readonly message: string;
|
|
223
|
-
/** The path of the issue, if any. */
|
|
224
|
-
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
225
|
-
}
|
|
226
|
-
/** The path segment interface of the issue. */
|
|
227
|
-
interface PathSegment {
|
|
228
|
-
/** The key representing a path segment. */
|
|
229
|
-
readonly key: PropertyKey;
|
|
230
|
-
}
|
|
231
|
-
/** The Standard types interface. */
|
|
232
|
-
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
|
|
233
|
-
/** Infers the input type of a Standard. */
|
|
234
|
-
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
235
|
-
/** Infers the output type of a Standard. */
|
|
236
|
-
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
237
|
-
}
|
|
238
|
-
//#endregion
|
|
239
|
-
//#region src/exports/streams-service.d.ts
|
|
240
|
-
declare function streamsService(): import("@prisma/composer").RunnableServiceNode<{
|
|
241
|
-
store: import("@prisma/composer").DependencyEnd<S3Config, import("@prisma/composer").Contract<"s3", S3Config>>;
|
|
242
|
-
}, Record<never, never> & {
|
|
243
|
-
readonly port: import("@prisma/composer").ConfigParam<StandardSchemaV1<number, number>>;
|
|
244
|
-
}, {
|
|
245
|
-
streams: import("@prisma/composer").Contract<"streams", StreamDefs>;
|
|
246
|
-
}, Record<never, never>>;
|
|
247
|
-
//#endregion
|
|
248
221
|
export { type StreamDef, type StreamDefs, StreamHandle, type StreamHandles, StreamsClient, type StreamsConfig, type StreamsContract, type StreamsReadResult, type StreamsTailResult, durableStreams, streamDef, streams, streamsContract, streamsService };
|
|
249
222
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/streams/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dependency, hydrateSecrets, hydrateSync, module, number, provisionNeed, resource, service, string } from "@prisma/composer";
|
|
2
2
|
import { blindCast } from "@prisma/composer/casts";
|
|
3
|
-
import { RPC_PEER_KEY } from "@prisma/composer/service-rpc";
|
|
4
3
|
import { type } from "arktype";
|
|
4
|
+
import { RPC_PEER_KEY } from "@prisma/composer/service-rpc";
|
|
5
5
|
import node from "@prisma/composer/node";
|
|
6
6
|
blindCast(Symbol.for("prisma:prisma-cloud-secret-source"));
|
|
7
7
|
/**
|
|
@@ -191,6 +191,35 @@ function stashProviderParams(entries, address) {
|
|
|
191
191
|
process.env[configKey("", d)] = encode("service", value);
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
+
/** The framework-resolved origin row: COMPOSER_<addr>_ORIGIN. Written per
|
|
195
|
+
* compute service at serialize — the service's own provisioned endpoint URL,
|
|
196
|
+
* riding the reserved-provider-param machinery (`origin-key.ts`'s
|
|
197
|
+
* `ORIGIN_PARAM`); never a declared param, never in config(). A harness with
|
|
198
|
+
* no deploy behind it supplies it by setting `COMPOSER_ORIGIN` to the
|
|
199
|
+
* JSON-encoded origin URL — exactly how the existing entrypoint tests supply
|
|
200
|
+
* their other `COMPOSER_*` rows. */
|
|
201
|
+
const ORIGIN_KEY_NAME = "ORIGIN";
|
|
202
|
+
/**
|
|
203
|
+
* Reads this service's origin back out of the address-free stash
|
|
204
|
+
* `stashProviderParams` wrote for the ORIGIN entry. `COMPOSER_ORIGIN` unset is
|
|
205
|
+
* a loud failure — a deployed environment always writes it, so an unset row
|
|
206
|
+
* means either a local harness that hasn't supplied it or a boot() called
|
|
207
|
+
* before run().
|
|
208
|
+
*/
|
|
209
|
+
function readOrigin() {
|
|
210
|
+
const d = {
|
|
211
|
+
owner: "service",
|
|
212
|
+
name: ORIGIN_KEY_NAME,
|
|
213
|
+
param: {
|
|
214
|
+
schema: type("string"),
|
|
215
|
+
optional: true
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const key = configKey("", d);
|
|
219
|
+
const value = coerce(process.env[key], d, key);
|
|
220
|
+
if (value === void 0) throw new Error("this service's origin is not available (env COMPOSER_ORIGIN is unset) — a deployed environment writes it automatically; a local harness must supply it like any other config value (set COMPOSER_ORIGIN to the JSON-encoded origin URL).");
|
|
221
|
+
return blindCast(value);
|
|
222
|
+
}
|
|
194
223
|
/** Synchronous Standard Schema validation — see the matching note in core's `config.ts`. */
|
|
195
224
|
function standardValidateSync(schema, value) {
|
|
196
225
|
const result = schema["~standard"].validate(value);
|
|
@@ -199,7 +228,41 @@ function standardValidateSync(schema, value) {
|
|
|
199
228
|
return result.value;
|
|
200
229
|
}
|
|
201
230
|
//#endregion
|
|
202
|
-
//#region ../../1-prisma-cloud/1-extensions/target/dist/provisioned-edges-
|
|
231
|
+
//#region ../../1-prisma-cloud/1-extensions/target/dist/provisioned-edges-B_XS1Mz-.mjs
|
|
232
|
+
/**
|
|
233
|
+
* The service's own origin as a reserved provider param (ADR-0031): the ONE
|
|
234
|
+
* brand and the ONE entry — shared by control.ts (which registers the
|
|
235
|
+
* deploy-side value function that resolves the provisioned service's
|
|
236
|
+
* `endpointDomain` — see its `selfOriginValue`) and compute.ts (which
|
|
237
|
+
* validates and stashes the row at boot through the generic
|
|
238
|
+
* `stashProviderParams` loop), so writer and reader cannot drift.
|
|
239
|
+
*
|
|
240
|
+
* Unlike the key-minting brands (`service-keys.ts`, `streams-keys.ts`) this
|
|
241
|
+
* brand has no provisioner and no consumer edges: the value derives from the
|
|
242
|
+
* service's OWN provisioned attributes, so control.ts registers it as a
|
|
243
|
+
* service-derived provider param (`descriptors/shared.ts`'s
|
|
244
|
+
* `ServiceProviderParam`) and the descriptor writes it for EVERY compute
|
|
245
|
+
* service, exposing or not.
|
|
246
|
+
*
|
|
247
|
+
* This module is reachable from the RUNTIME/authoring side — it must never
|
|
248
|
+
* import `@internal/lowering` or `effect`, or those tokens leak into a user
|
|
249
|
+
* service's bundle (the deploy-side value function lives in control.ts, the
|
|
250
|
+
* control-plane-only entry).
|
|
251
|
+
*/
|
|
252
|
+
/** ADR-0031's brand for the service's own origin — control.ts registers the deploy-side value function under this. */
|
|
253
|
+
const SELF_ORIGIN = Symbol.for("prisma:self-origin");
|
|
254
|
+
/**
|
|
255
|
+
* The reserved provider param for the origin row: the var name is `ORIGIN`,
|
|
256
|
+
* derived through `configKey` at both ends (`configKey(address, …)` at
|
|
257
|
+
* deploy, `configKey('', …)` — `COMPOSER_ORIGIN` — at boot, where
|
|
258
|
+
* `readOrigin` reads it back). `brand` is `SELF_ORIGIN` — control.ts looks
|
|
259
|
+
* its deploy-side value function up by this field.
|
|
260
|
+
*/
|
|
261
|
+
const ORIGIN_PARAM = {
|
|
262
|
+
name: ORIGIN_KEY_NAME,
|
|
263
|
+
schema: type("string"),
|
|
264
|
+
brand: SELF_ORIGIN
|
|
265
|
+
};
|
|
203
266
|
/**
|
|
204
267
|
* RPC's reserved provider param (ADR-0030/ADR-0031): the declaration —
|
|
205
268
|
* name + schema + brand — for the accepted-keys set a provider stores, shared
|
|
@@ -252,17 +315,51 @@ configKey("", {
|
|
|
252
315
|
owner: "service",
|
|
253
316
|
name: STREAMS_API_KEY_PARAM.name
|
|
254
317
|
});
|
|
255
|
-
|
|
318
|
+
/**
|
|
319
|
+
* The list of provider-side reserved params the boot path validates and
|
|
320
|
+
* stashes (ADR-0031): every brand's `{name, schema, brand}` declaration,
|
|
321
|
+
* collected from that brand's own module (`service-keys.ts`,
|
|
322
|
+
* `streams-keys.ts`, `origin-key.ts`) so `compute.ts` names no brand itself.
|
|
323
|
+
*
|
|
324
|
+
* This list exists separately from `control.ts`'s deploy-side registry
|
|
325
|
+
* (`PROVIDER_PARAMS`) because `control.ts` is deploy-only code — it imports
|
|
326
|
+
* `@internal/lowering` and `effect` to mint values — and a booted service
|
|
327
|
+
* must never import it. This module is reachable from a user service's
|
|
328
|
+
* bundle through `compute.ts`, so it must never import `@internal/lowering`,
|
|
329
|
+
* `effect`, `alchemy`, or `control.ts`.
|
|
330
|
+
*
|
|
331
|
+
* This is the single source of which reserved provider params exist:
|
|
332
|
+
* control.ts builds `PROVIDER_PARAMS` by mapping over this list and looking
|
|
333
|
+
* up each entry's deploy-side value function (edge-derived `value(refs)` or
|
|
334
|
+
* service-derived `valueForService(provisioned, address)`) by its `brand`,
|
|
335
|
+
* throwing at module load if one is missing. Adding a brand means adding its
|
|
336
|
+
* entry here, plus its deploy-side value function in control.ts — a brand
|
|
337
|
+
* registered for deploy but absent here is no longer expressible, because
|
|
338
|
+
* deploy no longer names its own param set independently.
|
|
339
|
+
*/
|
|
340
|
+
const RESERVED_PROVIDER_PARAMS = [
|
|
341
|
+
RPC_ACCEPTED_KEYS_PARAM,
|
|
342
|
+
STREAMS_API_KEY_PARAM,
|
|
343
|
+
ORIGIN_PARAM
|
|
344
|
+
];
|
|
256
345
|
blindCast(Symbol.for("prisma:prisma-cloud-param-source"));
|
|
257
|
-
|
|
258
|
-
|
|
346
|
+
Object.freeze({
|
|
347
|
+
kind: "s3",
|
|
348
|
+
__cmp: {
|
|
349
|
+
url: "",
|
|
350
|
+
bucket: "",
|
|
351
|
+
accessKeyId: "",
|
|
352
|
+
secretAccessKey: ""
|
|
353
|
+
},
|
|
354
|
+
satisfies: (required) => required.kind === "s3"
|
|
355
|
+
});
|
|
259
356
|
const reservedParams = { port: number({ default: 3e3 }) };
|
|
260
357
|
/**
|
|
261
358
|
* A Prisma Compute service — declarations only (deps + params + build + the
|
|
262
359
|
* ports it exposes), no descriptor. `params` merges with the reserved
|
|
263
360
|
* `ReservedParams` (`port`); a user param whose name collides with a reserved
|
|
264
361
|
* one fails at authoring, the same way a colliding dependency name does.
|
|
265
|
-
*
|
|
362
|
+
*
|
|
266
363
|
* · run(address, boot) — the process controller: deserialize the platform
|
|
267
364
|
* environment (keyed off `address`, the extension's ONE env read) into a
|
|
268
365
|
* typed Config, re-emit it under address-free process-local stash keys,
|
|
@@ -270,23 +367,69 @@ const reservedParams = { port: number({ default: 3e3 }) };
|
|
|
270
367
|
* · load() / config() — called from inside the app's entry: read the stash;
|
|
271
368
|
* load() hydrates + memoizes the deps, config() returns the typed params.
|
|
272
369
|
* Separate accessors so a dep and a param never share a namespace (ADR-0021).
|
|
370
|
+
* · origin() — this service's platform-assigned public origin, read from the
|
|
371
|
+
* stash `run()` populates; memoized per process.
|
|
273
372
|
*
|
|
274
|
-
*
|
|
373
|
+
* The underlying node carries `extension: '@prisma/composer-prisma-cloud'` —
|
|
275
374
|
* the control-plane registry key `prisma-composer deploy` resolves through the
|
|
276
375
|
* app's `prisma-composer.config.ts` (ADR-0017). This module loads nothing at
|
|
277
|
-
* deploy time; nodes are pure data.
|
|
376
|
+
* deploy time; nodes are pure data until run() or load() is called.
|
|
278
377
|
*/
|
|
378
|
+
var ComputeService = class {
|
|
379
|
+
#resolved;
|
|
380
|
+
#loadedDeps;
|
|
381
|
+
#loadedParams;
|
|
382
|
+
#loadedSecrets;
|
|
383
|
+
#origin;
|
|
384
|
+
constructor(node) {
|
|
385
|
+
Object.assign(this, node);
|
|
386
|
+
}
|
|
387
|
+
#processConfig() {
|
|
388
|
+
if (this.#resolved === void 0) this.#resolved = deserialize(this, "");
|
|
389
|
+
return this.#resolved;
|
|
390
|
+
}
|
|
391
|
+
async run(address, boot) {
|
|
392
|
+
const config = deserialize(this, address);
|
|
393
|
+
stash(this, config);
|
|
394
|
+
stashProviderParams(RESERVED_PROVIDER_PARAMS, address);
|
|
395
|
+
stashSecrets(this, address);
|
|
396
|
+
const port = config.service["port"];
|
|
397
|
+
if (typeof port === "number") process.env["PORT"] = String(port);
|
|
398
|
+
return boot();
|
|
399
|
+
}
|
|
400
|
+
load() {
|
|
401
|
+
if (this.#loadedDeps === void 0) this.#loadedDeps = blindCast(hydrateSync(this, this.#processConfig()));
|
|
402
|
+
return this.#loadedDeps;
|
|
403
|
+
}
|
|
404
|
+
config() {
|
|
405
|
+
if (this.#loadedParams === void 0) this.#loadedParams = blindCast(this.#processConfig().service);
|
|
406
|
+
return this.#loadedParams;
|
|
407
|
+
}
|
|
408
|
+
secrets() {
|
|
409
|
+
if (this.#loadedSecrets === void 0) this.#loadedSecrets = blindCast(hydrateSecrets(this, deserializeSecrets(this, "")));
|
|
410
|
+
return this.#loadedSecrets;
|
|
411
|
+
}
|
|
412
|
+
/** This service's platform-assigned public origin — read from the stash
|
|
413
|
+
* run() populates and memoized per process. Throws if called before run()
|
|
414
|
+
* has stashed it (readOrigin's pinned message). */
|
|
415
|
+
origin() {
|
|
416
|
+
this.#origin ??= readOrigin();
|
|
417
|
+
return this.#origin;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
279
420
|
const compute = (def) => {
|
|
280
421
|
const userParams = def.params ?? blindCast({});
|
|
281
422
|
for (const reserved of Object.keys(reservedParams)) {
|
|
282
423
|
if (reserved in def.deps) throw new Error(`compute(): dependency "${reserved}" collides with the reserved service param of the same name — rename the dependency.`);
|
|
283
424
|
if (reserved in userParams) throw new Error(`compute(): param "${reserved}" collides with the reserved service param of the same name — rename the param.`);
|
|
284
425
|
}
|
|
426
|
+
for (const name of Object.keys(userParams)) if (name.toUpperCase() === "ORIGIN") throw new Error(`compute(): param "${name}" collides with the framework-written origin row — rename the param.`);
|
|
427
|
+
for (const name of Object.keys(def.secrets ?? {})) if (name.toUpperCase() === "ORIGIN") throw new Error(`compute(): secret "${name}" collides with the framework-written origin row — rename the secret.`);
|
|
285
428
|
const params = blindCast({
|
|
286
429
|
...userParams,
|
|
287
430
|
...reservedParams
|
|
288
431
|
});
|
|
289
|
-
const
|
|
432
|
+
const instance = new ComputeService(service({
|
|
290
433
|
name: def.name,
|
|
291
434
|
extension: "@prisma/composer-prisma-cloud",
|
|
292
435
|
type: "compute",
|
|
@@ -295,40 +438,9 @@ const compute = (def) => {
|
|
|
295
438
|
...def.secrets !== void 0 ? { secrets: def.secrets } : {},
|
|
296
439
|
build: def.build,
|
|
297
440
|
...def.expose !== void 0 ? { expose: def.expose } : {}
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
let loadedParams;
|
|
302
|
-
let loadedSecrets;
|
|
303
|
-
function processConfig() {
|
|
304
|
-
if (resolved === void 0) resolved = deserialize(node, "");
|
|
305
|
-
return resolved;
|
|
306
|
-
}
|
|
307
|
-
const runnable = {
|
|
308
|
-
...node,
|
|
309
|
-
async run(address, boot) {
|
|
310
|
-
const config = deserialize(node, address);
|
|
311
|
-
stash(node, config);
|
|
312
|
-
stashProviderParams(RESERVED_PROVIDER_PARAMS, address);
|
|
313
|
-
stashSecrets(node, address);
|
|
314
|
-
const port = config.service["port"];
|
|
315
|
-
if (typeof port === "number") process.env["PORT"] = String(port);
|
|
316
|
-
return boot();
|
|
317
|
-
},
|
|
318
|
-
load() {
|
|
319
|
-
if (loadedDeps === void 0) loadedDeps = blindCast(hydrateSync(node, processConfig()));
|
|
320
|
-
return loadedDeps;
|
|
321
|
-
},
|
|
322
|
-
config() {
|
|
323
|
-
if (loadedParams === void 0) loadedParams = blindCast(processConfig().service);
|
|
324
|
-
return loadedParams;
|
|
325
|
-
},
|
|
326
|
-
secrets() {
|
|
327
|
-
if (loadedSecrets === void 0) loadedSecrets = blindCast(hydrateSecrets(node, deserializeSecrets(node, "")));
|
|
328
|
-
return loadedSecrets;
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
return Object.freeze(blindCast(runnable));
|
|
441
|
+
}));
|
|
442
|
+
Object.freeze(instance);
|
|
443
|
+
return instance;
|
|
332
444
|
};
|
|
333
445
|
/**
|
|
334
446
|
* The contract a Postgres provides — and the contract its consumers require.
|
|
@@ -399,16 +511,24 @@ function s3Credentials(opts) {
|
|
|
399
511
|
* return type is compute's exactly (including the reserved `port` param). The
|
|
400
512
|
* storage module (D4b) calls this with its `db`/`credentials` deps, a `bucket`
|
|
401
513
|
* param, and `expose: { store: s3Contract }`.
|
|
514
|
+
*
|
|
515
|
+
* `compute()`'s result is a `ComputeService` instance — its run/load/config/
|
|
516
|
+
* secrets/origin methods live on the class prototype, not as the instance's
|
|
517
|
+
* own properties, so a plain object spread (`{ ...node }`) would silently
|
|
518
|
+
* drop them. Building a fresh `ComputeService` from the same data fields
|
|
519
|
+
* (which `{ ...node }` DOES copy — they're the node's own enumerable
|
|
520
|
+
* properties) with `type` overridden keeps every method intact.
|
|
402
521
|
*/
|
|
403
522
|
function s3StoreService(def) {
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
...node,
|
|
523
|
+
const instance = new ComputeService({
|
|
524
|
+
...compute(def),
|
|
407
525
|
type: "s3-store"
|
|
408
|
-
})
|
|
526
|
+
});
|
|
527
|
+
Object.freeze(instance);
|
|
528
|
+
return instance;
|
|
409
529
|
}
|
|
410
530
|
//#endregion
|
|
411
|
-
//#region ../../1-prisma-cloud/2-shared-modules/storage/dist/storage-service-
|
|
531
|
+
//#region ../../1-prisma-cloud/2-shared-modules/storage/dist/storage-service-DSaZsAC4.mjs
|
|
412
532
|
const s3Contract = Object.freeze({
|
|
413
533
|
kind: "s3",
|
|
414
534
|
__cmp: {
|
|
@@ -465,7 +585,7 @@ function storageService(opts) {
|
|
|
465
585
|
}
|
|
466
586
|
storageService({ bucket: "storage" });
|
|
467
587
|
//#endregion
|
|
468
|
-
//#region ../../1-prisma-cloud/2-shared-modules/streams/dist/streams-service-
|
|
588
|
+
//#region ../../1-prisma-cloud/2-shared-modules/streams/dist/streams-service-Cg8rwrZa.mjs
|
|
469
589
|
var __create = Object.create;
|
|
470
590
|
var __defProp = Object.defineProperty;
|
|
471
591
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|