@prisma-next/cli 0.10.0 → 0.11.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli-errors-Bw2GlweY.mjs +175 -0
- package/dist/cli-errors-Bw2GlweY.mjs.map +1 -0
- package/dist/cli.mjs +400 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Brv4qlfB.mjs → client-UnIveZxZ.mjs} +6 -5
- package/dist/client-UnIveZxZ.mjs.map +1 -0
- package/dist/{command-helpers-D3vL5yi8.mjs → command-helpers-CRfjbZRz.mjs} +109 -12
- package/dist/command-helpers-CRfjbZRz.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +47 -21
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +6 -10
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +8 -12
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +47 -19
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +5 -1
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +47 -15
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.mjs +5 -8
- package/dist/commands/migration-check.mjs.map +1 -1
- package/dist/commands/migration-graph.d.mts +1 -1
- package/dist/commands/migration-graph.mjs +6 -10
- package/dist/commands/migration-graph.mjs.map +1 -1
- package/dist/commands/migration-list.mjs +5 -9
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +7 -10
- package/dist/commands/migration-log.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +6 -10
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +2 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +9 -13
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +1 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +37 -15
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +41 -25
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/{contract-emit-iynA3BCA.mjs → contract-emit-C6rlsljO.mjs} +7 -6
- package/dist/contract-emit-C6rlsljO.mjs.map +1 -0
- package/dist/{contract-emit-C3STUIBg.mjs → contract-emit-mqXmapxB.mjs} +22 -20
- package/dist/contract-emit-mqXmapxB.mjs.map +1 -0
- package/dist/{contract-infer-Cnj8G1E2.mjs → contract-infer-C4jxc1aZ.mjs} +9 -14
- package/dist/contract-infer-C4jxc1aZ.mjs.map +1 -0
- package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs → contract-space-aggregate-loader-CGakRlKM.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs.map → contract-space-aggregate-loader-CGakRlKM.mjs.map} +1 -1
- package/dist/{db-verify-D7cyH_zz.mjs → db-verify-1d8tDoFN.mjs} +9 -13
- package/dist/db-verify-1d8tDoFN.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +2 -2
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-xFLFpZUO.mjs → framework-components-Bexd0f4E.mjs} +2 -2
- package/dist/{framework-components-xFLFpZUO.mjs.map → framework-components-Bexd0f4E.mjs.map} +1 -1
- package/dist/{global-flags-DGmw6Kqg.d.mts → global-flags-CdE7M0d9.d.mts} +4 -1
- package/dist/global-flags-CdE7M0d9.d.mts.map +1 -0
- package/dist/{graph-render-eJDcLWny.mjs → graph-render-BE8vmJ_7.mjs} +1 -1
- package/dist/{graph-render-eJDcLWny.mjs.map → graph-render-BE8vmJ_7.mjs.map} +1 -1
- package/dist/{init-eh2z5Tl6.mjs → init-ByoeQphC.mjs} +528 -627
- package/dist/init-ByoeQphC.mjs.map +1 -0
- package/dist/{inspect-live-schema-CWLK_lgs.mjs → inspect-live-schema-B1Q49RF0.mjs} +4 -4
- package/dist/{inspect-live-schema-CWLK_lgs.mjs.map → inspect-live-schema-B1Q49RF0.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-CmXXC1UZ.mjs → migration-command-scaffold-oY4P1Qto.mjs} +4 -4
- package/dist/{migration-command-scaffold-CmXXC1UZ.mjs.map → migration-command-scaffold-oY4P1Qto.mjs.map} +1 -1
- package/dist/{migration-plan-CHyUlBV0.mjs → migration-plan-jdAHg_gK.mjs} +349 -94
- package/dist/migration-plan-jdAHg_gK.mjs.map +1 -0
- package/dist/{migration-types-D2FW63pr.d.mts → migration-types-BXWvz12q.d.mts} +1 -1
- package/dist/{migration-types-D2FW63pr.d.mts.map → migration-types-BXWvz12q.d.mts.map} +1 -1
- package/dist/{migrations-DyUf5lTt.mjs → migrations-B7n518mT.mjs} +11 -2
- package/dist/migrations-B7n518mT.mjs.map +1 -0
- package/dist/{output-B60Gw5fu.mjs → output-CUIdfYo5.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-CUIdfYo5.mjs.map} +1 -1
- package/dist/quick-reference-mongo.md +1 -1
- package/dist/quick-reference-postgres.md +1 -1
- package/dist/readme-mongo.md +35 -0
- package/dist/readme-postgres.md +34 -0
- package/dist/ref-advancement-DRh5Nquq.mjs +50 -0
- package/dist/ref-advancement-DRh5Nquq.mjs.map +1 -0
- package/dist/{terminal-ui-XtOQsqe9.mjs → terminal-ui-BiB_8KNo.mjs} +131 -24
- package/dist/terminal-ui-BiB_8KNo.mjs.map +1 -0
- package/dist/{types-0aS865QN.d.mts → types-UWB2-rrw.d.mts} +12 -4
- package/dist/types-UWB2-rrw.d.mts.map +1 -0
- package/dist/{verify-D7ypCCe6.mjs → verify-C5UvbrF1.mjs} +2 -2
- package/dist/{verify-D7ypCCe6.mjs.map → verify-C5UvbrF1.mjs.map} +1 -1
- package/package.json +20 -18
- package/src/cli.ts +42 -0
- package/src/commands/contract-emit.ts +23 -11
- package/src/commands/contract-infer.ts +7 -7
- package/src/commands/db-init.ts +61 -7
- package/src/commands/db-schema.ts +4 -4
- package/src/commands/db-sign.ts +4 -4
- package/src/commands/db-update.ts +58 -5
- package/src/commands/db-verify.ts +5 -5
- package/src/commands/init/detect-package-manager.ts +15 -0
- package/src/commands/init/errors.ts +33 -2
- package/src/commands/init/hygiene-gitattributes.ts +2 -2
- package/src/commands/init/index.ts +15 -6
- package/src/commands/init/init.ts +61 -32
- package/src/commands/init/inputs.ts +82 -5
- package/src/commands/init/output.ts +1 -1
- package/src/commands/init/{agent-skill-install.ts → skill-install.ts} +42 -31
- package/src/commands/init/templates/code-templates.ts +26 -24
- package/src/commands/init/templates/env.ts +8 -1
- package/src/commands/init/templates/quick-reference-mongo.md +1 -1
- package/src/commands/init/templates/quick-reference-postgres.md +1 -1
- package/src/commands/init/templates/readme-mongo.md +35 -0
- package/src/commands/init/templates/readme-postgres.md +34 -0
- package/src/commands/init/templates/readme.ts +62 -0
- package/src/commands/migrate.ts +77 -10
- package/src/commands/migration-check.ts +4 -4
- package/src/commands/migration-graph.ts +4 -4
- package/src/commands/migration-list.ts +4 -4
- package/src/commands/migration-log.ts +6 -5
- package/src/commands/migration-new.ts +4 -4
- package/src/commands/migration-plan.ts +369 -132
- package/src/commands/migration-show.ts +4 -4
- package/src/commands/migration-status.ts +49 -6
- package/src/commands/ref.ts +54 -14
- package/src/control-api/operations/apply-aggregate.ts +1 -0
- package/src/control-api/operations/contract-emit.ts +7 -4
- package/src/control-api/types.ts +7 -0
- package/src/utils/cli-errors.ts +177 -0
- package/src/utils/command-helpers.ts +14 -6
- package/src/utils/formatters/migrations.ts +25 -0
- package/src/utils/global-flags.ts +105 -16
- package/src/utils/is-ci.ts +18 -0
- package/src/utils/plan-resolution.ts +257 -0
- package/src/utils/ref-advancement.ts +68 -0
- package/src/utils/telemetry.ts +141 -0
- package/src/utils/terminal-ui.ts +44 -23
- package/dist/cli-errors-CF60g2cG.mjs +0 -71
- package/dist/cli-errors-CF60g2cG.mjs.map +0 -1
- package/dist/cli-errors-DdcjVLJV.d.mts +0 -3
- package/dist/client-Brv4qlfB.mjs.map +0 -1
- package/dist/command-helpers-D3vL5yi8.mjs.map +0 -1
- package/dist/contract-emit-C3STUIBg.mjs.map +0 -1
- package/dist/contract-emit-iynA3BCA.mjs.map +0 -1
- package/dist/contract-infer-Cnj8G1E2.mjs.map +0 -1
- package/dist/db-verify-D7cyH_zz.mjs.map +0 -1
- package/dist/errors-Cw6kyTyV.mjs +0 -56
- package/dist/errors-Cw6kyTyV.mjs.map +0 -1
- package/dist/global-flags-DGmw6Kqg.d.mts.map +0 -1
- package/dist/helpers-eqdN8tH6.mjs +0 -25
- package/dist/helpers-eqdN8tH6.mjs.map +0 -1
- package/dist/init-eh2z5Tl6.mjs.map +0 -1
- package/dist/migration-plan-CHyUlBV0.mjs.map +0 -1
- package/dist/migrations-DyUf5lTt.mjs.map +0 -1
- package/dist/result-handler-Bm_6dDYg.mjs +0 -25
- package/dist/result-handler-Bm_6dDYg.mjs.map +0 -1
- package/dist/terminal-ui-XtOQsqe9.mjs.map +0 -1
- package/dist/types-0aS865QN.d.mts.map +0 -1
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
setCommandDescriptions,
|
|
5
5
|
setCommandExamples,
|
|
6
6
|
} from '../../utils/command-helpers';
|
|
7
|
-
import { type CommonCommandOptions,
|
|
7
|
+
import { type CommonCommandOptions, parseGlobalFlagsOrExit } from '../../utils/global-flags';
|
|
8
|
+
import { fireTelemetryAfterInitConsent } from '../../utils/telemetry';
|
|
8
9
|
import {
|
|
9
10
|
INIT_EXIT_EMIT_FAILED,
|
|
10
11
|
INIT_EXIT_INSTALL_FAILED,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
INIT_EXIT_SKILL_INSTALL_FAILED,
|
|
15
16
|
INIT_EXIT_USER_ABORTED,
|
|
16
17
|
} from './exit-codes';
|
|
18
|
+
import { defaultSchemaPath } from './templates/code-templates';
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* Commander.js parsed options for `init`. The init-specific options live
|
|
@@ -63,7 +65,7 @@ export function createInitCommand(): Command {
|
|
|
63
65
|
'prisma-next init --yes --target mongodb --authoring typescript --json',
|
|
64
66
|
'prisma-next init --yes --force --target postgres --authoring psl # overwrite an existing scaffold',
|
|
65
67
|
'prisma-next init --no-install # skip pnpm/npm install + emit',
|
|
66
|
-
'prisma-next init --no-skill # skip the
|
|
68
|
+
'prisma-next init --no-skill # skip the skills install (air-gapped / restricted env)',
|
|
67
69
|
]);
|
|
68
70
|
|
|
69
71
|
return addGlobalOptions(command)
|
|
@@ -71,7 +73,7 @@ export function createInitCommand(): Command {
|
|
|
71
73
|
.option('--authoring <style>', 'Schema authoring style: psl or typescript')
|
|
72
74
|
.option(
|
|
73
75
|
'--schema-path <path>',
|
|
74
|
-
|
|
76
|
+
`Where to write the starter schema (default: ${defaultSchemaPath('psl')})`,
|
|
75
77
|
)
|
|
76
78
|
.option('--force', 'Overwrite an existing scaffold without prompting')
|
|
77
79
|
.option(
|
|
@@ -91,15 +93,22 @@ export function createInitCommand(): Command {
|
|
|
91
93
|
'--no-skill',
|
|
92
94
|
'Skip Prisma Next skills install (air-gapped CI, restricted registries, etc.)',
|
|
93
95
|
)
|
|
94
|
-
.action(async (options: InitCommandOptions) => {
|
|
96
|
+
.action(async (options: InitCommandOptions, actionCommand: Command) => {
|
|
95
97
|
const { runInit } = await import('./init');
|
|
96
|
-
const flags =
|
|
98
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
97
99
|
const canPrompt = deriveCanPrompt({
|
|
98
100
|
flagsInteractive: flags.interactive,
|
|
99
101
|
optionInteractive: options.interactive,
|
|
100
102
|
stdinIsTTY: Boolean(process.stdin.isTTY),
|
|
101
103
|
});
|
|
102
|
-
const exitCode = await runInit(process.cwd(), {
|
|
104
|
+
const exitCode = await runInit(process.cwd(), {
|
|
105
|
+
options,
|
|
106
|
+
flags,
|
|
107
|
+
canPrompt,
|
|
108
|
+
afterFirstTelemetryConsent: (inputs) => {
|
|
109
|
+
fireTelemetryAfterInitConsent(actionCommand, { databaseTarget: inputs.target });
|
|
110
|
+
},
|
|
111
|
+
});
|
|
103
112
|
process.exit(exitCode);
|
|
104
113
|
});
|
|
105
114
|
}
|
|
@@ -6,14 +6,7 @@ import { basename, dirname, isAbsolute, join } from 'pathe';
|
|
|
6
6
|
import { CliStructuredError } from '../../utils/cli-errors';
|
|
7
7
|
import { formatErrorJson, formatErrorOutput } from '../../utils/formatters/errors';
|
|
8
8
|
import type { GlobalFlags } from '../../utils/global-flags';
|
|
9
|
-
import { TerminalUI } from '../../utils/terminal-ui';
|
|
10
|
-
import {
|
|
11
|
-
DEFAULT_AGENT_SKILL_SOURCES,
|
|
12
|
-
formatClaudeSkillInstallCommand,
|
|
13
|
-
formatSkillInstallCommand,
|
|
14
|
-
LEGACY_SKILL_FILE,
|
|
15
|
-
runProjectLevelSkillInstall,
|
|
16
|
-
} from './agent-skill-install';
|
|
9
|
+
import { createTerminalUI, type TerminalUI } from '../../utils/terminal-ui';
|
|
17
10
|
import {
|
|
18
11
|
detectPackageManager,
|
|
19
12
|
formatAddArgs,
|
|
@@ -56,9 +49,16 @@ import {
|
|
|
56
49
|
} from './output';
|
|
57
50
|
import { type ProbeOutcome, type ProbeOverrides, probeServerVersion } from './probe-db';
|
|
58
51
|
import { findStaleArtefacts, removeDependency } from './reinit-cleanup';
|
|
52
|
+
import {
|
|
53
|
+
DEFAULT_SKILL_SOURCES,
|
|
54
|
+
formatSkillInstallCommand,
|
|
55
|
+
LEGACY_SKILL_FILE,
|
|
56
|
+
runProjectLevelSkillInstall,
|
|
57
|
+
} from './skill-install';
|
|
59
58
|
import { configFile, dbFile, starterSchema, targetPackageName } from './templates/code-templates';
|
|
60
59
|
import { envExampleContent, envFileContent, MIN_SERVER_VERSION } from './templates/env';
|
|
61
60
|
import { quickReferenceMd } from './templates/quick-reference';
|
|
61
|
+
import { minimalProjectReadmeMd } from './templates/readme';
|
|
62
62
|
import { defaultTsConfig, mergeTsConfig, TsConfigParseError } from './templates/tsconfig';
|
|
63
63
|
|
|
64
64
|
interface FileEntry {
|
|
@@ -81,11 +81,11 @@ interface InstallReport {
|
|
|
81
81
|
readonly warnings: readonly string[];
|
|
82
82
|
/**
|
|
83
83
|
* The package manager that actually ran. Equal to the detected `pm`
|
|
84
|
-
* on the common path; differs when the
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
84
|
+
* on the common path; differs when the pnpm → npm fallback fired, in
|
|
85
|
+
* which case it's `'npm'`. Threaded into the skills install so the
|
|
86
|
+
* runner stays consistent with the install we just ran — re-trying
|
|
87
|
+
* through `pnpm dlx` when `pnpm install` just failed for
|
|
88
|
+
* workspace/catalog reasons would fail again for the same reason.
|
|
89
89
|
*/
|
|
90
90
|
readonly effectivePm: PackageManager;
|
|
91
91
|
}
|
|
@@ -95,7 +95,7 @@ interface InstallReport {
|
|
|
95
95
|
* structured CLI errors raised at every phase (input resolution, install,
|
|
96
96
|
* emit) and renders them via the same UI surface as success output
|
|
97
97
|
* (`--json` to stdout, human to stderr). Exit codes follow the documented
|
|
98
|
-
* stable set in `./exit-codes.ts`
|
|
98
|
+
* stable set in `./exit-codes.ts` and the
|
|
99
99
|
* [Style Guide § Exit Codes](../../../../../../../docs/CLI%20Style%20Guide.md#exit-codes).
|
|
100
100
|
*
|
|
101
101
|
* Layered for testability: the action handler in `./index.ts` is
|
|
@@ -113,6 +113,11 @@ export async function runInit(
|
|
|
113
113
|
* mode) — see [Style Guide § Interactivity](../../../../../../../docs/CLI%20Style%20Guide.md#interactivity).
|
|
114
114
|
*/
|
|
115
115
|
readonly canPrompt: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Called once after the first affirmative telemetry consent is persisted.
|
|
118
|
+
* Failures are swallowed by the caller; init success must not depend on telemetry.
|
|
119
|
+
*/
|
|
120
|
+
readonly afterFirstTelemetryConsent?: (inputs: ResolvedInitInputs) => void | Promise<void>;
|
|
116
121
|
/**
|
|
117
122
|
* FR8.3 — test-only seam for the optional database version probe.
|
|
118
123
|
* Production callers omit this; tests inject stub `probePostgres` /
|
|
@@ -124,8 +129,8 @@ export async function runInit(
|
|
|
124
129
|
readonly probeOverrides?: ProbeOverrides;
|
|
125
130
|
},
|
|
126
131
|
): Promise<number> {
|
|
127
|
-
const { options, flags, canPrompt, probeOverrides } = runOptions;
|
|
128
|
-
const ui =
|
|
132
|
+
const { options, flags, canPrompt, probeOverrides, afterFirstTelemetryConsent } = runOptions;
|
|
133
|
+
const ui = createTerminalUI(flags);
|
|
129
134
|
const warnings: string[] = [];
|
|
130
135
|
const filesWritten: string[] = [];
|
|
131
136
|
const filesDeleted: string[] = [];
|
|
@@ -144,6 +149,14 @@ export async function runInit(
|
|
|
144
149
|
throw error;
|
|
145
150
|
}
|
|
146
151
|
|
|
152
|
+
if (inputs.enableTelemetry === true && afterFirstTelemetryConsent !== undefined) {
|
|
153
|
+
try {
|
|
154
|
+
await afterFirstTelemetryConsent(inputs);
|
|
155
|
+
} catch {
|
|
156
|
+
// telemetry is best-effort and must never affect init
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
147
160
|
const pm = await detectPackageManager(baseDir);
|
|
148
161
|
const pkgRun = formatRunCommand(pm, 'prisma-next', '').trimEnd();
|
|
149
162
|
|
|
@@ -336,6 +349,26 @@ export async function runInit(
|
|
|
336
349
|
}
|
|
337
350
|
}
|
|
338
351
|
|
|
352
|
+
if (existsSync(join(baseDir, 'src/index.ts'))) {
|
|
353
|
+
if (!existsSync(join(baseDir, 'README.md'))) {
|
|
354
|
+
const rawName =
|
|
355
|
+
parsedPackageJson !== null && typeof parsedPackageJson['name'] === 'string'
|
|
356
|
+
? parsedPackageJson['name']
|
|
357
|
+
: basename(baseDir);
|
|
358
|
+
filesToWrite.push({
|
|
359
|
+
path: 'README.md',
|
|
360
|
+
content: minimalProjectReadmeMd(
|
|
361
|
+
inputs.target,
|
|
362
|
+
inputs.schemaPath,
|
|
363
|
+
sanitisePackageName(rawName),
|
|
364
|
+
pm,
|
|
365
|
+
),
|
|
366
|
+
});
|
|
367
|
+
} else {
|
|
368
|
+
warnings.push('README.md already exists; leaving it untouched.');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
339
372
|
// -----------------------------------------------------------------
|
|
340
373
|
// Write phase — every input has been parsed and every merged file is
|
|
341
374
|
// staged. From here on, failures are only possible at the
|
|
@@ -445,25 +478,20 @@ export async function runInit(
|
|
|
445
478
|
// framework relies on. A project-level failure is fatal
|
|
446
479
|
// (`INIT_EXIT_SKILL_INSTALL_FAILED`).
|
|
447
480
|
//
|
|
448
|
-
// Runs after install + emit
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
// `--no-
|
|
453
|
-
//
|
|
454
|
-
const manualProjectSkillCommands =
|
|
455
|
-
formatSkillInstallCommand(install.effectivePm, source),
|
|
456
|
-
|
|
457
|
-
]);
|
|
481
|
+
// Runs after the install + emit phase when those steps are enabled,
|
|
482
|
+
// but is not coupled to them: the skills are pulled directly from
|
|
483
|
+
// the Prisma Next GitHub repo and do not require `node_modules`.
|
|
484
|
+
// `--no-install` therefore skips only dependency installation and
|
|
485
|
+
// contract emission; `--no-skill` is the explicit escape hatch for
|
|
486
|
+
// skipping skills.
|
|
487
|
+
const manualProjectSkillCommands = DEFAULT_SKILL_SOURCES.map((source) =>
|
|
488
|
+
formatSkillInstallCommand({ pm: install.effectivePm, source }),
|
|
489
|
+
);
|
|
458
490
|
const manualProjectSkillSummary = manualProjectSkillCommands.map((c) => `\`${c}\``).join(' && ');
|
|
459
491
|
let skillRegistered = false;
|
|
460
492
|
if (!inputs.installProjectSkill) {
|
|
461
493
|
warnings.push(
|
|
462
|
-
`Skipped Prisma Next
|
|
463
|
-
);
|
|
464
|
-
} else if (install.skipped) {
|
|
465
|
-
warnings.push(
|
|
466
|
-
`Skipped Prisma Next agent-skill install because --no-install was passed. After you run install manually, install the skills with: ${manualProjectSkillSummary}`,
|
|
494
|
+
`Skipped Prisma Next skills install (--no-skill). To install the skills later, run: ${manualProjectSkillSummary}`,
|
|
467
495
|
);
|
|
468
496
|
} else {
|
|
469
497
|
const spinner = ui.spinner();
|
|
@@ -588,6 +616,7 @@ export function exitCodeForError(error: { readonly code: string }): number {
|
|
|
588
616
|
case '5010': // invalid manifest (malformed package.json) — precondition
|
|
589
617
|
case '5011': // invalid tsconfig (unparseable JSONC) — precondition
|
|
590
618
|
case '5012': // probe failed under --strict-probe — precondition
|
|
619
|
+
case '5014': // --authoring / --schema-path extension mismatch — precondition
|
|
591
620
|
return INIT_EXIT_PRECONDITION;
|
|
592
621
|
case '5006': // user aborted interactive prompt
|
|
593
622
|
return INIT_EXIT_USER_ABORTED;
|
|
@@ -597,7 +626,7 @@ export function exitCodeForError(error: { readonly code: string }): number {
|
|
|
597
626
|
return INIT_EXIT_EMIT_FAILED;
|
|
598
627
|
case '5009': // invalid output document — internal bug in prisma-next
|
|
599
628
|
return INIT_EXIT_INTERNAL_ERROR;
|
|
600
|
-
case '5013': //
|
|
629
|
+
case '5013': // skill install failed
|
|
601
630
|
return INIT_EXIT_SKILL_INSTALL_FAILED;
|
|
602
631
|
default:
|
|
603
632
|
// Any unexpected code is treated as an internal bug rather than
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import * as clack from '@clack/prompts';
|
|
3
|
+
import { readUserConfig, resolveGating, writeUserConfig } from '@prisma-next/cli-telemetry';
|
|
3
4
|
import { extname, join, normalize } from 'pathe';
|
|
4
5
|
import type { GlobalFlags } from '../../utils/global-flags';
|
|
6
|
+
import { isCI } from '../../utils/is-ci';
|
|
5
7
|
import {
|
|
8
|
+
errorInitAuthoringSchemaPathMismatch,
|
|
6
9
|
errorInitInvalidFlagValue,
|
|
7
10
|
errorInitMissingFlags,
|
|
8
11
|
errorInitReinitNeedsForce,
|
|
@@ -68,12 +71,24 @@ export interface ResolvedInitInputs {
|
|
|
68
71
|
* is added separately via the install step.
|
|
69
72
|
*/
|
|
70
73
|
readonly removePreviousFacade: string | null;
|
|
74
|
+
/**
|
|
75
|
+
* Telemetry consent answer recorded during this `init` run, or `null`
|
|
76
|
+
* when no prompt was shown. The prompt fires only on the
|
|
77
|
+
* canPrompt + !autoAcceptPrompts + no env/CI opt-out +
|
|
78
|
+
* `enableTelemetry === undefined` intersection; outside that window
|
|
79
|
+
* the field is `null` and the stored preference (if any) stays
|
|
80
|
+
* unchanged. The answer has already been persisted to
|
|
81
|
+
* `$XDG_CONFIG_HOME/prisma-next/config.json` by
|
|
82
|
+
* the time `runInit` sees this value — it's surfaced here purely so
|
|
83
|
+
* the post-init summary can mention what the user chose.
|
|
84
|
+
*/
|
|
85
|
+
readonly enableTelemetry: boolean | null;
|
|
71
86
|
/**
|
|
72
87
|
* Whether to run `npx skills add prisma/prisma-next#v<version>` at the
|
|
73
88
|
* project level after install + emit. True by default; `--no-skill`
|
|
74
89
|
* sets it to `false`. The skill is always project-level (never
|
|
75
90
|
* user-level / global) so its version stays locked to the project's
|
|
76
|
-
* Prisma Next version — see `
|
|
91
|
+
* Prisma Next version — see `skill-install.ts`.
|
|
77
92
|
*/
|
|
78
93
|
readonly installProjectSkill: boolean;
|
|
79
94
|
}
|
|
@@ -91,6 +106,12 @@ const AUTHORING_VALUES: ReadonlyMap<string, AuthoringId> = new Map([
|
|
|
91
106
|
['ts', 'typescript'],
|
|
92
107
|
]);
|
|
93
108
|
|
|
109
|
+
export const TELEMETRY_CONSENT_MESSAGE = [
|
|
110
|
+
'Help us prioritize features by sharing anonymous CLI usage data?',
|
|
111
|
+
'The telemetry implementation is open source and fully transparent.',
|
|
112
|
+
'(packages/1-framework/3-tooling/cli-telemetry and apps/telemetry-backend).',
|
|
113
|
+
].join(' ');
|
|
114
|
+
|
|
94
115
|
/**
|
|
95
116
|
* Resolves every required input for `runInit`. In interactive mode, missing
|
|
96
117
|
* inputs are prompted via clack; in non-interactive mode, missing required
|
|
@@ -176,6 +197,11 @@ export async function resolveInitInputs(ctx: {
|
|
|
176
197
|
autoAcceptPrompts,
|
|
177
198
|
});
|
|
178
199
|
|
|
200
|
+
const enableTelemetry = await resolveTelemetryConsent({
|
|
201
|
+
canPrompt,
|
|
202
|
+
autoAcceptPrompts,
|
|
203
|
+
});
|
|
204
|
+
|
|
179
205
|
// Skill-install gating. `--no-skill` (commander parses
|
|
180
206
|
// `options.skill === false`) is the only escape hatch; otherwise
|
|
181
207
|
// project-level install is unconditional. The skill is always
|
|
@@ -193,10 +219,60 @@ export async function resolveInitInputs(ctx: {
|
|
|
193
219
|
strictProbe: Boolean(options.strictProbe),
|
|
194
220
|
reinit,
|
|
195
221
|
removePreviousFacade,
|
|
222
|
+
enableTelemetry,
|
|
196
223
|
installProjectSkill,
|
|
197
224
|
};
|
|
198
225
|
}
|
|
199
226
|
|
|
227
|
+
/**
|
|
228
|
+
* The interactive telemetry consent prompt. Shown as the last
|
|
229
|
+
* question of the `init` sequence iff:
|
|
230
|
+
* 1. `canPrompt === true` (interactive stdin / stdout combo),
|
|
231
|
+
* 2. `autoAcceptPrompts === false` (the user did not pass `--yes`),
|
|
232
|
+
* 3. neither telemetry env opt-out is active,
|
|
233
|
+
* 4. the process is not running in CI,
|
|
234
|
+
* 5. the stored `enableTelemetry` value is `undefined` (the user
|
|
235
|
+
* has never been asked, or skipped the prompt previously).
|
|
236
|
+
*
|
|
237
|
+
* Outside that intersection the function returns `null` and leaves the
|
|
238
|
+
* stored preference untouched. Inside it, the user's answer is
|
|
239
|
+
* persisted via `writeUserConfig({ enableTelemetry })` before this
|
|
240
|
+
* function returns; on an affirmative answer `writeUserConfig`
|
|
241
|
+
* generates and stores the v4 `installationId` in the same write.
|
|
242
|
+
*
|
|
243
|
+
* The wording names CLI usage data and points to the open-source
|
|
244
|
+
* client/backend paths. Default value is `true` to match precedent
|
|
245
|
+
* and to make the consent answer a single keystroke once it's been
|
|
246
|
+
* disclosed.
|
|
247
|
+
*/
|
|
248
|
+
async function resolveTelemetryConsent(opts: {
|
|
249
|
+
readonly canPrompt: boolean;
|
|
250
|
+
readonly autoAcceptPrompts: boolean;
|
|
251
|
+
}): Promise<boolean | null> {
|
|
252
|
+
if (!opts.canPrompt || opts.autoAcceptPrompts || isCI()) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
const config = readUserConfig();
|
|
256
|
+
const gating = resolveGating({ env: process.env, config });
|
|
257
|
+
if (!gating.enabled && gating.reason === 'env-override') {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const stored = config.enableTelemetry;
|
|
261
|
+
if (stored !== undefined) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const result = await clack.confirm({
|
|
265
|
+
message: TELEMETRY_CONSENT_MESSAGE,
|
|
266
|
+
initialValue: true,
|
|
267
|
+
output: process.stderr,
|
|
268
|
+
});
|
|
269
|
+
if (clack.isCancel(result)) {
|
|
270
|
+
throw errorInitUserAborted();
|
|
271
|
+
}
|
|
272
|
+
writeUserConfig({ enableTelemetry: Boolean(result) });
|
|
273
|
+
return Boolean(result);
|
|
274
|
+
}
|
|
275
|
+
|
|
200
276
|
async function resolveWriteEnv(opts: {
|
|
201
277
|
readonly flag: boolean | undefined;
|
|
202
278
|
readonly canPrompt: boolean;
|
|
@@ -376,10 +452,11 @@ function validateSchemaPath(value: string, authoring: AuthoringId): string {
|
|
|
376
452
|
const ext = extname(trimmed).toLowerCase();
|
|
377
453
|
const expected = authoring === 'typescript' ? '.ts' : '.prisma';
|
|
378
454
|
if (ext !== expected) {
|
|
379
|
-
throw
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
455
|
+
throw errorInitAuthoringSchemaPathMismatch({
|
|
456
|
+
authoring,
|
|
457
|
+
schemaPath: trimmed,
|
|
458
|
+
actualExtension: ext.length > 0 ? ext : '(none)',
|
|
459
|
+
expectedExtension: expected,
|
|
383
460
|
});
|
|
384
461
|
}
|
|
385
462
|
return normalize(trimmed);
|
|
@@ -123,7 +123,7 @@ export function buildNextSteps(options: {
|
|
|
123
123
|
/**
|
|
124
124
|
* Whether the project-level Prisma Next skills install actually ran
|
|
125
125
|
* and succeeded during this `init`. When false (the user passed
|
|
126
|
-
* `--no-skill
|
|
126
|
+
* `--no-skill`, so the install was skipped), the
|
|
127
127
|
* "registered with your agent runtime" step is omitted — the skip is
|
|
128
128
|
* already surfaced in the warnings array with a manual-install hint.
|
|
129
129
|
*/
|
|
@@ -11,12 +11,12 @@ const exec = promisify(execFile);
|
|
|
11
11
|
* upstream `skills add`. Each `SkillSource` joins this base with its
|
|
12
12
|
* own subpath (and optional `#ref` for version-pinned clusters).
|
|
13
13
|
*/
|
|
14
|
-
export const
|
|
14
|
+
export const DEFAULT_SKILL_BASE = 'prisma/prisma-next';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* One discovery scope inside the Prisma Next monorepo. The CLI emits
|
|
18
|
-
* one `skills add <base>/<subpath>[#ref] --
|
|
19
|
-
* during `init`.
|
|
18
|
+
* one `skills add <base>/<subpath>[#ref] --agent ... --skill '*' -y`
|
|
19
|
+
* invocation per source during `init`.
|
|
20
20
|
*
|
|
21
21
|
* `ref` semantics:
|
|
22
22
|
* - `cli`: pin to the CLI's own package version (lockstep with the
|
|
@@ -35,7 +35,7 @@ export interface SkillSource {
|
|
|
35
35
|
readonly description: string;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export const
|
|
38
|
+
export const DEFAULT_SKILL_SOURCES: readonly SkillSource[] = [
|
|
39
39
|
{
|
|
40
40
|
subpath: 'skills',
|
|
41
41
|
ref: 'cli',
|
|
@@ -56,7 +56,7 @@ export const DEFAULT_AGENT_SKILL_SOURCES: readonly SkillSource[] = [
|
|
|
56
56
|
/**
|
|
57
57
|
* Test-only escape hatch for pinning the install base to a local
|
|
58
58
|
* checkout. Production runs leave this unset, so installs always use
|
|
59
|
-
* `
|
|
59
|
+
* `DEFAULT_SKILL_BASE`.
|
|
60
60
|
*
|
|
61
61
|
* When set to an absolute filesystem path (typical for tests), the
|
|
62
62
|
* `#ref` fragment is dropped — local-path mode in upstream's CLI does
|
|
@@ -66,13 +66,28 @@ export const DEFAULT_AGENT_SKILL_SOURCES: readonly SkillSource[] = [
|
|
|
66
66
|
*/
|
|
67
67
|
function resolveAgentSkillBase(): string {
|
|
68
68
|
const override = process.env['PRISMA_NEXT_SKILLS_BASE']?.trim();
|
|
69
|
-
return override && override.length > 0 ? override :
|
|
69
|
+
return override && override.length > 0 ? override : DEFAULT_SKILL_BASE;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function isLocalPath(base: string): boolean {
|
|
73
73
|
return base.startsWith('/') || /^[a-zA-Z]:[\\/]/.test(base);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/** Agent slugs accepted by the upstream `skills add --agent` flag. */
|
|
77
|
+
export type SkillAgent = 'cursor' | 'claude-code' | 'codex' | 'windsurf';
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Agents passed to every project-level init install. Upstream `skills add`
|
|
81
|
+
* is the source of truth for per-agent install behaviour; the CLI lists
|
|
82
|
+
* every supported runtime on one invocation and delegates the rest.
|
|
83
|
+
*/
|
|
84
|
+
export const DEFAULT_SKILL_AGENTS: readonly SkillAgent[] = [
|
|
85
|
+
'cursor',
|
|
86
|
+
'claude-code',
|
|
87
|
+
'codex',
|
|
88
|
+
'windsurf',
|
|
89
|
+
];
|
|
90
|
+
|
|
76
91
|
/**
|
|
77
92
|
* Build the `<base>/<subpath>[#ref]` URL the `skills` CLI will
|
|
78
93
|
* resolve. Exported for unit tests so the per-source format can be
|
|
@@ -94,37 +109,36 @@ export function formatSkillSourceUrl(source: SkillSource): string {
|
|
|
94
109
|
* rest of the install step so a single project consistently uses one
|
|
95
110
|
* runner.
|
|
96
111
|
*
|
|
97
|
-
* `--
|
|
98
|
-
*
|
|
99
|
-
* shows by default. A non-interactive scaffold step cannot present
|
|
100
|
-
* prompts.
|
|
112
|
+
* `--agent` takes space-separated slugs on one flag; `--skill '*'` and `-y`
|
|
113
|
+
* skip the multi-select prompts a non-interactive scaffold step cannot show.
|
|
101
114
|
*
|
|
102
115
|
* Exported for unit tests so the per-PM dispatch can be asserted
|
|
103
116
|
* without a live subprocess.
|
|
104
117
|
*/
|
|
105
|
-
export function formatSkillInstallCommand(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
* project-local Claude symlinks when `.claude/` does not already exist. Run
|
|
113
|
-
* the explicit Claude Code install as well so fresh projects get
|
|
114
|
-
* `.claude/skills` without asking users to create that folder first.
|
|
115
|
-
*/
|
|
116
|
-
export function formatClaudeSkillInstallCommand(pm: PackageManager, source: SkillSource): string {
|
|
117
|
-
const args = [
|
|
118
|
+
export function formatSkillInstallCommand(args: {
|
|
119
|
+
readonly pm: PackageManager;
|
|
120
|
+
readonly source: SkillSource;
|
|
121
|
+
readonly agents?: readonly SkillAgent[];
|
|
122
|
+
}): string {
|
|
123
|
+
const agents = args.agents ?? DEFAULT_SKILL_AGENTS;
|
|
124
|
+
const cliArgs = [
|
|
118
125
|
'skills@latest',
|
|
119
126
|
'add',
|
|
120
|
-
formatSkillSourceUrl(source),
|
|
127
|
+
formatSkillSourceUrl(args.source),
|
|
121
128
|
'--agent',
|
|
122
|
-
|
|
129
|
+
...agents,
|
|
123
130
|
'--skill',
|
|
124
131
|
"'*'",
|
|
125
132
|
'-y',
|
|
126
133
|
];
|
|
127
|
-
return formatPackageManagerCommand(pm,
|
|
134
|
+
return formatPackageManagerCommand(args.pm, cliArgs);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Ordered skill-install commands for one init run. Exported for unit tests.
|
|
139
|
+
*/
|
|
140
|
+
export function resolveProjectSkillInstallCommands(pm: PackageManager): readonly string[] {
|
|
141
|
+
return DEFAULT_SKILL_SOURCES.map((source) => formatSkillInstallCommand({ pm, source }));
|
|
128
142
|
}
|
|
129
143
|
|
|
130
144
|
function formatPackageManagerCommand(pm: PackageManager, args: readonly string[]): string {
|
|
@@ -162,7 +176,7 @@ function commandToExec(command: string): {
|
|
|
162
176
|
|
|
163
177
|
/**
|
|
164
178
|
* Runs the project-level skill install for every source in
|
|
165
|
-
* `
|
|
179
|
+
* `DEFAULT_SKILL_SOURCES`, in order. Returns
|
|
166
180
|
* `{ ok: true, commands }` on success; throws a structured
|
|
167
181
|
* `errorInitSkillInstallFailed` on the first failure (subsequent
|
|
168
182
|
* sources are not attempted — the user opted into Prisma Next by
|
|
@@ -176,10 +190,7 @@ export async function runProjectLevelSkillInstall(ctx: {
|
|
|
176
190
|
readonly filesWritten: readonly string[];
|
|
177
191
|
}): Promise<{ readonly ok: true; readonly commands: readonly string[] }> {
|
|
178
192
|
const commands: string[] = [];
|
|
179
|
-
const installCommands =
|
|
180
|
-
formatSkillInstallCommand(ctx.pm, source),
|
|
181
|
-
formatClaudeSkillInstallCommand(ctx.pm, source),
|
|
182
|
-
]);
|
|
193
|
+
const installCommands = resolveProjectSkillInstallCommands(ctx.pm);
|
|
183
194
|
|
|
184
195
|
for (const command of installCommands) {
|
|
185
196
|
const { file, args } = commandToExec(command);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DEFAULT_CONTRACT_SOURCE_DIR } from '@prisma-next/config/config-types';
|
|
2
|
+
|
|
1
3
|
export type TargetId = 'postgres' | 'mongo';
|
|
2
4
|
export type AuthoringId = 'psl' | 'typescript';
|
|
3
5
|
|
|
@@ -11,9 +13,9 @@ export function targetLabel(target: TargetId): string {
|
|
|
11
13
|
|
|
12
14
|
export function defaultSchemaPath(authoring: AuthoringId): string {
|
|
13
15
|
if (authoring === 'typescript') {
|
|
14
|
-
return
|
|
16
|
+
return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.ts`;
|
|
15
17
|
}
|
|
16
|
-
return
|
|
18
|
+
return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.prisma`;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export function starterSchema(target: TargetId, authoring: AuthoringId): string {
|
|
@@ -42,9 +44,10 @@ export function schemaSample(target: TargetId, authoring: AuthoringId): string {
|
|
|
42
44
|
function schemaSamplePslPostgres(): string {
|
|
43
45
|
return `\`\`\`prisma
|
|
44
46
|
model User {
|
|
45
|
-
id
|
|
46
|
-
email
|
|
47
|
-
|
|
47
|
+
id Int @id @default(autoincrement())
|
|
48
|
+
email String @unique
|
|
49
|
+
username String?
|
|
50
|
+
name String?
|
|
48
51
|
}
|
|
49
52
|
\`\`\``;
|
|
50
53
|
}
|
|
@@ -52,9 +55,10 @@ model User {
|
|
|
52
55
|
function schemaSamplePslMongo(): string {
|
|
53
56
|
return `\`\`\`prisma
|
|
54
57
|
model User {
|
|
55
|
-
id
|
|
56
|
-
email
|
|
57
|
-
|
|
58
|
+
id ObjectId @id @map("_id")
|
|
59
|
+
email String @unique
|
|
60
|
+
username String?
|
|
61
|
+
name String?
|
|
58
62
|
@@map("users")
|
|
59
63
|
}
|
|
60
64
|
\`\`\``;
|
|
@@ -63,17 +67,16 @@ model User {
|
|
|
63
67
|
function schemaSampleTsPostgres(): string {
|
|
64
68
|
return `\`\`\`typescript
|
|
65
69
|
import { defineContract } from '@prisma-next/postgres/contract-builder';
|
|
66
|
-
import sqlFamily from '@prisma-next/postgres/family';
|
|
67
|
-
import postgresTarget from '@prisma-next/postgres/target';
|
|
68
70
|
|
|
69
71
|
export const contract = defineContract(
|
|
70
|
-
{
|
|
72
|
+
{},
|
|
71
73
|
({ field, model }) => ({
|
|
72
74
|
models: {
|
|
73
75
|
User: model('User', {
|
|
74
76
|
fields: {
|
|
75
77
|
id: field.id.uuidv7(),
|
|
76
78
|
email: field.text().unique(),
|
|
79
|
+
username: field.text().optional(),
|
|
77
80
|
name: field.text().optional(),
|
|
78
81
|
},
|
|
79
82
|
}),
|
|
@@ -86,11 +89,9 @@ export const contract = defineContract(
|
|
|
86
89
|
function schemaSampleTsMongo(): string {
|
|
87
90
|
return `\`\`\`typescript
|
|
88
91
|
import { defineContract } from '@prisma-next/mongo/contract-builder';
|
|
89
|
-
import mongoFamily from '@prisma-next/mongo/family';
|
|
90
|
-
import mongoTarget from '@prisma-next/mongo/target';
|
|
91
92
|
|
|
92
93
|
export const contract = defineContract(
|
|
93
|
-
{
|
|
94
|
+
{},
|
|
94
95
|
({ field, model }) => ({
|
|
95
96
|
models: {
|
|
96
97
|
User: model('User', {
|
|
@@ -98,6 +99,7 @@ export const contract = defineContract(
|
|
|
98
99
|
fields: {
|
|
99
100
|
_id: field.objectId(),
|
|
100
101
|
email: field.string(),
|
|
102
|
+
username: field.string().optional(),
|
|
101
103
|
name: field.string().optional(),
|
|
102
104
|
},
|
|
103
105
|
}),
|
|
@@ -113,6 +115,7 @@ function starterSchemaPslPostgres(): string {
|
|
|
113
115
|
model User {
|
|
114
116
|
id Int @id @default(autoincrement())
|
|
115
117
|
email String @unique
|
|
118
|
+
username String?
|
|
116
119
|
name String?
|
|
117
120
|
posts Post[]
|
|
118
121
|
createdAt DateTime @default(now())
|
|
@@ -135,10 +138,11 @@ function starterSchemaPslMongo(): string {
|
|
|
135
138
|
return `// use prisma-next
|
|
136
139
|
|
|
137
140
|
model User {
|
|
138
|
-
id
|
|
139
|
-
email
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
id ObjectId @id @map("_id")
|
|
142
|
+
email String @unique
|
|
143
|
+
username String?
|
|
144
|
+
name String?
|
|
145
|
+
posts Post[]
|
|
142
146
|
@@map("users")
|
|
143
147
|
}
|
|
144
148
|
|
|
@@ -155,17 +159,16 @@ model Post {
|
|
|
155
159
|
|
|
156
160
|
function starterSchemaTsPostgres(): string {
|
|
157
161
|
return `import { defineContract } from '@prisma-next/postgres/contract-builder';
|
|
158
|
-
import sqlFamily from '@prisma-next/postgres/family';
|
|
159
|
-
import postgresTarget from '@prisma-next/postgres/target';
|
|
160
162
|
|
|
161
163
|
export const contract = defineContract(
|
|
162
|
-
{
|
|
164
|
+
{},
|
|
163
165
|
({ field, model, rel }) => ({
|
|
164
166
|
models: {
|
|
165
167
|
User: model('User', {
|
|
166
168
|
fields: {
|
|
167
169
|
id: field.id.uuidv7(),
|
|
168
170
|
email: field.text().unique(),
|
|
171
|
+
username: field.text().optional(),
|
|
169
172
|
name: field.text().optional(),
|
|
170
173
|
createdAt: field.temporal.createdAt(),
|
|
171
174
|
updatedAt: field.temporal.updatedAt(),
|
|
@@ -196,11 +199,9 @@ export const contract = defineContract(
|
|
|
196
199
|
|
|
197
200
|
function starterSchemaTsMongo(): string {
|
|
198
201
|
return `import { defineContract } from '@prisma-next/mongo/contract-builder';
|
|
199
|
-
import mongoFamily from '@prisma-next/mongo/family';
|
|
200
|
-
import mongoTarget from '@prisma-next/mongo/target';
|
|
201
202
|
|
|
202
203
|
export const contract = defineContract(
|
|
203
|
-
{
|
|
204
|
+
{},
|
|
204
205
|
({ field, model, rel }) => ({
|
|
205
206
|
models: {
|
|
206
207
|
User: model('User', {
|
|
@@ -208,6 +209,7 @@ export const contract = defineContract(
|
|
|
208
209
|
fields: {
|
|
209
210
|
_id: field.objectId(),
|
|
210
211
|
email: field.string(),
|
|
212
|
+
username: field.string().optional(),
|
|
211
213
|
name: field.string().optional(),
|
|
212
214
|
},
|
|
213
215
|
relations: {
|