@prisma/composer-prisma-cloud 0.2.0-dev.11 → 0.2.0-dev.13

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 (61) hide show
  1. package/dist/buckets-main.mjs +795 -0
  2. package/dist/buckets-main.mjs.map +1 -0
  3. package/dist/compute-main.mjs +532 -0
  4. package/dist/compute-main.mjs.map +1 -0
  5. package/dist/control.mjs +41 -1257
  6. package/dist/control.mjs.map +1 -1
  7. package/dist/cron/index.mjs +2 -3
  8. package/dist/cron/index.mjs.map +1 -1
  9. package/dist/cron/scheduler-entrypoint.mjs.map +1 -1
  10. package/dist/cron/scheduler-service.mjs +2 -3
  11. package/dist/cron/scheduler-service.mjs.map +1 -1
  12. package/dist/email/email-entrypoint.mjs.map +1 -1
  13. package/dist/email/email-service.mjs +2 -3
  14. package/dist/email/email-service.mjs.map +1 -1
  15. package/dist/email/index.mjs +2 -3
  16. package/dist/email/index.mjs.map +1 -1
  17. package/dist/email/testing.mjs.map +1 -1
  18. package/dist/get-port-BYnpbW5H.mjs +111 -0
  19. package/dist/get-port-BYnpbW5H.mjs.map +1 -0
  20. package/dist/index.mjs +4 -2
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/local-target.d.mts +12 -0
  23. package/dist/local-target.d.mts.map +1 -0
  24. package/dist/local-target.mjs +6129 -0
  25. package/dist/local-target.mjs.map +1 -0
  26. package/dist/param-BTzY0ne5-CW6ojZ3E.mjs +66 -0
  27. package/dist/param-BTzY0ne5-CW6ojZ3E.mjs.map +1 -0
  28. package/dist/pg-connection-CadPZuEK-CF3FsSQu.mjs +79 -0
  29. package/dist/pg-connection-CadPZuEK-CF3FsSQu.mjs.map +1 -0
  30. package/dist/postgres-main.mjs +402 -0
  31. package/dist/postgres-main.mjs.map +1 -0
  32. package/dist/preflight-names-BPL-qsZF-BfoRgbgb.mjs +1252 -0
  33. package/dist/preflight-names-BPL-qsZF-BfoRgbgb.mjs.map +1 -0
  34. package/dist/{prisma-next-BvBwGCIt-CSauMX4l.mjs → prisma-next-BvBwGCIt-DssgnctU.mjs} +3 -78
  35. package/dist/prisma-next-BvBwGCIt-DssgnctU.mjs.map +1 -0
  36. package/dist/prisma-next.mjs +1 -1
  37. package/dist/{provisioned-edges-B_XS1Mz--NFJgcXK7.mjs → provisioned-edges-C1wSO3cx-YC5C19f9.mjs} +5 -65
  38. package/dist/provisioned-edges-C1wSO3cx-YC5C19f9.mjs.map +1 -0
  39. package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs +47 -0
  40. package/dist/secret-rz_ZqNeq-_xd97Jd9.mjs.map +1 -0
  41. package/dist/segments-NpKN-46R-B01DmCqy.mjs +1441 -0
  42. package/dist/segments-NpKN-46R-B01DmCqy.mjs.map +1 -0
  43. package/dist/{serializer-D8_84XWO-DA2B6YbX.mjs → serializer-CJiOhF2d-DJUjQj1i.mjs} +4 -44
  44. package/dist/serializer-CJiOhF2d-DJUjQj1i.mjs.map +1 -0
  45. package/dist/storage/index.mjs +2 -3
  46. package/dist/storage/index.mjs.map +1 -1
  47. package/dist/storage/storage-entrypoint.mjs.map +1 -1
  48. package/dist/storage/storage-service.mjs +2 -3
  49. package/dist/storage/storage-service.mjs.map +1 -1
  50. package/dist/streams/index.mjs +2 -3
  51. package/dist/streams/index.mjs.map +1 -1
  52. package/dist/streams/streams-entrypoint.mjs.map +1 -1
  53. package/dist/streams/streams-service.mjs +2 -3
  54. package/dist/streams/streams-service.mjs.map +1 -1
  55. package/dist/testing.mjs +1 -1
  56. package/dist/testing.mjs.map +1 -1
  57. package/package.json +21 -15
  58. package/src/exports/local-target.ts +1 -0
  59. package/dist/prisma-next-BvBwGCIt-CSauMX4l.mjs.map +0 -1
  60. package/dist/provisioned-edges-B_XS1Mz--NFJgcXK7.mjs.map +0 -1
  61. package/dist/serializer-D8_84XWO-DA2B6YbX.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buckets-main.mjs","names":["fs"],"sources":["../../../1-prisma-cloud/0-lowering/s3-protocol/dist/index.mjs","../../../1-prisma-cloud/0-lowering/dev-emulators/dist/buckets-main.mjs"],"sourcesContent":["import { createHash, createHmac, randomUUID, timingSafeEqual } from \"node:crypto\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nconst DEFAULT_CONTENT_TYPE$1 = \"application/octet-stream\";\nconst TMP_DIR_NAME = \".tmp\";\nconst META_DIR_NAME = \".meta\";\nconst RESERVED_SEGMENTS = /* @__PURE__ */ new Set([TMP_DIR_NAME, META_DIR_NAME]);\nconst BUCKET_NAME_RE = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;\nfunction etagOf$1(bytes) {\n\treturn `\"${createHash(\"sha256\").update(bytes).digest(\"hex\")}\"`;\n}\nfunction isErrnoException(err) {\n\treturn err instanceof Error && \"code\" in err;\n}\nfunction isEnoent(err) {\n\treturn isErrnoException(err) && err.code === \"ENOENT\";\n}\n/**\n* Splits a key into its `/` segments, rejecting anything that could escape\n* the bucket dir or collide with the reserved `.tmp`/`.meta` namespaces:\n* `..` segments, an empty segment (leading/trailing/doubled `/`, which also\n* catches a leading-slash \"absolute\" key), or a segment literally `.tmp` or\n* `.meta` at any depth.\n*/\nfunction keySegments(key) {\n\tconst segments = key.split(\"/\");\n\tfor (const segment of segments) if (segment === \"\" || segment === \".\" || segment === \"..\" || RESERVED_SEGMENTS.has(segment)) throw new Error(`invalid object key: \"${key}\"`);\n\treturn segments;\n}\n/** `<bucketDir>/<key's segments>`, double-checked to still resolve inside `bucketDir`. */\nfunction objectPath(bucketDir, key) {\n\tconst target = path.join(bucketDir, ...keySegments(key));\n\tconst resolvedRoot = path.resolve(bucketDir) + path.sep;\n\tif (!(path.resolve(target) + path.sep).startsWith(resolvedRoot)) throw new Error(`invalid object key: \"${key}\"`);\n\treturn target;\n}\n/** `<bucketDir>/.meta/<key's segments>.json` — mirrors `objectPath`'s tree under `.meta`. */\nfunction sidecarPath(bucketDir, key) {\n\tconst segments = keySegments(key);\n\tconst last = segments[segments.length - 1];\n\tconst dirs = segments.slice(0, -1);\n\treturn path.join(bucketDir, META_DIR_NAME, ...dirs, `${last}.json`);\n}\n/** Write-temp-then-rename: never leaves a reader observing a partial file. */\nasync function writeAtomic(finalPath, tmpRoot, bytes) {\n\tawait fs.mkdir(tmpRoot, { recursive: true });\n\tconst tmpPath = path.join(tmpRoot, randomUUID());\n\tawait fs.writeFile(tmpPath, bytes);\n\tawait fs.mkdir(path.dirname(finalPath), { recursive: true });\n\tawait fs.rename(tmpPath, finalPath);\n}\nfunction isSidecar(value) {\n\treturn typeof value === \"object\" && value !== null && \"contentType\" in value && typeof value.contentType === \"string\" && \"etag\" in value && typeof value.etag === \"string\";\n}\nasync function readSidecar(sidecar) {\n\tlet raw;\n\ttry {\n\t\traw = await fs.readFile(sidecar, \"utf8\");\n\t} catch (err) {\n\t\tif (isEnoent(err)) return null;\n\t\tthrow err;\n\t}\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (isSidecar(parsed)) return parsed;\n\t} catch {}\n\treturn null;\n}\n/** Read the object's bytes plus its metadata — adopting a sidecar-less file (dropped in by a developer) by computing and lazily persisting one. `null` when the object is missing. */\nasync function readObject(bucketDir, key) {\n\tconst target = objectPath(bucketDir, key);\n\tlet bytes;\n\ttry {\n\t\tbytes = await fs.readFile(target);\n\t} catch (err) {\n\t\tif (isEnoent(err)) return null;\n\t\tthrow err;\n\t}\n\tconst existing = await readSidecar(sidecarPath(bucketDir, key));\n\tif (existing) return {\n\t\tbytes,\n\t\tmeta: existing\n\t};\n\tconst meta = {\n\t\tcontentType: DEFAULT_CONTENT_TYPE$1,\n\t\tetag: etagOf$1(bytes)\n\t};\n\tawait writeAtomic(sidecarPath(bucketDir, key), path.join(bucketDir, TMP_DIR_NAME), Buffer.from(JSON.stringify(meta)));\n\treturn {\n\t\tbytes,\n\t\tmeta\n\t};\n}\n/** Remove now-empty directories from `startDir` up to (never including) `root`. */\nasync function pruneEmptyDirs(root, startDir) {\n\tconst resolvedRoot = path.resolve(root);\n\tlet dir = path.resolve(startDir);\n\twhile (dir !== resolvedRoot && dir.startsWith(resolvedRoot + path.sep)) {\n\t\tlet entries;\n\t\ttry {\n\t\t\tentries = await fs.readdir(dir);\n\t\t} catch (err) {\n\t\t\tif (isEnoent(err)) {\n\t\t\t\tdir = path.dirname(dir);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\t\tif (entries.length > 0) break;\n\t\ttry {\n\t\t\tawait fs.rmdir(dir);\n\t\t} catch (err) {\n\t\t\tif (!isEnoent(err)) throw err;\n\t\t}\n\t\tdir = path.dirname(dir);\n\t}\n}\n/** Recursively lists every object key under `dir`, skipping `.tmp`/`.meta` at any depth. */\nasync function walkKeys(dir) {\n\tconst keys = [];\n\tasync function walk(current, prefix) {\n\t\tlet entries;\n\t\ttry {\n\t\t\tentries = await fs.readdir(current, { withFileTypes: true });\n\t\t} catch (err) {\n\t\t\tif (isEnoent(err)) return;\n\t\t\tthrow err;\n\t\t}\n\t\tfor (const entry of entries) {\n\t\t\tif (RESERVED_SEGMENTS.has(entry.name)) continue;\n\t\t\tconst rel = prefix === \"\" ? entry.name : `${prefix}/${entry.name}`;\n\t\t\tif (entry.isDirectory()) await walk(path.join(current, entry.name), rel);\n\t\t\telse if (entry.isFile()) keys.push(rel);\n\t\t}\n\t}\n\tawait walk(dir, \"\");\n\treturn keys;\n}\n/**\n* A disk-backed `ObjectStore`: object bytes and a metadata sidecar under a\n* per-bucket directory the caller resolves. See the module doc for the\n* unknown-bucket / invalid-key failure shapes.\n*/\nfunction fsStore(resolveBucketDir) {\n\tfunction resolveDir(bucket) {\n\t\tif (!BUCKET_NAME_RE.test(bucket)) return void 0;\n\t\treturn resolveBucketDir(bucket);\n\t}\n\treturn {\n\t\tasync put(bucket, key, bytes, opts = {}) {\n\t\t\tconst dir = resolveDir(bucket);\n\t\t\tif (dir === void 0) throw new Error(`no such bucket: \"${bucket}\"`);\n\t\t\tconst target = objectPath(dir, key);\n\t\t\tconst tmpRoot = path.join(dir, TMP_DIR_NAME);\n\t\t\tconst etag = etagOf$1(bytes);\n\t\t\tconst contentType = opts.contentType ?? DEFAULT_CONTENT_TYPE$1;\n\t\t\tawait writeAtomic(target, tmpRoot, bytes);\n\t\t\tawait writeAtomic(sidecarPath(dir, key), tmpRoot, Buffer.from(JSON.stringify({\n\t\t\t\tcontentType,\n\t\t\t\tetag\n\t\t\t})));\n\t\t\treturn { etag };\n\t\t},\n\t\tasync get(bucket, key, opts = {}) {\n\t\t\tconst dir = resolveDir(bucket);\n\t\t\tif (dir === void 0) return null;\n\t\t\tconst found = await readObject(dir, key);\n\t\t\tif (!found) return null;\n\t\t\tconst { bytes, meta } = found;\n\t\t\tconst size = bytes.byteLength;\n\t\t\tif (opts.range) {\n\t\t\t\tconst start = opts.range.start;\n\t\t\t\tconst end = opts.range.end === void 0 ? size - 1 : Math.min(opts.range.end, size - 1);\n\t\t\t\treturn {\n\t\t\t\t\tbytes: start > end ? /* @__PURE__ */ new Uint8Array(0) : bytes.subarray(start, end + 1),\n\t\t\t\t\tetag: meta.etag,\n\t\t\t\t\tcontentType: meta.contentType,\n\t\t\t\t\tsize\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbytes: new Uint8Array(bytes),\n\t\t\t\tetag: meta.etag,\n\t\t\t\tcontentType: meta.contentType,\n\t\t\t\tsize\n\t\t\t};\n\t\t},\n\t\tasync head(bucket, key) {\n\t\t\tconst dir = resolveDir(bucket);\n\t\t\tif (dir === void 0) return null;\n\t\t\tconst found = await readObject(dir, key);\n\t\t\tif (!found) return null;\n\t\t\treturn {\n\t\t\t\tetag: found.meta.etag,\n\t\t\t\tsize: found.bytes.byteLength,\n\t\t\t\tcontentType: found.meta.contentType\n\t\t\t};\n\t\t},\n\t\tasync delete(bucket, key) {\n\t\t\tconst dir = resolveDir(bucket);\n\t\t\tif (dir === void 0) return;\n\t\t\tconst target = objectPath(dir, key);\n\t\t\tconst sidecar = sidecarPath(dir, key);\n\t\t\ttry {\n\t\t\t\tawait fs.unlink(target);\n\t\t\t} catch (err) {\n\t\t\t\tif (!isEnoent(err)) throw err;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait fs.unlink(sidecar);\n\t\t\t} catch (err) {\n\t\t\t\tif (!isEnoent(err)) throw err;\n\t\t\t}\n\t\t\tawait pruneEmptyDirs(dir, path.dirname(target));\n\t\t\tawait pruneEmptyDirs(path.join(dir, META_DIR_NAME), path.dirname(sidecar));\n\t\t},\n\t\tasync list(bucket, opts = {}) {\n\t\t\tconst dir = resolveDir(bucket);\n\t\t\tif (dir === void 0) return {\n\t\t\t\tkeys: [],\n\t\t\t\tisTruncated: false\n\t\t\t};\n\t\t\tconst prefix = opts.prefix ?? \"\";\n\t\t\tconst maxKeys = opts.maxKeys ?? 1e3;\n\t\t\tconst token = opts.continuationToken;\n\t\t\tconst matching = (await walkKeys(dir)).filter((key) => key.startsWith(prefix)).sort().filter((key) => token === void 0 ? true : key > token);\n\t\t\tconst page = matching.slice(0, maxKeys);\n\t\t\tconst isTruncated = matching.length > maxKeys;\n\t\t\tconst last = page.at(-1);\n\t\t\treturn {\n\t\t\t\tkeys: page,\n\t\t\t\tisTruncated,\n\t\t\t\t...isTruncated && last !== void 0 ? { nextContinuationToken: last } : {}\n\t\t\t};\n\t\t}\n\t};\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*\n* Also owns `mintKeyPair` (local-dev spec § 1) — the one key-pair generator\n* both the deploy-time `S3Credentials` resource and the local dev bucket\n* emulator's credential provisioning use.\n*/\nfunction randomBytes(n) {\n\treturn crypto.getRandomValues(new Uint8Array(n));\n}\nfunction toHexUpper(bytes) {\n\treturn Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\").toUpperCase();\n}\n/** A fresh SigV4 key pair: an AKIA-prefixed id and a 40-char base64 secret. */\nfunction mintKeyPair() {\n\treturn {\n\t\taccessKeyId: `AKIA${toHexUpper(randomBytes(8))}`,\n\t\tsecretAccessKey: btoa(String.fromCharCode(...randomBytes(30)))\n\t};\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$1 = 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$1;\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/memory-store.ts\n/**\n* An in-memory `ObjectStore` for the protocol tests — the same contract the\n* Postgres store (D3) implements. Test-only; never wired into a deployed\n* service. Not re-exported from the authoring barrel.\n*/\nconst DEFAULT_MAX_KEYS = 1e3;\nfunction etagOf(bytes) {\n\treturn `\"${createHash(\"sha256\").update(bytes).digest(\"hex\")}\"`;\n}\nvar MemoryObjectStore = class {\n\tentries = /* @__PURE__ */ new Map();\n\tid(bucket, key) {\n\t\treturn `${bucket}\\x00${key}`;\n\t}\n\tasync put(bucket, key, bytes, opts = {}) {\n\t\tconst copy = bytes.slice();\n\t\tconst etag = etagOf(copy);\n\t\tthis.entries.set(this.id(bucket, key), {\n\t\t\tbytes: copy,\n\t\t\tetag,\n\t\t\tcontentType: opts.contentType ?? \"application/octet-stream\"\n\t\t});\n\t\treturn { etag };\n\t}\n\tasync get(bucket, key, opts = {}) {\n\t\tconst entry = this.entries.get(this.id(bucket, key));\n\t\tif (!entry) return null;\n\t\tconst size = entry.bytes.byteLength;\n\t\tif (opts.range) {\n\t\t\tconst start = opts.range.start;\n\t\t\tconst end = opts.range.end === void 0 ? size - 1 : Math.min(opts.range.end, size - 1);\n\t\t\treturn {\n\t\t\t\tbytes: start > end ? /* @__PURE__ */ new Uint8Array(0) : entry.bytes.slice(start, end + 1),\n\t\t\t\tetag: entry.etag,\n\t\t\t\tcontentType: entry.contentType,\n\t\t\t\tsize\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tbytes: entry.bytes.slice(),\n\t\t\tetag: entry.etag,\n\t\t\tcontentType: entry.contentType,\n\t\t\tsize\n\t\t};\n\t}\n\tasync head(bucket, key) {\n\t\tconst entry = this.entries.get(this.id(bucket, key));\n\t\tif (!entry) return null;\n\t\treturn {\n\t\t\tetag: entry.etag,\n\t\t\tsize: entry.bytes.byteLength,\n\t\t\tcontentType: entry.contentType\n\t\t};\n\t}\n\tasync delete(bucket, key) {\n\t\tthis.entries.delete(this.id(bucket, key));\n\t}\n\tasync list(bucket, opts = {}) {\n\t\tconst prefix = opts.prefix ?? \"\";\n\t\tconst maxKeys = opts.maxKeys ?? DEFAULT_MAX_KEYS;\n\t\tconst token = opts.continuationToken;\n\t\tconst prefixHit = `${bucket}\\x00${prefix}`;\n\t\tconst matching = [...this.entries.keys()].filter((id) => id.startsWith(prefixHit)).map((id) => id.slice(bucket.length + 1)).sort().filter((key) => token === void 0 ? true : key > token);\n\t\tconst page = matching.slice(0, maxKeys);\n\t\tconst isTruncated = matching.length > maxKeys;\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//#endregion\nexport { MemoryObjectStore, createS3Handler, fsStore, mintKeyPair, verifyRequest };\n\n//# sourceMappingURL=index.mjs.map","import { c as readOwnVersion, f as StateFile, p as readJsonFile, t as isValidSegment } from \"./segments-NpKN-46R.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as http from \"node:http\";\nimport { createS3Handler, fsStore } from \"@internal/s3-protocol\";\n//#region src/buckets-main.ts\n/**\n* The bucket emulator daemon (local-dev spec § 2 `buckets-main.ts`): the S3\n* wire protocol (`@internal/s3-protocol`'s handler + `fsStore`) over\n* registered per-app, per-bucket directories, multi-tenant via physical\n* names `<app>--<name>`. Admin lives under `/_pcdev/` (the underscore can't\n* collide with a valid bucket name). Plain `node:http`.\n*\n* Runs as its own OS process, started by `daemon.ts`'s `ensureDaemon` via\n* `process.execPath <this file> --port <n> --state-dir <dir>`.\n*/\nconst STATE_MODE = 384;\nconst PHYSICAL_BUCKET_NAME_RE = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;\nconst MULTIPART_MESSAGE = \"multipart upload is not supported by the local dev bucket emulator yet\";\nfunction isBucketRegistration(value) {\n\treturn typeof value === \"object\" && value !== null && \"app\" in value && typeof value.app === \"string\" && \"name\" in value && typeof value.name === \"string\" && \"dir\" in value && typeof value.dir === \"string\";\n}\nfunction isCredentialRecord(value) {\n\treturn typeof value === \"object\" && value !== null && \"app\" in value && typeof value.app === \"string\" && \"secretAccessKey\" in value && typeof value.secretAccessKey === \"string\";\n}\nfunction isBucketsState(value) {\n\treturn typeof value === \"object\" && value !== null && \"buckets\" in value && typeof value.buckets === \"object\" && value.buckets !== null && Object.values(value.buckets).every(isBucketRegistration) && \"credentials\" in value && typeof value.credentials === \"object\" && value.credentials !== null && Object.values(value.credentials).every(isCredentialRecord);\n}\nfunction isBucketBody(value) {\n\treturn typeof value === \"object\" && value !== null && \"dir\" in value && typeof value.dir === \"string\";\n}\nfunction isCredentialsBody(value) {\n\treturn typeof value === \"object\" && value !== null && \"accessKeyId\" in value && typeof value.accessKeyId === \"string\" && \"secretAccessKey\" in value && typeof value.secretAccessKey === \"string\";\n}\nfunction parseArgs(argv) {\n\tlet port;\n\tlet stateDir;\n\tfor (let i = 0; i < argv.length; i++) if (argv[i] === \"--port\") port = Number(argv[i + 1]);\n\telse if (argv[i] === \"--state-dir\") stateDir = argv[i + 1];\n\tif (port === void 0 || Number.isNaN(port)) throw new Error(\"buckets-main: --port <n> is required\");\n\tif (stateDir === void 0) throw new Error(\"buckets-main: --state-dir <dir> is required\");\n\treturn {\n\t\tport,\n\t\tstateDir\n\t};\n}\nfunction readBody(req) {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks = [];\n\t\treq.on(\"data\", (chunk) => chunks.push(chunk));\n\t\treq.on(\"end\", () => resolve(Buffer.concat(chunks)));\n\t\treq.on(\"error\", reject);\n\t});\n}\nfunction toWebHeaders(nodeHeaders) {\n\tconst headers = new Headers();\n\tfor (const [key, value] of Object.entries(nodeHeaders)) {\n\t\tif (value === void 0) continue;\n\t\tif (Array.isArray(value)) for (const v of value) headers.append(key, v);\n\t\telse headers.set(key, value);\n\t}\n\treturn headers;\n}\nasync function sendWebResponse(res, webRes) {\n\tconst headers = {};\n\twebRes.headers.forEach((value, key) => {\n\t\theaders[key] = value;\n\t});\n\tconst buf = Buffer.from(await webRes.arrayBuffer());\n\tres.writeHead(webRes.status, headers);\n\tres.end(buf);\n}\nfunction main() {\n\tconst { port, stateDir } = parseArgs(process.argv.slice(2));\n\tconst ownVersion = readOwnVersion();\n\tconst stateJsonPath = path.join(stateDir, \"state.json\");\n\tconst stateFile = new StateFile(stateJsonPath, STATE_MODE);\n\tlet state = {\n\t\tbuckets: {},\n\t\tcredentials: {}\n\t};\n\tfunction schedulePersist() {\n\t\tstateFile.write(state);\n\t}\n\tconst store = fsStore((physicalName) => state.buckets[physicalName]?.dir);\n\tfunction json(res, status, body) {\n\t\tres.writeHead(status, { \"content-type\": \"application/json\" });\n\t\tres.end(JSON.stringify(body));\n\t}\n\tfunction text(res, status, body) {\n\t\tres.writeHead(status, { \"content-type\": \"text/plain; charset=utf-8\" });\n\t\tres.end(body);\n\t}\n\tfunction badSegment(res, segment) {\n\t\ttext(res, 400, `invalid path segment \"${segment}\": must match /^[a-z0-9][a-z0-9-]*$/ and be at most 63 characters`);\n\t}\n\tasync function handlePutBucket(req, res, app, name) {\n\t\tconst physicalName = `${app}--${name}`;\n\t\tif (!PHYSICAL_BUCKET_NAME_RE.test(physicalName)) return text(res, 400, `invalid bucket \"${physicalName}\" (app \"${app}\", name \"${name}\"): the physical bucket name must match /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/ and be at most 63 characters`);\n\t\tconst raw = await readBody(req);\n\t\tlet parsed;\n\t\ttry {\n\t\t\tparsed = JSON.parse(raw.toString(\"utf8\"));\n\t\t} catch {\n\t\t\treturn text(res, 400, \"malformed JSON body\");\n\t\t}\n\t\tif (!isBucketBody(parsed)) return text(res, 400, \"malformed bucket body: expected { \\\"dir\\\": string }\");\n\t\tawait fs.promises.mkdir(parsed.dir, { recursive: true });\n\t\tstate.buckets[physicalName] = {\n\t\t\tapp,\n\t\t\tname,\n\t\t\tdir: parsed.dir\n\t\t};\n\t\tschedulePersist();\n\t\tres.writeHead(204);\n\t\tres.end();\n\t}\n\tasync function handlePutCredentials(req, res, app) {\n\t\tconst raw = await readBody(req);\n\t\tlet parsed;\n\t\ttry {\n\t\t\tparsed = JSON.parse(raw.toString(\"utf8\"));\n\t\t} catch {\n\t\t\treturn text(res, 400, \"malformed JSON body\");\n\t\t}\n\t\tif (!isCredentialsBody(parsed)) return text(res, 400, \"malformed credentials body: expected { \\\"accessKeyId\\\", \\\"secretAccessKey\\\" }\");\n\t\tconst existing = state.credentials[parsed.accessKeyId];\n\t\tif (existing && existing.app !== app) return text(res, 409, `accessKeyId \"${parsed.accessKeyId}\" is already registered by a different app`);\n\t\tstate.credentials[parsed.accessKeyId] = {\n\t\t\tapp,\n\t\t\tsecretAccessKey: parsed.secretAccessKey\n\t\t};\n\t\tschedulePersist();\n\t\tres.writeHead(204);\n\t\tres.end();\n\t}\n\tfunction handleDeleteApp(res, app) {\n\t\tfor (const [key, reg] of Object.entries(state.buckets)) if (reg.app === app) delete state.buckets[key];\n\t\tfor (const [key, cred] of Object.entries(state.credentials)) if (cred.app === app) delete state.credentials[key];\n\t\tschedulePersist();\n\t\tres.writeHead(204);\n\t\tres.end();\n\t}\n\t/** Path-style addressing: the bucket is the first non-empty path segment. Mirrors the handler's own `parseTarget`, which isn't exported. */\n\tfunction bucketFromPath(pathname) {\n\t\tconst first = pathname.split(\"/\").find((s) => s.length > 0);\n\t\treturn first !== void 0 ? decodeURIComponent(first) : void 0;\n\t}\n\t/**\n\t* Credentials accepted for THIS request's target bucket only — its\n\t* owning app, derived from the bucket's registration (the authoritative\n\t* source for the `<app>--<name>` split; unregistered apps/names may\n\t* themselves contain `--`, so the registration is trusted over re-parsing\n\t* the string). An unknown bucket or an app with no registered credentials\n\t* yields no candidates, which still resolves through the real 403 path\n\t* below — never a bespoke \"unknown bucket\" shortcut that would reveal\n\t* anything.\n\t*/\n\tfunction credentialsForBucket(bucket) {\n\t\tconst owningApp = bucket !== void 0 ? state.buckets[bucket]?.app : void 0;\n\t\tif (owningApp === void 0) return [];\n\t\treturn Object.entries(state.credentials).filter(([, rec]) => rec.app === owningApp).map(([accessKeyId, rec]) => ({\n\t\t\taccessKeyId,\n\t\t\tsecretAccessKey: rec.secretAccessKey\n\t\t}));\n\t}\n\tasync function handleS3Wire(req, res, url) {\n\t\tif (url.searchParams.has(\"uploads\") || url.searchParams.has(\"uploadId\") || url.searchParams.has(\"partNumber\")) return text(res, 501, MULTIPART_MESSAGE);\n\t\tconst method = req.method ?? \"GET\";\n\t\tconst bodyBuf = method !== \"GET\" && method !== \"HEAD\" ? await readBody(req) : void 0;\n\t\tconst fullUrl = `http://${req.headers.host ?? `127.0.0.1:${String(port)}`}${req.url ?? \"/\"}`;\n\t\tconst headers = toWebHeaders(req.headers);\n\t\tconst candidates = credentialsForBucket(bucketFromPath(url.pathname));\n\t\tif (candidates.length === 0) candidates.push({\n\t\t\taccessKeyId: \"\",\n\t\t\tsecretAccessKey: \"\"\n\t\t});\n\t\tlet last;\n\t\tfor (const credentials of candidates) {\n\t\t\tconst webReq = new Request(fullUrl, {\n\t\t\t\tmethod,\n\t\t\t\theaders,\n\t\t\t\t...bodyBuf && bodyBuf.length > 0 ? { body: bodyBuf } : {}\n\t\t\t});\n\t\t\tconst webRes = await createS3Handler({\n\t\t\t\tstore,\n\t\t\t\tcredentials\n\t\t\t})(webReq);\n\t\t\tif (webRes.status !== 403) return sendWebResponse(res, webRes);\n\t\t\tlast = webRes;\n\t\t}\n\t\tif (last) await sendWebResponse(res, last);\n\t}\n\tasync function handleRequest(req, res) {\n\t\tconst url = new URL(req.url ?? \"/\", `http://127.0.0.1:${String(port)}`);\n\t\tconst method = req.method ?? \"GET\";\n\t\tif (method === \"GET\" && url.pathname === \"/health\") return json(res, 200, { version: ownVersion });\n\t\tif (url.pathname === \"/_pcdev/health\" || url.pathname.startsWith(\"/_pcdev/\")) {\n\t\t\tconst segments = url.pathname.split(\"/\").filter((s) => s.length > 0).map((s) => decodeURIComponent(s));\n\t\t\tif (method === \"GET\" && segments.length === 2 && segments[1] === \"health\") return json(res, 200, { version: ownVersion });\n\t\t\tif (segments[1] === \"apps\" && segments.length >= 3) {\n\t\t\t\tconst app = segments[2];\n\t\t\t\tif (app === void 0 || !isValidSegment(app)) return badSegment(res, app ?? \"\");\n\t\t\t\tif (method === \"PUT\" && segments.length === 5 && segments[3] === \"buckets\") {\n\t\t\t\t\tconst name = segments[4];\n\t\t\t\t\tif (name === void 0 || !isValidSegment(name)) return badSegment(res, name ?? \"\");\n\t\t\t\t\treturn handlePutBucket(req, res, app, name);\n\t\t\t\t}\n\t\t\t\tif (method === \"PUT\" && segments.length === 4 && segments[3] === \"credentials\") return handlePutCredentials(req, res, app);\n\t\t\t\tif (method === \"DELETE\" && segments.length === 3) return handleDeleteApp(res, app);\n\t\t\t}\n\t\t\tres.writeHead(404);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\t\treturn handleS3Wire(req, res, url);\n\t}\n\tconst server = http.createServer((req, res) => {\n\t\thandleRequest(req, res).catch((err) => {\n\t\t\tif (!res.headersSent) res.writeHead(500, { \"content-type\": \"text/plain\" });\n\t\t\tres.end(err instanceof Error ? err.message : String(err));\n\t\t});\n\t});\n\tasync function shutdown() {\n\t\tawait stateFile.flush();\n\t\tserver.close();\n\t\tprocess.exit(0);\n\t}\n\tprocess.on(\"SIGTERM\", () => void shutdown());\n\tprocess.on(\"SIGINT\", () => void shutdown());\n\treadJsonFile(stateJsonPath, isBucketsState).then((loaded) => {\n\t\tif (loaded) state = loaded;\n\t\tserver.listen(port, \"127.0.0.1\", () => {\n\t\t\tconsole.log(`[dev-emulators] buckets-main listening on 127.0.0.1:${String(port)}`);\n\t\t});\n\t}).catch((err) => {\n\t\tconsole.error(\"buckets-main: failed to load state\", err);\n\t\tprocess.exit(1);\n\t});\n}\nmain();\n//#endregion\nexport {};\n\n//# sourceMappingURL=buckets-main.mjs.map"],"mappings":"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"}
@@ -0,0 +1,532 @@
1
+ import { i as readOwnVersion, n as isValidSegment, r as readJsonFile, t as StateFile } from "./segments-NpKN-46R-B01DmCqy.mjs";
2
+ import { n as portNumbers, t as getPorts } from "./get-port-BYnpbW5H.mjs";
3
+ import * as fs from "node:fs";
4
+ import { spawn } from "node:child_process";
5
+ import * as path from "node:path";
6
+ import * as http from "node:http";
7
+ //#region ../../1-prisma-cloud/0-lowering/dev-emulators/dist/compute-main.mjs
8
+ /**
9
+ * The Compute emulator daemon (local-dev spec § 2 `compute-main.ts`): a small
10
+ * local counterpart of the platform's compute service. Owns service child
11
+ * processes (spawned `bun bootstrap.js` from a real packaged artifact),
12
+ * supervises them (crash backoff, held after repeated fast crashes), and
13
+ * serves a loopback JSON admin API plus per-service log streaming.
14
+ *
15
+ * Runs as its own OS process, started by `daemon.ts`'s `ensureDaemon` via
16
+ * `process.execPath <this file> --port <n> --state-dir <dir>`. Everything it
17
+ * needs travels on argv and each request's own body — it reads no
18
+ * environment variable of its own.
19
+ */
20
+ const MIN_SERVICE_PORT = 3e3;
21
+ const MAX_SERVICE_PORT = 65535;
22
+ const TERMINATE_GRACE_MS = 5e3;
23
+ const STABLE_UPTIME_MS = 3e4;
24
+ const BASE_BACKOFF_MS = 1e3;
25
+ const MAX_BACKOFF_MS = 3e4;
26
+ const MAX_CONSECUTIVE_FAST_EXITS = 5;
27
+ const LOG_POLL_INTERVAL_MS = 100;
28
+ const APPS_STATE_MODE = 384;
29
+ const BUN_NOT_FOUND_MESSAGE = "local dev runs services under bun — the Prisma Compute runtime — and `bun` was not found on PATH. Install it: https://bun.sh.";
30
+ function isServiceStatus(value) {
31
+ return value === "running" || value === "backoff" || value === "held" || value === "stopped";
32
+ }
33
+ function isStringRecord(value) {
34
+ return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
35
+ }
36
+ function isServiceRecord(value) {
37
+ if (typeof value !== "object" || value === null) return false;
38
+ if (!("id" in value) || typeof value.id !== "string") return false;
39
+ if (!("address" in value) || typeof value.address !== "string") return false;
40
+ if (!("port" in value) || typeof value.port !== "number") return false;
41
+ if (!("status" in value) || !isServiceStatus(value.status)) return false;
42
+ if (!("logPath" in value) || typeof value.logPath !== "string") return false;
43
+ if ("pid" in value && value.pid !== void 0 && typeof value.pid !== "number") return false;
44
+ if ("lastExitCode" in value && value.lastExitCode !== void 0 && typeof value.lastExitCode !== "number") return false;
45
+ if ("artifactHash" in value && value.artifactHash !== void 0 && typeof value.artifactHash !== "string") return false;
46
+ if ("artifactDir" in value && value.artifactDir !== void 0 && typeof value.artifactDir !== "string") return false;
47
+ if ("env" in value && value.env !== void 0 && !isStringRecord(value.env)) return false;
48
+ return true;
49
+ }
50
+ function isAppRecord(value) {
51
+ return typeof value === "object" && value !== null && "services" in value && typeof value.services === "object" && value.services !== null && Object.values(value.services).every(isServiceRecord);
52
+ }
53
+ function isAppsState(value) {
54
+ return typeof value === "object" && value !== null && Object.values(value).every(isAppRecord);
55
+ }
56
+ function isDeploymentBody(value) {
57
+ return typeof value === "object" && value !== null && "address" in value && typeof value.address === "string" && "artifactDir" in value && typeof value.artifactDir === "string" && "artifactHash" in value && typeof value.artifactHash === "string" && "env" in value && isStringRecord(value.env) && "port" in value && typeof value.port === "number";
58
+ }
59
+ function sleep(ms) {
60
+ return new Promise((resolve) => setTimeout(resolve, ms));
61
+ }
62
+ /** Append-only per-service log file — child stdout/stderr plus `[emulator]` supervision lines. No rotation in v1. */
63
+ var ServiceLog = class {
64
+ filePath;
65
+ fd;
66
+ constructor(filePath) {
67
+ this.filePath = filePath;
68
+ }
69
+ ensureOpen() {
70
+ if (this.fd === void 0) {
71
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
72
+ this.fd = fs.openSync(this.filePath, "a");
73
+ }
74
+ return this.fd;
75
+ }
76
+ writeRaw(chunk) {
77
+ fs.writeSync(this.ensureOpen(), chunk);
78
+ }
79
+ writeLine(line) {
80
+ fs.writeSync(this.ensureOpen(), `${line}\n`);
81
+ }
82
+ /** Closes the fd if one was ever opened. Idempotent. */
83
+ close() {
84
+ if (this.fd === void 0) return;
85
+ fs.closeSync(this.fd);
86
+ this.fd = void 0;
87
+ }
88
+ };
89
+ function parseArgs(argv) {
90
+ let port;
91
+ let stateDir;
92
+ for (let i = 0; i < argv.length; i++) if (argv[i] === "--port") port = Number(argv[i + 1]);
93
+ else if (argv[i] === "--state-dir") stateDir = argv[i + 1];
94
+ if (port === void 0 || Number.isNaN(port)) throw new Error("compute-main: --port <n> is required");
95
+ if (stateDir === void 0) throw new Error("compute-main: --state-dir <dir> is required");
96
+ return {
97
+ port,
98
+ stateDir
99
+ };
100
+ }
101
+ /** Resolves `bun` from THIS request's env PATH — never the daemon's own. POSIX-only (Windows is out of scope). */
102
+ function resolveBunOnPath(env) {
103
+ const pathVar = env["PATH"];
104
+ if (!pathVar) return void 0;
105
+ for (const dir of pathVar.split(path.delimiter)) {
106
+ if (dir === "") continue;
107
+ const candidate = path.join(dir, "bun");
108
+ try {
109
+ fs.accessSync(candidate, fs.constants.X_OK);
110
+ return candidate;
111
+ } catch {}
112
+ }
113
+ }
114
+ function main() {
115
+ const { port, stateDir } = parseArgs(process.argv.slice(2));
116
+ const ownVersion = readOwnVersion();
117
+ const appsJsonPath = path.join(stateDir, "apps.json");
118
+ const stateFile = new StateFile(appsJsonPath, APPS_STATE_MODE);
119
+ let state = {};
120
+ const runtimes = /* @__PURE__ */ new Map();
121
+ function runtimeKey(app, id) {
122
+ return `${app}/${id}`;
123
+ }
124
+ function getRuntime(app, id) {
125
+ const key = runtimeKey(app, id);
126
+ let rt = runtimes.get(key);
127
+ if (!rt) {
128
+ rt = {
129
+ child: void 0,
130
+ consecutiveFastExits: 0,
131
+ startedAt: void 0,
132
+ stableTimer: void 0,
133
+ backoffTimer: void 0,
134
+ expectedExit: false,
135
+ log: void 0
136
+ };
137
+ runtimes.set(key, rt);
138
+ }
139
+ return rt;
140
+ }
141
+ function serviceLogPath(app, id) {
142
+ return path.join(stateDir, "logs", app, `${id}.log`);
143
+ }
144
+ function getLog(app, id, logPath) {
145
+ const rt = getRuntime(app, id);
146
+ if (!rt.log) rt.log = new ServiceLog(logPath);
147
+ return rt.log;
148
+ }
149
+ function schedulePersist() {
150
+ stateFile.write(state);
151
+ }
152
+ function clearStableTimer(rt) {
153
+ if (rt.stableTimer) clearTimeout(rt.stableTimer);
154
+ rt.stableTimer = void 0;
155
+ }
156
+ function clearBackoffTimer(rt) {
157
+ if (rt.backoffTimer) clearTimeout(rt.backoffTimer);
158
+ rt.backoffTimer = void 0;
159
+ }
160
+ function usedServicePorts() {
161
+ const ports = /* @__PURE__ */ new Set();
162
+ for (const app of Object.values(state)) for (const svc of Object.values(app.services)) ports.add(svc.port);
163
+ return ports;
164
+ }
165
+ /**
166
+ * The smallest genuinely free port at or above `MIN_SERVICE_PORT`,
167
+ * excluding this daemon's own persisted allocations — persistence and
168
+ * the range policy stay ours; whether a candidate is actually bindable
169
+ * is `get-port`'s (spec § 2's dependency razor).
170
+ */
171
+ async function smallestUnusedServicePort() {
172
+ return getPorts({
173
+ port: portNumbers(MIN_SERVICE_PORT, MAX_SERVICE_PORT),
174
+ exclude: usedServicePorts()
175
+ });
176
+ }
177
+ async function getOrCreateService(app, id) {
178
+ let appRec = state[app];
179
+ if (!appRec) {
180
+ appRec = { services: {} };
181
+ state[app] = appRec;
182
+ }
183
+ let svc = appRec.services[id];
184
+ if (svc) return svc;
185
+ svc = {
186
+ id,
187
+ address: id,
188
+ port: await smallestUnusedServicePort(),
189
+ status: "stopped",
190
+ logPath: serviceLogPath(app, id)
191
+ };
192
+ appRec.services[id] = svc;
193
+ schedulePersist();
194
+ return svc;
195
+ }
196
+ function waitForExit(child) {
197
+ return new Promise((resolve) => {
198
+ child.once("exit", () => resolve());
199
+ });
200
+ }
201
+ /** SIGTERM, wait up to `graceMs`, SIGKILL. Marks the exit as expected so supervision doesn't fire. */
202
+ async function killChild(rt, graceMs) {
203
+ const child = rt.child;
204
+ if (!child || child.pid === void 0) return;
205
+ rt.expectedExit = true;
206
+ const exited = waitForExit(child);
207
+ child.kill("SIGTERM");
208
+ const timedOut = Symbol("timeout");
209
+ if (await Promise.race([exited.then(() => void 0), sleep(graceMs).then(() => timedOut)]) === timedOut) {
210
+ child.kill("SIGKILL");
211
+ await exited;
212
+ }
213
+ }
214
+ function handleChildExit(app, id, svc, rt, code) {
215
+ clearStableTimer(rt);
216
+ rt.child = void 0;
217
+ delete svc.pid;
218
+ if (code !== null) svc.lastExitCode = code;
219
+ if (rt.expectedExit) {
220
+ rt.expectedExit = false;
221
+ schedulePersist();
222
+ return;
223
+ }
224
+ const uptime = rt.startedAt !== void 0 ? Date.now() - rt.startedAt : 0;
225
+ if (uptime >= STABLE_UPTIME_MS) rt.consecutiveFastExits = 0;
226
+ const attemptNumber = rt.consecutiveFastExits;
227
+ if (uptime < STABLE_UPTIME_MS) rt.consecutiveFastExits += 1;
228
+ if (rt.consecutiveFastExits >= MAX_CONSECUTIVE_FAST_EXITS) {
229
+ svc.status = "held";
230
+ schedulePersist();
231
+ getLog(app, id, svc.logPath).writeLine(`[emulator] held after ${String(MAX_CONSECUTIVE_FAST_EXITS)} consecutive fast exits — send a new deployment to resume`);
232
+ return;
233
+ }
234
+ const delayMs = Math.min(MAX_BACKOFF_MS, BASE_BACKOFF_MS * 2 ** attemptNumber);
235
+ svc.status = "backoff";
236
+ schedulePersist();
237
+ getLog(app, id, svc.logPath).writeLine(`[emulator] exited (code ${code === null ? "null" : String(code)}) — restarting in ${String(delayMs / 1e3)}s`);
238
+ rt.backoffTimer = setTimeout(() => {
239
+ rt.backoffTimer = void 0;
240
+ spawnService(app, id, svc, rt);
241
+ }, delayMs);
242
+ }
243
+ async function spawnService(app, id, svc, rt) {
244
+ const env = svc.env ?? {};
245
+ const artifactDir = svc.artifactDir ?? ".";
246
+ const bunPath = resolveBunOnPath(env);
247
+ if (!bunPath) {
248
+ svc.status = "stopped";
249
+ delete svc.pid;
250
+ schedulePersist();
251
+ return {
252
+ ok: false,
253
+ message: BUN_NOT_FOUND_MESSAGE
254
+ };
255
+ }
256
+ const log = getLog(app, id, svc.logPath);
257
+ const child = spawn(bunPath, ["bootstrap.js"], {
258
+ cwd: artifactDir,
259
+ env,
260
+ stdio: [
261
+ "ignore",
262
+ "pipe",
263
+ "pipe"
264
+ ]
265
+ });
266
+ rt.child = child;
267
+ rt.expectedExit = false;
268
+ rt.startedAt = Date.now();
269
+ clearStableTimer(rt);
270
+ rt.stableTimer = setTimeout(() => {
271
+ rt.consecutiveFastExits = 0;
272
+ }, STABLE_UPTIME_MS);
273
+ child.stdout?.on("data", (chunk) => log.writeRaw(chunk));
274
+ child.stderr?.on("data", (chunk) => log.writeRaw(chunk));
275
+ child.on("exit", (code) => handleChildExit(app, id, svc, rt, code));
276
+ svc.status = "running";
277
+ if (child.pid !== void 0) svc.pid = child.pid;
278
+ schedulePersist();
279
+ return { ok: true };
280
+ }
281
+ async function stopService(svc, rt) {
282
+ clearBackoffTimer(rt);
283
+ clearStableTimer(rt);
284
+ await killChild(rt, TERMINATE_GRACE_MS);
285
+ svc.status = "stopped";
286
+ delete svc.pid;
287
+ schedulePersist();
288
+ }
289
+ /**
290
+ * The session-resume signal: Alchemy's no-op reconcile never fires a
291
+ * deployment PUT, so nothing else restarts a service a previous session
292
+ * stopped. Reuses the exact deployment-PUT start rules — same spawn
293
+ * path, same supervision reset, and an explicit resume clears `held`
294
+ * the same way a deployment PUT does — but from the service's already
295
+ * STORED deployment spec, since no new one arrives with a start.
296
+ */
297
+ async function startService(app, id, svc) {
298
+ if (svc.artifactHash === void 0) return;
299
+ if (svc.status === "running") return;
300
+ const rt = getRuntime(app, id);
301
+ clearBackoffTimer(rt);
302
+ clearStableTimer(rt);
303
+ rt.consecutiveFastExits = 0;
304
+ await spawnService(app, id, svc, rt);
305
+ }
306
+ function json(res, status, body) {
307
+ const text = JSON.stringify(body);
308
+ res.writeHead(status, { "content-type": "application/json" });
309
+ res.end(text);
310
+ }
311
+ function text(res, status, body) {
312
+ res.writeHead(status, { "content-type": "text/plain; charset=utf-8" });
313
+ res.end(body);
314
+ }
315
+ function badSegment(res, segment) {
316
+ text(res, 400, `invalid path segment "${segment}": must match /^[a-z0-9][a-z0-9-]*$/ and be at most 63 characters`);
317
+ }
318
+ function readBody(req) {
319
+ return new Promise((resolve, reject) => {
320
+ const chunks = [];
321
+ req.on("data", (chunk) => chunks.push(chunk));
322
+ req.on("end", () => resolve(Buffer.concat(chunks)));
323
+ req.on("error", reject);
324
+ });
325
+ }
326
+ function serviceView(svc) {
327
+ return {
328
+ id: svc.id,
329
+ address: svc.address,
330
+ port: svc.port,
331
+ url: `http://localhost:${String(svc.port)}`,
332
+ status: svc.status,
333
+ ...svc.pid !== void 0 ? { pid: svc.pid } : {},
334
+ ...svc.lastExitCode !== void 0 ? { lastExitCode: svc.lastExitCode } : {},
335
+ ...svc.artifactHash !== void 0 ? { artifactHash: svc.artifactHash } : {},
336
+ logPath: svc.logPath
337
+ };
338
+ }
339
+ function envEquals(a, b) {
340
+ if (!a) return false;
341
+ const aKeys = Object.keys(a);
342
+ const bKeys = Object.keys(b);
343
+ if (aKeys.length !== bKeys.length) return false;
344
+ return aKeys.every((k) => a[k] === b[k]);
345
+ }
346
+ async function handleDeployment(req, res, app, id) {
347
+ const raw = await readBody(req);
348
+ let parsed;
349
+ try {
350
+ parsed = JSON.parse(raw.toString("utf8"));
351
+ } catch {
352
+ return text(res, 400, "malformed JSON body");
353
+ }
354
+ if (!isDeploymentBody(parsed)) return text(res, 400, "malformed deployment body");
355
+ const svc = await getOrCreateService(app, id);
356
+ const rt = getRuntime(app, id);
357
+ const changed = svc.artifactHash !== parsed.artifactHash || !envEquals(svc.env, parsed.env);
358
+ if (svc.status === "running") {
359
+ if (!changed) {
360
+ res.writeHead(204);
361
+ res.end();
362
+ return;
363
+ }
364
+ await killChild(rt, TERMINATE_GRACE_MS);
365
+ } else clearBackoffTimer(rt);
366
+ svc.address = parsed.address;
367
+ svc.port = parsed.port;
368
+ clearStableTimer(rt);
369
+ rt.consecutiveFastExits = 0;
370
+ svc.artifactHash = parsed.artifactHash;
371
+ svc.env = parsed.env;
372
+ svc.artifactDir = parsed.artifactDir;
373
+ schedulePersist();
374
+ const result = await spawnService(app, id, svc, rt);
375
+ if (!result.ok) return text(res, 500, result.message ?? "failed to start the service");
376
+ res.writeHead(204);
377
+ res.end();
378
+ }
379
+ function handleFollowLogs(res, logPath) {
380
+ fs.mkdirSync(path.dirname(logPath), { recursive: true });
381
+ if (!fs.existsSync(logPath)) fs.closeSync(fs.openSync(logPath, "a"));
382
+ res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
383
+ let offset = 0;
384
+ let stopped = false;
385
+ let timer;
386
+ const tick = () => {
387
+ if (stopped) return;
388
+ let stat;
389
+ try {
390
+ stat = fs.statSync(logPath);
391
+ } catch {
392
+ stat = void 0;
393
+ }
394
+ if (stat && stat.size > offset) {
395
+ const fd = fs.openSync(logPath, "r");
396
+ const buf = Buffer.alloc(stat.size - offset);
397
+ fs.readSync(fd, buf, 0, buf.length, offset);
398
+ fs.closeSync(fd);
399
+ offset = stat.size;
400
+ res.write(buf);
401
+ }
402
+ if (!stopped) timer = setTimeout(tick, LOG_POLL_INTERVAL_MS);
403
+ };
404
+ tick();
405
+ const stop = () => {
406
+ stopped = true;
407
+ if (timer) clearTimeout(timer);
408
+ };
409
+ res.on("close", stop);
410
+ }
411
+ async function handleRequest(req, res) {
412
+ const url = new URL(req.url ?? "/", `http://127.0.0.1:${String(port)}`);
413
+ const method = req.method ?? "GET";
414
+ const segments = url.pathname.split("/").filter((s) => s.length > 0).map((s) => decodeURIComponent(s));
415
+ if (method === "GET" && segments.length === 1 && segments[0] === "health") return json(res, 200, { version: ownVersion });
416
+ if (segments[0] === "apps" && segments.length >= 2) {
417
+ const app = segments[1];
418
+ if (app === void 0 || !isValidSegment(app)) return badSegment(res, app ?? "");
419
+ if (method === "PUT" && segments.length === 4 && segments[2] === "services") {
420
+ const id = segments[3];
421
+ if (id === void 0 || !isValidSegment(id)) return badSegment(res, id ?? "");
422
+ const svc = await getOrCreateService(app, id);
423
+ return json(res, 200, {
424
+ port: svc.port,
425
+ url: `http://localhost:${String(svc.port)}`
426
+ });
427
+ }
428
+ if (method === "PUT" && segments.length === 5 && segments[2] === "services" && segments[4] === "deployment") {
429
+ const id = segments[3];
430
+ if (id === void 0 || !isValidSegment(id)) return badSegment(res, id ?? "");
431
+ return handleDeployment(req, res, app, id);
432
+ }
433
+ if (method === "GET" && segments.length === 3 && segments[2] === "services") {
434
+ const appRec = state[app];
435
+ return json(res, 200, appRec ? Object.values(appRec.services).map(serviceView) : []);
436
+ }
437
+ if (method === "GET" && segments.length === 5 && segments[2] === "services" && segments[4] === "logs") {
438
+ const id = segments[3];
439
+ if (id === void 0 || !isValidSegment(id)) return badSegment(res, id ?? "");
440
+ const svc = state[app]?.services[id];
441
+ if (!svc) return text(res, 404, `no such service "${id}" in app "${app}"`);
442
+ if (url.searchParams.get("follow") === "1") {
443
+ handleFollowLogs(res, svc.logPath);
444
+ return;
445
+ }
446
+ const content = fs.existsSync(svc.logPath) ? fs.readFileSync(svc.logPath) : Buffer.alloc(0);
447
+ res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
448
+ res.end(content);
449
+ return;
450
+ }
451
+ if (method === "POST" && segments.length === 3 && segments[2] === "stop") {
452
+ const appRec = state[app];
453
+ if (appRec) await Promise.all(Object.entries(appRec.services).map(([id, svc]) => stopService(svc, getRuntime(app, id))));
454
+ res.writeHead(204);
455
+ res.end();
456
+ return;
457
+ }
458
+ if (method === "POST" && segments.length === 3 && segments[2] === "start") {
459
+ const appRec = state[app];
460
+ if (appRec) await Promise.all(Object.entries(appRec.services).map(([id, svc]) => startService(app, id, svc)));
461
+ res.writeHead(204);
462
+ res.end();
463
+ return;
464
+ }
465
+ if (method === "DELETE" && segments.length === 2) {
466
+ const appRec = state[app];
467
+ if (appRec) {
468
+ await Promise.all(Object.entries(appRec.services).map(([id, svc]) => stopService(svc, getRuntime(app, id))));
469
+ for (const id of Object.keys(appRec.services)) {
470
+ const key = runtimeKey(app, id);
471
+ runtimes.get(key)?.log?.close();
472
+ runtimes.delete(key);
473
+ }
474
+ delete state[app];
475
+ schedulePersist();
476
+ }
477
+ await fs.promises.rm(path.join(stateDir, "logs", app), {
478
+ recursive: true,
479
+ force: true
480
+ });
481
+ res.writeHead(204);
482
+ res.end();
483
+ return;
484
+ }
485
+ }
486
+ res.writeHead(404);
487
+ res.end();
488
+ }
489
+ const server = http.createServer((req, res) => {
490
+ handleRequest(req, res).catch((err) => {
491
+ if (!res.headersSent) res.writeHead(500, { "content-type": "text/plain" });
492
+ res.end(err instanceof Error ? err.message : String(err));
493
+ });
494
+ });
495
+ let shuttingDown = false;
496
+ async function shutdown() {
497
+ if (shuttingDown) return;
498
+ shuttingDown = true;
499
+ const kills = [];
500
+ for (const rt of runtimes.values()) {
501
+ clearBackoffTimer(rt);
502
+ clearStableTimer(rt);
503
+ if (rt.child) kills.push(killChild(rt, TERMINATE_GRACE_MS));
504
+ }
505
+ await Promise.all(kills);
506
+ await stateFile.flush();
507
+ server.close();
508
+ process.exit(0);
509
+ }
510
+ process.on("SIGTERM", () => void shutdown());
511
+ process.on("SIGINT", () => void shutdown());
512
+ readJsonFile(appsJsonPath, isAppsState).then((loaded) => {
513
+ if (loaded) {
514
+ for (const appRec of Object.values(loaded)) for (const svc of Object.values(appRec.services)) if (svc.status === "running" || svc.status === "backoff") {
515
+ svc.status = "stopped";
516
+ delete svc.pid;
517
+ }
518
+ state = loaded;
519
+ }
520
+ server.listen(port, "127.0.0.1", () => {
521
+ console.log(`[dev-emulators] compute-main listening on 127.0.0.1:${String(port)}`);
522
+ });
523
+ }).catch((err) => {
524
+ console.error("compute-main: failed to load state", err);
525
+ process.exit(1);
526
+ });
527
+ }
528
+ main();
529
+ //#endregion
530
+ export {};
531
+
532
+ //# sourceMappingURL=compute-main.mjs.map