@prisma/composer 0.1.0-dev.1 → 0.1.0-dev.10
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/{app-config-CpWN1ZfP-CZ1c6Eqk.d.mts → app-config-Bhu93gjR-BFLsU-gF.d.mts} +6 -6
- package/dist/assertions.d.mts +1 -1
- package/dist/assertions.mjs.map +1 -1
- package/dist/bin.mjs.map +1 -1
- package/dist/casts-Ci5rYYaR.mjs.map +1 -1
- package/dist/casts.d.mts +1 -1
- package/dist/config-Bz1VQOKQ.d.mts +1 -0
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs.map +1 -1
- package/dist/deploy-Bz1VQOKQ.d.mts +1 -0
- package/dist/deploy.d.mts +2 -2
- package/dist/deploy.mjs.map +1 -1
- package/dist/dist-B0axxnBf.mjs.map +1 -1
- package/dist/{graph-DXuL5tN6-BeAHOb0u.d.mts → graph-B7NcPiOr-UazPNQTc.d.mts} +3 -3
- package/dist/{config-ad92ubCB-D0-dZUgA.d.mts → graph-types-BgT9UEdm-Cg7wPD1I.d.mts} +106 -106
- package/dist/{index-Cy4C23u1.d.mts → index-BoUJ4fEs.d.mts} +3 -3
- package/dist/{index-C1f1Aot7.d.mts → index-DYfGGlv4.d.mts} +4 -4
- package/dist/index.d.mts +3 -3
- package/dist/nextjs-control.d.mts +5 -5
- package/dist/nextjs-control.mjs.map +1 -1
- package/dist/nextjs.d.mts +1 -1
- package/dist/nextjs.mjs.map +1 -1
- package/dist/node-control.d.mts +4 -4
- package/dist/node-control.mjs.map +1 -1
- package/dist/node.d.mts +3 -3
- package/dist/node.mjs.map +1 -1
- package/dist/report.d.mts +4 -4
- package/dist/report.mjs +1 -1
- package/dist/report.mjs.map +1 -1
- package/dist/{rpc.d.mts → service-rpc.d.mts} +4 -4
- package/dist/{rpc.mjs → service-rpc.mjs} +2 -2
- package/dist/service-rpc.mjs.map +1 -0
- package/dist/testing.d.mts +2 -2
- package/dist/testing.mjs.map +1 -1
- package/package.json +13 -13
- package/dist/config-D-h0FACe.d.mts +0 -1
- package/dist/deploy-D-h0FACe.d.mts +0 -1
- package/dist/rpc.mjs.map +0 -1
package/dist/node-control.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as Bundle, i as AssembleInput, l as ExtensionDescriptor } from "./app-config-
|
|
2
|
-
import "./config-
|
|
3
|
-
import "./deploy-
|
|
1
|
+
import { a as Bundle, i as AssembleInput, l as ExtensionDescriptor } from "./app-config-Bhu93gjR-BFLsU-gF.mjs";
|
|
2
|
+
import "./config-Bz1VQOKQ.mjs";
|
|
3
|
+
import "./deploy-Bz1VQOKQ.mjs";
|
|
4
4
|
//#region ../../0-framework/2-authoring/node/dist/control.d.mts
|
|
5
|
-
//#region src/control.d.ts
|
|
5
|
+
//#region src/exports/control.d.ts
|
|
6
6
|
declare function assemble(input: AssembleInput): Promise<Bundle>;
|
|
7
7
|
/** The node build extension descriptor — `prisma-composer.config.ts` lists it under `extensions`. */
|
|
8
8
|
declare const nodeBuild: () => ExtensionDescriptor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-control.mjs","names":[],"sources":["../../../0-framework/2-authoring/node/dist/control.mjs"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { build } from \"esbuild\";\n//#region src/control.ts\n/**\n* The extension's control entry (ADR-0017): `nodeBuild()` returns the build\n* descriptor `prisma-composer.config.ts` lists. Deploy-only (ADR-0005): the user\n* builds their own runnable; `assemble` copies what they built under `bundle/`\n* and adds the framework's boot wrapper — it never bundles or transforms the\n* app's code.\n*\n* Two forms, chosen by the descriptor: without `dir`, `entry` is a single\n* self-contained file and only that file is copied. With `dir`, the whole\n* directory is copied verbatim and `entry` names the file inside it that boots.\n* Neither form discovers anything — no tree-walking for an entry, no filename\n* heuristics; the author states the paths and we copy exactly those.\n*\n* The wrapper is a SEPARATE esbuild build of the service module (declarations\n* only, whose node carries run()/load()), emitted as `main.mjs` at the\n* working-dir root — a dictated name (object entry `{ main }`), not a\n* discovered one. run() and the app entry must be independent module instances\n* that hand off through process.env, so the wrapper is its own self-contained\n* build; `@prisma/*` is inlined, `bun` is a Compute built-in.\n*\n* Artifact layout: `<cwd>/.prisma-composer/artifacts/<address>/` (deploy-owned,\n* ADR-0005) holds `main.mjs` at the root and the app's built runnable under\n* `bundle/`.\n*/\n/** Narrows the shared BuildAdapter to this extension's own descriptor — the value-level mirror of the registry routing on (extension, type). `dir` is optional: absent is the single-file form. */\nfunction isNodeBuild(descriptor) {\n\treturn descriptor.type === \"node\" && (!(\"dir\" in descriptor) || typeof descriptor.dir === \"string\");\n}\n/** The single-file form: `entry` is the whole built runnable, resolved against dirname(module) (ADR-0004). */\nfunction resolveFile(entrySpec, moduleDir) {\n\tconst entryPath = path.resolve(moduleDir, entrySpec);\n\tif (!fs.existsSync(entryPath)) throw new Error(`no built entry at ${entryPath} — run your build first (the build adapter's entry, \"${entrySpec}\", resolves against dirname(module)).`);\n\tconst entryFile = path.basename(entryPath);\n\treturn {\n\t\tsource: entryPath,\n\t\tsourceField: \"entry\",\n\t\tentry: entryFile,\n\t\tcopyInto: async (bundleDir) => {\n\t\t\tawait fs.promises.mkdir(bundleDir, { recursive: true });\n\t\t\tawait fs.promises.copyFile(entryPath, path.join(bundleDir, entryFile));\n\t\t}\n\t};\n}\n/**\n* The directory form: `dir` is the built tree, resolved against dirname(module)\n* (ADR-0004) and copied whole; `entry` resolves inside `dir` and names the file\n* that boots. An `entry` that resolves outside `dir` is rejected rather than\n* followed — only `dir` is ever copied.\n*/\nasync function resolveDir(dirSpec, entrySpec, moduleDir) {\n\tconst dirPath = path.resolve(moduleDir, dirSpec);\n\tif (!fs.existsSync(dirPath)) throw new Error(`no built directory at ${dirPath} — run your build first (the build adapter's dir, \"${dirSpec}\", resolves against dirname(module)).`);\n\tif (!fs.statSync(dirPath).isDirectory()) throw new Error(`the build adapter's dir (\"${dirPath}\") is not a directory — drop dir to deploy a single built file, naming it as entry.`);\n\tconst entryPath = path.resolve(dirPath, entrySpec);\n\tif (!entryPath.startsWith(dirPath + path.sep)) throw new Error(`the build adapter's entry (\"${entrySpec}\") resolves to ${entryPath}, which is not inside dir (\"${dirPath}\") — in the directory form entry names a file inside dir, and only dir is copied.`);\n\tif (!fs.existsSync(entryPath) || !fs.statSync(entryPath).isFile()) throw new Error(`no built entry at ${entryPath} — run your build first (the build adapter's entry, \"${entrySpec}\", resolves inside dir, \"${dirPath}\").`);\n\tawait assertNoSymlinks(dirPath);\n\treturn {\n\t\tsource: dirPath,\n\t\tsourceField: \"dir\",\n\t\tentry: path.relative(dirPath, entryPath).split(path.sep).join(\"/\"),\n\t\tcopyInto: (bundleDir) => fs.promises.cp(dirPath, bundleDir, { recursive: true })\n\t};\n}\n/**\n* Compute's packager rejects symlinks, so a tree containing one cannot deploy.\n* We fail here, naming the links, rather than dereferencing them on the copy:\n* the artifact must be what the author's build produced (ADR-0005), and\n* following a link that points outside `dir` would pull in files the author\n* never named. The walk reads dirents (lstat semantics), so a symlinked\n* directory is reported and never descended into.\n*/\nasync function assertNoSymlinks(dirPath) {\n\tconst found = [];\n\tconst walk = async (current) => {\n\t\tfor (const entry of await fs.promises.readdir(current, { withFileTypes: true })) {\n\t\t\tconst full = path.join(current, entry.name);\n\t\t\tif (entry.isSymbolicLink()) found.push(full);\n\t\t\telse if (entry.isDirectory()) await walk(full);\n\t\t}\n\t};\n\tawait walk(dirPath);\n\tif (found.length === 0) return;\n\tconst listed = found.slice(0, 5).join(\", \");\n\tthrow new Error(`the build adapter's dir (\"${dirPath}\") contains symlinks, which the platform's packager rejects: ${listed}${found.length > 5 ? `, and ${found.length - 5} more` : \"\"}. The tree is copied verbatim, so make your build emit real files in dir (for example, a hoisted node_modules, or dereference the links into dir with cp -RL).`);\n}\n/**\n* The working dir is cleared on every assemble, so it must not overlap the copy\n* source: inside it, the rm would delete the source before the copy; the other\n* way round, the copy would recurse into its own output.\n*/\nfunction assertOutsideWorkDir(runnable, workDir) {\n\tconst { source, sourceField } = runnable;\n\tif (source === workDir || source.startsWith(workDir + path.sep)) throw new Error(`the build adapter's ${sourceField} (\"${source}\") resolves inside the deploy working dir (\"${workDir}\"), which is cleared on every assemble — point ${sourceField} at your build output elsewhere.`);\n\tif (workDir.startsWith(source + path.sep)) throw new Error(`the deploy working dir (\"${workDir}\") sits inside the build adapter's ${sourceField} (\"${source}\"), so assembling would copy the artifact into itself — point ${sourceField} at your build output elsewhere.`);\n}\nasync function assemble(input) {\n\tif (!isNodeBuild(input.build)) throw new Error(`@prisma/composer/node/control: expected a \"node\" build adapter, got \"${input.build.type}\".`);\n\tconst buildDescriptor = input.build;\n\tconst serviceModule = fileURLToPath(buildDescriptor.module);\n\tconst moduleDir = path.dirname(serviceModule);\n\tconst runnable = buildDescriptor.dir === void 0 ? resolveFile(buildDescriptor.entry, moduleDir) : await resolveDir(buildDescriptor.dir, buildDescriptor.entry, moduleDir);\n\tconst workDir = path.join(input.cwd, \".prisma-composer\", \"artifacts\", input.address);\n\tassertOutsideWorkDir(runnable, workDir);\n\tawait fs.promises.rm(workDir, {\n\t\trecursive: true,\n\t\tforce: true\n\t});\n\tawait fs.promises.mkdir(workDir, { recursive: true });\n\tawait build({\n\t\tentryPoints: { main: serviceModule },\n\t\toutdir: workDir,\n\t\tbundle: true,\n\t\tformat: \"esm\",\n\t\tplatform: \"node\",\n\t\texternal: [\"bun\", \"bun:*\"],\n\t\toutExtension: { \".js\": \".mjs\" }\n\t});\n\tif (!fs.existsSync(path.join(workDir, \"main.mjs\"))) throw new Error(`esbuild produced no main.mjs in ${workDir}`);\n\tawait runnable.copyInto(path.join(workDir, \"bundle\"));\n\treturn {\n\t\tdir: workDir,\n\t\tentry: path.posix.join(\"bundle\", runnable.entry)\n\t};\n}\n/** The node build extension descriptor — `prisma-composer.config.ts` lists it under `extensions`. */\nconst nodeBuild = () => ({\n\tid: \"@prisma/composer/node\",\n\tnodes: { node: {\n\t\tkind: \"build\",\n\t\tassemble\n\t} }\n});\n//#endregion\nexport { assemble, nodeBuild };\n\n//# sourceMappingURL=control.mjs.map"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"node-control.mjs","names":[],"sources":["../../../0-framework/2-authoring/node/dist/control.mjs"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { build } from \"esbuild\";\n//#region src/exports/control.ts\n/**\n* The extension's control entry (ADR-0017): `nodeBuild()` returns the build\n* descriptor `prisma-composer.config.ts` lists. Deploy-only (ADR-0005): the user\n* builds their own runnable; `assemble` copies what they built under `bundle/`\n* and adds the framework's boot wrapper — it never bundles or transforms the\n* app's code.\n*\n* Two forms, chosen by the descriptor: without `dir`, `entry` is a single\n* self-contained file and only that file is copied. With `dir`, the whole\n* directory is copied verbatim and `entry` names the file inside it that boots.\n* Neither form discovers anything — no tree-walking for an entry, no filename\n* heuristics; the author states the paths and we copy exactly those.\n*\n* The wrapper is a SEPARATE esbuild build of the service module (declarations\n* only, whose node carries run()/load()), emitted as `main.mjs` at the\n* working-dir root — a dictated name (object entry `{ main }`), not a\n* discovered one. run() and the app entry must be independent module instances\n* that hand off through process.env, so the wrapper is its own self-contained\n* build; `@prisma/*` is inlined, `bun` is a Compute built-in.\n*\n* Artifact layout: `<cwd>/.prisma-composer/artifacts/<address>/` (deploy-owned,\n* ADR-0005) holds `main.mjs` at the root and the app's built runnable under\n* `bundle/`.\n*/\n/** Narrows the shared BuildAdapter to this extension's own descriptor — the value-level mirror of the registry routing on (extension, type). `dir` is optional: absent is the single-file form. */\nfunction isNodeBuild(descriptor) {\n\treturn descriptor.type === \"node\" && (!(\"dir\" in descriptor) || typeof descriptor.dir === \"string\");\n}\n/** The single-file form: `entry` is the whole built runnable, resolved against dirname(module) (ADR-0004). */\nfunction resolveFile(entrySpec, moduleDir) {\n\tconst entryPath = path.resolve(moduleDir, entrySpec);\n\tif (!fs.existsSync(entryPath)) throw new Error(`no built entry at ${entryPath} — run your build first (the build adapter's entry, \"${entrySpec}\", resolves against dirname(module)).`);\n\tconst entryFile = path.basename(entryPath);\n\treturn {\n\t\tsource: entryPath,\n\t\tsourceField: \"entry\",\n\t\tentry: entryFile,\n\t\tcopyInto: async (bundleDir) => {\n\t\t\tawait fs.promises.mkdir(bundleDir, { recursive: true });\n\t\t\tawait fs.promises.copyFile(entryPath, path.join(bundleDir, entryFile));\n\t\t}\n\t};\n}\n/**\n* The directory form: `dir` is the built tree, resolved against dirname(module)\n* (ADR-0004) and copied whole; `entry` resolves inside `dir` and names the file\n* that boots. An `entry` that resolves outside `dir` is rejected rather than\n* followed — only `dir` is ever copied.\n*/\nasync function resolveDir(dirSpec, entrySpec, moduleDir) {\n\tconst dirPath = path.resolve(moduleDir, dirSpec);\n\tif (!fs.existsSync(dirPath)) throw new Error(`no built directory at ${dirPath} — run your build first (the build adapter's dir, \"${dirSpec}\", resolves against dirname(module)).`);\n\tif (!fs.statSync(dirPath).isDirectory()) throw new Error(`the build adapter's dir (\"${dirPath}\") is not a directory — drop dir to deploy a single built file, naming it as entry.`);\n\tconst entryPath = path.resolve(dirPath, entrySpec);\n\tif (!entryPath.startsWith(dirPath + path.sep)) throw new Error(`the build adapter's entry (\"${entrySpec}\") resolves to ${entryPath}, which is not inside dir (\"${dirPath}\") — in the directory form entry names a file inside dir, and only dir is copied.`);\n\tif (!fs.existsSync(entryPath) || !fs.statSync(entryPath).isFile()) throw new Error(`no built entry at ${entryPath} — run your build first (the build adapter's entry, \"${entrySpec}\", resolves inside dir, \"${dirPath}\").`);\n\tawait assertNoSymlinks(dirPath);\n\treturn {\n\t\tsource: dirPath,\n\t\tsourceField: \"dir\",\n\t\tentry: path.relative(dirPath, entryPath).split(path.sep).join(\"/\"),\n\t\tcopyInto: (bundleDir) => fs.promises.cp(dirPath, bundleDir, { recursive: true })\n\t};\n}\n/**\n* Compute's packager rejects symlinks, so a tree containing one cannot deploy.\n* We fail here, naming the links, rather than dereferencing them on the copy:\n* the artifact must be what the author's build produced (ADR-0005), and\n* following a link that points outside `dir` would pull in files the author\n* never named. The walk reads dirents (lstat semantics), so a symlinked\n* directory is reported and never descended into.\n*/\nasync function assertNoSymlinks(dirPath) {\n\tconst found = [];\n\tconst walk = async (current) => {\n\t\tfor (const entry of await fs.promises.readdir(current, { withFileTypes: true })) {\n\t\t\tconst full = path.join(current, entry.name);\n\t\t\tif (entry.isSymbolicLink()) found.push(full);\n\t\t\telse if (entry.isDirectory()) await walk(full);\n\t\t}\n\t};\n\tawait walk(dirPath);\n\tif (found.length === 0) return;\n\tconst listed = found.slice(0, 5).join(\", \");\n\tthrow new Error(`the build adapter's dir (\"${dirPath}\") contains symlinks, which the platform's packager rejects: ${listed}${found.length > 5 ? `, and ${found.length - 5} more` : \"\"}. The tree is copied verbatim, so make your build emit real files in dir (for example, a hoisted node_modules, or dereference the links into dir with cp -RL).`);\n}\n/**\n* The working dir is cleared on every assemble, so it must not overlap the copy\n* source: inside it, the rm would delete the source before the copy; the other\n* way round, the copy would recurse into its own output.\n*/\nfunction assertOutsideWorkDir(runnable, workDir) {\n\tconst { source, sourceField } = runnable;\n\tif (source === workDir || source.startsWith(workDir + path.sep)) throw new Error(`the build adapter's ${sourceField} (\"${source}\") resolves inside the deploy working dir (\"${workDir}\"), which is cleared on every assemble — point ${sourceField} at your build output elsewhere.`);\n\tif (workDir.startsWith(source + path.sep)) throw new Error(`the deploy working dir (\"${workDir}\") sits inside the build adapter's ${sourceField} (\"${source}\"), so assembling would copy the artifact into itself — point ${sourceField} at your build output elsewhere.`);\n}\nasync function assemble(input) {\n\tif (!isNodeBuild(input.build)) throw new Error(`@prisma/composer/node/control: expected a \"node\" build adapter, got \"${input.build.type}\".`);\n\tconst buildDescriptor = input.build;\n\tconst serviceModule = fileURLToPath(buildDescriptor.module);\n\tconst moduleDir = path.dirname(serviceModule);\n\tconst runnable = buildDescriptor.dir === void 0 ? resolveFile(buildDescriptor.entry, moduleDir) : await resolveDir(buildDescriptor.dir, buildDescriptor.entry, moduleDir);\n\tconst workDir = path.join(input.cwd, \".prisma-composer\", \"artifacts\", input.address);\n\tassertOutsideWorkDir(runnable, workDir);\n\tawait fs.promises.rm(workDir, {\n\t\trecursive: true,\n\t\tforce: true\n\t});\n\tawait fs.promises.mkdir(workDir, { recursive: true });\n\tawait build({\n\t\tentryPoints: { main: serviceModule },\n\t\toutdir: workDir,\n\t\tbundle: true,\n\t\tformat: \"esm\",\n\t\tplatform: \"node\",\n\t\texternal: [\"bun\", \"bun:*\"],\n\t\toutExtension: { \".js\": \".mjs\" }\n\t});\n\tif (!fs.existsSync(path.join(workDir, \"main.mjs\"))) throw new Error(`esbuild produced no main.mjs in ${workDir}`);\n\tawait runnable.copyInto(path.join(workDir, \"bundle\"));\n\treturn {\n\t\tdir: workDir,\n\t\tentry: path.posix.join(\"bundle\", runnable.entry)\n\t};\n}\n/** The node build extension descriptor — `prisma-composer.config.ts` lists it under `extensions`. */\nconst nodeBuild = () => ({\n\tid: \"@prisma/composer/node\",\n\tnodes: { node: {\n\t\tkind: \"build\",\n\t\tassemble\n\t} }\n});\n//#endregion\nexport { assemble, nodeBuild };\n\n//# sourceMappingURL=control.mjs.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAS,YAAY,YAAY;CAChC,OAAO,WAAW,SAAS,WAAW,EAAE,SAAS,eAAe,OAAO,WAAW,QAAQ;AAC3F;;AAEA,SAAS,YAAY,WAAW,WAAW;CAC1C,MAAM,YAAY,KAAK,QAAQ,WAAW,SAAS;CACnD,IAAI,CAAC,GAAG,WAAW,SAAS,GAAG,MAAM,IAAI,MAAM,qBAAqB,UAAU,uDAAuD,UAAU,sCAAsC;CACrL,MAAM,YAAY,KAAK,SAAS,SAAS;CACzC,OAAO;EACN,QAAQ;EACR,aAAa;EACb,OAAO;EACP,UAAU,OAAO,cAAc;GAC9B,MAAM,GAAG,SAAS,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;GACtD,MAAM,GAAG,SAAS,SAAS,WAAW,KAAK,KAAK,WAAW,SAAS,CAAC;EACtE;CACD;AACD;;;;;;;AAOA,eAAe,WAAW,SAAS,WAAW,WAAW;CACxD,MAAM,UAAU,KAAK,QAAQ,WAAW,OAAO;CAC/C,IAAI,CAAC,GAAG,WAAW,OAAO,GAAG,MAAM,IAAI,MAAM,yBAAyB,QAAQ,qDAAqD,QAAQ,sCAAsC;CACjL,IAAI,CAAC,GAAG,SAAS,OAAO,CAAC,CAAC,YAAY,GAAG,MAAM,IAAI,MAAM,6BAA6B,QAAQ,oFAAoF;CAClL,MAAM,YAAY,KAAK,QAAQ,SAAS,SAAS;CACjD,IAAI,CAAC,UAAU,WAAW,UAAU,KAAK,GAAG,GAAG,MAAM,IAAI,MAAM,+BAA+B,UAAU,iBAAiB,UAAU,8BAA8B,QAAQ,kFAAkF;CAC3P,IAAI,CAAC,GAAG,WAAW,SAAS,KAAK,CAAC,GAAG,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,MAAM,IAAI,MAAM,qBAAqB,UAAU,uDAAuD,UAAU,2BAA2B,QAAQ,IAAI;CAC1N,MAAM,iBAAiB,OAAO;CAC9B,OAAO;EACN,QAAQ;EACR,aAAa;EACb,OAAO,KAAK,SAAS,SAAS,SAAS,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;EACjE,WAAW,cAAc,GAAG,SAAS,GAAG,SAAS,WAAW,EAAE,WAAW,KAAK,CAAC;CAChF;AACD;;;;;;;;;AASA,eAAe,iBAAiB,SAAS;CACxC,MAAM,QAAQ,CAAC;CACf,MAAM,OAAO,OAAO,YAAY;EAC/B,KAAK,MAAM,SAAS,MAAM,GAAG,SAAS,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;GAChF,MAAM,OAAO,KAAK,KAAK,SAAS,MAAM,IAAI;GAC1C,IAAI,MAAM,eAAe,GAAG,MAAM,KAAK,IAAI;QACtC,IAAI,MAAM,YAAY,GAAG,MAAM,KAAK,IAAI;EAC9C;CACD;CACA,MAAM,KAAK,OAAO;CAClB,IAAI,MAAM,WAAW,GAAG;CACxB,MAAM,SAAS,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;CAC1C,MAAM,IAAI,MAAM,6BAA6B,QAAQ,+DAA+D,SAAS,MAAM,SAAS,IAAI,SAAS,MAAM,SAAS,EAAE,SAAS,GAAG,+JAA+J;AACtV;;;;;;AAMA,SAAS,qBAAqB,UAAU,SAAS;CAChD,MAAM,EAAE,QAAQ,gBAAgB;CAChC,IAAI,WAAW,WAAW,OAAO,WAAW,UAAU,KAAK,GAAG,GAAG,MAAM,IAAI,MAAM,uBAAuB,YAAY,KAAK,OAAO,8CAA8C,QAAQ,iDAAiD,YAAY,iCAAiC;CACpR,IAAI,QAAQ,WAAW,SAAS,KAAK,GAAG,GAAG,MAAM,IAAI,MAAM,4BAA4B,QAAQ,qCAAqC,YAAY,KAAK,OAAO,gEAAgE,YAAY,iCAAiC;AAC1Q;AACA,eAAe,SAAS,OAAO;CAC9B,IAAI,CAAC,YAAY,MAAM,KAAK,GAAG,MAAM,IAAI,MAAM,wEAAwE,MAAM,MAAM,KAAK,GAAG;CAC3I,MAAM,kBAAkB,MAAM;CAC9B,MAAM,gBAAgB,cAAc,gBAAgB,MAAM;CAC1D,MAAM,YAAY,KAAK,QAAQ,aAAa;CAC5C,MAAM,WAAW,gBAAgB,QAAQ,KAAK,IAAI,YAAY,gBAAgB,OAAO,SAAS,IAAI,MAAM,WAAW,gBAAgB,KAAK,gBAAgB,OAAO,SAAS;CACxK,MAAM,UAAU,KAAK,KAAK,MAAM,KAAK,oBAAoB,aAAa,MAAM,OAAO;CACnF,qBAAqB,UAAU,OAAO;CACtC,MAAM,GAAG,SAAS,GAAG,SAAS;EAC7B,WAAW;EACX,OAAO;CACR,CAAC;CACD,MAAM,GAAG,SAAS,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;CACpD,MAAM,MAAM;EACX,aAAa,EAAE,MAAM,cAAc;EACnC,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,UAAU;EACV,UAAU,CAAC,OAAO,OAAO;EACzB,cAAc,EAAE,OAAO,OAAO;CAC/B,CAAC;CACD,IAAI,CAAC,GAAG,WAAW,KAAK,KAAK,SAAS,UAAU,CAAC,GAAG,MAAM,IAAI,MAAM,mCAAmC,SAAS;CAChH,MAAM,SAAS,SAAS,KAAK,KAAK,SAAS,QAAQ,CAAC;CACpD,OAAO;EACN,KAAK;EACL,OAAO,KAAK,MAAM,KAAK,UAAU,SAAS,KAAK;CAChD;AACD;;AAEA,MAAM,mBAAmB;CACxB,IAAI;CACJ,OAAO,EAAE,MAAM;EACd,MAAM;EACN;CACD,EAAE;AACH"}
|
package/dist/node.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as BuildAdapter } from "./
|
|
2
|
-
import "./index-
|
|
1
|
+
import { t as BuildAdapter } from "./graph-types-BgT9UEdm-Cg7wPD1I.mjs";
|
|
2
|
+
import "./index-BoUJ4fEs.mjs";
|
|
3
3
|
//#region ../../0-framework/2-authoring/node/dist/index.d.mts
|
|
4
|
-
//#region src/index.d.ts
|
|
4
|
+
//#region src/exports/index.d.ts
|
|
5
5
|
/** The node build adapter's descriptor. `dir` is the directory form's own extra path input (the built tree to copy verbatim), beyond the shared `{ extension, type, module, entry }`; absent, `entry` is the whole built runnable. */
|
|
6
6
|
interface NodeBuildAdapter extends BuildAdapter {
|
|
7
7
|
readonly type: 'node';
|
package/dist/node.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.mjs","names":[],"sources":["../../../0-framework/2-authoring/node/dist/index.mjs"],"sourcesContent":["//#region src/index.ts\nconst nodeBuild = (opts) => ({\n\textension: \"@prisma/composer/node\",\n\ttype: \"node\",\n\tmodule: opts.module,\n\tentry: opts.entry,\n\t...opts.dir === void 0 ? {} : { dir: opts.dir }\n});\n//#endregion\nexport { nodeBuild as default };\n\n//# sourceMappingURL=index.mjs.map"],"mappings":";AACA,MAAM,aAAa,UAAU;CAC5B,WAAW;CACX,MAAM;CACN,QAAQ,KAAK;CACb,OAAO,KAAK;CACZ,GAAG,KAAK,QAAQ,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI;AAC/C"}
|
|
1
|
+
{"version":3,"file":"node.mjs","names":[],"sources":["../../../0-framework/2-authoring/node/dist/index.mjs"],"sourcesContent":["//#region src/exports/index.ts\nconst nodeBuild = (opts) => ({\n\textension: \"@prisma/composer/node\",\n\ttype: \"node\",\n\tmodule: opts.module,\n\tentry: opts.entry,\n\t...opts.dir === void 0 ? {} : { dir: opts.dir }\n});\n//#endregion\nexport { nodeBuild as default };\n\n//# sourceMappingURL=index.mjs.map"],"mappings":";AACA,MAAM,aAAa,UAAU;CAC5B,WAAW;CACX,MAAM;CACN,QAAQ,KAAK;CACb,OAAO,KAAK;CACZ,GAAG,KAAK,QAAQ,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI;AAC/C"}
|
package/dist/report.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { c as DeploymentResult } from "./app-config-
|
|
2
|
-
import "./deploy-
|
|
3
|
-
//#region ../../0-framework/3-tooling/cli/dist/
|
|
4
|
-
//#region src/render-deployment.d.ts
|
|
1
|
+
import { c as DeploymentResult } from "./app-config-Bhu93gjR-BFLsU-gF.mjs";
|
|
2
|
+
import "./deploy-Bz1VQOKQ.mjs";
|
|
3
|
+
//#region ../../0-framework/3-tooling/cli/dist/report.d.mts
|
|
4
|
+
//#region src/exports/render-deployment.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* Renders a deploy's result as the app's own topology. Pure — returns the
|
|
7
7
|
* string; the caller prints.
|
package/dist/report.mjs
CHANGED
package/dist/report.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.mjs","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/
|
|
1
|
+
{"version":3,"file":"report.mjs","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.mjs"],"sourcesContent":["//#region src/exports/render-deployment.ts\n/** Gap between the deepest tree label and the entity column. */\nconst LABEL_GAP = 3;\nconst emptyNode = (segment) => ({\n\tsegment,\n\tchildren: /* @__PURE__ */ new Map()\n});\n/** Builds the address tree, splitting each dot-address into its segments. */\nfunction buildTree(nodes) {\n\tconst root = emptyNode(\"\");\n\tfor (const deployed of nodes) {\n\t\tlet node = root;\n\t\tfor (const segment of deployed.address.split(\".\")) {\n\t\t\tlet child = node.children.get(segment);\n\t\t\tif (child === void 0) {\n\t\t\t\tchild = emptyNode(segment);\n\t\t\t\tnode.children.set(segment, child);\n\t\t\t}\n\t\t\tnode = child;\n\t\t}\n\t\tnode.deployed = deployed;\n\t}\n\treturn root;\n}\n/** Flattens the tree to rows in address order, drawing the box guides. */\nfunction toRows(node, guides, rows) {\n\tconst children = Array.from(node.children.values());\n\tchildren.forEach((child, index) => {\n\t\tconst isLast = index === children.length - 1;\n\t\trows.push({\n\t\t\tlabel: `${guides}${isLast ? \"└─ \" : \"├─ \"}${child.segment}`,\n\t\t\tcontinuation: `${guides}${isLast ? \" \" : \"│ \"}`,\n\t\t\tdeployed: child.deployed\n\t\t});\n\t\ttoRows(child, `${guides}${isLast ? \" \" : \"│ \"}`, rows);\n\t});\n}\n/** `kind id` — the one line an entity gets. */\nconst entityLine = (entity) => `${entity.kind} ${entity.id}`;\n/** Pads `prefix` out to `width`, so every entity starts in the same column. */\nconst pad = (prefix, width) => prefix.padEnd(width, \" \");\n/**\n* Renders a deploy's result as the app's own topology. Pure — returns the\n* string; the caller prints.\n*/\nfunction renderDeployment(result) {\n\tconst rows = [];\n\ttoRows(buildTree(result.nodes), \"\", rows);\n\tconst column = Math.max(0, ...rows.map((row) => row.label.length)) + LABEL_GAP;\n\tconst lines = [result.app];\n\tfor (const row of rows) {\n\t\tif (row.deployed === void 0) {\n\t\t\tlines.push(row.label);\n\t\t\tcontinue;\n\t\t}\n\t\tif (row.deployed.entities.length === 0) {\n\t\t\tlines.push(`${pad(row.label, column)}(no entities reported)`);\n\t\t\tcontinue;\n\t\t}\n\t\trow.deployed.entities.forEach((entity, index) => {\n\t\t\tconst prefix = index === 0 ? row.label : row.continuation;\n\t\t\tlines.push(`${pad(prefix, column)}${entityLine(entity)}`);\n\t\t\tif (entity.url !== void 0) lines.push(`${pad(row.continuation, column)}${entity.url}`);\n\t\t});\n\t}\n\treturn lines.join(\"\\n\");\n}\n/**\n* The report hook the generated stack file wires into `LowerOptions`. Prints a\n* leading blank line so the summary separates from alchemy's own apply output.\n*/\nfunction deploymentReport(result) {\n\tconsole.log(\"\");\n\tconsole.log(renderDeployment(result));\n}\n//#endregion\nexport { deploymentReport, renderDeployment };\n\n//# sourceMappingURL=report.mjs.map"],"mappings":";;AAEA,MAAM,YAAY;AAClB,MAAM,aAAa,aAAa;CAC/B;CACA,0BAA0B,IAAI,IAAI;AACnC;;AAEA,SAAS,UAAU,OAAO;CACzB,MAAM,OAAO,UAAU,EAAE;CACzB,KAAK,MAAM,YAAY,OAAO;EAC7B,IAAI,OAAO;EACX,KAAK,MAAM,WAAW,SAAS,QAAQ,MAAM,GAAG,GAAG;GAClD,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO;GACrC,IAAI,UAAU,KAAK,GAAG;IACrB,QAAQ,UAAU,OAAO;IACzB,KAAK,SAAS,IAAI,SAAS,KAAK;GACjC;GACA,OAAO;EACR;EACA,KAAK,WAAW;CACjB;CACA,OAAO;AACR;;AAEA,SAAS,OAAO,MAAM,QAAQ,MAAM;CACnC,MAAM,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;CAClD,SAAS,SAAS,OAAO,UAAU;EAClC,MAAM,SAAS,UAAU,SAAS,SAAS;EAC3C,KAAK,KAAK;GACT,OAAO,GAAG,SAAS,SAAS,QAAQ,QAAQ,MAAM;GAClD,cAAc,GAAG,SAAS,SAAS,QAAQ;GAC3C,UAAU,MAAM;EACjB,CAAC;EACD,OAAO,OAAO,GAAG,SAAS,SAAS,QAAQ,SAAS,IAAI;CACzD,CAAC;AACF;;AAEA,MAAM,cAAc,WAAW,GAAG,OAAO,KAAK,GAAG,OAAO;;AAExD,MAAM,OAAO,QAAQ,UAAU,OAAO,OAAO,OAAO,GAAG;;;;;AAKvD,SAAS,iBAAiB,QAAQ;CACjC,MAAM,OAAO,CAAC;CACd,OAAO,UAAU,OAAO,KAAK,GAAG,IAAI,IAAI;CACxC,MAAM,SAAS,KAAK,IAAI,GAAG,GAAG,KAAK,KAAK,QAAQ,IAAI,MAAM,MAAM,CAAC,IAAI;CACrE,MAAM,QAAQ,CAAC,OAAO,GAAG;CACzB,KAAK,MAAM,OAAO,MAAM;EACvB,IAAI,IAAI,aAAa,KAAK,GAAG;GAC5B,MAAM,KAAK,IAAI,KAAK;GACpB;EACD;EACA,IAAI,IAAI,SAAS,SAAS,WAAW,GAAG;GACvC,MAAM,KAAK,GAAG,IAAI,IAAI,OAAO,MAAM,EAAE,uBAAuB;GAC5D;EACD;EACA,IAAI,SAAS,SAAS,SAAS,QAAQ,UAAU;GAChD,MAAM,SAAS,UAAU,IAAI,IAAI,QAAQ,IAAI;GAC7C,MAAM,KAAK,GAAG,IAAI,QAAQ,MAAM,IAAI,WAAW,MAAM,GAAG;GACxD,IAAI,OAAO,QAAQ,KAAK,GAAG,MAAM,KAAK,GAAG,IAAI,IAAI,cAAc,MAAM,IAAI,OAAO,KAAK;EACtF,CAAC;CACF;CACA,OAAO,MAAM,KAAK,IAAI;AACvB;;;;;AAKA,SAAS,iBAAiB,QAAQ;CACjC,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,iBAAiB,MAAM,CAAC;AACrC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as RunnableServiceNode, k as ProvisionNeed, o as Contract, s as DependencyEnd } from "./
|
|
2
|
-
import "./index-
|
|
1
|
+
import { P as RunnableServiceNode, k as ProvisionNeed, o as Contract, s as DependencyEnd } from "./graph-types-BgT9UEdm-Cg7wPD1I.mjs";
|
|
2
|
+
import "./index-BoUJ4fEs.mjs";
|
|
3
3
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
|
-
//#region ../../0-framework/2-authoring/rpc/dist/index.d.mts
|
|
4
|
+
//#region ../../0-framework/2-authoring/service-rpc/dist/index.d.mts
|
|
5
5
|
//#region src/rpc.d.ts
|
|
6
6
|
/** ADR-0031's need brand for RPC's per-binding service key — the target registers a provisioner under this. */
|
|
7
7
|
declare const RPC_PEER_KEY: unique symbol;
|
|
@@ -50,4 +50,4 @@ type Handlers<S extends AnyRunnable> = { [Port in keyof NonNullable<S['expose']>
|
|
|
50
50
|
declare function serve<S extends AnyRunnable, H extends Handlers<S>>(service: S, handlers: H): (req: Request) => Promise<Response>;
|
|
51
51
|
//#endregion
|
|
52
52
|
export { type Client, type Handlers, RPC_ACCEPTED_KEYS_ENV, RPC_PEER_KEY, type Transport, contract, makeClient, perBindingToken, rpc, serve };
|
|
53
|
-
//# sourceMappingURL=rpc.d.mts.map
|
|
53
|
+
//# sourceMappingURL=service-rpc.d.mts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as blindCast } from "./casts-Ci5rYYaR.mjs";
|
|
2
2
|
import { i as dependency, p as provisionNeed } from "./graph-BmrUEdo9-6Oq1hSmS.mjs";
|
|
3
3
|
import { l as string } from "./dist-B0axxnBf.mjs";
|
|
4
|
-
//#region ../../0-framework/2-authoring/rpc/dist/index.mjs
|
|
4
|
+
//#region ../../0-framework/2-authoring/service-rpc/dist/index.mjs
|
|
5
5
|
async function standardValidate(schema, value) {
|
|
6
6
|
const result = await schema["~standard"].validate(value);
|
|
7
7
|
if (result.issues !== void 0) throw new Error(`Schema validation failed: ${result.issues.map((issue) => issue.message).join("; ")}`);
|
|
@@ -181,4 +181,4 @@ function serve(service, handlers) {
|
|
|
181
181
|
//#endregion
|
|
182
182
|
export { RPC_ACCEPTED_KEYS_ENV, RPC_PEER_KEY, contract, makeClient, perBindingToken, rpc, serve };
|
|
183
183
|
|
|
184
|
-
//# sourceMappingURL=rpc.mjs.map
|
|
184
|
+
//# sourceMappingURL=service-rpc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-rpc.mjs","names":[],"sources":["../../../0-framework/2-authoring/service-rpc/dist/index.mjs"],"sourcesContent":["import { blindCast } from \"@internal/foundation/casts\";\nimport { dependency, provisionNeed, string } from \"@internal/core\";\n//#region src/standard-schema.ts\nasync function standardValidate(schema, value) {\n\tconst result = await schema[\"~standard\"].validate(value);\n\tif (result.issues !== void 0) throw new Error(`Schema validation failed: ${result.issues.map((issue) => issue.message).join(\"; \")}`);\n\treturn result.value;\n}\n//#endregion\n//#region src/client.ts\n/** `<base>/rpc/<method>`, preserving a base URL's own path (e.g. a mount point). */\nfunction methodUrl(base, method) {\n\tconst normalizedBase = base.endsWith(\"/\") ? base : `${base}/`;\n\treturn new URL(`rpc/${method}`, normalizedBase).toString();\n}\n/** The server's `{ error }` body, if the response has one — undefined otherwise. */\nasync function errorDetail(res) {\n\ttry {\n\t\tconst body = await res.json();\n\t\treturn typeof body === \"object\" && body !== null && \"error\" in body ? String(body.error) : void 0;\n\t} catch {\n\t\treturn;\n\t}\n}\nfunction makeClient(contract, url, opts) {\n\tconst send = opts?.fetch ?? fetch;\n\tconst headers = { \"content-type\": \"application/json\" };\n\tif (opts?.serviceKey !== void 0) headers[\"Authorization\"] = `Bearer ${opts.serviceKey}`;\n\tconst client = {};\n\tfor (const [method, schemas] of Object.entries(blindCast(contract.__cmp))) client[method] = async (input) => {\n\t\tconst res = await send(new Request(methodUrl(url, method), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders,\n\t\t\tbody: JSON.stringify(input)\n\t\t}));\n\t\tif (!res.ok) {\n\t\t\tconst detail = await errorDetail(res);\n\t\t\tthrow new Error(`RPC call \"${method}\" failed: ${res.status} ${res.statusText}` + (detail !== void 0 ? ` — ${detail}` : \"\"));\n\t\t}\n\t\treturn standardValidate(schemas.output, await res.json());\n\t};\n\treturn blindCast(client);\n}\n//#endregion\n//#region src/contract.ts\nfunction contract(fns) {\n\tconst value = {\n\t\tkind: \"rpc\",\n\t\t__cmp: fns,\n\t\tsatisfies: (required) => value === required\n\t};\n\treturn Object.freeze(value);\n}\n//#endregion\n//#region src/rpc.ts\n/** ADR-0031's need brand for RPC's per-binding service key — the target registers a provisioner under this. */\nconst RPC_PEER_KEY = Symbol.for(\"prisma:rpc/per-binding-key\");\n/** The provisioning need `rpc()`'s `serviceKey` param declares (ADR-0030): a shared, unguessable value the target mints per consumer edge. */\nconst perBindingToken = () => provisionNeed(RPC_PEER_KEY);\nfunction rpc(arg) {\n\tif (!isRpcContract(arg)) return arg;\n\treturn dependency({\n\t\ttype: \"rpc\",\n\t\tconnection: {\n\t\t\tparams: {\n\t\t\t\turl: string(),\n\t\t\t\tserviceKey: string({\n\t\t\t\t\toptional: true,\n\t\t\t\t\tprovision: perBindingToken()\n\t\t\t\t})\n\t\t\t},\n\t\t\thydrate: ({ url, serviceKey }) => makeClient(arg, url, { serviceKey })\n\t\t},\n\t\trequired: arg\n\t});\n}\nfunction isRpcContract(value) {\n\treturn typeof value === \"object\" && value !== null && \"kind\" in value && value.kind === \"rpc\" && \"__cmp\" in value && \"satisfies\" in value;\n}\n//#endregion\n//#region src/serve.ts\n/** The reserved env var the target (slice 2) writes the accepted key set to. */\nconst RPC_ACCEPTED_KEYS_ENV = \"COMPOSER_RPC_ACCEPTED_KEYS\";\nfunction jsonResponse(body, status = 200) {\n\treturn new Response(JSON.stringify(body), {\n\t\tstatus,\n\t\theaders: { \"content-type\": \"application/json\" }\n\t});\n}\n/** The provisioned accepted key set, or undefined when the deploy never provisioned one (local/test — enforcement off). */\nfunction acceptedKeys() {\n\tconst raw = process.env[RPC_ACCEPTED_KEYS_ENV];\n\tif (raw === void 0 || raw === \"\") return void 0;\n\tlet parsed;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn [];\n\t}\n\treturn Array.isArray(parsed) && parsed.every((key) => typeof key === \"string\") ? parsed : [];\n}\n/**\n* Length-independent constant-time string equality — no early exit on the\n* first mismatched character or on a length difference, so a caller cannot\n* time its way toward a valid key. No `node:crypto`, to keep this module\n* runtime-agnostic.\n*/\nfunction constantTimeEquals(a, b) {\n\tconst length = Math.max(a.length, b.length);\n\tlet diff = a.length ^ b.length;\n\tfor (let i = 0; i < length; i++) diff |= (i < a.length ? a.charCodeAt(i) : 0) ^ (i < b.length ? b.charCodeAt(i) : 0);\n\treturn diff === 0;\n}\n/** Whether `presented` is a member of `accepted` — always compares against every key. */\nfunction isAcceptedKey(presented, accepted) {\n\tlet matched = false;\n\tfor (const key of accepted) matched = constantTimeEquals(presented, key) || matched;\n\treturn matched;\n}\nconst BEARER_PREFIX = \"Bearer \";\n/** The bearer token on `Authorization`, or `''` if the header is missing or malformed. */\nfunction bearerToken(req) {\n\tconst header = req.headers.get(\"authorization\");\n\treturn header?.startsWith(BEARER_PREFIX) ? header.slice(7) : \"\";\n}\n/**\n* Flattens every exposed port's methods into one method → {schemas, handler}\n* table. RPC dispatch is flat (`/rpc/<method>`), so a method name exposed by\n* more than one port is a construction-time error, as is a missing handler.\n*/\nfunction methodTable(expose, handlers) {\n\tconst table = /* @__PURE__ */ new Map();\n\tfor (const [port, contract] of Object.entries(expose)) {\n\t\tconst portHandlers = handlers[port] ?? {};\n\t\tfor (const [method, fn] of Object.entries(contract.__cmp)) {\n\t\t\tif (table.has(method)) throw new Error(`serve(): method \"${method}\" is exposed by more than one port — RPC dispatch is flat (POST /rpc/<method>), so method names must be unique across a service's exposed ports.`);\n\t\t\tconst handler = portHandlers[method];\n\t\t\tif (handler === void 0) throw new Error(`serve(): no handler supplied for exposed method \"${port}.${method}\".`);\n\t\t\tconst { input, output } = blindCast(fn);\n\t\t\ttable.set(method, {\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\thandler\n\t\t\t});\n\t\t}\n\t}\n\treturn table;\n}\n/**\n* Routes `POST /rpc/<method>`: parses JSON, validates input, calls the\n* handler with `service.load()`'s deps, validates the output, and responds\n* JSON. An unknown method or invalid input is a 4xx; a handler (or output\n* validation) failure is a 5xx — either way the process does not crash.\n* `load()` is called exactly once, here, before the handler ever runs.\n*/\nfunction serve(service, handlers) {\n\tconst table = methodTable(service.expose ?? {}, blindCast(handlers));\n\tconst deps = service.load();\n\treturn async (req) => {\n\t\tconst accepted = acceptedKeys();\n\t\tif (accepted !== void 0 && !isAcceptedKey(bearerToken(req), accepted)) return jsonResponse({ error: \"Unauthorized: missing or invalid service key\" }, 401);\n\t\tconst { pathname } = new URL(req.url);\n\t\tconst methodName = /^\\/rpc\\/([^/]+)$/.exec(pathname)?.[1];\n\t\tif (methodName === void 0) return jsonResponse({ error: `Not found: ${pathname}` }, 404);\n\t\tconst method = table.get(methodName);\n\t\tif (method === void 0) return jsonResponse({ error: `Unknown RPC method \"${methodName}\"` }, 404);\n\t\tif (req.method !== \"POST\") return jsonResponse({ error: `Method \"${methodName}\" requires POST` }, 405);\n\t\tlet body;\n\t\ttry {\n\t\t\tbody = await req.json();\n\t\t} catch {\n\t\t\treturn jsonResponse({ error: \"Request body must be JSON\" }, 400);\n\t\t}\n\t\tlet input;\n\t\ttry {\n\t\t\tinput = await standardValidate(method.input, body);\n\t\t} catch (err) {\n\t\t\treturn jsonResponse({ error: err instanceof Error ? err.message : String(err) }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst result = await method.handler(input, deps);\n\t\t\treturn jsonResponse(await standardValidate(method.output, result));\n\t\t} catch (err) {\n\t\t\treturn jsonResponse({ error: err instanceof Error ? err.message : String(err) }, 500);\n\t\t}\n\t};\n}\n//#endregion\nexport { RPC_ACCEPTED_KEYS_ENV, RPC_PEER_KEY, contract, makeClient, perBindingToken, rpc, serve };\n\n//# sourceMappingURL=index.mjs.map"],"mappings":"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"}
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { B as Secrets, H as Values, O as Params, P as RunnableServiceNode, c as Deps, m as HydratedDeps, u as Expose } from "./
|
|
1
|
+
import { B as Secrets, H as Values, O as Params, P as RunnableServiceNode, c as Deps, m as HydratedDeps, u as Expose } from "./graph-types-BgT9UEdm-Cg7wPD1I.mjs";
|
|
2
2
|
//#region ../../0-framework/1-core/core/dist/testing.d.mts
|
|
3
|
-
//#region src/testing.d.ts
|
|
3
|
+
//#region src/exports/testing.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* `mockService`'s override argument: every declared dependency, typed against
|
|
6
6
|
* its own hydrated shape (`Client<C>` for an RPC dep, the resource binding
|
package/dist/testing.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.mjs","names":[],"sources":["../../../0-framework/1-core/core/dist/testing.mjs"],"sourcesContent":["import { blindCast } from \"@internal/foundation/casts\";\n//#region src/testing.ts\n/**\n* The unit-test seam (testing.md § Unit): `mockService` replaces a service\n* node's `load()` and `config()` output so any code that pulls dependencies or\n* params through them — a page, a server action, a helper — runs against typed\n* doubles with no server and no environment. Target-agnostic: every service\n* node has `load()`/`config()`. It does no module mocking; wiring the\n* substitution into a test runner (`vi.mock`, `mock.module`) stays in the test.\n* The integration seam (`bootstrapService`) is target-specific and lives in the\n* target's own testing entry (e.g. `@prisma/composer-prisma-cloud/testing`).\n*/\nfunction paramDefaults(params) {\n\tconst defaults = {};\n\tfor (const [name, param] of Object.entries(params)) if (param.default !== void 0) defaults[name] = param.default;\n\treturn blindCast(defaults);\n}\n/**\n* Returns a service node whose `load()` yields the dependency doubles and\n* `config()` yields the service's params (defaults overlaid with any\n* overrides) — everything else about the node (its deps, params, build,\n* expose) is unchanged. `overrides` is one flat object: dependency keys route\n* to `load()`, param keys to `config()`. `run()` is not meaningful on a mock\n* (there is no boot, no environment) and throws if called.\n*/\nfunction mockService(service, overrides) {\n\tconst entries = Object.entries(overrides);\n\tconst deps = blindCast(Object.fromEntries(entries.filter(([name]) => name in service.inputs)));\n\tconst config = blindCast({\n\t\t...paramDefaults(service.params),\n\t\t...Object.fromEntries(entries.filter(([name]) => name in service.params))\n\t});\n\treturn Object.freeze({\n\t\t...service,\n\t\trun() {\n\t\t\tthrow new Error(`mockService(): \"${service.name}\" is a load()/config()-only mock — it has no run() (no boot, no environment).`);\n\t\t},\n\t\tload: () => deps,\n\t\tconfig: () => config\n\t});\n}\n//#endregion\nexport { mockService };\n\n//# sourceMappingURL=testing.mjs.map"],"mappings":";;;;;;;;;;;;AAYA,SAAS,cAAc,QAAQ;CAC9B,MAAM,WAAW,CAAC;CAClB,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAAG,IAAI,MAAM,YAAY,KAAK,GAAG,SAAS,QAAQ,MAAM;CACzG,OAAO,UAAU,QAAQ;AAC1B;;;;;;;;;AASA,SAAS,YAAY,SAAS,WAAW;CACxC,MAAM,UAAU,OAAO,QAAQ,SAAS;CACxC,MAAM,OAAO,UAAU,OAAO,YAAY,QAAQ,QAAQ,CAAC,UAAU,QAAQ,QAAQ,MAAM,CAAC,CAAC;CAC7F,MAAM,SAAS,UAAU;EACxB,GAAG,cAAc,QAAQ,MAAM;EAC/B,GAAG,OAAO,YAAY,QAAQ,QAAQ,CAAC,UAAU,QAAQ,QAAQ,MAAM,CAAC;CACzE,CAAC;CACD,OAAO,OAAO,OAAO;EACpB,GAAG;EACH,MAAM;GACL,MAAM,IAAI,MAAM,mBAAmB,QAAQ,KAAK,8EAA8E;EAC/H;EACA,YAAY;EACZ,cAAc;CACf,CAAC;AACF"}
|
|
1
|
+
{"version":3,"file":"testing.mjs","names":[],"sources":["../../../0-framework/1-core/core/dist/testing.mjs"],"sourcesContent":["import { blindCast } from \"@internal/foundation/casts\";\n//#region src/exports/testing.ts\n/**\n* The unit-test seam (testing.md § Unit): `mockService` replaces a service\n* node's `load()` and `config()` output so any code that pulls dependencies or\n* params through them — a page, a server action, a helper — runs against typed\n* doubles with no server and no environment. Target-agnostic: every service\n* node has `load()`/`config()`. It does no module mocking; wiring the\n* substitution into a test runner (`vi.mock`, `mock.module`) stays in the test.\n* The integration seam (`bootstrapService`) is target-specific and lives in the\n* target's own testing entry (e.g. `@prisma/composer-prisma-cloud/testing`).\n*/\nfunction paramDefaults(params) {\n\tconst defaults = {};\n\tfor (const [name, param] of Object.entries(params)) if (param.default !== void 0) defaults[name] = param.default;\n\treturn blindCast(defaults);\n}\n/**\n* Returns a service node whose `load()` yields the dependency doubles and\n* `config()` yields the service's params (defaults overlaid with any\n* overrides) — everything else about the node (its deps, params, build,\n* expose) is unchanged. `overrides` is one flat object: dependency keys route\n* to `load()`, param keys to `config()`. `run()` is not meaningful on a mock\n* (there is no boot, no environment) and throws if called.\n*/\nfunction mockService(service, overrides) {\n\tconst entries = Object.entries(overrides);\n\tconst deps = blindCast(Object.fromEntries(entries.filter(([name]) => name in service.inputs)));\n\tconst config = blindCast({\n\t\t...paramDefaults(service.params),\n\t\t...Object.fromEntries(entries.filter(([name]) => name in service.params))\n\t});\n\treturn Object.freeze({\n\t\t...service,\n\t\trun() {\n\t\t\tthrow new Error(`mockService(): \"${service.name}\" is a load()/config()-only mock — it has no run() (no boot, no environment).`);\n\t\t},\n\t\tload: () => deps,\n\t\tconfig: () => config\n\t});\n}\n//#endregion\nexport { mockService };\n\n//# sourceMappingURL=testing.mjs.map"],"mappings":";;;;;;;;;;;;AAYA,SAAS,cAAc,QAAQ;CAC9B,MAAM,WAAW,CAAC;CAClB,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAAG,IAAI,MAAM,YAAY,KAAK,GAAG,SAAS,QAAQ,MAAM;CACzG,OAAO,UAAU,QAAQ;AAC1B;;;;;;;;;AASA,SAAS,YAAY,SAAS,WAAW;CACxC,MAAM,UAAU,OAAO,QAAQ,SAAS;CACxC,MAAM,OAAO,UAAU,OAAO,YAAY,QAAQ,QAAQ,CAAC,UAAU,QAAQ,QAAQ,MAAM,CAAC,CAAC;CAC7F,MAAM,SAAS,UAAU;EACxB,GAAG,cAAc,QAAQ,MAAM;EAC/B,GAAG,OAAO,YAAY,QAAQ,QAAQ,CAAC,UAAU,QAAQ,QAAQ,MAAM,CAAC;CACzE,CAAC;CACD,OAAO,OAAO,OAAO;EACpB,GAAG;EACH,MAAM;GACL,MAAM,IAAI,MAAM,mBAAmB,QAAQ,KAAK,8EAA8E;EAC/H;EACA,YAAY;EACZ,cAAc;CACf,CAAC;AACF"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/composer",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.10",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Prisma Composer — build a Prisma App by composing Modules. Core authoring, deploy pipeline, the prisma-composer CLI, and the rpc/node/nextjs authoring surfaces.",
|
|
5
|
+
"description": "Prisma Composer — build a Prisma App by composing Modules. Core authoring, deploy pipeline, the prisma-composer CLI, and the service-rpc/node/nextjs authoring surfaces.",
|
|
6
6
|
"bin": {
|
|
7
7
|
"prisma-composer": "./dist/bin.mjs"
|
|
8
8
|
},
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"./testing": "./dist/testing.mjs",
|
|
15
15
|
"./casts": "./dist/casts.mjs",
|
|
16
16
|
"./assertions": "./dist/assertions.mjs",
|
|
17
|
-
"./rpc": "./dist/rpc.mjs",
|
|
17
|
+
"./service-rpc": "./dist/service-rpc.mjs",
|
|
18
18
|
"./node": "./dist/node.mjs",
|
|
19
19
|
"./node/control": "./dist/node-control.mjs",
|
|
20
20
|
"./nextjs": "./dist/nextjs.mjs",
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
"@prisma/management-api-sdk": "^1.47.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@internal/assemble": "0.1.0-dev.
|
|
40
|
-
"@internal/cli": "0.1.0-dev.
|
|
41
|
-
"@internal/core": "0.1.0-dev.
|
|
42
|
-
"@internal/foundation": "0.1.0-dev.
|
|
43
|
-
"@internal/lowering": "0.1.0-dev.
|
|
44
|
-
"@internal/nextjs": "0.1.0-dev.
|
|
45
|
-
"@internal/node": "0.1.0-dev.
|
|
46
|
-
"@internal/rpc": "0.1.0-dev.
|
|
47
|
-
"@internal/tsdown-config": "0.1.0-dev.
|
|
39
|
+
"@internal/assemble": "0.1.0-dev.10",
|
|
40
|
+
"@internal/cli": "0.1.0-dev.10",
|
|
41
|
+
"@internal/core": "0.1.0-dev.10",
|
|
42
|
+
"@internal/foundation": "0.1.0-dev.10",
|
|
43
|
+
"@internal/lowering": "0.1.0-dev.10",
|
|
44
|
+
"@internal/nextjs": "0.1.0-dev.10",
|
|
45
|
+
"@internal/node": "0.1.0-dev.10",
|
|
46
|
+
"@internal/service-rpc": "0.1.0-dev.10",
|
|
47
|
+
"@internal/tsdown-config": "0.1.0-dev.10",
|
|
48
48
|
"@types/node": "^25.9.3",
|
|
49
|
-
"tsdown": "^0.22.
|
|
49
|
+
"tsdown": "^0.22.7",
|
|
50
50
|
"typescript": "^6.0.3"
|
|
51
51
|
},
|
|
52
52
|
"license": "Apache-2.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import "./app-config-CpWN1ZfP-CZ1c6Eqk.mjs";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import "./app-config-CpWN1ZfP-CZ1c6Eqk.mjs";
|
package/dist/rpc.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.mjs","names":[],"sources":["../../../0-framework/2-authoring/rpc/dist/index.mjs"],"sourcesContent":["import { blindCast } from \"@internal/foundation/casts\";\nimport { dependency, provisionNeed, string } from \"@internal/core\";\n//#region src/standard-schema.ts\nasync function standardValidate(schema, value) {\n\tconst result = await schema[\"~standard\"].validate(value);\n\tif (result.issues !== void 0) throw new Error(`Schema validation failed: ${result.issues.map((issue) => issue.message).join(\"; \")}`);\n\treturn result.value;\n}\n//#endregion\n//#region src/client.ts\n/** `<base>/rpc/<method>`, preserving a base URL's own path (e.g. a mount point). */\nfunction methodUrl(base, method) {\n\tconst normalizedBase = base.endsWith(\"/\") ? base : `${base}/`;\n\treturn new URL(`rpc/${method}`, normalizedBase).toString();\n}\n/** The server's `{ error }` body, if the response has one — undefined otherwise. */\nasync function errorDetail(res) {\n\ttry {\n\t\tconst body = await res.json();\n\t\treturn typeof body === \"object\" && body !== null && \"error\" in body ? String(body.error) : void 0;\n\t} catch {\n\t\treturn;\n\t}\n}\nfunction makeClient(contract, url, opts) {\n\tconst send = opts?.fetch ?? fetch;\n\tconst headers = { \"content-type\": \"application/json\" };\n\tif (opts?.serviceKey !== void 0) headers[\"Authorization\"] = `Bearer ${opts.serviceKey}`;\n\tconst client = {};\n\tfor (const [method, schemas] of Object.entries(blindCast(contract.__cmp))) client[method] = async (input) => {\n\t\tconst res = await send(new Request(methodUrl(url, method), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders,\n\t\t\tbody: JSON.stringify(input)\n\t\t}));\n\t\tif (!res.ok) {\n\t\t\tconst detail = await errorDetail(res);\n\t\t\tthrow new Error(`RPC call \"${method}\" failed: ${res.status} ${res.statusText}` + (detail !== void 0 ? ` — ${detail}` : \"\"));\n\t\t}\n\t\treturn standardValidate(schemas.output, await res.json());\n\t};\n\treturn blindCast(client);\n}\n//#endregion\n//#region src/contract.ts\nfunction contract(fns) {\n\tconst value = {\n\t\tkind: \"rpc\",\n\t\t__cmp: fns,\n\t\tsatisfies: (required) => value === required\n\t};\n\treturn Object.freeze(value);\n}\n//#endregion\n//#region src/rpc.ts\n/** ADR-0031's need brand for RPC's per-binding service key — the target registers a provisioner under this. */\nconst RPC_PEER_KEY = Symbol.for(\"prisma:rpc/per-binding-key\");\n/** The provisioning need `rpc()`'s `serviceKey` param declares (ADR-0030): a shared, unguessable value the target mints per consumer edge. */\nconst perBindingToken = () => provisionNeed(RPC_PEER_KEY);\nfunction rpc(arg) {\n\tif (!isRpcContract(arg)) return arg;\n\treturn dependency({\n\t\ttype: \"rpc\",\n\t\tconnection: {\n\t\t\tparams: {\n\t\t\t\turl: string(),\n\t\t\t\tserviceKey: string({\n\t\t\t\t\toptional: true,\n\t\t\t\t\tprovision: perBindingToken()\n\t\t\t\t})\n\t\t\t},\n\t\t\thydrate: ({ url, serviceKey }) => makeClient(arg, url, { serviceKey })\n\t\t},\n\t\trequired: arg\n\t});\n}\nfunction isRpcContract(value) {\n\treturn typeof value === \"object\" && value !== null && \"kind\" in value && value.kind === \"rpc\" && \"__cmp\" in value && \"satisfies\" in value;\n}\n//#endregion\n//#region src/serve.ts\n/** The reserved env var the target (slice 2) writes the accepted key set to. */\nconst RPC_ACCEPTED_KEYS_ENV = \"COMPOSER_RPC_ACCEPTED_KEYS\";\nfunction jsonResponse(body, status = 200) {\n\treturn new Response(JSON.stringify(body), {\n\t\tstatus,\n\t\theaders: { \"content-type\": \"application/json\" }\n\t});\n}\n/** The provisioned accepted key set, or undefined when the deploy never provisioned one (local/test — enforcement off). */\nfunction acceptedKeys() {\n\tconst raw = process.env[RPC_ACCEPTED_KEYS_ENV];\n\tif (raw === void 0 || raw === \"\") return void 0;\n\tlet parsed;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn [];\n\t}\n\treturn Array.isArray(parsed) && parsed.every((key) => typeof key === \"string\") ? parsed : [];\n}\n/**\n* Length-independent constant-time string equality — no early exit on the\n* first mismatched character or on a length difference, so a caller cannot\n* time its way toward a valid key. No `node:crypto`, to keep this module\n* runtime-agnostic.\n*/\nfunction constantTimeEquals(a, b) {\n\tconst length = Math.max(a.length, b.length);\n\tlet diff = a.length ^ b.length;\n\tfor (let i = 0; i < length; i++) diff |= (i < a.length ? a.charCodeAt(i) : 0) ^ (i < b.length ? b.charCodeAt(i) : 0);\n\treturn diff === 0;\n}\n/** Whether `presented` is a member of `accepted` — always compares against every key. */\nfunction isAcceptedKey(presented, accepted) {\n\tlet matched = false;\n\tfor (const key of accepted) matched = constantTimeEquals(presented, key) || matched;\n\treturn matched;\n}\nconst BEARER_PREFIX = \"Bearer \";\n/** The bearer token on `Authorization`, or `''` if the header is missing or malformed. */\nfunction bearerToken(req) {\n\tconst header = req.headers.get(\"authorization\");\n\treturn header?.startsWith(BEARER_PREFIX) ? header.slice(7) : \"\";\n}\n/**\n* Flattens every exposed port's methods into one method → {schemas, handler}\n* table. RPC dispatch is flat (`/rpc/<method>`), so a method name exposed by\n* more than one port is a construction-time error, as is a missing handler.\n*/\nfunction methodTable(expose, handlers) {\n\tconst table = /* @__PURE__ */ new Map();\n\tfor (const [port, contract] of Object.entries(expose)) {\n\t\tconst portHandlers = handlers[port] ?? {};\n\t\tfor (const [method, fn] of Object.entries(contract.__cmp)) {\n\t\t\tif (table.has(method)) throw new Error(`serve(): method \"${method}\" is exposed by more than one port — RPC dispatch is flat (POST /rpc/<method>), so method names must be unique across a service's exposed ports.`);\n\t\t\tconst handler = portHandlers[method];\n\t\t\tif (handler === void 0) throw new Error(`serve(): no handler supplied for exposed method \"${port}.${method}\".`);\n\t\t\tconst { input, output } = blindCast(fn);\n\t\t\ttable.set(method, {\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\thandler\n\t\t\t});\n\t\t}\n\t}\n\treturn table;\n}\n/**\n* Routes `POST /rpc/<method>`: parses JSON, validates input, calls the\n* handler with `service.load()`'s deps, validates the output, and responds\n* JSON. An unknown method or invalid input is a 4xx; a handler (or output\n* validation) failure is a 5xx — either way the process does not crash.\n* `load()` is called exactly once, here, before the handler ever runs.\n*/\nfunction serve(service, handlers) {\n\tconst table = methodTable(service.expose ?? {}, blindCast(handlers));\n\tconst deps = service.load();\n\treturn async (req) => {\n\t\tconst accepted = acceptedKeys();\n\t\tif (accepted !== void 0 && !isAcceptedKey(bearerToken(req), accepted)) return jsonResponse({ error: \"Unauthorized: missing or invalid service key\" }, 401);\n\t\tconst { pathname } = new URL(req.url);\n\t\tconst methodName = /^\\/rpc\\/([^/]+)$/.exec(pathname)?.[1];\n\t\tif (methodName === void 0) return jsonResponse({ error: `Not found: ${pathname}` }, 404);\n\t\tconst method = table.get(methodName);\n\t\tif (method === void 0) return jsonResponse({ error: `Unknown RPC method \"${methodName}\"` }, 404);\n\t\tif (req.method !== \"POST\") return jsonResponse({ error: `Method \"${methodName}\" requires POST` }, 405);\n\t\tlet body;\n\t\ttry {\n\t\t\tbody = await req.json();\n\t\t} catch {\n\t\t\treturn jsonResponse({ error: \"Request body must be JSON\" }, 400);\n\t\t}\n\t\tlet input;\n\t\ttry {\n\t\t\tinput = await standardValidate(method.input, body);\n\t\t} catch (err) {\n\t\t\treturn jsonResponse({ error: err instanceof Error ? err.message : String(err) }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst result = await method.handler(input, deps);\n\t\t\treturn jsonResponse(await standardValidate(method.output, result));\n\t\t} catch (err) {\n\t\t\treturn jsonResponse({ error: err instanceof Error ? err.message : String(err) }, 500);\n\t\t}\n\t};\n}\n//#endregion\nexport { RPC_ACCEPTED_KEYS_ENV, RPC_PEER_KEY, contract, makeClient, perBindingToken, rpc, serve };\n\n//# sourceMappingURL=index.mjs.map"],"mappings":"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"}
|