zenstack-kit 0.1.4 → 0.1.7
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 +18 -6
- package/dist/cli/app.d.ts.map +1 -1
- package/dist/cli/app.js +7 -1
- package/dist/cli/commands.d.ts +2 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +97 -6
- package/dist/cli/prompts.d.ts.map +1 -1
- package/dist/cli/prompts.js +1 -3
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +11 -9
- package/dist/migrations/prisma/apply.d.ts +54 -0
- package/dist/migrations/prisma/apply.d.ts.map +1 -0
- package/dist/migrations/prisma/apply.js +384 -0
- package/dist/migrations/prisma/create.d.ts +63 -0
- package/dist/migrations/prisma/create.d.ts.map +1 -0
- package/dist/migrations/prisma/create.js +119 -0
- package/dist/migrations/prisma/diff.d.ts +104 -0
- package/dist/migrations/prisma/diff.d.ts.map +1 -0
- package/dist/migrations/prisma/diff.js +442 -0
- package/dist/migrations/prisma/log.d.ts +31 -0
- package/dist/migrations/prisma/log.d.ts.map +1 -0
- package/dist/migrations/prisma/log.js +101 -0
- package/dist/migrations/prisma/rename.d.ts +23 -0
- package/dist/migrations/prisma/rename.d.ts.map +1 -0
- package/dist/migrations/prisma/rename.js +57 -0
- package/dist/migrations/prisma/snapshot.d.ts +32 -0
- package/dist/migrations/prisma/snapshot.d.ts.map +1 -0
- package/dist/migrations/prisma/snapshot.js +65 -0
- package/dist/migrations/prisma.d.ts +5 -202
- package/dist/migrations/prisma.d.ts.map +1 -1
- package/dist/migrations/prisma.js +5 -1168
- package/dist/schema/pull.d.ts +2 -0
- package/dist/schema/pull.d.ts.map +1 -1
- package/dist/schema/pull.js +102 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ The `init` command offers two options:
|
|
|
79
79
|
### 4. Generate migrations
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
zenstack-kit migrate
|
|
82
|
+
zenstack-kit migrate create --name add_posts
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
This creates a migration in Prisma format:
|
|
@@ -95,7 +95,7 @@ prisma/migrations/
|
|
|
95
95
|
### 5. Apply migrations
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
|
-
zenstack-kit migrate
|
|
98
|
+
zenstack-kit migrate apply
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
Migrations are tracked in the `_prisma_migrations` table, making them compatible with `prisma migrate deploy`.
|
|
@@ -124,13 +124,14 @@ Options:
|
|
|
124
124
|
- `-m, --migrations <path>` - Migrations directory
|
|
125
125
|
- `--baseline` - Create snapshot only, no migration
|
|
126
126
|
- `--create-initial` - Create snapshot and initial migration
|
|
127
|
+
- `-c, --config <path>` - Path to zenstack-kit config file
|
|
127
128
|
|
|
128
|
-
### `zenstack-kit migrate
|
|
129
|
+
### `zenstack-kit migrate create`
|
|
129
130
|
|
|
130
131
|
Generate a new SQL migration from schema changes.
|
|
131
132
|
|
|
132
133
|
```bash
|
|
133
|
-
zenstack-kit migrate
|
|
134
|
+
zenstack-kit migrate create --name add_users
|
|
134
135
|
```
|
|
135
136
|
|
|
136
137
|
Options:
|
|
@@ -138,13 +139,14 @@ Options:
|
|
|
138
139
|
- `-s, --schema <path>` - Path to ZenStack schema
|
|
139
140
|
- `-m, --migrations <path>` - Migrations directory
|
|
140
141
|
- `--dialect <dialect>` - Database dialect (`sqlite`, `postgres`, `mysql`)
|
|
142
|
+
- `-c, --config <path>` - Path to zenstack-kit config file
|
|
141
143
|
|
|
142
|
-
### `zenstack-kit migrate
|
|
144
|
+
### `zenstack-kit migrate apply`
|
|
143
145
|
|
|
144
146
|
Apply pending migrations to the database.
|
|
145
147
|
|
|
146
148
|
```bash
|
|
147
|
-
zenstack-kit migrate
|
|
149
|
+
zenstack-kit migrate apply
|
|
148
150
|
```
|
|
149
151
|
|
|
150
152
|
Options:
|
|
@@ -153,6 +155,9 @@ Options:
|
|
|
153
155
|
- `--url <url>` - Database connection URL (overrides config)
|
|
154
156
|
- `--table <name>` - Migrations table name (default: `_prisma_migrations`)
|
|
155
157
|
- `--db-schema <name>` - Database schema for migrations table (PostgreSQL only, default: `public`)
|
|
158
|
+
- `--preview` - Preview pending migrations without applying
|
|
159
|
+
- `--mark-applied` - Mark pending migrations as applied without running SQL
|
|
160
|
+
- `-c, --config <path>` - Path to zenstack-kit config file
|
|
156
161
|
|
|
157
162
|
### `zenstack-kit pull`
|
|
158
163
|
|
|
@@ -166,6 +171,8 @@ Options:
|
|
|
166
171
|
- `-o, --output <path>` - Output path for schema (default: `./schema.zmodel`)
|
|
167
172
|
- `--dialect <dialect>` - Database dialect
|
|
168
173
|
- `--url <url>` - Database connection URL
|
|
174
|
+
- `--preview` - Preview generated schema and diff without writing files
|
|
175
|
+
- `-c, --config <path>` - Path to zenstack-kit config file
|
|
169
176
|
|
|
170
177
|
Features:
|
|
171
178
|
- Detects tables, columns, and types
|
|
@@ -289,6 +296,11 @@ const { db, destroy } = await createKyselyAdapter({
|
|
|
289
296
|
await destroy();
|
|
290
297
|
```
|
|
291
298
|
|
|
299
|
+
## Experimental
|
|
300
|
+
|
|
301
|
+
The `introspectSchema` API is experimental and uses a simplified parser. Expect
|
|
302
|
+
limitations with complex schemas.
|
|
303
|
+
|
|
292
304
|
## Prisma Compatibility
|
|
293
305
|
|
|
294
306
|
zenstack-kit is designed to be compatible with Prisma's migration system:
|
package/dist/cli/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":";AAEA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":";AAEA;;;;;;;;GAQG;AA6SH,wBAAgB,MAAM,SAkBrB"}
|
package/dist/cli/app.js
CHANGED
|
@@ -74,9 +74,15 @@ function parseArgs() {
|
|
|
74
74
|
else if (arg === "--preview") {
|
|
75
75
|
options.preview = true;
|
|
76
76
|
}
|
|
77
|
+
else if (arg === "--mark-applied") {
|
|
78
|
+
options.markApplied = true;
|
|
79
|
+
}
|
|
77
80
|
else if (arg === "--force" || arg === "-f") {
|
|
78
81
|
options.force = true;
|
|
79
82
|
}
|
|
83
|
+
else if (arg === "--config" || arg === "-c") {
|
|
84
|
+
options.config = args[++i];
|
|
85
|
+
}
|
|
80
86
|
}
|
|
81
87
|
return { command, options };
|
|
82
88
|
}
|
|
@@ -98,7 +104,7 @@ function Status({ type, message }) {
|
|
|
98
104
|
}
|
|
99
105
|
// Help display component
|
|
100
106
|
function HelpDisplay() {
|
|
101
|
-
return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "zenstack-kit" }), _jsx(Text, { dimColor: true, children: "Database tooling for ZenStack schemas" }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Commands:" }), commands.filter(c => c.value !== "exit").map((cmd) => (_jsxs(Box, { marginLeft: 2, children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: cmd.label }) }), _jsx(Text, { dimColor: true, children: cmd.description })] }, cmd.value))), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Options:" }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "-s, --schema <path> Path to ZenStack schema" }), _jsx(Text, { dimColor: true, children: "-m, --migrations <path> Migrations directory" }), _jsx(Text, { dimColor: true, children: "-n, --name <name> Migration name" }), _jsx(Text, { dimColor: true, children: "--dialect <dialect> Database dialect (sqlite, postgres, mysql)" }), _jsx(Text, { dimColor: true, children: "--url <url> Database connection URL" }), _jsx(Text, { dimColor: true, children: "--create-initial Create initial migration (skip prompt)" }), _jsx(Text, { dimColor: true, children: "--baseline Create baseline only (skip prompt)" }), _jsx(Text, { dimColor: true, children: "--preview Preview pending migrations without applying" }), _jsx(Text, { dimColor: true, children: "-f, --force Force operation without confirmation" })] })] }));
|
|
107
|
+
return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "zenstack-kit" }), _jsx(Text, { dimColor: true, children: "Database tooling for ZenStack schemas" }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Commands:" }), commands.filter(c => c.value !== "exit").map((cmd) => (_jsxs(Box, { marginLeft: 2, children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: cmd.label }) }), _jsx(Text, { dimColor: true, children: cmd.description })] }, cmd.value))), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Options:" }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "-s, --schema <path> Path to ZenStack schema" }), _jsx(Text, { dimColor: true, children: "-m, --migrations <path> Migrations directory" }), _jsx(Text, { dimColor: true, children: "-n, --name <name> Migration name" }), _jsx(Text, { dimColor: true, children: "--dialect <dialect> Database dialect (sqlite, postgres, mysql)" }), _jsx(Text, { dimColor: true, children: "--url <url> Database connection URL" }), _jsx(Text, { dimColor: true, children: "--create-initial Create initial migration (skip prompt)" }), _jsx(Text, { dimColor: true, children: "--baseline Create baseline only (skip prompt)" }), _jsx(Text, { dimColor: true, children: "--preview Preview pending migrations without applying" }), _jsx(Text, { dimColor: true, children: "--mark-applied Mark pending migrations as applied without running SQL" }), _jsx(Text, { dimColor: true, children: "-f, --force Force operation without confirmation" }), _jsx(Text, { dimColor: true, children: "-c, --config <path> Path to zenstack-kit config file" })] })] }));
|
|
102
108
|
}
|
|
103
109
|
function CliApp({ initialCommand, options }) {
|
|
104
110
|
const { exit } = useApp();
|
package/dist/cli/commands.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/commands.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from "fs";
|
|
8
8
|
import * as path from "path";
|
|
9
|
+
import * as os from "os";
|
|
10
|
+
import { execFileSync } from "child_process";
|
|
9
11
|
import { loadConfig } from "../config/loader.js";
|
|
10
12
|
import { pullSchema } from "../schema/pull.js";
|
|
11
13
|
import { createPrismaMigration, applyPrismaMigrations, previewPrismaMigrations, hasPrismaSchemaChanges, hasSnapshot, scanMigrationFolders, writeMigrationLog, initializeSnapshot, createInitialMigration, detectPotentialRenames, } from "../migrations/prisma.js";
|
|
@@ -19,8 +21,11 @@ export class CommandError extends Error {
|
|
|
19
21
|
* Load and validate config, returning resolved paths
|
|
20
22
|
*/
|
|
21
23
|
export async function resolveConfig(ctx) {
|
|
22
|
-
const loaded = await loadConfig(ctx.cwd);
|
|
24
|
+
const loaded = await loadConfig(ctx.cwd, ctx.options.config);
|
|
23
25
|
if (!loaded) {
|
|
26
|
+
if (ctx.options.config) {
|
|
27
|
+
throw new CommandError(`Config file not found: ${ctx.options.config}`);
|
|
28
|
+
}
|
|
24
29
|
throw new CommandError("No zenstack-kit config file found.");
|
|
25
30
|
}
|
|
26
31
|
const { config, configDir } = loaded;
|
|
@@ -121,6 +126,7 @@ export async function runMigrateGenerate(ctx) {
|
|
|
121
126
|
}
|
|
122
127
|
ctx.log("success", `Migration created: ${migration.folderName}/migration.sql`);
|
|
123
128
|
ctx.log("info", `Path: ${migration.folderPath}`);
|
|
129
|
+
ctx.log("info", "Next: run 'zenstack-kit migrate apply' (or --preview to review SQL).");
|
|
124
130
|
}
|
|
125
131
|
/**
|
|
126
132
|
* migrate:apply command
|
|
@@ -144,9 +150,12 @@ export async function runMigrateApply(ctx) {
|
|
|
144
150
|
throw new CommandError("Database connection URL is required for non-sqlite dialects.");
|
|
145
151
|
}
|
|
146
152
|
const databasePath = dialect === "sqlite" ? connectionUrl : undefined;
|
|
153
|
+
if (ctx.options.preview && ctx.options.markApplied) {
|
|
154
|
+
throw new CommandError("Cannot use --preview and --mark-applied together.");
|
|
155
|
+
}
|
|
147
156
|
// Preview mode - show pending migrations without applying
|
|
148
157
|
if (ctx.options.preview) {
|
|
149
|
-
ctx.log("info", "Preview mode -
|
|
158
|
+
ctx.log("info", "Preview mode - no changes will be applied.");
|
|
150
159
|
const preview = await previewPrismaMigrations({
|
|
151
160
|
migrationsFolder: outputPath,
|
|
152
161
|
dialect,
|
|
@@ -162,13 +171,26 @@ export async function runMigrateApply(ctx) {
|
|
|
162
171
|
}
|
|
163
172
|
return;
|
|
164
173
|
}
|
|
174
|
+
ctx.log("info", `Pending migrations: ${preview.pending.length}`);
|
|
175
|
+
if (preview.alreadyApplied.length > 0) {
|
|
176
|
+
ctx.log("info", `${preview.alreadyApplied.length} migration(s) already applied`);
|
|
177
|
+
}
|
|
165
178
|
for (const migration of preview.pending) {
|
|
166
|
-
|
|
167
|
-
|
|
179
|
+
const statementCount = migration.sql
|
|
180
|
+
.split(/;(?:\s*\n|\s*$)/)
|
|
181
|
+
.map((s) => s.trim())
|
|
182
|
+
.filter((s) => s.length > 0 && !s.startsWith("--")).length;
|
|
183
|
+
ctx.log("info", `Migration: ${migration.name} (${statementCount} statement${statementCount === 1 ? "" : "s"})`);
|
|
168
184
|
}
|
|
185
|
+
ctx.log("info", "Use the migration.sql files to review full SQL.");
|
|
169
186
|
return;
|
|
170
187
|
}
|
|
171
|
-
ctx.
|
|
188
|
+
if (ctx.options.markApplied) {
|
|
189
|
+
ctx.log("info", "Marking migrations as applied (no SQL will be executed)...");
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
ctx.log("info", "Applying migrations...");
|
|
193
|
+
}
|
|
172
194
|
const result = await applyPrismaMigrations({
|
|
173
195
|
migrationsFolder: outputPath,
|
|
174
196
|
dialect,
|
|
@@ -176,6 +198,7 @@ export async function runMigrateApply(ctx) {
|
|
|
176
198
|
databasePath,
|
|
177
199
|
migrationsTable,
|
|
178
200
|
migrationsSchema,
|
|
201
|
+
markApplied: ctx.options.markApplied,
|
|
179
202
|
});
|
|
180
203
|
// Handle coherence errors
|
|
181
204
|
if (result.coherenceErrors && result.coherenceErrors.length > 0) {
|
|
@@ -202,7 +225,8 @@ export async function runMigrateApply(ctx) {
|
|
|
202
225
|
return;
|
|
203
226
|
}
|
|
204
227
|
for (const item of result.applied) {
|
|
205
|
-
ctx.
|
|
228
|
+
const action = ctx.options.markApplied ? "Marked applied" : "Applied";
|
|
229
|
+
ctx.log("success", `${action}: ${item.migrationName} (${item.duration}ms)`);
|
|
206
230
|
}
|
|
207
231
|
if (result.failed) {
|
|
208
232
|
throw new CommandError(`Migration failed: ${result.failed.migrationName} - ${result.failed.error}`);
|
|
@@ -326,6 +350,42 @@ export async function runPull(ctx) {
|
|
|
326
350
|
return;
|
|
327
351
|
}
|
|
328
352
|
}
|
|
353
|
+
if (ctx.options.preview) {
|
|
354
|
+
ctx.log("info", "Preview mode - no files will be written.");
|
|
355
|
+
const result = await pullSchema({
|
|
356
|
+
dialect,
|
|
357
|
+
connectionUrl,
|
|
358
|
+
databasePath,
|
|
359
|
+
outputPath: schemaOutputPath,
|
|
360
|
+
writeFile: false,
|
|
361
|
+
});
|
|
362
|
+
if (fs.existsSync(schemaOutputPath)) {
|
|
363
|
+
const diffOutput = await buildSchemaDiff(schemaOutputPath, result.schema);
|
|
364
|
+
if (diffOutput) {
|
|
365
|
+
const { text, truncated } = truncateLines(diffOutput, 200);
|
|
366
|
+
ctx.log("info", `Diff (existing -> generated):\n${text}`);
|
|
367
|
+
if (truncated) {
|
|
368
|
+
ctx.log("info", "Diff truncated. Use --output to write and inspect the full schema.");
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
ctx.log("info", "Diff unavailable; showing generated schema preview.");
|
|
373
|
+
const { text, truncated } = truncateLines(result.schema, 200);
|
|
374
|
+
ctx.log("info", `Generated schema:\n${text}`);
|
|
375
|
+
if (truncated) {
|
|
376
|
+
ctx.log("info", "Preview truncated. Use --output to write and inspect the full schema.");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
const { text, truncated } = truncateLines(result.schema, 200);
|
|
382
|
+
ctx.log("info", `Generated schema:\n${text}`);
|
|
383
|
+
if (truncated) {
|
|
384
|
+
ctx.log("info", "Preview truncated. Use --output to write and inspect the full schema.");
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
329
389
|
ctx.log("info", "Pulling schema from database...");
|
|
330
390
|
const result = await pullSchema({
|
|
331
391
|
dialect,
|
|
@@ -335,8 +395,39 @@ export async function runPull(ctx) {
|
|
|
335
395
|
});
|
|
336
396
|
ctx.log("success", `Schema generated: ${result.outputPath}`);
|
|
337
397
|
ctx.log("info", `${result.tableCount} table(s) introspected`);
|
|
398
|
+
ctx.log("info", "Next: review the schema, then run 'zenstack-kit init' to reset the snapshot.");
|
|
338
399
|
// If we have existing migrations, warn about resetting
|
|
339
400
|
if (snapshotExists || migrations.length > 0) {
|
|
340
401
|
ctx.log("warning", "You should run 'zenstack-kit init' to reset the snapshot after reviewing the schema.");
|
|
341
402
|
}
|
|
342
403
|
}
|
|
404
|
+
async function buildSchemaDiff(existingPath, nextSchema) {
|
|
405
|
+
const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "zenstack-kit-pull-"));
|
|
406
|
+
const nextPath = path.join(tempDir, "schema.zmodel");
|
|
407
|
+
try {
|
|
408
|
+
await fs.promises.writeFile(nextPath, nextSchema, "utf-8");
|
|
409
|
+
try {
|
|
410
|
+
return execFileSync("git", ["diff", "--no-index", "--no-color", "--", existingPath, nextPath], { encoding: "utf-8" });
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
const stdout = error.stdout;
|
|
414
|
+
if (stdout) {
|
|
415
|
+
return stdout.toString();
|
|
416
|
+
}
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
finally {
|
|
421
|
+
await fs.promises.rm(tempDir, { recursive: true, force: true });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function truncateLines(text, maxLines) {
|
|
425
|
+
const lines = text.split("\n");
|
|
426
|
+
if (lines.length <= maxLines) {
|
|
427
|
+
return { text, truncated: false };
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
text: lines.slice(0, maxLines).join("\n"),
|
|
431
|
+
truncated: true,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/cli/prompts.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,GAAG,gBAAgB,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,CAAC;AAsCzC;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,UAAU,CAAC,CAyBhE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,UAAU,CAAC,CAyB3D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CA+BjF;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/cli/prompts.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,GAAG,gBAAgB,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,CAAC;AAsCzC;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,UAAU,CAAC,CAyBhE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,UAAU,CAAC,CAyB3D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CA+BjF;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,eAAe,CAAC;AAyCtD;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,GAAE,MAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5F;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEzD;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAkCnG;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAyBvF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,YAAY,CAAC,CAyBvB"}
|
package/dist/cli/prompts.js
CHANGED
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
* Interactive prompts for the init command using ink
|
|
4
4
|
*/
|
|
5
5
|
import React, { useState } from "react";
|
|
6
|
-
import { render, Box, Text } from "ink";
|
|
6
|
+
import { render, Box, Text, useInput } from "ink";
|
|
7
7
|
import SelectInput from "ink-select-input";
|
|
8
8
|
function SelectPrompt({ message, items, onSelect }) {
|
|
9
9
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
@@ -101,8 +101,6 @@ function TextInputPrompt({ message, placeholder, onSubmit, }) {
|
|
|
101
101
|
setValue((prev) => prev + input);
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
|
-
// Use ink's useInput hook
|
|
105
|
-
const { useInput } = require("ink");
|
|
106
104
|
useInput(handleInput);
|
|
107
105
|
return (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: "? " }), _jsxs(Text, { children: [message, " "] }), _jsxs(Text, { dimColor: true, children: ["(", placeholder, "): "] }), _jsx(Text, { children: value }), _jsx(Text, { color: "gray", children: "\u2588" })] }) }));
|
|
108
106
|
}
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ export interface LoadedConfig {
|
|
|
7
7
|
configPath: string;
|
|
8
8
|
configDir: string;
|
|
9
9
|
}
|
|
10
|
-
export declare function loadConfig(cwd: string): Promise<LoadedConfig | null>;
|
|
10
|
+
export declare function loadConfig(cwd: string, configPath?: string): Promise<LoadedConfig | null>;
|
|
11
11
|
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAUpD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAUpD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA+B/F"}
|
package/dist/config/loader.js
CHANGED
|
@@ -10,32 +10,34 @@ const CONFIG_FILES = [
|
|
|
10
10
|
"zenstack-kit.config.mjs",
|
|
11
11
|
"zenstack-kit.config.cjs",
|
|
12
12
|
];
|
|
13
|
-
export async function loadConfig(cwd) {
|
|
14
|
-
const
|
|
15
|
-
|
|
13
|
+
export async function loadConfig(cwd, configPath) {
|
|
14
|
+
const resolvedConfigPath = configPath ? path.resolve(cwd, configPath) : null;
|
|
15
|
+
const configPathToLoad = resolvedConfigPath ??
|
|
16
|
+
CONFIG_FILES.map((file) => path.join(cwd, file)).find((file) => fs.existsSync(file));
|
|
17
|
+
if (!configPathToLoad) {
|
|
16
18
|
return null;
|
|
17
19
|
}
|
|
18
|
-
const ext = path.extname(
|
|
20
|
+
const ext = path.extname(configPathToLoad);
|
|
19
21
|
let config;
|
|
20
22
|
if (ext === ".cjs") {
|
|
21
23
|
const require = createRequire(import.meta.url);
|
|
22
|
-
const loaded = require(
|
|
24
|
+
const loaded = require(configPathToLoad);
|
|
23
25
|
config = (loaded.default ?? loaded);
|
|
24
26
|
}
|
|
25
27
|
else if (ext === ".js" || ext === ".mjs") {
|
|
26
|
-
const loaded = await import(pathToFileUrl(
|
|
28
|
+
const loaded = await import(pathToFileUrl(configPathToLoad));
|
|
27
29
|
config = (loaded.default ?? loaded);
|
|
28
30
|
}
|
|
29
31
|
else {
|
|
30
32
|
const { default: jiti } = await import("jiti");
|
|
31
33
|
const loader = jiti(import.meta.url, { interopDefault: true });
|
|
32
|
-
const loaded = loader(
|
|
34
|
+
const loaded = loader(configPathToLoad);
|
|
33
35
|
config = (loaded.default ?? loaded);
|
|
34
36
|
}
|
|
35
37
|
return {
|
|
36
38
|
config,
|
|
37
|
-
configPath,
|
|
38
|
-
configDir: path.dirname(
|
|
39
|
+
configPath: configPathToLoad,
|
|
40
|
+
configDir: path.dirname(configPathToLoad),
|
|
39
41
|
};
|
|
40
42
|
}
|
|
41
43
|
function pathToFileUrl(filePath) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { KyselyDialect } from "../../sql/kysely-adapter.js";
|
|
2
|
+
export interface ApplyPrismaMigrationsOptions {
|
|
3
|
+
/** Migrations folder path */
|
|
4
|
+
migrationsFolder: string;
|
|
5
|
+
/** Database dialect */
|
|
6
|
+
dialect: KyselyDialect;
|
|
7
|
+
/** Database connection URL */
|
|
8
|
+
connectionUrl?: string;
|
|
9
|
+
/** SQLite database path */
|
|
10
|
+
databasePath?: string;
|
|
11
|
+
/** Migrations table name (default: _prisma_migrations) */
|
|
12
|
+
migrationsTable?: string;
|
|
13
|
+
/** Migrations schema (PostgreSQL only, default: public) */
|
|
14
|
+
migrationsSchema?: string;
|
|
15
|
+
/** Mark migrations as applied without executing SQL */
|
|
16
|
+
markApplied?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface ApplyPrismaMigrationsResult {
|
|
19
|
+
applied: Array<{
|
|
20
|
+
migrationName: string;
|
|
21
|
+
duration: number;
|
|
22
|
+
}>;
|
|
23
|
+
alreadyApplied: string[];
|
|
24
|
+
failed?: {
|
|
25
|
+
migrationName: string;
|
|
26
|
+
error: string;
|
|
27
|
+
};
|
|
28
|
+
coherenceErrors?: MigrationCoherenceError[];
|
|
29
|
+
}
|
|
30
|
+
export interface MigrationCoherenceError {
|
|
31
|
+
type: "missing_from_log" | "missing_from_db" | "missing_from_disk" | "order_mismatch" | "checksum_mismatch";
|
|
32
|
+
migrationName: string;
|
|
33
|
+
details: string;
|
|
34
|
+
}
|
|
35
|
+
export interface MigrationCoherenceResult {
|
|
36
|
+
isCoherent: boolean;
|
|
37
|
+
errors: MigrationCoherenceError[];
|
|
38
|
+
}
|
|
39
|
+
export interface PreviewPrismaMigrationsResult {
|
|
40
|
+
pending: Array<{
|
|
41
|
+
name: string;
|
|
42
|
+
sql: string;
|
|
43
|
+
}>;
|
|
44
|
+
alreadyApplied: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Apply pending Prisma migrations
|
|
48
|
+
*/
|
|
49
|
+
export declare function applyPrismaMigrations(options: ApplyPrismaMigrationsOptions): Promise<ApplyPrismaMigrationsResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Preview pending migrations without applying them
|
|
52
|
+
*/
|
|
53
|
+
export declare function previewPrismaMigrations(options: ApplyPrismaMigrationsOptions): Promise<PreviewPrismaMigrationsResult>;
|
|
54
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/migrations/prisma/apply.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAIjE,MAAM,WAAW,4BAA4B;IAC3C,6BAA6B;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,uBAAuB;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,KAAK,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,eAAe,CAAC,EAAE,uBAAuB,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,GAAG,iBAAiB,GAAG,mBAAmB,GAAG,gBAAgB,GAAG,mBAAmB,CAAC;IAC5G,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,uBAAuB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9C,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AA2QD;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,2BAA2B,CAAC,CAyHtC;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,6BAA6B,CAAC,CA0DxC"}
|