@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.
- package/dist/composer-config-CY9fET8H-KpGjlYgO.mjs +432 -0
- package/dist/composer-config-CY9fET8H-KpGjlYgO.mjs.map +1 -0
- package/dist/{pipeline-C7gNjMzJ-CMqZQxqM.mjs → container-transport-HcvNOGZL-CHqecFc7.mjs} +109 -322
- package/dist/container-transport-HcvNOGZL-CHqecFc7.mjs.map +1 -0
- package/dist/{execute-deploy-destroy-CvKCwVkD-B3vcxYJF.mjs → execute-deploy-destroy-c0eko3AO-9npuGXd3.mjs} +108 -85
- package/dist/execute-deploy-destroy-c0eko3AO-9npuGXd3.mjs.map +1 -0
- package/dist/{execute-dev-BLCK5wF7-CuzMSK7T.mjs → execute-dev-BICPaq1g-CSoZJuhB.mjs} +162 -132
- package/dist/execute-dev-BICPaq1g-CSoZJuhB.mjs.map +1 -0
- package/dist/{family-B1RaH4f8-ChoTnv3A.d.mts → family-CgeZQdNg-gH8LuqqL.d.mts} +136 -172
- package/dist/family-CgeZQdNg-gH8LuqqL.d.mts.map +1 -0
- package/dist/family.d.mts +4 -39
- package/dist/family.d.mts.map +1 -1
- package/dist/family.mjs +49 -551
- package/dist/family.mjs.map +1 -1
- package/dist/generate-dev-stack-BUadNY_w-DF_lHVaP.mjs +87 -0
- package/dist/generate-dev-stack-BUadNY_w-DF_lHVaP.mjs.map +1 -0
- package/dist/run-alchemy-BEvB2sYQ-BgV2deuO.mjs +154 -0
- package/dist/run-alchemy-BEvB2sYQ-BgV2deuO.mjs.map +1 -0
- package/dist/testing.d.mts +24 -24
- package/dist/testing.d.mts.map +1 -1
- package/dist/testing.mjs +17 -45
- package/dist/testing.mjs.map +1 -1
- package/package.json +7 -11
- package/src/exports/testing.ts +5 -3
- package/dist/bin.mjs +0 -1040
- package/dist/bin.mjs.map +0 -1
- package/dist/container-transport-HcvNOGZL-CIoZc7Rs.mjs +0 -34
- package/dist/container-transport-HcvNOGZL-CIoZc7Rs.mjs.map +0 -1
- package/dist/execute-deploy-destroy-CvKCwVkD-B3vcxYJF.mjs.map +0 -1
- package/dist/execute-deploy-destroy-CvKCwVkD-DCufHnkW.mjs +0 -528
- package/dist/execute-deploy-destroy-CvKCwVkD-DCufHnkW.mjs.map +0 -1
- package/dist/execute-dev-BLCK5wF7-B-fG_E31.mjs +0 -2011
- package/dist/execute-dev-BLCK5wF7-B-fG_E31.mjs.map +0 -1
- package/dist/execute-dev-BLCK5wF7-CuzMSK7T.mjs.map +0 -1
- package/dist/execute-log-B_zCJ17b-BrLUt7vo.mjs +0 -157
- package/dist/execute-log-B_zCJ17b-BrLUt7vo.mjs.map +0 -1
- package/dist/execute-log-B_zCJ17b-C4a0uxJj.mjs +0 -158
- package/dist/execute-log-B_zCJ17b-C4a0uxJj.mjs.map +0 -1
- package/dist/family-B1RaH4f8-ChoTnv3A.d.mts.map +0 -1
- package/dist/local-target-BOGjATc2.mjs +0 -68
- package/dist/local-target-BOGjATc2.mjs.map +0 -1
- package/dist/local-target-hoEGqgVA.mjs +0 -68
- package/dist/local-target-hoEGqgVA.mjs.map +0 -1
- package/dist/pipeline-C7gNjMzJ-CMqZQxqM.mjs.map +0 -1
- package/dist/pipeline-C7gNjMzJ-CixaMvnR.mjs +0 -1205
- package/dist/pipeline-C7gNjMzJ-CixaMvnR.mjs.map +0 -1
- package/dist/result-B874OKwb.mjs +0 -383
- package/dist/result-B874OKwb.mjs.map +0 -1
- package/dist/result-sR7PBi61.mjs +0 -229
- package/dist/result-sR7PBi61.mjs.map +0 -1
- package/dist/run-alchemy-pANK8XNX-BH1wC0r6.mjs +0 -99
- package/dist/run-alchemy-pANK8XNX-BH1wC0r6.mjs.map +0 -1
- package/dist/run-alchemy-pANK8XNX-XcCQncKN.mjs +0 -99
- package/dist/run-alchemy-pANK8XNX-XcCQncKN.mjs.map +0 -1
- package/dist/shared-BTnATsqm-BH4axbJg.mjs +0 -158
- package/dist/shared-BTnATsqm-BH4axbJg.mjs.map +0 -1
package/dist/family.mjs
CHANGED
|
@@ -1,64 +1,8 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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/
|
|
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
|
|
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
|
-
|
|
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:
|
|
202
|
-
severity:
|
|
203
|
-
summary:
|
|
204
|
-
...
|
|
205
|
-
nextActions:
|
|
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:
|
|
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
|
|
212
|
-
|
|
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:
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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:
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
|
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
|
|
719
|
-
*
|
|
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
|
|
730
|
-
*
|
|
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
|
-
|
|
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 {
|
|
472
|
+
export { composerSection, createComposerFamily, realOperations, toEngineError };
|
|
975
473
|
|
|
976
474
|
//# sourceMappingURL=family.mjs.map
|