@prisma/composer-cli 0.25.0 → 0.26.0-dev.2

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 (56) hide show
  1. package/dist/composer-config-CY9fET8H-KpGjlYgO.mjs +432 -0
  2. package/dist/composer-config-CY9fET8H-KpGjlYgO.mjs.map +1 -0
  3. package/dist/{pipeline-C7gNjMzJ-CMqZQxqM.mjs → container-transport-HcvNOGZL-CHqecFc7.mjs} +109 -322
  4. package/dist/container-transport-HcvNOGZL-CHqecFc7.mjs.map +1 -0
  5. package/dist/{execute-deploy-destroy-CvKCwVkD-B3vcxYJF.mjs → execute-deploy-destroy-c0eko3AO-9npuGXd3.mjs} +108 -85
  6. package/dist/execute-deploy-destroy-c0eko3AO-9npuGXd3.mjs.map +1 -0
  7. package/dist/{execute-dev-BLCK5wF7-CuzMSK7T.mjs → execute-dev-BICPaq1g-CSoZJuhB.mjs} +162 -132
  8. package/dist/execute-dev-BICPaq1g-CSoZJuhB.mjs.map +1 -0
  9. package/dist/{family-B1RaH4f8-ChoTnv3A.d.mts → family-CgeZQdNg-gH8LuqqL.d.mts} +136 -172
  10. package/dist/family-CgeZQdNg-gH8LuqqL.d.mts.map +1 -0
  11. package/dist/family.d.mts +4 -39
  12. package/dist/family.d.mts.map +1 -1
  13. package/dist/family.mjs +49 -551
  14. package/dist/family.mjs.map +1 -1
  15. package/dist/generate-dev-stack-BUadNY_w-DF_lHVaP.mjs +87 -0
  16. package/dist/generate-dev-stack-BUadNY_w-DF_lHVaP.mjs.map +1 -0
  17. package/dist/run-alchemy-BEvB2sYQ-BgV2deuO.mjs +154 -0
  18. package/dist/run-alchemy-BEvB2sYQ-BgV2deuO.mjs.map +1 -0
  19. package/dist/testing.d.mts +24 -24
  20. package/dist/testing.d.mts.map +1 -1
  21. package/dist/testing.mjs +17 -45
  22. package/dist/testing.mjs.map +1 -1
  23. package/package.json +7 -11
  24. package/src/exports/testing.ts +5 -3
  25. package/dist/bin.mjs +0 -1040
  26. package/dist/bin.mjs.map +0 -1
  27. package/dist/container-transport-HcvNOGZL-CIoZc7Rs.mjs +0 -34
  28. package/dist/container-transport-HcvNOGZL-CIoZc7Rs.mjs.map +0 -1
  29. package/dist/execute-deploy-destroy-CvKCwVkD-B3vcxYJF.mjs.map +0 -1
  30. package/dist/execute-deploy-destroy-CvKCwVkD-DCufHnkW.mjs +0 -528
  31. package/dist/execute-deploy-destroy-CvKCwVkD-DCufHnkW.mjs.map +0 -1
  32. package/dist/execute-dev-BLCK5wF7-B-fG_E31.mjs +0 -2011
  33. package/dist/execute-dev-BLCK5wF7-B-fG_E31.mjs.map +0 -1
  34. package/dist/execute-dev-BLCK5wF7-CuzMSK7T.mjs.map +0 -1
  35. package/dist/execute-log-B_zCJ17b-BrLUt7vo.mjs +0 -157
  36. package/dist/execute-log-B_zCJ17b-BrLUt7vo.mjs.map +0 -1
  37. package/dist/execute-log-B_zCJ17b-C4a0uxJj.mjs +0 -158
  38. package/dist/execute-log-B_zCJ17b-C4a0uxJj.mjs.map +0 -1
  39. package/dist/family-B1RaH4f8-ChoTnv3A.d.mts.map +0 -1
  40. package/dist/local-target-BOGjATc2.mjs +0 -68
  41. package/dist/local-target-BOGjATc2.mjs.map +0 -1
  42. package/dist/local-target-hoEGqgVA.mjs +0 -68
  43. package/dist/local-target-hoEGqgVA.mjs.map +0 -1
  44. package/dist/pipeline-C7gNjMzJ-CMqZQxqM.mjs.map +0 -1
  45. package/dist/pipeline-C7gNjMzJ-CixaMvnR.mjs +0 -1205
  46. package/dist/pipeline-C7gNjMzJ-CixaMvnR.mjs.map +0 -1
  47. package/dist/result-B874OKwb.mjs +0 -383
  48. package/dist/result-B874OKwb.mjs.map +0 -1
  49. package/dist/result-sR7PBi61.mjs +0 -229
  50. package/dist/result-sR7PBi61.mjs.map +0 -1
  51. package/dist/run-alchemy-pANK8XNX-BH1wC0r6.mjs +0 -99
  52. package/dist/run-alchemy-pANK8XNX-BH1wC0r6.mjs.map +0 -1
  53. package/dist/run-alchemy-pANK8XNX-XcCQncKN.mjs +0 -99
  54. package/dist/run-alchemy-pANK8XNX-XcCQncKN.mjs.map +0 -1
  55. package/dist/shared-BTnATsqm-BH4axbJg.mjs +0 -158
  56. package/dist/shared-BTnATsqm-BH4axbJg.mjs.map +0 -1
package/dist/family.mjs CHANGED
@@ -1,64 +1,8 @@
1
- import { t as notOk$1 } from "./result-sR7PBi61.mjs";
2
- import { n as executionDiagnostics, r as executorLoadFailure } from "./shared-BTnATsqm-BH4axbJg.mjs";
3
- import { t as alchemyCommandLine } from "./run-alchemy-pANK8XNX-XcCQncKN.mjs";
4
- import spawn from "cross-spawn";
5
- import { EnvironmentCredentialManager, createCli, defineCommand, defineCommandFamily, defineConfigSection, defineSessionCommand, exitWithChildStatus, flag, loadConfig, positional, resolveSectionPath } from "@prisma/cli-engine";
1
+ import { i as sectionMissing, t as checkComposerConfig } from "./composer-config-CY9fET8H-KpGjlYgO.mjs";
2
+ import { a as devWithDeps, i as deployWithDeps, o as executionDiagnostics, t as alchemyCommandLine } from "./run-alchemy-BEvB2sYQ-BgV2deuO.mjs";
3
+ import { defineCommand, defineCommandFamily, defineConfigSection, defineSessionCommand, exitWithChildStatus, flag, positional } from "@prisma/cli-engine";
6
4
  import { CliStructuredError, notOk, ok } from "@prisma/cli-engine/protocol";
7
- //#region ../../0-framework/3-tooling/cli/dist/log-DHFQEBKS.mjs
8
- /** In-package variant threading the injection seam (the CLI's RunDeps, unit
9
- * tests). Deliberately NOT re-exported through `./control` — the seam mirrors
10
- * internal types and is not part of the published surface. */
11
- async function deployWithDeps(input, deps) {
12
- const cwd = input.cwd ?? process.cwd();
13
- let executor;
14
- try {
15
- executor = await import("./execute-deploy-destroy-CvKCwVkD-B3vcxYJF.mjs");
16
- } catch (error) {
17
- return notOk$1(executorLoadFailure("deploy", error, cwd));
18
- }
19
- return executor.executeDeploy(input, deps, cwd);
20
- }
21
- /** In-package variant threading the injection seam (the CLI's RunDeps, unit
22
- * tests). Deliberately NOT re-exported through `./control` — the seam mirrors
23
- * internal types and is not part of the published surface. */
24
- async function destroyWithDeps(input, deps) {
25
- const cwd = input.cwd ?? process.cwd();
26
- let executor;
27
- try {
28
- executor = await import("./execute-deploy-destroy-CvKCwVkD-B3vcxYJF.mjs");
29
- } catch (error) {
30
- return notOk$1(executorLoadFailure("destroy", error, cwd));
31
- }
32
- return executor.executeDestroy(input, deps, cwd);
33
- }
34
- /** In-package variant threading the injection seam (the CLI's RunDeps, unit
35
- * tests). Deliberately NOT re-exported through `./control` — the seam mirrors
36
- * internal types and is not part of the published surface. */
37
- async function devWithDeps(input, deps) {
38
- const cwd = input.cwd ?? process.cwd();
39
- let executor;
40
- try {
41
- executor = await import("./execute-dev-BLCK5wF7-CuzMSK7T.mjs");
42
- } catch (error) {
43
- return notOk$1(executorLoadFailure("dev", error, cwd));
44
- }
45
- return executor.executeDev(input, deps, cwd);
46
- }
47
- /** In-package variant threading the injection seam (the CLI's LogRunDeps,
48
- * unit tests). Deliberately NOT re-exported through `./control` — the seam
49
- * mirrors internal types and is not part of the published surface. */
50
- async function logWithDeps(input, deps) {
51
- const cwd = input.cwd ?? process.cwd();
52
- let executor;
53
- try {
54
- executor = await import("./execute-log-B_zCJ17b-C4a0uxJj.mjs");
55
- } catch (error) {
56
- return notOk$1(executorLoadFailure("log", error, cwd));
57
- }
58
- return executor.executeLog(input, deps, cwd);
59
- }
60
- //#endregion
61
- //#region ../../0-framework/3-tooling/cli/dist/engine-cli-BGthfw1R.mjs
5
+ //#region ../../0-framework/3-tooling/cli/dist/family.mjs
62
6
  /**
63
7
  * The family boundary's error translation.
64
8
  *
@@ -120,7 +64,6 @@ function convergeSpawn(ctx) {
120
64
  function operationDeps(spec) {
121
65
  return {
122
66
  alchemy: spec.alchemy,
123
- configPath: spec.configPath,
124
67
  credentials: {
125
68
  workspaceId: spec.workspaceId,
126
69
  client: spec.client
@@ -142,7 +85,7 @@ function reproduceHint(failure) {
142
85
  }];
143
86
  }
144
87
  /**
145
- * How a FAILED converge settles. `deploy`, `destroy` and `dev` all end this
88
+ * How a FAILED converge settles. `deploy` and `dev` both end this
146
89
  * way and must not drift apart, so the decision lives here once rather than
147
90
  * inline in each handler.
148
91
  *
@@ -181,122 +124,47 @@ function settleConverge(result, ctx, present) {
181
124
  if (!result.ok) return settleConvergeFailure(result.failure, ctx);
182
125
  return ok(present(result.value));
183
126
  }
184
- /**
185
- * Composer's projection into `prisma.config.ts` — the `composer` section.
186
- *
187
- * The section is deliberately tiny. Composer's real configuration lives in
188
- * `prisma-composer.config.ts`, which holds executable values (Effect layers,
189
- * provider factories, container lifecycles) and can only be understood by
190
- * evaluating it inside a running command. A config-section validator loads
191
- * with the command tree at start-up and must be dependency-light and total,
192
- * so it is the wrong place to evaluate any of that. What the section carries
193
- * is therefore only the one fact the engine can usefully know before a
194
- * command runs: WHERE that file is, when the user wants to say so.
195
- *
196
- * Its fields grow only by amending the slice contract.
197
- */
198
- const KNOWN_FIELDS = ["configPath"];
199
- function diagnostic(spec) {
127
+ function diagnostic(finding, file) {
128
+ const where = finding.where ?? file;
200
129
  return {
201
- code: spec.code,
202
- severity: spec.severity,
203
- summary: spec.summary,
204
- ...spec.why === void 0 ? {} : { why: spec.why },
205
- nextActions: spec.fix === void 0 ? [] : [{
130
+ code: finding.code,
131
+ severity: "error",
132
+ summary: finding.summary,
133
+ ...finding.why === void 0 ? {} : { why: finding.why },
134
+ nextActions: [{
206
135
  kind: "edit-file",
207
- label: spec.fix
208
- }]
136
+ label: finding.fix
137
+ }],
138
+ ...where === void 0 ? {} : { where: { path: where } },
139
+ ...finding.field === void 0 ? {} : { meta: { field: finding.field } }
209
140
  };
210
141
  }
211
- function validate(raw, provenance) {
212
- if (raw === void 0) return {
213
- ok: true,
214
- value: {},
215
- diagnostics: []
216
- };
217
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {
218
- ok: false,
219
- diagnostics: [diagnostic({
220
- code: "CONFIG.FIELD_INVALID",
221
- severity: "error",
222
- summary: "The `composer` section of prisma.config.ts must be an object.",
223
- fix: "Write `composer: { configPath: \"./prisma-composer.config.ts\" }`, or remove the section entirely."
224
- })]
225
- };
226
- let record;
227
- try {
228
- record = { ...raw };
229
- } catch {
230
- return {
231
- ok: false,
232
- diagnostics: [diagnostic({
233
- code: "CONFIG.FIELD_INVALID",
234
- severity: "error",
235
- summary: "The `composer` section of prisma.config.ts could not be read.",
236
- why: "Reading its fields threw, so nothing in it can be trusted.",
237
- fix: "Write it as a plain object literal, e.g. `composer: { configPath: \"./prisma-composer.config.ts\" }`."
238
- })]
239
- };
240
- }
241
- const configPath = record["configPath"];
242
- if (configPath !== void 0 && (typeof configPath !== "string" || configPath.length === 0)) return {
142
+ function refuse(findings, file) {
143
+ return {
243
144
  ok: false,
244
- diagnostics: [diagnostic({
245
- code: "CONFIG.FIELD_INVALID",
246
- severity: "error",
247
- summary: "`composer.configPath` must be a non-empty string.",
248
- why: "It names the prisma-composer.config.ts file to load.",
249
- fix: "Set it to a path, or remove it to search upward from the entry."
250
- })]
145
+ diagnostics: findings.map((finding) => diagnostic(finding, file))
251
146
  };
252
- let resolvedConfigPath;
253
- if (configPath !== void 0) try {
254
- resolvedConfigPath = resolveSectionPath(provenance, "configPath", configPath);
255
- } catch {
256
- return {
257
- ok: false,
258
- diagnostics: [diagnostic({
259
- code: "CONFIG.FIELD_INVALID",
260
- severity: "error",
261
- summary: "`composer.configPath` could not be resolved against the file that declared it.",
262
- fix: "Write `configPath` as an absolute path, or check the `composer` section of prisma.config.ts."
263
- })]
264
- };
265
- }
266
- const unknown = Object.keys(record).filter((key) => !KNOWN_FIELDS.includes(key));
147
+ }
148
+ function validate(raw, provenance) {
149
+ const file = provenance.files[0];
150
+ if (raw === void 0 || file === void 0) return refuse([sectionMissing], void 0);
151
+ const checked = checkComposerConfig(raw, file);
152
+ if (!checked.ok) return refuse(checked.findings, file);
267
153
  return {
268
154
  ok: true,
269
- value: resolvedConfigPath === void 0 ? {} : { configPath: resolvedConfigPath },
270
- diagnostics: unknown.map((key) => diagnostic({
271
- code: "CONFIG.FIELD_UNKNOWN",
272
- severity: "warn",
273
- summary: `The \`composer\` section has no field \`${key}\`; it is ignored.`,
274
- fix: `Remove \`${key}\`, or check it against the version of @prisma/composer you have installed.`
275
- }))
155
+ value: {
156
+ value: checked.value,
157
+ file
158
+ },
159
+ diagnostics: []
276
160
  };
277
161
  }
278
162
  const composerSection = defineConfigSection({
279
163
  name: "composer",
280
- validate
164
+ validate,
165
+ merge: (_parent, child) => child
281
166
  });
282
167
  /**
283
- * `destroy`'s target, from its two mutually exclusive flags. Kept out of the
284
- * grammar because the engine's flag layer has no "exactly one of these"
285
- * construct — and because both wrong shapes need their own remedy, which a
286
- * generic arity error could not give.
287
- */
288
- function targetOf(stage, production) {
289
- if (stage !== void 0 && production) return notOk(new CliStructuredError("DEPLOY.TARGET_CONFLICT", "Pass either --stage <name> or --production to `destroy`, not both."));
290
- if (stage === void 0 && !production) return notOk(new CliStructuredError("DEPLOY.TARGET_MISSING", "`destroy` requires an explicit target.", { nextActions: [{
291
- kind: "user-choice",
292
- label: "Pass --stage <name> to tear down a branch environment, or --production to tear down the production environment."
293
- }] }));
294
- return ok(stage !== void 0 ? {
295
- kind: "stage",
296
- stage
297
- } : { kind: "production" });
298
- }
299
- /**
300
168
  * The workspace the in-process leg acts in, from the engine's credential
301
169
  * read. Handlers never decode a token and never read PRISMA_WORKSPACE_ID:
302
170
  * whether the credential came from a stored session or the environment, the
@@ -311,155 +179,6 @@ async function workspaceIdOf(ctx) {
311
179
  return (await ctx.activeCredential())?.workspaceId;
312
180
  }
313
181
  /**
314
- * `destroy <entry>` — deploy's mirror: same derivation, alchemy destroy.
315
- *
316
- * No confirmation prompt, matching the CLI this replaces. The front door
317
- * cannot know what the child will tear down, so a consent step here would be
318
- * asking the user to approve a list nobody has computed yet; if destroy
319
- * deserves one it belongs in composer's own operation, not in the grammar.
320
- */
321
- const createDestroyCommand = (operations) => defineCommand({
322
- help: {
323
- summary: "Tear down the application whose root node is <entry>'s default export.",
324
- description: "Same derivation as deploy. Requires an explicit target: --stage <name> for a branch environment, or --production for the production environment.",
325
- examples: ["{bin} destroy module.ts --stage feat-auth", "{bin} destroy module.ts --production"]
326
- },
327
- args: {
328
- positionals: { entry: positional.string({
329
- brief: "The file whose default export is the application root module, built with module(...).",
330
- placeholder: "entry"
331
- }) },
332
- flags: {
333
- name: flag.string({
334
- brief: "Override the root node's name — the application name to tear down.",
335
- placeholder: "name"
336
- }),
337
- stage: flag.string({
338
- brief: "Tear down this branch environment.",
339
- placeholder: "stage"
340
- }),
341
- production: flag.boolean({ brief: "Tear down the project-level production environment." })
342
- }
343
- },
344
- needs: {
345
- config: composerSection,
346
- credentials: "child"
347
- },
348
- maySpawn: true,
349
- handler: async (args, ctx) => {
350
- const target = targetOf(args.flags.stage, args.flags.production);
351
- if (!target.ok) return target;
352
- const alchemy = convergeSpawn(ctx);
353
- return settleConverge(await operations.destroy({
354
- entry: args.positionals.entry,
355
- name: args.flags.name,
356
- target: target.value,
357
- cwd: ctx.cwd,
358
- onEvent: (event) => {
359
- if (event.kind !== "no-local-deploy-state") return;
360
- ctx.report({
361
- kind: "message",
362
- severity: "warn",
363
- text: `No prior deploy state under ${event.cwd} — if you deployed from a different directory, run destroy from there; otherwise this is a no-op.`
364
- });
365
- }
366
- }, operationDeps({
367
- alchemy,
368
- configPath: ctx.config.configPath,
369
- workspaceId: await workspaceIdOf(ctx),
370
- client: ctx.api
371
- })), ctx, () => ctx.present({ data: void 0 }, {
372
- human: () => [{
373
- kind: "summary",
374
- status: "ok",
375
- text: "Destroyed."
376
- }],
377
- stdout: () => [],
378
- json: () => void 0,
379
- next: () => []
380
- }));
381
- }
382
- });
383
- /**
384
- * `log <entry> [address]` — a session command that tails the merged logs of
385
- * the app running locally on this machine.
386
- *
387
- * It reads the LOCAL dev-emulator daemon, not the platform's logs surface, so
388
- * it is credential-free. It hands the terminal to nothing, which is why it
389
- * does not declare `maySpawn` and keeps json support: the log lines ARE its
390
- * json surface.
391
- *
392
- * Windows is refused inside the operation itself (LOG.PLATFORM_UNSUPPORTED),
393
- * which is why nothing here reads the platform.
394
- */
395
- /** An empty screen reads as broken, so show a little recent history before going live. */
396
- const DEFAULT_TAIL = 20;
397
- const createLogCommand = (operations) => defineSessionCommand({
398
- help: {
399
- summary: "Tail the merged logs of the locally-running application whose root node is <entry>'s default export.",
400
- examples: ["{bin} log module.ts", "{bin} log module.ts catalog.service"]
401
- },
402
- args: {
403
- positionals: {
404
- entry: positional.string({
405
- brief: "The file whose default export is the application root module, built with module(...).",
406
- placeholder: "entry"
407
- }),
408
- address: positional.optionalString({
409
- brief: "Only this service's lines, by its dotted address (catalog.service); every service when absent.",
410
- placeholder: "address"
411
- })
412
- },
413
- flags: {
414
- name: flag.string({
415
- brief: "Override the root node's name — the dev instance's application name.",
416
- placeholder: "name"
417
- }),
418
- tail: flag.number({
419
- brief: `How many trailing history lines to show before live output (default ${String(DEFAULT_TAIL)}).`,
420
- placeholder: "lines",
421
- default: DEFAULT_TAIL
422
- })
423
- }
424
- },
425
- needs: { config: composerSection },
426
- handler: async (args, ctx) => {
427
- const reportLogEvent = (event) => {
428
- ctx.report({
429
- kind: "message",
430
- severity: "warn",
431
- text: event.kind === "stream-failed" ? `Stream failed: ${event.message}` : `Falling behind — dropped the ${String(event.count)} oldest lines.`
432
- });
433
- };
434
- const result = await operations.log({
435
- entry: args.positionals.entry,
436
- name: args.flags.name,
437
- address: args.positionals.address,
438
- tail: args.flags.tail ?? DEFAULT_TAIL,
439
- cwd: ctx.cwd,
440
- signal: ctx.signal,
441
- onEvent: reportLogEvent
442
- }, { configPath: ctx.config.configPath });
443
- if (!result.ok) return notOk(toEngineError(result.failure));
444
- const attached = result.value;
445
- if (attached.services.length === 0) {
446
- ctx.report({
447
- kind: "message",
448
- severity: "warn",
449
- text: `No running services for "${attached.appName}" — start it first with \`dev ${args.positionals.entry}\`.`
450
- });
451
- return ok(void 0);
452
- }
453
- for await (const { service, line } of attached.lines) ctx.report({
454
- kind: "output",
455
- source: service,
456
- channel: "data",
457
- line: `[${service}] ${line}`
458
- });
459
- return ok(void 0);
460
- }
461
- });
462
- /**
463
182
  * `deploy <entry>` — a result command that hands the terminal to alchemy.
464
183
  *
465
184
  * `--production` is gone. It was accepted and then always errored ("only
@@ -504,6 +223,7 @@ const createDeployCommand = (operations) => defineCommand({
504
223
  const alchemy = convergeSpawn(ctx);
505
224
  return settleConverge(await operations.deploy({
506
225
  entry: args.positionals.entry,
226
+ config: ctx.config,
507
227
  name: args.flags.name,
508
228
  stage: args.flags.stage,
509
229
  cwd: ctx.cwd,
@@ -511,7 +231,6 @@ const createDeployCommand = (operations) => defineCommand({
511
231
  reportId: args.flags.buildId
512
232
  }, operationDeps({
513
233
  alchemy,
514
- configPath: ctx.config.configPath,
515
234
  workspaceId: await workspaceIdOf(ctx),
516
235
  client: ctx.api
517
236
  })), ctx, ({ summary }) => ctx.present({ data: { summary: summary ?? null } }, {
@@ -615,6 +334,13 @@ function reportDevEvent(report, lastChild) {
615
334
  text: `Rebuild failed: ${event.message}`
616
335
  });
617
336
  return;
337
+ case "config-changed":
338
+ report({
339
+ kind: "message",
340
+ severity: "warn",
341
+ text: `${event.file} changed. Restart dev to apply it; rebuilds are paused until then.`
342
+ });
343
+ return;
618
344
  case "watch-error":
619
345
  report({
620
346
  kind: "message",
@@ -693,14 +419,12 @@ const createDevCommand = (operations) => defineSessionCommand({
693
419
  const alchemy = convergeSpawn(ctx);
694
420
  const result = await operations.dev({
695
421
  entry: args.positionals.entry,
422
+ config: ctx.config,
696
423
  name: args.flags.name,
697
424
  fresh: args.flags.fresh,
698
425
  cwd: ctx.cwd,
699
426
  onEvent: reportDevEvent(ctx.report, ctx.lastChild)
700
- }, {
701
- alchemy: coalescedConverge(alchemy),
702
- configPath: ctx.config.configPath
703
- });
427
+ }, { alchemy: coalescedConverge(alchemy) });
704
428
  if (!result.ok) return settleConvergeFailure(result.failure, ctx);
705
429
  await stopRequested(ctx.signal);
706
430
  await result.value.stop();
@@ -708,16 +432,14 @@ const createDevCommand = (operations) => defineSessionCommand({
708
432
  }
709
433
  });
710
434
  /**
711
- * Composer's `CommandFamily` — the unit the engine mounts, whether the process
712
- * is composer's own CLI or the `prisma` bin.
435
+ * Composer's `CommandFamily`: the unit the `prisma` bin mounts.
713
436
  *
714
437
  * This module and everything it reaches statically must stay free of alchemy
715
438
  * and of effect VALUE imports: the `prisma` bin imports the family directly,
716
439
  * so anything in this static graph loads on `prisma --version`. The mechanism
717
440
  * that holds it is the existing lazy boundary inside the operation modules —
718
- * `operations/deploy.ts`, `destroy.ts`, `dev.ts` and `log.ts` each `await
719
- * import()` their executor, and it is the executors that reach the provider
720
- * tree. Importing the operations here is therefore free; importing an
441
+ * `operations/deploy.ts` and `dev.ts` each `await import()` their executor,
442
+ * and it is the executors that reach the provider tree. Importing the operations here is therefore free; importing an
721
443
  * executor, or flattening one of those dynamic imports, is not.
722
444
  * scripts/check-family-static-graph.mjs enforces this against BUILT output,
723
445
  * where type-only imports have already been erased.
@@ -726,16 +448,12 @@ const createDevCommand = (operations) => defineSessionCommand({
726
448
  * mount this family against the test double and exercise real grammar, real
727
449
  * arg validation and real handlers with no alchemy behind them.
728
450
  *
729
- * The family ships `deploy` and `dev` only: `destroy` and `log` were retired
730
- * from the family surface (2026-08-21 PM review), so hosts mounting the family
731
- * — the `prisma` bin — never see them. They remain first-class commands of
732
- * composer's own bin, mounted on top of the family in engine-cli.ts.
451
+ * The family ships `deploy` and `dev` only. `destroy` and `log` are
452
+ * programmatic operations in `@prisma/composer/control`, not commands.
733
453
  */
734
454
  const realOperations = {
735
455
  deploy: deployWithDeps,
736
- destroy: destroyWithDeps,
737
- dev: devWithDeps,
738
- log: logWithDeps
456
+ dev: devWithDeps
739
457
  };
740
458
  /** The `prisma` CLI's error reference; the engine appends `/<CODE>` to it for every error envelope. */
741
459
  const CLI_DOCS_BASE = "https://www.prisma.io/docs/cli/error-reference/";
@@ -750,227 +468,7 @@ function createComposerFamily(options = {}) {
750
468
  docsBaseUrl: CLI_DOCS_BASE
751
469
  });
752
470
  }
753
- /**
754
- * Everything environmental the engine needs, assembled from a host process.
755
- *
756
- * The engine takes no globals: streams, cwd, env, TTY-ness, exit and signal
757
- * subscription all arrive through `Runtime`, which is what lets a test drive a
758
- * whole run without touching `process`. Composing one is the substantive part
759
- * of hosting the engine — `createCli` and `Cli.run` are two calls.
760
- *
761
- * Credentials come from the engine's own environment-only manager, which
762
- * composes a session from PRISMA_SERVICE_TOKEN / PRISMA_WORKSPACE_ID and
763
- * refuses every mutation. That is the whole of composer's standalone auth
764
- * story: this CLI has no login flow and mounts no auth commands, so there is
765
- * nothing to store — the two variables ARE the credential.
766
- */
767
- /** Where the management API lives. Matches the lowering client's default origin; the env var is the escape hatch for staging. */
768
- const DEFAULT_MANAGEMENT_API_BASE_URL = "https://api.prisma.io";
769
- const DEFAULT_AUTH_BASE_URL = "https://auth.prisma.io";
770
- /**
771
- * Starts the converge child: inherited stdio, this process's own group, no
772
- * `detached` and no new console — which is what lets the terminal deliver
773
- * Ctrl-C to the child natively instead of the CLI forwarding it. The engine
774
- * never imports node:child_process; this adapter is the whole of the host's
775
- * side of that seam.
776
- */
777
- const spawnChild = (request) => {
778
- const child = spawn(request.command, [...request.args], {
779
- cwd: request.cwd,
780
- stdio: "inherit",
781
- env: request.env
782
- });
783
- return {
784
- ended: new Promise((resolve, reject) => {
785
- child.on("error", reject);
786
- child.on("close", (exitCode, signal) => {
787
- resolve({
788
- exitCode,
789
- signal
790
- });
791
- });
792
- }),
793
- kill: (signal) => {
794
- child.kill(signal);
795
- }
796
- };
797
- };
798
- /**
799
- * The SDK's client construction config. The engine requires all four fields
800
- * whenever a credential manager is wired, but this host reaches none of the
801
- * login paths: an environment credential carries no refresh token, so nothing
802
- * ever refreshes and `clientId`/`redirectUri` are never read. They are
803
- * env-overridable rather than hard-coded so a staging run can point the whole
804
- * client somewhere else in one place.
805
- */
806
- function clientConfig(env, apiBaseUrl) {
807
- return {
808
- clientId: env["PRISMA_CLIENT_ID"] ?? "prisma-composer-cli",
809
- redirectUri: env["PRISMA_REDIRECT_URI"] ?? "http://127.0.0.1/callback",
810
- apiBaseUrl,
811
- authBaseUrl: env["PRISMA_AUTH_URL"] ?? DEFAULT_AUTH_BASE_URL
812
- };
813
- }
814
- /**
815
- * What this process runs on, for `ctx.host`. Bun and Deno both announce
816
- * themselves in `versions`; nothing else does, so an absent marker means Node.
817
- */
818
- function describeHost(host) {
819
- const name = ["bun", "deno"].find((candidate) => host.versions[candidate] !== void 0) ?? "node";
820
- return {
821
- runtime: {
822
- name,
823
- version: host.versions[name] ?? host.version
824
- },
825
- platform: host.platform,
826
- arch: host.arch
827
- };
828
- }
829
- /**
830
- * Which package manager invoked us, read from the `npm_config_user_agent`
831
- * every major manager sets (`pnpm/10.27.0 npm/? node/v24.16.0 darwin arm64`).
832
- * `undefined` when the CLI was run directly rather than through a manager — a
833
- * normal case, not a failure, so nothing is inferred from the filesystem, and
834
- * the engine falls back to its own detection from the project at cwd.
835
- */
836
- function detectPackageManager(env) {
837
- const agent = env["npm_config_user_agent"];
838
- if (agent === void 0) return void 0;
839
- const name = agent.split("/")[0];
840
- switch (name) {
841
- case "npm":
842
- case "pnpm":
843
- case "yarn":
844
- case "bun":
845
- case "deno": return name;
846
- default: return;
847
- }
848
- }
849
- /**
850
- * The config loader arrives as a function rather than an already-loaded config
851
- * because the engine reads `prisma.config.ts` on demand — only when the command
852
- * it is about to run declares a config section, and with whatever file
853
- * `--config` named. A host that loaded the file up front would read it for runs
854
- * that never needed it, and would have nowhere to put `--config`.
855
- *
856
- * Nothing here answers "is this CI": the engine detects it from `env` itself,
857
- * and `isCIOverride` exists only for hosts where that detection cannot be
858
- * right — composer is not one.
859
- */
860
- const nonEmpty = (value) => value !== void 0 && value.length > 0 ? value : void 0;
861
- function createRuntime(host, loadConfig) {
862
- const env = host.env;
863
- const apiBaseUrl = nonEmpty(env["PRISMA_API_URL"]) ?? nonEmpty(env["PRISMA_MANAGEMENT_API_URL"]) ?? DEFAULT_MANAGEMENT_API_BASE_URL;
864
- const packageManager = detectPackageManager(env);
865
- return {
866
- stdout: host.stdout,
867
- stderr: host.stderr,
868
- stdin: host.stdin,
869
- cwd: host.cwd(),
870
- env,
871
- isTty: {
872
- stdin: host.stdin.isTTY === true,
873
- stdout: host.stdout.isTTY === true,
874
- stderr: host.stderr.isTTY === true
875
- },
876
- exit: (code) => host.exit(code),
877
- onSignal: (cb) => {
878
- const onSigint = () => {
879
- cb("SIGINT");
880
- };
881
- const onSigterm = () => {
882
- cb("SIGTERM");
883
- };
884
- host.on("SIGINT", onSigint);
885
- host.on("SIGTERM", onSigterm);
886
- return () => {
887
- host.off("SIGINT", onSigint);
888
- host.off("SIGTERM", onSigterm);
889
- };
890
- },
891
- loadConfig,
892
- credentialManager: new EnvironmentCredentialManager({ env }),
893
- managementApiClientConfig: clientConfig(env, apiBaseUrl),
894
- spawn: spawnChild,
895
- managementApi: { baseUrl: apiBaseUrl },
896
- ...packageManager !== void 0 && { packageManager },
897
- host: describeHost(host)
898
- };
899
- }
900
- /**
901
- * Composer's own CLI, rebuilt as a thin composition of the family it
902
- * publishes: `createCli` over `createComposerFamily()`, `Cli.run` with a
903
- * Runtime. Grammar, help, arg validation, output framing, exit codes and
904
- * signal ownership all belong to the engine now — this module contributes the
905
- * family and the environment, and nothing else.
906
- *
907
- * Running composer's commands through the same path an external host uses is
908
- * the point: it is what proves the family works standalone before the `prisma`
909
- * bin mounts it.
910
- *
911
- * This IS composer's CLI. The clipanion shell it replaced, and the bespoke
912
- * runner that shelled out to alchemy, are gone; `bin.ts` is a call into here.
913
- */
914
- const BINARY_NAME = "prisma-composer";
915
- /**
916
- * Composer's commands mount at the top level of its own CLI (`prisma-composer
917
- * deploy`). The bin mounts more than the family carries: `destroy` and `log`
918
- * were retired from the family (the surface the `prisma` bin mounts, per the
919
- * 2026-08-21 PM review) but stay first-class commands of `prisma-composer`
920
- * itself, so their definitions are mounted here on top of the family.
921
- */
922
- function mountedTree(family, operations) {
923
- return {
924
- ...family.commands,
925
- destroy: createDestroyCommand(operations),
926
- log: createLogCommand(operations)
927
- };
928
- }
929
- /**
930
- * The ORM's slice of prisma.config.ts, declared so a config shared with the
931
- * unified `prisma` CLI loads here: the engine rejects any top-level key no
932
- * mounted family declares, and this bin does not mount the ORM family. The
933
- * value passes through unvalidated — the ORM CLI owns its section's shape,
934
- * and no composer command reads it.
935
- */
936
- const foreignOrmSectionFamily = defineCommandFamily({
937
- configSection: defineConfigSection({
938
- name: "orm",
939
- validate: (raw) => ({
940
- ok: true,
941
- value: raw,
942
- diagnostics: []
943
- })
944
- }),
945
- commands: {}
946
- });
947
- function createComposerCli(spec) {
948
- const operations = spec.operations ?? realOperations;
949
- const family = createComposerFamily({ operations });
950
- return createCli({
951
- name: BINARY_NAME,
952
- version: spec.version,
953
- commandFamilies: [family, foreignOrmSectionFamily],
954
- groups: {},
955
- commands: mountedTree(family, operations)
956
- });
957
- }
958
- /**
959
- * Composes the Runtime and runs one invocation. Returns the exit code rather
960
- * than exiting, so the caller owns the process — a bin assigns it to
961
- * `process.exitCode` and lets the streams drain, as composer's CLI has always
962
- * done.
963
- *
964
- * `prisma.config.ts` is not read here. The loader goes in as a function, and the
965
- * engine calls it only when the command it is about to run declares a config
966
- * section, passing it the file `--config` named; the loader resolves that
967
- * against the host's cwd.
968
- */
969
- function runComposerCli(argv, host, spec, hooks) {
970
- const runtime = createRuntime(host, (configPath) => loadConfig(host.cwd(), configPath));
971
- return createComposerCli(spec).run(argv, runtime, hooks);
972
- }
973
471
  //#endregion
974
- export { BINARY_NAME, composerSection, createComposerCli, createComposerFamily, realOperations, runComposerCli, toEngineError };
472
+ export { composerSection, createComposerFamily, realOperations, toEngineError };
975
473
 
976
474
  //# sourceMappingURL=family.mjs.map