@prisma/composer 0.6.0-dev.2 → 0.6.0-dev.20

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 (75) hide show
  1. package/dist/{app-config-Cbv_lA38-BHJsd1DF.d.mts → app-config-aIrriqVU-Dpj1RqnY.d.mts} +43 -17
  2. package/dist/app-config-aIrriqVU-Dpj1RqnY.d.mts.map +1 -0
  3. package/dist/config-BeBRB-6m.d.mts +1 -0
  4. package/dist/config.d.mts +3 -3
  5. package/dist/control.d.mts +219 -0
  6. package/dist/control.d.mts.map +1 -0
  7. package/dist/control.mjs +70 -0
  8. package/dist/control.mjs.map +1 -0
  9. package/dist/deploy-BeBRB-6m.d.mts +1 -0
  10. package/dist/deploy.d.mts +2 -2
  11. package/dist/deploy.mjs +312 -1
  12. package/dist/deploy.mjs.map +1 -0
  13. package/dist/deployment-summary-DswOl_9E-C03NJ98H.mjs +70 -0
  14. package/dist/deployment-summary-DswOl_9E-C03NJ98H.mjs.map +1 -0
  15. package/dist/{dist-BdvFDCLV.mjs → dist-C5rZnr4n.mjs} +2 -2
  16. package/dist/{dist-BdvFDCLV.mjs.map → dist-C5rZnr4n.mjs.map} +1 -1
  17. package/dist/emulator-retry-DGonap4g-S8BNrXFD.mjs +24 -0
  18. package/dist/emulator-retry-DGonap4g-S8BNrXFD.mjs.map +1 -0
  19. package/dist/errors-0e8IVwzi.mjs +88 -0
  20. package/dist/errors-0e8IVwzi.mjs.map +1 -0
  21. package/dist/execute-deploy-destroy-DfVJUICu-Dbgn1GR_.mjs +275 -0
  22. package/dist/execute-deploy-destroy-DfVJUICu-Dbgn1GR_.mjs.map +1 -0
  23. package/dist/execute-dev-BMTFWfFc-CGDFqR4w.mjs +2014 -0
  24. package/dist/execute-dev-BMTFWfFc-CGDFqR4w.mjs.map +1 -0
  25. package/dist/execute-log-Cay9hlKW-ChlIv192.mjs +160 -0
  26. package/dist/execute-log-Cay9hlKW-ChlIv192.mjs.map +1 -0
  27. package/dist/{graph-DgbALPDo-BEHF94BN.mjs → graph-BJgUfGB0-kvgFzT4q.mjs} +13 -7
  28. package/dist/graph-BJgUfGB0-kvgFzT4q.mjs.map +1 -0
  29. package/dist/{graph-DDpXh7S8-b-93BcHn.d.mts → graph-DqklX5Sf-BNS2aO1j.d.mts} +3 -3
  30. package/dist/graph-DqklX5Sf-BNS2aO1j.d.mts.map +1 -0
  31. package/dist/{graph-types-C3FOaaXm-C6_rGzfn.d.mts → graph-types-N6brq1zY-1VMNwtkJ.d.mts} +88 -5
  32. package/dist/graph-types-N6brq1zY-1VMNwtkJ.d.mts.map +1 -0
  33. package/dist/{index-BQVrMGfe.d.mts → index-DryPyF9U.d.mts} +3 -3
  34. package/dist/{index-BQVrMGfe.d.mts.map → index-DryPyF9U.d.mts.map} +1 -1
  35. package/dist/index.d.mts +3 -3
  36. package/dist/index.mjs +2 -2
  37. package/dist/internal-error-BIc-ehme-Ck_lgxD_.mjs +18 -0
  38. package/dist/internal-error-BIc-ehme-Ck_lgxD_.mjs.map +1 -0
  39. package/dist/local-target-DnA2E8IN.mjs +47 -0
  40. package/dist/local-target-DnA2E8IN.mjs.map +1 -0
  41. package/dist/local-target.d.mts +1 -1
  42. package/dist/local-target.mjs +2 -46
  43. package/dist/{nextjs-DLyeRR7M-D47aMmfr.d.mts → nextjs-DLyeRR7M-DZODs9tk.d.mts} +3 -3
  44. package/dist/{nextjs-DLyeRR7M-D47aMmfr.d.mts.map → nextjs-DLyeRR7M-DZODs9tk.d.mts.map} +1 -1
  45. package/dist/nextjs-control.d.mts +4 -4
  46. package/dist/nextjs.d.mts +1 -1
  47. package/dist/node-control.d.mts +3 -3
  48. package/dist/node.d.mts +2 -2
  49. package/dist/pipeline-AoW8zq4I-CUon5KZH.mjs +452 -0
  50. package/dist/pipeline-AoW8zq4I-CUon5KZH.mjs.map +1 -0
  51. package/dist/report.d.mts +4 -3
  52. package/dist/report.d.mts.map +1 -1
  53. package/dist/report.mjs +4 -1
  54. package/dist/report.mjs.map +1 -1
  55. package/dist/result-CY_TB7bn.mjs +247 -0
  56. package/dist/result-CY_TB7bn.mjs.map +1 -0
  57. package/dist/run-alchemy-D44OZlyB-gVq_0gf4.mjs +93 -0
  58. package/dist/run-alchemy-D44OZlyB-gVq_0gf4.mjs.map +1 -0
  59. package/dist/service-rpc.d.mts +2 -2
  60. package/dist/service-rpc.mjs +2 -2
  61. package/dist/testing.d.mts +1 -1
  62. package/package.json +17 -21
  63. package/src/exports/control.ts +1 -0
  64. package/src/exports/testing.ts +5 -0
  65. package/dist/app-config-Cbv_lA38-BHJsd1DF.d.mts.map +0 -1
  66. package/dist/bin.mjs +0 -3283
  67. package/dist/bin.mjs.map +0 -1
  68. package/dist/config-whuqZ5xT.d.mts +0 -1
  69. package/dist/deploy-C4DxNkJ9-D73lmBqy.mjs +0 -313
  70. package/dist/deploy-C4DxNkJ9-D73lmBqy.mjs.map +0 -1
  71. package/dist/deploy-whuqZ5xT.d.mts +0 -1
  72. package/dist/graph-DDpXh7S8-b-93BcHn.d.mts.map +0 -1
  73. package/dist/graph-DgbALPDo-BEHF94BN.mjs.map +0 -1
  74. package/dist/graph-types-C3FOaaXm-C6_rGzfn.d.mts.map +0 -1
  75. package/dist/local-target.mjs.map +0 -1
@@ -0,0 +1,452 @@
1
+ import { t as blindCast } from "./casts-DpaahrlC-C5XMnP9S.mjs";
2
+ import { t as CliStructuredError } from "./errors-0e8IVwzi.mjs";
3
+ import { o as isNode, t as Load } from "./graph-BJgUfGB0-kvgFzT4q.mjs";
4
+ import "./dist-C5rZnr4n.mjs";
5
+ import { i as effectResolutionDiagnostic } from "./result-CY_TB7bn.mjs";
6
+ import * as fs from "node:fs";
7
+ import * as path from "node:path";
8
+ import { pathToFileURL } from "node:url";
9
+ import * as c12 from "c12";
10
+ //#region ../../0-framework/3-tooling/cli/dist/load-entry-BYBSCuWg.mjs
11
+ /**
12
+ * `loadEntry` imports a user's topology with the host runtime's own module
13
+ * loader — under node (the CLI's shebang runtime), that loader strips
14
+ * TypeScript types but has no JSX transform (ADR-0005: the framework
15
+ * doesn't bundle or transform the app's code; deploy loading is no
16
+ * exception). A `.tsx`/`.jsx` file anywhere in the topology's import graph
17
+ * dies with node's raw `ERR_UNKNOWN_FILE_EXTENSION`, which names the file
18
+ * but not the cause or the fix. This turns that one case into structured
19
+ * error parts (summary/why/fix) that do — every other load failure (syntax
20
+ * errors, missing files, non-JSX unknown extensions) is untouched.
21
+ */
22
+ const UNKNOWN_EXTENSION_CODE = "ERR_UNKNOWN_FILE_EXTENSION";
23
+ const JSX_EXTENSIONS = [".tsx", ".jsx"];
24
+ function errorCode(error) {
25
+ return "code" in error && typeof error.code === "string" ? error.code : void 0;
26
+ }
27
+ function unknownExtensionPath(error) {
28
+ if (!(error instanceof Error)) return void 0;
29
+ if (errorCode(error) !== UNKNOWN_EXTENSION_CODE) return void 0;
30
+ return /Unknown file extension "\.\w+" for (.+)$/.exec(error.message)?.[1];
31
+ }
32
+ /**
33
+ * Returns structured error parts when `error` is node's
34
+ * `ERR_UNKNOWN_FILE_EXTENSION` for a `.tsx`/`.jsx` file — `undefined` for
35
+ * every other error (including unknown-extension failures for some other
36
+ * extension), so the caller can fall through to its normal rethrow.
37
+ */
38
+ function explainJsxLoadError(error, entryPath) {
39
+ const offendingPath = unknownExtensionPath(error);
40
+ if (offendingPath === void 0) return void 0;
41
+ if (!JSX_EXTENSIONS.some((ext) => offendingPath.endsWith(ext))) return void 0;
42
+ return {
43
+ summary: `"${offendingPath}" can't be loaded.`,
44
+ why: `deploy loads "${entryPath}"'s topology with node's own module loader, which strips TypeScript types but has no JSX transform — so a .tsx/.jsx file can't sit anywhere in that import graph.`,
45
+ fix: "Precompile that file in your own build (transform the JSX away, keep the real npm packages external) and import the compiled output instead of the raw .tsx/.jsx — see examples/email/scripts/build.ts in the prisma/composer repo for a worked example."
46
+ };
47
+ }
48
+ /**
49
+ * Pipeline step 1 (deploy-cli.md § The pipeline): import the entry module
50
+ * (resolved against cwd) and require its default export to be a node — a
51
+ * service or module, branded by core's factories. Whatever this module exports
52
+ * IS the application; nothing else marks a root (ADR-0003).
53
+ */
54
+ async function loadEntry(entryArg, cwd) {
55
+ const resolvedPath = path.resolve(cwd, entryArg);
56
+ let mod;
57
+ try {
58
+ mod = await import(pathToFileURL(resolvedPath).href);
59
+ } catch (error) {
60
+ const explained = explainJsxLoadError(error, resolvedPath);
61
+ if (explained !== void 0) throw new CliStructuredError("COMPOSE.ENTRY_UNLOADABLE", explained.summary, {
62
+ why: explained.why,
63
+ fix: explained.fix,
64
+ where: { path: resolvedPath },
65
+ cause: error
66
+ });
67
+ throw new CliStructuredError("COMPOSE.ENTRY_UNLOADABLE", `Failed to import entry module "${resolvedPath}": ${error instanceof Error ? error.message : String(error)}`, {
68
+ where: { path: resolvedPath },
69
+ cause: error
70
+ });
71
+ }
72
+ const root = blindCast(mod).default;
73
+ if (!isNode(root) || root.kind === "dependency" || root.kind === "resource") throw new CliStructuredError("COMPOSE.ENTRY_EXPORT_INVALID", `Entry module "${resolvedPath}" must default-export a node (a service or a module).`, {
74
+ fix: "Construct it with service() or module() from @prisma/composer.",
75
+ where: { path: resolvedPath }
76
+ });
77
+ return {
78
+ path: resolvedPath,
79
+ root: blindCast(root)
80
+ };
81
+ }
82
+ //#endregion
83
+ //#region ../../0-framework/3-tooling/assemble/dist/index.mjs
84
+ /**
85
+ * A user-facing assembly failure, structured at origin (base-type rule 6):
86
+ * a `CliStructuredError` whose code names which way assembly went wrong.
87
+ * This package's second consumer is the programmatic deploy API, not just
88
+ * the CLI — hosts branch on `error.code`, the CLI renders the envelope.
89
+ */
90
+ var AssembleError = class extends CliStructuredError {
91
+ constructor(code, summary, options) {
92
+ super(code, summary, options);
93
+ }
94
+ };
95
+ /**
96
+ * The registry route for one service's build: extension by
97
+ * `build.extension`, node descriptor by `build.type`, kind must be "build".
98
+ * The CLI's coverage validation reports the same misses earlier with the
99
+ * config fix; these errors are the backstop for programmatic callers.
100
+ */
101
+ function buildDescriptorAssemble(config, node, address, cwd) {
102
+ const { extension, type } = node.build;
103
+ const extensionDescriptor = config.extensions.find((candidate) => candidate.id === extension);
104
+ if (extensionDescriptor === void 0) throw new AssembleError("ASSEMBLE.EXTENSION_MISSING", `No extension "${extension}" is configured (needed by service "${node.name}"'s build).`, { fix: "Add it to prisma-composer.config.ts's `extensions`." });
105
+ const nodeDescriptor = extensionDescriptor.nodes[type];
106
+ if (nodeDescriptor === void 0) throw new AssembleError("ASSEMBLE.DESCRIPTOR_MISSING", `Extension "${extension}" has no descriptor for build type "${type}".`, { why: `Known types: ${Object.keys(extensionDescriptor.nodes).join(", ")}.` });
107
+ if (nodeDescriptor.kind !== "build") throw new AssembleError("ASSEMBLE.DESCRIPTOR_KIND_MISMATCH", `Extension "${extension}"'s descriptor for type "${type}" is a "${nodeDescriptor.kind}" descriptor.`, { why: "Assembling a service build needs a \"build\" descriptor." });
108
+ return nodeDescriptor.assemble({
109
+ build: node.build,
110
+ address,
111
+ cwd
112
+ });
113
+ }
114
+ async function assembleServices(graph, config, cwd, run) {
115
+ const runAssembler = run ?? ((node, address, nodeCwd) => buildDescriptorAssemble(config, node, address, nodeCwd));
116
+ const serviceNodes = graph.nodes.filter((n) => n.node.kind === "service");
117
+ if (serviceNodes.length === 0) throw new AssembleError("ASSEMBLE.SERVICE_MISSING", "The loaded graph has no service to assemble.");
118
+ const bundles = {};
119
+ for (const { id, node } of serviceNodes) try {
120
+ bundles[id] = await runAssembler(node, id, cwd);
121
+ } catch (error) {
122
+ if (CliStructuredError.is(error)) throw error;
123
+ throw new AssembleError("ASSEMBLE.BUILD_FAILED", error instanceof Error ? error.message : String(error), {
124
+ meta: { address: id },
125
+ cause: error
126
+ });
127
+ }
128
+ return { bundles };
129
+ }
130
+ //#endregion
131
+ //#region ../../0-framework/3-tooling/cli/dist/pipeline-AoW8zq4I.mjs
132
+ /**
133
+ * Pipeline step: find and load `prisma-composer.config.ts` (ADR-0017) — the ONE
134
+ * file that imports control-plane code. Discovery is the standard walk-up
135
+ * from the deploy entry's directory (mirrors prisma-next's config-loader);
136
+ * loading is c12 with that explicit path (rc/global/package.json lookups
137
+ * disabled), so the config file's own static imports resolve from the app
138
+ * root by whatever package manager runs — no specifier construction, no
139
+ * anchoring.
140
+ *
141
+ * Two shapes of the same machinery:
142
+ *
143
+ * loadAppConfigDiagnostics — returns the evaluated value together with
144
+ * EVERY problem found, and never throws. This is the shape the engine
145
+ * command family consumes: the engine renders diagnostics itself and
146
+ * decides per command whether a broken section is fatal, so a loader that
147
+ * threw on the first bad field would both hide the rest and bypass that
148
+ * rendering.
149
+ *
150
+ * loadAppConfig — the same load, throwing its first diagnostic. The
151
+ * clipanion CLI still runs on it; it goes when clipanion does.
152
+ */
153
+ const CONFIG_FILENAME = "prisma-composer.config.ts";
154
+ /** Walks UP from the entry file's directory looking for the literal CONFIG_FILENAME; undefined when the walk hits the filesystem root. */
155
+ function findConfigPathForEntry(entryPath) {
156
+ let current = path.dirname(path.resolve(entryPath));
157
+ while (true) {
158
+ const candidate = path.join(current, CONFIG_FILENAME);
159
+ if (fs.existsSync(candidate)) return candidate;
160
+ const parent = path.dirname(current);
161
+ if (parent === current) return void 0;
162
+ current = parent;
163
+ }
164
+ }
165
+ function missingConfigError(entryPath) {
166
+ const searchedFrom = path.dirname(path.resolve(entryPath));
167
+ return new CliStructuredError("CONFIG.FILE_MISSING", `No ${CONFIG_FILENAME} found walking up from "${searchedFrom}".`, {
168
+ why: "The deploy needs the app's config file.",
169
+ fix: "Create one next to (or above) the entry, default-exporting defineConfig({ extensions: [...], state: ... }) from '@prisma/composer/config'.",
170
+ where: { path: searchedFrom }
171
+ });
172
+ }
173
+ function fieldError(field, requirement) {
174
+ return new CliStructuredError("CONFIG.FIELD_INVALID", `${CONFIG_FILENAME}: \`${field}\` ${requirement}.`, {
175
+ fix: "See defineConfig() in '@prisma/composer/config'.",
176
+ meta: { field }
177
+ });
178
+ }
179
+ function isRecord(value) {
180
+ return typeof value === "object" && value !== null;
181
+ }
182
+ /**
183
+ * Field-by-field validation of the loaded default export — deliberately no
184
+ * schema library: each check is a structured error naming the offending field.
185
+ *
186
+ * Collects rather than throws, so one bad config reports every bad field
187
+ * instead of only the first. The `extensions` and `state` checks are
188
+ * independent, and within `extensions` each entry is judged on its own; a
189
+ * field whose own shape check already failed is not probed further, because
190
+ * anything derived from it would be noise rather than a second finding.
191
+ */
192
+ function configShapeDiagnostics(loaded, configPath) {
193
+ if (!isRecord(loaded) || Object.keys(loaded).length === 0) return [new CliStructuredError("CONFIG.EXPORT_INVALID", `"${configPath}" exported no config.`, {
194
+ fix: "It must default-export defineConfig({ extensions: [...], state: ... }) from '@prisma/composer/config'.",
195
+ where: { path: configPath }
196
+ })];
197
+ const diagnostics = [];
198
+ const extensions = loaded["extensions"];
199
+ if (!Array.isArray(extensions)) diagnostics.push(fieldError("extensions", "must be an array"));
200
+ else {
201
+ const seen = /* @__PURE__ */ new Set();
202
+ for (const [index, entry] of extensions.entries()) {
203
+ if (!isRecord(entry)) {
204
+ diagnostics.push(fieldError(`extensions[${index}]`, "must be an extension descriptor object"));
205
+ continue;
206
+ }
207
+ const id = entry["id"];
208
+ if (typeof id !== "string" || id.length === 0) diagnostics.push(fieldError(`extensions[${index}].id`, "must be a non-empty string (the extension package name)"));
209
+ else if (seen.has(id)) diagnostics.push(new CliStructuredError("CONFIG.EXTENSION_DUPLICATE", `${CONFIG_FILENAME}: extension "${id}" is listed more than once in \`extensions\`.`));
210
+ else seen.add(id);
211
+ if (!isRecord(entry["nodes"])) diagnostics.push(fieldError(`extensions[${index}].nodes`, "must be an object (the node-ID → control registry)"));
212
+ }
213
+ }
214
+ const state = loaded["state"];
215
+ if (!isRecord(state) || typeof state["extension"] !== "string" || typeof state["create"] !== "function") diagnostics.push(fieldError("state", "must be a state descriptor (e.g. prismaState())"));
216
+ return diagnostics;
217
+ }
218
+ /** The throwing form of configShapeDiagnostics: raises the first finding, returns the same object typed. Used by the clipanion pipeline. */
219
+ function validateConfigShape(loaded, configPath) {
220
+ const [first] = configShapeDiagnostics(loaded, configPath);
221
+ if (first !== void 0) throw first;
222
+ return blindCast(loaded);
223
+ }
224
+ /**
225
+ * Evaluates `configPath` with c12 (explicit file; rc / global-rc /
226
+ * package.json lookups disabled). `verifySamePath` runs the same-file check
227
+ * against the discovered path — see loadAppConfigDiagnostics for when it does
228
+ * not apply.
229
+ */
230
+ async function evaluateConfig(configPath, verifySamePath) {
231
+ let result;
232
+ try {
233
+ result = await c12.loadConfig({
234
+ name: "prisma-composer",
235
+ configFile: configPath,
236
+ cwd: path.dirname(configPath),
237
+ rcFile: false,
238
+ globalRc: false,
239
+ packageJson: false
240
+ });
241
+ } catch (error) {
242
+ return {
243
+ value: void 0,
244
+ diagnostics: [new CliStructuredError("CONFIG.EVALUATION_FAILED", `Evaluating "${configPath}" failed: ${error instanceof Error ? error.message : String(error)}`, {
245
+ where: { path: configPath },
246
+ cause: error
247
+ })]
248
+ };
249
+ }
250
+ const loadedFile = result.configFile;
251
+ if (verifySamePath && (typeof loadedFile !== "string" || fs.realpathSync(loadedFile) !== fs.realpathSync(configPath))) return {
252
+ value: result.config,
253
+ diagnostics: [new CliStructuredError("CONFIG.PATH_MISMATCH", `Config loading resolved "${String(loadedFile)}" instead of the discovered "${configPath}".`, {
254
+ why: "Refusing to deploy against a different file.",
255
+ where: { path: configPath }
256
+ })]
257
+ };
258
+ return {
259
+ value: result.config,
260
+ diagnostics: configShapeDiagnostics(result.config, configPath)
261
+ };
262
+ }
263
+ /**
264
+ * The front of every config load, shared by the throwing and the
265
+ * diagnostics-list shapes: verify the installed tree can evaluate a config at
266
+ * all, then settle which file to load — the section's path, or the
267
+ * entry-anchored walk.
268
+ *
269
+ * The effect-resolution check comes first because evaluating a config imports
270
+ * alchemy's provider tree: in a tree where alchemy resolves an `effect` we did
271
+ * not pin, nothing downstream can load, so the dependency conflict is the
272
+ * finding with the fix in it and every later failure is its symptom.
273
+ */
274
+ function configSource(request) {
275
+ const resolvedEntry = path.resolve(request.entryPath);
276
+ const cwd = request.cwd ?? path.dirname(resolvedEntry);
277
+ const effectConflict = effectResolutionDiagnostic(cwd);
278
+ if (effectConflict !== void 0) return {
279
+ ok: false,
280
+ path: void 0,
281
+ diagnostic: effectConflict
282
+ };
283
+ if (request.configPath === void 0) {
284
+ const discovered = findConfigPathForEntry(resolvedEntry);
285
+ return discovered === void 0 ? {
286
+ ok: false,
287
+ path: void 0,
288
+ diagnostic: missingConfigError(resolvedEntry)
289
+ } : {
290
+ ok: true,
291
+ path: discovered,
292
+ explicit: false
293
+ };
294
+ }
295
+ const configPath = path.resolve(cwd, request.configPath);
296
+ if (!fs.existsSync(configPath)) return {
297
+ ok: false,
298
+ path: configPath,
299
+ diagnostic: new CliStructuredError("CONFIG.FILE_MISSING", `The \`composer\` config section points at "${configPath}", which does not exist.`, {
300
+ why: "An explicit configPath is used as given — there is no walk to fall back on.",
301
+ fix: "Correct `configPath` in the `composer` section of prisma.config.ts, or remove it to search upward from the entry.",
302
+ where: { path: configPath }
303
+ })
304
+ };
305
+ return {
306
+ ok: true,
307
+ path: configPath,
308
+ explicit: true
309
+ };
310
+ }
311
+ /**
312
+ * The throwing form of that front, for the pipeline: the file the load will
313
+ * use, or the finding raised. `explicit` says the section named the file,
314
+ * which is what retires the same-file check for that case.
315
+ */
316
+ function resolveConfigFile(request) {
317
+ const source = configSource(request);
318
+ if (!source.ok) throw source.diagnostic;
319
+ return {
320
+ path: source.path,
321
+ explicit: source.explicit
322
+ };
323
+ }
324
+ /**
325
+ * Loads + validates the config at `configPath`, throwing its first diagnostic.
326
+ * The clipanion CLI's pipeline runs on this; it goes when clipanion does.
327
+ */
328
+ async function loadAppConfig(configPath, verifySamePath = true) {
329
+ const { value, diagnostics } = await evaluateConfig(configPath, verifySamePath);
330
+ const [first] = diagnostics;
331
+ if (first !== void 0) throw first;
332
+ return {
333
+ path: configPath,
334
+ config: validateConfigShape(value, configPath)
335
+ };
336
+ }
337
+ function lookup(extensions, extension, type, expectedKind, what) {
338
+ const ext = extensions.get(extension);
339
+ if (ext === void 0) throw new CliStructuredError("CONFIG.EXTENSION_MISSING", `No extension "${extension}" is configured (needed by ${what}).`, {
340
+ fix: `Add it to ${CONFIG_FILENAME}'s \`extensions\` (import its /control entry and list its descriptor).`,
341
+ meta: {
342
+ extension,
343
+ type
344
+ }
345
+ });
346
+ const descriptor = ext.nodes[type];
347
+ if (descriptor === void 0) throw new CliStructuredError("CONFIG.DESCRIPTOR_MISSING", `Extension "${extension}" has no descriptor for node type "${type}" (needed by ${what}).`, {
348
+ why: `Known types: ${Object.keys(ext.nodes).join(", ")}.`,
349
+ meta: {
350
+ extension,
351
+ type
352
+ }
353
+ });
354
+ if (descriptor.kind !== expectedKind) throw new CliStructuredError("CONFIG.DESCRIPTOR_KIND_MISMATCH", `Extension "${extension}"'s descriptor for node type "${type}" is a "${descriptor.kind}" descriptor — ${what} needs a "${expectedKind}" descriptor.`, { meta: {
355
+ extension,
356
+ type,
357
+ kind: descriptor.kind
358
+ } });
359
+ }
360
+ /** Throws a structured CONFIG.* error on the first uncovered `(extension, type)`; silent when the config covers the whole graph. */
361
+ function validateRegistryCoverage(graph, config) {
362
+ const extensions = new Map(config.extensions.map((descriptor) => [descriptor.id, descriptor]));
363
+ for (const { id, node } of graph.nodes) {
364
+ if (node.kind === "resource") {
365
+ lookup(extensions, node.extension, node.type, "resource", `resource node "${id}"`);
366
+ continue;
367
+ }
368
+ if (node.kind !== "service") continue;
369
+ lookup(extensions, node.extension, node.type, "service", `service node "${id}"`);
370
+ lookup(extensions, node.build.extension, node.build.type, "build", `service node "${id}"'s build descriptor`);
371
+ }
372
+ }
373
+ /**
374
+ * The shared prefix of `deploy`/`destroy`/`dev` (deploy-cli.md § The
375
+ * pipeline; local-dev spec § 6): config discovery/load, entry load, Load,
376
+ * registry coverage validation, name resolution, assemble. Deploy and dev
377
+ * diverge after this — deploy resolves containers/preflight/stack file
378
+ * against the hosted providers, dev against the local ones — so everything
379
+ * up to and including assemble lives here once, consumed verbatim by both
380
+ * `run()` (main.ts) and `runDev()` (dev/run-dev.ts), so the two pipelines
381
+ * cannot drift.
382
+ */
383
+ /**
384
+ * The config step both pipelines share: the effect-resolution check and the
385
+ * choice of config file (load-config.ts's shared front), then evaluation —
386
+ * unless the caller substituted a config, which replaces the evaluation and
387
+ * nothing before it.
388
+ */
389
+ async function loadConfigStep(entryPath, cwd, deps) {
390
+ const { path: configPath, explicit } = resolveConfigFile({
391
+ entryPath,
392
+ configPath: deps.configPath,
393
+ cwd
394
+ });
395
+ return {
396
+ configPath,
397
+ config: deps.config ?? (await loadAppConfig(configPath, !explicit)).config
398
+ };
399
+ }
400
+ /**
401
+ * The pipeline's front — config discovery/load, entry load, name resolution —
402
+ * WITHOUT Load, coverage, or assemble. `log` needs only who the app is (its
403
+ * config and resolved name) to reach the already-running local instance; it
404
+ * neither builds nor provisions, so it must not require the user's built
405
+ * output the way the full pipeline does.
406
+ */
407
+ async function resolveAppIdentity(entry, overrideName, cwd, deps = {}) {
408
+ const { configPath, config } = await loadConfigStep(path.resolve(cwd, entry), cwd, deps);
409
+ const entryModule = await loadEntry(entry, cwd);
410
+ const name = overrideName ?? entryModule.root.name;
411
+ if (name.length === 0) throw new CliStructuredError("COMPOSE.NAME_MISSING", "The root node has no name.", { fix: "Name it at authoring, or pass --name." });
412
+ return {
413
+ configPath,
414
+ config,
415
+ name
416
+ };
417
+ }
418
+ /**
419
+ * Runs config discovery/load, entry load, Load, registry coverage, name
420
+ * resolution, and assemble — steps 1–6 of `run()`. `onAssembleError`, when
421
+ * given, lets a caller decorate an assemble failure with command-specific
422
+ * guidance (destroy's "build first" hint) without this shared step knowing
423
+ * about any one command.
424
+ */
425
+ async function runPipeline(entry, overrideName, cwd, deps = {}, onAssembleError) {
426
+ const { configPath, config } = await loadConfigStep(path.resolve(cwd, entry), cwd, deps);
427
+ const entryModule = await loadEntry(entry, cwd);
428
+ const graph = Load(entryModule.root);
429
+ if (graph.root.node.kind !== "module") throw new CliStructuredError("COMPOSE.ROOT_NOT_MODULE", "The deploy root must be a module.", { fix: "Wrap your service, e.g. export default module('name', ({ provision }) => { provision(service); })." });
430
+ validateRegistryCoverage(graph, config);
431
+ const name = overrideName ?? entryModule.root.name;
432
+ if (name.length === 0) throw new CliStructuredError("COMPOSE.NAME_MISSING", "The root node has no name.", { fix: "Name it at authoring, or pass --name." });
433
+ let assembled;
434
+ try {
435
+ assembled = await assembleServices(graph, config, cwd, deps.runAssembler);
436
+ } catch (error) {
437
+ if (onAssembleError !== void 0 && error instanceof Error) throw onAssembleError(error);
438
+ throw error;
439
+ }
440
+ return {
441
+ configPath,
442
+ config,
443
+ entryModule,
444
+ graph,
445
+ name,
446
+ assembled
447
+ };
448
+ }
449
+ //#endregion
450
+ export { runPipeline as n, resolveAppIdentity as t };
451
+
452
+ //# sourceMappingURL=pipeline-AoW8zq4I-CUon5KZH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-AoW8zq4I-CUon5KZH.mjs","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/load-entry-BYBSCuWg.mjs","../../../0-framework/3-tooling/assemble/dist/index.mjs","../../../0-framework/3-tooling/cli/dist/pipeline-AoW8zq4I.mjs"],"sourcesContent":["import { CliStructuredError } from \"@internal/foundation/errors\";\nimport * as path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { blindCast } from \"@internal/foundation/casts\";\nimport { isNode } from \"@internal/core\";\n//#region src/jsx-load-error.ts\n/**\n* `loadEntry` imports a user's topology with the host runtime's own module\n* loader — under node (the CLI's shebang runtime), that loader strips\n* TypeScript types but has no JSX transform (ADR-0005: the framework\n* doesn't bundle or transform the app's code; deploy loading is no\n* exception). A `.tsx`/`.jsx` file anywhere in the topology's import graph\n* dies with node's raw `ERR_UNKNOWN_FILE_EXTENSION`, which names the file\n* but not the cause or the fix. This turns that one case into structured\n* error parts (summary/why/fix) that do — every other load failure (syntax\n* errors, missing files, non-JSX unknown extensions) is untouched.\n*/\nconst UNKNOWN_EXTENSION_CODE = \"ERR_UNKNOWN_FILE_EXTENSION\";\nconst JSX_EXTENSIONS = [\".tsx\", \".jsx\"];\nfunction errorCode(error) {\n\treturn \"code\" in error && typeof error.code === \"string\" ? error.code : void 0;\n}\nfunction unknownExtensionPath(error) {\n\tif (!(error instanceof Error)) return void 0;\n\tif (errorCode(error) !== UNKNOWN_EXTENSION_CODE) return void 0;\n\treturn /Unknown file extension \"\\.\\w+\" for (.+)$/.exec(error.message)?.[1];\n}\n/**\n* Returns structured error parts when `error` is node's\n* `ERR_UNKNOWN_FILE_EXTENSION` for a `.tsx`/`.jsx` file — `undefined` for\n* every other error (including unknown-extension failures for some other\n* extension), so the caller can fall through to its normal rethrow.\n*/\nfunction explainJsxLoadError(error, entryPath) {\n\tconst offendingPath = unknownExtensionPath(error);\n\tif (offendingPath === void 0) return void 0;\n\tif (!JSX_EXTENSIONS.some((ext) => offendingPath.endsWith(ext))) return void 0;\n\treturn {\n\t\tsummary: `\"${offendingPath}\" can't be loaded.`,\n\t\twhy: `deploy loads \"${entryPath}\"'s topology with node's own module loader, which strips TypeScript types but has no JSX transform — so a .tsx/.jsx file can't sit anywhere in that import graph.`,\n\t\tfix: \"Precompile that file in your own build (transform the JSX away, keep the real npm packages external) and import the compiled output instead of the raw .tsx/.jsx — see examples/email/scripts/build.ts in the prisma/composer repo for a worked example.\"\n\t};\n}\n//#endregion\n//#region src/load-entry.ts\n/**\n* Pipeline step 1 (deploy-cli.md § The pipeline): import the entry module\n* (resolved against cwd) and require its default export to be a node — a\n* service or module, branded by core's factories. Whatever this module exports\n* IS the application; nothing else marks a root (ADR-0003).\n*/\nasync function loadEntry(entryArg, cwd) {\n\tconst resolvedPath = path.resolve(cwd, entryArg);\n\tlet mod;\n\ttry {\n\t\tmod = await import(pathToFileURL(resolvedPath).href);\n\t} catch (error) {\n\t\tconst explained = explainJsxLoadError(error, resolvedPath);\n\t\tif (explained !== void 0) throw new CliStructuredError(\"COMPOSE.ENTRY_UNLOADABLE\", explained.summary, {\n\t\t\twhy: explained.why,\n\t\t\tfix: explained.fix,\n\t\t\twhere: { path: resolvedPath },\n\t\t\tcause: error\n\t\t});\n\t\tthrow new CliStructuredError(\"COMPOSE.ENTRY_UNLOADABLE\", `Failed to import entry module \"${resolvedPath}\": ${error instanceof Error ? error.message : String(error)}`, {\n\t\t\twhere: { path: resolvedPath },\n\t\t\tcause: error\n\t\t});\n\t}\n\tconst root = blindCast(mod).default;\n\tif (!isNode(root) || root.kind === \"dependency\" || root.kind === \"resource\") throw new CliStructuredError(\"COMPOSE.ENTRY_EXPORT_INVALID\", `Entry module \"${resolvedPath}\" must default-export a node (a service or a module).`, {\n\t\tfix: \"Construct it with service() or module() from @prisma/composer.\",\n\t\twhere: { path: resolvedPath }\n\t});\n\treturn {\n\t\tpath: resolvedPath,\n\t\troot: blindCast(root)\n\t};\n}\n//#endregion\nexport { loadEntry as t };\n\n//# sourceMappingURL=load-entry-BYBSCuWg.mjs.map","import { CliStructuredError } from \"@internal/foundation/errors\";\n//#region src/assemble-error.ts\n/**\n* A user-facing assembly failure, structured at origin (base-type rule 6):\n* a `CliStructuredError` whose code names which way assembly went wrong.\n* This package's second consumer is the programmatic deploy API, not just\n* the CLI — hosts branch on `error.code`, the CLI renders the envelope.\n*/\nvar AssembleError = class extends CliStructuredError {\n\tconstructor(code, summary, options) {\n\t\tsuper(code, summary, options);\n\t}\n};\n//#endregion\n//#region src/assemble-services.ts\n/**\n* The registry route for one service's build: extension by\n* `build.extension`, node descriptor by `build.type`, kind must be \"build\".\n* The CLI's coverage validation reports the same misses earlier with the\n* config fix; these errors are the backstop for programmatic callers.\n*/\nfunction buildDescriptorAssemble(config, node, address, cwd) {\n\tconst { extension, type } = node.build;\n\tconst extensionDescriptor = config.extensions.find((candidate) => candidate.id === extension);\n\tif (extensionDescriptor === void 0) throw new AssembleError(\"ASSEMBLE.EXTENSION_MISSING\", `No extension \"${extension}\" is configured (needed by service \"${node.name}\"'s build).`, { fix: \"Add it to prisma-composer.config.ts's `extensions`.\" });\n\tconst nodeDescriptor = extensionDescriptor.nodes[type];\n\tif (nodeDescriptor === void 0) throw new AssembleError(\"ASSEMBLE.DESCRIPTOR_MISSING\", `Extension \"${extension}\" has no descriptor for build type \"${type}\".`, { why: `Known types: ${Object.keys(extensionDescriptor.nodes).join(\", \")}.` });\n\tif (nodeDescriptor.kind !== \"build\") throw new AssembleError(\"ASSEMBLE.DESCRIPTOR_KIND_MISMATCH\", `Extension \"${extension}\"'s descriptor for type \"${type}\" is a \"${nodeDescriptor.kind}\" descriptor.`, { why: \"Assembling a service build needs a \\\"build\\\" descriptor.\" });\n\treturn nodeDescriptor.assemble({\n\t\tbuild: node.build,\n\t\taddress,\n\t\tcwd\n\t});\n}\nasync function assembleServices(graph, config, cwd, run) {\n\tconst runAssembler = run ?? ((node, address, nodeCwd) => buildDescriptorAssemble(config, node, address, nodeCwd));\n\tconst serviceNodes = graph.nodes.filter((n) => n.node.kind === \"service\");\n\tif (serviceNodes.length === 0) throw new AssembleError(\"ASSEMBLE.SERVICE_MISSING\", \"The loaded graph has no service to assemble.\");\n\tconst bundles = {};\n\tfor (const { id, node } of serviceNodes) try {\n\t\tbundles[id] = await runAssembler(node, id, cwd);\n\t} catch (error) {\n\t\tif (CliStructuredError.is(error)) throw error;\n\t\tthrow new AssembleError(\"ASSEMBLE.BUILD_FAILED\", error instanceof Error ? error.message : String(error), {\n\t\t\tmeta: { address: id },\n\t\t\tcause: error\n\t\t});\n\t}\n\treturn { bundles };\n}\n//#endregion\nexport { AssembleError, assembleServices };\n\n//# sourceMappingURL=index.mjs.map","import { i as effectResolutionDiagnostic } from \"./shared-BTnATsqm.mjs\";\nimport { t as loadEntry } from \"./load-entry-BYBSCuWg.mjs\";\nimport { CliStructuredError } from \"@internal/foundation/errors\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { blindCast } from \"@internal/foundation/casts\";\nimport { Load } from \"@internal/core\";\nimport { assembleServices } from \"@internal/assemble\";\nimport * as c12 from \"c12\";\n//#region src/load-config.ts\n/**\n* Pipeline step: find and load `prisma-composer.config.ts` (ADR-0017) — the ONE\n* file that imports control-plane code. Discovery is the standard walk-up\n* from the deploy entry's directory (mirrors prisma-next's config-loader);\n* loading is c12 with that explicit path (rc/global/package.json lookups\n* disabled), so the config file's own static imports resolve from the app\n* root by whatever package manager runs — no specifier construction, no\n* anchoring.\n*\n* Two shapes of the same machinery:\n*\n* loadAppConfigDiagnostics — returns the evaluated value together with\n* EVERY problem found, and never throws. This is the shape the engine\n* command family consumes: the engine renders diagnostics itself and\n* decides per command whether a broken section is fatal, so a loader that\n* threw on the first bad field would both hide the rest and bypass that\n* rendering.\n*\n* loadAppConfig — the same load, throwing its first diagnostic. The\n* clipanion CLI still runs on it; it goes when clipanion does.\n*/\nconst CONFIG_FILENAME = \"prisma-composer.config.ts\";\n/** Walks UP from the entry file's directory looking for the literal CONFIG_FILENAME; undefined when the walk hits the filesystem root. */\nfunction findConfigPathForEntry(entryPath) {\n\tlet current = path.dirname(path.resolve(entryPath));\n\twhile (true) {\n\t\tconst candidate = path.join(current, CONFIG_FILENAME);\n\t\tif (fs.existsSync(candidate)) return candidate;\n\t\tconst parent = path.dirname(current);\n\t\tif (parent === current) return void 0;\n\t\tcurrent = parent;\n\t}\n}\nfunction missingConfigError(entryPath) {\n\tconst searchedFrom = path.dirname(path.resolve(entryPath));\n\treturn new CliStructuredError(\"CONFIG.FILE_MISSING\", `No ${CONFIG_FILENAME} found walking up from \"${searchedFrom}\".`, {\n\t\twhy: \"The deploy needs the app's config file.\",\n\t\tfix: \"Create one next to (or above) the entry, default-exporting defineConfig({ extensions: [...], state: ... }) from '@prisma/composer/config'.\",\n\t\twhere: { path: searchedFrom }\n\t});\n}\nfunction fieldError(field, requirement) {\n\treturn new CliStructuredError(\"CONFIG.FIELD_INVALID\", `${CONFIG_FILENAME}: \\`${field}\\` ${requirement}.`, {\n\t\tfix: \"See defineConfig() in '@prisma/composer/config'.\",\n\t\tmeta: { field }\n\t});\n}\nfunction isRecord(value) {\n\treturn typeof value === \"object\" && value !== null;\n}\n/**\n* Field-by-field validation of the loaded default export — deliberately no\n* schema library: each check is a structured error naming the offending field.\n*\n* Collects rather than throws, so one bad config reports every bad field\n* instead of only the first. The `extensions` and `state` checks are\n* independent, and within `extensions` each entry is judged on its own; a\n* field whose own shape check already failed is not probed further, because\n* anything derived from it would be noise rather than a second finding.\n*/\nfunction configShapeDiagnostics(loaded, configPath) {\n\tif (!isRecord(loaded) || Object.keys(loaded).length === 0) return [new CliStructuredError(\"CONFIG.EXPORT_INVALID\", `\"${configPath}\" exported no config.`, {\n\t\tfix: \"It must default-export defineConfig({ extensions: [...], state: ... }) from '@prisma/composer/config'.\",\n\t\twhere: { path: configPath }\n\t})];\n\tconst diagnostics = [];\n\tconst extensions = loaded[\"extensions\"];\n\tif (!Array.isArray(extensions)) diagnostics.push(fieldError(\"extensions\", \"must be an array\"));\n\telse {\n\t\tconst seen = /* @__PURE__ */ new Set();\n\t\tfor (const [index, entry] of extensions.entries()) {\n\t\t\tif (!isRecord(entry)) {\n\t\t\t\tdiagnostics.push(fieldError(`extensions[${index}]`, \"must be an extension descriptor object\"));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst id = entry[\"id\"];\n\t\t\tif (typeof id !== \"string\" || id.length === 0) diagnostics.push(fieldError(`extensions[${index}].id`, \"must be a non-empty string (the extension package name)\"));\n\t\t\telse if (seen.has(id)) diagnostics.push(new CliStructuredError(\"CONFIG.EXTENSION_DUPLICATE\", `${CONFIG_FILENAME}: extension \"${id}\" is listed more than once in \\`extensions\\`.`));\n\t\t\telse seen.add(id);\n\t\t\tif (!isRecord(entry[\"nodes\"])) diagnostics.push(fieldError(`extensions[${index}].nodes`, \"must be an object (the node-ID → control registry)\"));\n\t\t}\n\t}\n\tconst state = loaded[\"state\"];\n\tif (!isRecord(state) || typeof state[\"extension\"] !== \"string\" || typeof state[\"create\"] !== \"function\") diagnostics.push(fieldError(\"state\", \"must be a state descriptor (e.g. prismaState())\"));\n\treturn diagnostics;\n}\n/** The throwing form of configShapeDiagnostics: raises the first finding, returns the same object typed. Used by the clipanion pipeline. */\nfunction validateConfigShape(loaded, configPath) {\n\tconst [first] = configShapeDiagnostics(loaded, configPath);\n\tif (first !== void 0) throw first;\n\treturn blindCast(loaded);\n}\n/**\n* Evaluates `configPath` with c12 (explicit file; rc / global-rc /\n* package.json lookups disabled). `verifySamePath` runs the same-file check\n* against the discovered path — see loadAppConfigDiagnostics for when it does\n* not apply.\n*/\nasync function evaluateConfig(configPath, verifySamePath) {\n\tlet result;\n\ttry {\n\t\tresult = await c12.loadConfig({\n\t\t\tname: \"prisma-composer\",\n\t\t\tconfigFile: configPath,\n\t\t\tcwd: path.dirname(configPath),\n\t\t\trcFile: false,\n\t\t\tglobalRc: false,\n\t\t\tpackageJson: false\n\t\t});\n\t} catch (error) {\n\t\treturn {\n\t\t\tvalue: void 0,\n\t\t\tdiagnostics: [new CliStructuredError(\"CONFIG.EVALUATION_FAILED\", `Evaluating \"${configPath}\" failed: ${error instanceof Error ? error.message : String(error)}`, {\n\t\t\t\twhere: { path: configPath },\n\t\t\t\tcause: error\n\t\t\t})]\n\t\t};\n\t}\n\tconst loadedFile = result.configFile;\n\tif (verifySamePath && (typeof loadedFile !== \"string\" || fs.realpathSync(loadedFile) !== fs.realpathSync(configPath))) return {\n\t\tvalue: result.config,\n\t\tdiagnostics: [new CliStructuredError(\"CONFIG.PATH_MISMATCH\", `Config loading resolved \"${String(loadedFile)}\" instead of the discovered \"${configPath}\".`, {\n\t\t\twhy: \"Refusing to deploy against a different file.\",\n\t\t\twhere: { path: configPath }\n\t\t})]\n\t};\n\treturn {\n\t\tvalue: result.config,\n\t\tdiagnostics: configShapeDiagnostics(result.config, configPath)\n\t};\n}\n/**\n* The front of every config load, shared by the throwing and the\n* diagnostics-list shapes: verify the installed tree can evaluate a config at\n* all, then settle which file to load — the section's path, or the\n* entry-anchored walk.\n*\n* The effect-resolution check comes first because evaluating a config imports\n* alchemy's provider tree: in a tree where alchemy resolves an `effect` we did\n* not pin, nothing downstream can load, so the dependency conflict is the\n* finding with the fix in it and every later failure is its symptom.\n*/\nfunction configSource(request) {\n\tconst resolvedEntry = path.resolve(request.entryPath);\n\tconst cwd = request.cwd ?? path.dirname(resolvedEntry);\n\tconst effectConflict = effectResolutionDiagnostic(cwd);\n\tif (effectConflict !== void 0) return {\n\t\tok: false,\n\t\tpath: void 0,\n\t\tdiagnostic: effectConflict\n\t};\n\tif (request.configPath === void 0) {\n\t\tconst discovered = findConfigPathForEntry(resolvedEntry);\n\t\treturn discovered === void 0 ? {\n\t\t\tok: false,\n\t\t\tpath: void 0,\n\t\t\tdiagnostic: missingConfigError(resolvedEntry)\n\t\t} : {\n\t\t\tok: true,\n\t\t\tpath: discovered,\n\t\t\texplicit: false\n\t\t};\n\t}\n\tconst configPath = path.resolve(cwd, request.configPath);\n\tif (!fs.existsSync(configPath)) return {\n\t\tok: false,\n\t\tpath: configPath,\n\t\tdiagnostic: new CliStructuredError(\"CONFIG.FILE_MISSING\", `The \\`composer\\` config section points at \"${configPath}\", which does not exist.`, {\n\t\t\twhy: \"An explicit configPath is used as given — there is no walk to fall back on.\",\n\t\t\tfix: \"Correct `configPath` in the `composer` section of prisma.config.ts, or remove it to search upward from the entry.\",\n\t\t\twhere: { path: configPath }\n\t\t})\n\t};\n\treturn {\n\t\tok: true,\n\t\tpath: configPath,\n\t\texplicit: true\n\t};\n}\n/**\n* The throwing form of that front, for the pipeline: the file the load will\n* use, or the finding raised. `explicit` says the section named the file,\n* which is what retires the same-file check for that case.\n*/\nfunction resolveConfigFile(request) {\n\tconst source = configSource(request);\n\tif (!source.ok) throw source.diagnostic;\n\treturn {\n\t\tpath: source.path,\n\t\texplicit: source.explicit\n\t};\n}\n/**\n* Loads + validates the config at `configPath`, throwing its first diagnostic.\n* The clipanion CLI's pipeline runs on this; it goes when clipanion does.\n*/\nasync function loadAppConfig(configPath, verifySamePath = true) {\n\tconst { value, diagnostics } = await evaluateConfig(configPath, verifySamePath);\n\tconst [first] = diagnostics;\n\tif (first !== void 0) throw first;\n\treturn {\n\t\tpath: configPath,\n\t\tconfig: validateConfigShape(value, configPath)\n\t};\n}\n//#endregion\n//#region src/validate-coverage.ts\nfunction lookup(extensions, extension, type, expectedKind, what) {\n\tconst ext = extensions.get(extension);\n\tif (ext === void 0) throw new CliStructuredError(\"CONFIG.EXTENSION_MISSING\", `No extension \"${extension}\" is configured (needed by ${what}).`, {\n\t\tfix: `Add it to ${CONFIG_FILENAME}'s \\`extensions\\` (import its /control entry and list its descriptor).`,\n\t\tmeta: {\n\t\t\textension,\n\t\t\ttype\n\t\t}\n\t});\n\tconst descriptor = ext.nodes[type];\n\tif (descriptor === void 0) throw new CliStructuredError(\"CONFIG.DESCRIPTOR_MISSING\", `Extension \"${extension}\" has no descriptor for node type \"${type}\" (needed by ${what}).`, {\n\t\twhy: `Known types: ${Object.keys(ext.nodes).join(\", \")}.`,\n\t\tmeta: {\n\t\t\textension,\n\t\t\ttype\n\t\t}\n\t});\n\tif (descriptor.kind !== expectedKind) throw new CliStructuredError(\"CONFIG.DESCRIPTOR_KIND_MISMATCH\", `Extension \"${extension}\"'s descriptor for node type \"${type}\" is a \"${descriptor.kind}\" descriptor — ${what} needs a \"${expectedKind}\" descriptor.`, { meta: {\n\t\textension,\n\t\ttype,\n\t\tkind: descriptor.kind\n\t} });\n}\n/** Throws a structured CONFIG.* error on the first uncovered `(extension, type)`; silent when the config covers the whole graph. */\nfunction validateRegistryCoverage(graph, config) {\n\tconst extensions = new Map(config.extensions.map((descriptor) => [descriptor.id, descriptor]));\n\tfor (const { id, node } of graph.nodes) {\n\t\tif (node.kind === \"resource\") {\n\t\t\tlookup(extensions, node.extension, node.type, \"resource\", `resource node \"${id}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (node.kind !== \"service\") continue;\n\t\tlookup(extensions, node.extension, node.type, \"service\", `service node \"${id}\"`);\n\t\tlookup(extensions, node.build.extension, node.build.type, \"build\", `service node \"${id}\"'s build descriptor`);\n\t}\n}\n//#endregion\n//#region src/pipeline.ts\n/**\n* The shared prefix of `deploy`/`destroy`/`dev` (deploy-cli.md § The\n* pipeline; local-dev spec § 6): config discovery/load, entry load, Load,\n* registry coverage validation, name resolution, assemble. Deploy and dev\n* diverge after this — deploy resolves containers/preflight/stack file\n* against the hosted providers, dev against the local ones — so everything\n* up to and including assemble lives here once, consumed verbatim by both\n* `run()` (main.ts) and `runDev()` (dev/run-dev.ts), so the two pipelines\n* cannot drift.\n*/\n/**\n* The config step both pipelines share: the effect-resolution check and the\n* choice of config file (load-config.ts's shared front), then evaluation —\n* unless the caller substituted a config, which replaces the evaluation and\n* nothing before it.\n*/\nasync function loadConfigStep(entryPath, cwd, deps) {\n\tconst { path: configPath, explicit } = resolveConfigFile({\n\t\tentryPath,\n\t\tconfigPath: deps.configPath,\n\t\tcwd\n\t});\n\treturn {\n\t\tconfigPath,\n\t\tconfig: deps.config ?? (await loadAppConfig(configPath, !explicit)).config\n\t};\n}\n/**\n* The pipeline's front — config discovery/load, entry load, name resolution —\n* WITHOUT Load, coverage, or assemble. `log` needs only who the app is (its\n* config and resolved name) to reach the already-running local instance; it\n* neither builds nor provisions, so it must not require the user's built\n* output the way the full pipeline does.\n*/\nasync function resolveAppIdentity(entry, overrideName, cwd, deps = {}) {\n\tconst { configPath, config } = await loadConfigStep(path.resolve(cwd, entry), cwd, deps);\n\tconst entryModule = await loadEntry(entry, cwd);\n\tconst name = overrideName ?? entryModule.root.name;\n\tif (name.length === 0) throw new CliStructuredError(\"COMPOSE.NAME_MISSING\", \"The root node has no name.\", { fix: \"Name it at authoring, or pass --name.\" });\n\treturn {\n\t\tconfigPath,\n\t\tconfig,\n\t\tname\n\t};\n}\n/**\n* Runs config discovery/load, entry load, Load, registry coverage, name\n* resolution, and assemble — steps 1–6 of `run()`. `onAssembleError`, when\n* given, lets a caller decorate an assemble failure with command-specific\n* guidance (destroy's \"build first\" hint) without this shared step knowing\n* about any one command.\n*/\nasync function runPipeline(entry, overrideName, cwd, deps = {}, onAssembleError) {\n\tconst { configPath, config } = await loadConfigStep(path.resolve(cwd, entry), cwd, deps);\n\tconst entryModule = await loadEntry(entry, cwd);\n\tconst graph = Load(entryModule.root);\n\tif (graph.root.node.kind !== \"module\") throw new CliStructuredError(\"COMPOSE.ROOT_NOT_MODULE\", \"The deploy root must be a module.\", { fix: \"Wrap your service, e.g. export default module('name', ({ provision }) => { provision(service); }).\" });\n\tvalidateRegistryCoverage(graph, config);\n\tconst name = overrideName ?? entryModule.root.name;\n\tif (name.length === 0) throw new CliStructuredError(\"COMPOSE.NAME_MISSING\", \"The root node has no name.\", { fix: \"Name it at authoring, or pass --name.\" });\n\tlet assembled;\n\ttry {\n\t\tassembled = await assembleServices(graph, config, cwd, deps.runAssembler);\n\t} catch (error) {\n\t\tif (onAssembleError !== void 0 && error instanceof Error) throw onAssembleError(error);\n\t\tthrow error;\n\t}\n\treturn {\n\t\tconfigPath,\n\t\tconfig,\n\t\tentryModule,\n\t\tgraph,\n\t\tname,\n\t\tassembled\n\t};\n}\n//#endregion\nexport { runPipeline as n, resolveAppIdentity as t };\n\n//# sourceMappingURL=pipeline-AoW8zq4I.mjs.map"],"mappings":"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"}
package/dist/report.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { d as DeploymentResult } from "./app-config-Cbv_lA38-BHJsd1DF.mjs";
2
- import "./deploy-whuqZ5xT.mjs";
1
+ import { f as DeploymentResult } from "./app-config-aIrriqVU-Dpj1RqnY.mjs";
2
+ import "./deploy-BeBRB-6m.mjs";
3
3
  //#region ../../0-framework/3-tooling/cli/dist/report.d.mts
4
4
  //#region src/render-deployment.d.ts
5
5
  /**
@@ -9,7 +9,8 @@ import "./deploy-whuqZ5xT.mjs";
9
9
  declare function renderDeployment(result: DeploymentResult): string;
10
10
  /**
11
11
  * The report hook the generated stack file wires into `LowerOptions`. Prints a
12
- * leading blank line so the summary separates from alchemy's own apply output.
12
+ * leading blank line so the summary separates from alchemy's own apply output,
13
+ * then hands the result to the cross-process writer (deployment-summary.ts).
13
14
  */
14
15
  declare function deploymentReport(result: DeploymentResult): void;
15
16
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.mts","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.d.mts"],"mappings":";;;;;;;;iBAMiB,iBAAiB,QAAQ;;;;;iBAKzB,iBAAiB,QAAQ"}
1
+ {"version":3,"file":"report.d.mts","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.d.mts"],"mappings":";;;;;;;;iBAMiB,iBAAiB,QAAQ;;;;;;iBAMzB,iBAAiB,QAAQ"}
package/dist/report.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { r as writeDeploymentSummaryFile } from "./deployment-summary-DswOl_9E-C03NJ98H.mjs";
1
2
  //#region ../../0-framework/3-tooling/cli/dist/report.mjs
2
3
  /** Gap between the deepest tree label and the entity column. */
3
4
  const LABEL_GAP = 3;
@@ -71,11 +72,13 @@ function renderDeployment(result) {
71
72
  }
72
73
  /**
73
74
  * The report hook the generated stack file wires into `LowerOptions`. Prints a
74
- * leading blank line so the summary separates from alchemy's own apply output.
75
+ * leading blank line so the summary separates from alchemy's own apply output,
76
+ * then hands the result to the cross-process writer (deployment-summary.ts).
75
77
  */
76
78
  function deploymentReport(result) {
77
79
  console.log("");
78
80
  console.log(renderDeployment(result));
81
+ writeDeploymentSummaryFile(result);
79
82
  }
80
83
  //#endregion
81
84
  export { deploymentReport, renderDeployment };
@@ -1 +1 @@
1
- {"version":3,"file":"report.mjs","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.mjs"],"sourcesContent":["//#region src/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\tfor (const [key, value] of Object.entries(entity.details ?? {})) {\n\t\t\t\tif (value === \"\") continue;\n\t\t\t\tfor (const line of value.split(\"\\n\")) lines.push(`${pad(row.continuation, column)}${key} ${line}`);\n\t\t\t}\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;GACrF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,WAAW,CAAC,CAAC,GAAG;IAChE,IAAI,UAAU,IAAI;IAClB,KAAK,MAAM,QAAQ,MAAM,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,IAAI,IAAI,cAAc,MAAM,IAAI,IAAI,GAAG,MAAM;GAClG;EACD,CAAC;CACF;CACA,OAAO,MAAM,KAAK,IAAI;AACvB;;;;;AAKA,SAAS,iBAAiB,QAAQ;CACjC,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,iBAAiB,MAAM,CAAC;AACrC"}
1
+ {"version":3,"file":"report.mjs","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.mjs"],"sourcesContent":["import { r as writeDeploymentSummaryFile } from \"./deployment-summary-DswOl_9E.mjs\";\n//#region src/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\tfor (const [key, value] of Object.entries(entity.details ?? {})) {\n\t\t\t\tif (value === \"\") continue;\n\t\t\t\tfor (const line of value.split(\"\\n\")) lines.push(`${pad(row.continuation, column)}${key} ${line}`);\n\t\t\t}\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* then hands the result to the cross-process writer (deployment-summary.ts).\n*/\nfunction deploymentReport(result) {\n\tconsole.log(\"\");\n\tconsole.log(renderDeployment(result));\n\twriteDeploymentSummaryFile(result);\n}\n//#endregion\nexport { deploymentReport, renderDeployment };\n\n//# sourceMappingURL=report.mjs.map"],"mappings":";;;AAGA,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;GACrF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,WAAW,CAAC,CAAC,GAAG;IAChE,IAAI,UAAU,IAAI;IAClB,KAAK,MAAM,QAAQ,MAAM,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,IAAI,IAAI,cAAc,MAAM,IAAI,IAAI,GAAG,MAAM;GAClG;EACD,CAAC;CACF;CACA,OAAO,MAAM,KAAK,IAAI;AACvB;;;;;;AAMA,SAAS,iBAAiB,QAAQ;CACjC,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,iBAAiB,MAAM,CAAC;CACpC,2BAA2B,MAAM;AAClC"}