@kywi-software/cli 0.2.1 → 0.3.1
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
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The `kywi` command-line tool: applies the schema described by a project's
|
|
4
4
|
`kywi.config.ts` to its database, and seeds default/demo content. Built on
|
|
5
5
|
`@kywi-software/core`'s schema generator and Drizzle. See the
|
|
6
|
-
[root README](https://github.com/
|
|
6
|
+
[root README](https://github.com/Kywi-Software/kywi-cms#readme) for how it fits
|
|
7
7
|
into the rest of Kywi.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
@@ -25,17 +25,98 @@ program
|
|
|
25
25
|
mkdirSync(outDir, { recursive: true });
|
|
26
26
|
mkdirSync(migrationsDir, { recursive: true });
|
|
27
27
|
const { contentTypes, db } = config;
|
|
28
|
-
|
|
28
|
+
// ── Admin-created content types (#38) ────────────────────────────────────
|
|
29
|
+
// Types created through the admin Type Designer live in the DB, not in
|
|
30
|
+
// kywi.config.ts, but they get real `kywi_ct_*` tables. If schema generation
|
|
31
|
+
// reads only the config, drizzle-kit sees those tables as orphans and offers
|
|
32
|
+
// to DROP them (with their data). So when a database is reachable we read the
|
|
33
|
+
// admin-created types and generate their schema too — the generated schema
|
|
34
|
+
// then reflects the FULL content model and no admin table is ever an orphan.
|
|
35
|
+
let adminTypes = [];
|
|
36
|
+
let orphanTables = [];
|
|
37
|
+
let dbReadOk = false;
|
|
38
|
+
let reachable = false;
|
|
39
|
+
try {
|
|
40
|
+
// Imported at call time (mirrors migrate.ts): keeps schema generation
|
|
41
|
+
// dependency-light and lets a config-only build work even before core's
|
|
42
|
+
// DB helpers are present.
|
|
43
|
+
const { createDb, resolveDatabaseUrl, loadAdminContentTypes, listCustomContentTables } = await import('@kywi-software/core');
|
|
44
|
+
const { sql } = await import('drizzle-orm');
|
|
45
|
+
const dbUrl = resolveDatabaseUrl(db?.url, 'postgres://localhost:5432/kywi_dev').url;
|
|
46
|
+
const client = createDb(dbUrl, db?.provider);
|
|
47
|
+
try {
|
|
48
|
+
// Probe reachability FIRST, separately from the admin-type read. If the
|
|
49
|
+
// probe succeeds but the read below throws, the DB is reachable and we
|
|
50
|
+
// must NOT fall back to a config-only schema — that fallback is exactly
|
|
51
|
+
// the unprotected schema that lets drizzle-kit offer to DROP admin
|
|
52
|
+
// tables (#38). Reachable-read failures abort instead (see catch).
|
|
53
|
+
await client.execute(sql `select 1`);
|
|
54
|
+
reachable = true;
|
|
55
|
+
const admin = await loadAdminContentTypes(client);
|
|
56
|
+
// Only types that actually have a physical table (i.e. at least one
|
|
57
|
+
// custom field — matching where the runtime creates a `kywi_ct_*` table).
|
|
58
|
+
adminTypes = admin.filter(t => t.fields.length > 0);
|
|
59
|
+
// Any dynamic table present in the DB but backed by neither a config type
|
|
60
|
+
// nor a currently-registered admin type is an orphan (e.g. a type deleted
|
|
61
|
+
// via the admin, which intentionally leaves its table + rows in place).
|
|
62
|
+
// Excluding it from the drizzle-kit diff keeps that data safe.
|
|
63
|
+
const present = await listCustomContentTables(client);
|
|
64
|
+
const managed = new Set([
|
|
65
|
+
...contentTypes.map((ct) => contentTypeToTableName(ct.name)),
|
|
66
|
+
...adminTypes.map(ct => contentTypeToTableName(ct.name)),
|
|
67
|
+
]);
|
|
68
|
+
orphanTables = present.filter(t => !managed.has(t));
|
|
69
|
+
dbReadOk = true;
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
// postgres.js keeps a live socket; close it so this process (a child of
|
|
73
|
+
// `kywi migrate`) can exit instead of hanging.
|
|
74
|
+
try {
|
|
75
|
+
await client
|
|
76
|
+
.$client?.end?.({ timeout: 5 });
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
/* best-effort close */
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
if (reachable) {
|
|
85
|
+
// The database answered `select 1` but reading admin content types
|
|
86
|
+
// failed. Generating a config-only schema here would hand drizzle-kit
|
|
87
|
+
// a content model missing the admin-created `kywi_ct_*` tables — the
|
|
88
|
+
// exact DROP-offer data-loss path #38 closed. Refuse instead.
|
|
89
|
+
console.error(`\n✖ Database is reachable but reading admin-created content types failed:\n ${err.message}\n` +
|
|
90
|
+
' Refusing to generate a schema that omits (and therefore un-protects) admin-created\n' +
|
|
91
|
+
' content-type tables. Fix the error above and re-run, or unset DATABASE_URL to\n' +
|
|
92
|
+
' intentionally generate a config-only schema for an offline build.');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
// Genuinely unreachable (offline `migrate:generate`, stopped server, wrong
|
|
96
|
+
// DATABASE_URL). Fall back to config-only generation — the historical
|
|
97
|
+
// behaviour — and warn loudly, because in this mode drizzle-kit cannot be
|
|
98
|
+
// told about admin-created tables.
|
|
99
|
+
console.warn(' ⚠ Database not reachable — generating config-only schema. Run `kywi migrate` ' +
|
|
100
|
+
'with DATABASE_URL set so admin-created content-type tables are included and protected.');
|
|
101
|
+
}
|
|
102
|
+
if (contentTypes.length === 0 && adminTypes.length === 0) {
|
|
29
103
|
console.log('No custom content types found — only base schema will be used.');
|
|
30
104
|
}
|
|
105
|
+
// The full content model drizzle-kit should manage: config-defined first
|
|
106
|
+
// (an app type wins a name clash), then admin-created.
|
|
107
|
+
const allTypes = [...contentTypes, ...adminTypes];
|
|
31
108
|
// Write one file per content type
|
|
32
109
|
for (const ct of contentTypes) {
|
|
33
110
|
const tableName = contentTypeToTableName(ct.name);
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
111
|
+
const filePath = join(outDir, `${tableName}.ts`);
|
|
112
|
+
writeFileSync(filePath, generateContentTypeSchema(ct), 'utf-8');
|
|
113
|
+
console.log(` ✓ ${tableName}.ts`);
|
|
114
|
+
}
|
|
115
|
+
for (const ct of adminTypes) {
|
|
116
|
+
const tableName = contentTypeToTableName(ct.name);
|
|
117
|
+
const filePath = join(outDir, `${tableName}.ts`);
|
|
118
|
+
writeFileSync(filePath, generateContentTypeSchema(ct), 'utf-8');
|
|
119
|
+
console.log(` ✓ ${tableName}.ts (admin-created)`);
|
|
39
120
|
}
|
|
40
121
|
// Write the self-contained base re-export that the barrel index references
|
|
41
122
|
// as '../base.js'. Emitting it here means the generated output no longer
|
|
@@ -45,20 +126,30 @@ program
|
|
|
45
126
|
console.log(` ✓ base.ts`);
|
|
46
127
|
// Write the barrel index
|
|
47
128
|
const indexPath = join(outDir, 'index.ts');
|
|
48
|
-
writeFileSync(indexPath, generateSchemaIndex(
|
|
129
|
+
writeFileSync(indexPath, generateSchemaIndex(allTypes), 'utf-8');
|
|
49
130
|
console.log(` ✓ index.ts`);
|
|
50
|
-
// Write the drizzle.config.ts at the project root
|
|
131
|
+
// Write the drizzle.config.ts at the project root. When we read the DB, scope
|
|
132
|
+
// drizzle-kit to Kywi-managed tables and exclude any orphaned dynamic tables
|
|
133
|
+
// so a `push`/`migrate` can never DROP admin-authored data (#38 safety net).
|
|
51
134
|
const drizzleConfigPath = resolve(process.cwd(), 'drizzle.config.ts');
|
|
52
135
|
const schemaRelative = `./${join('kywi-generated/schema', 'index.ts')}`;
|
|
53
136
|
const migrationsRelative = './kywi-generated/migrations';
|
|
137
|
+
const tablesFilter = dbReadOk
|
|
138
|
+
? ['kywi_*', ...orphanTables.map(t => `!${t}`)]
|
|
139
|
+
: undefined;
|
|
54
140
|
const drizzleConfig = generateDrizzleConfig({
|
|
55
141
|
dbProvider: db.provider,
|
|
56
142
|
schemaRelativePath: schemaRelative,
|
|
57
143
|
migrationsRelativePath: migrationsRelative,
|
|
144
|
+
...(tablesFilter ? { tablesFilter } : {}),
|
|
58
145
|
});
|
|
59
146
|
writeFileSync(drizzleConfigPath, drizzleConfig, 'utf-8');
|
|
60
147
|
console.log(` ✓ drizzle.config.ts (project root)`);
|
|
61
|
-
console.log(`\nGenerated ${
|
|
148
|
+
console.log(`\nGenerated ${allTypes.length} content type schema(s) to ${options.out}/` +
|
|
149
|
+
(adminTypes.length > 0 ? ` (${adminTypes.length} admin-created)` : ''));
|
|
150
|
+
if (orphanTables.length > 0) {
|
|
151
|
+
console.log(`Protected ${orphanTables.length} orphaned dynamic table(s) from drizzle-kit DROP: ${orphanTables.join(', ')}`);
|
|
152
|
+
}
|
|
62
153
|
console.log(`Run 'kywi migrate' to apply the schema to your database.`);
|
|
63
154
|
});
|
|
64
155
|
//# sourceMappingURL=migrate-generate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-generate.js","sourceRoot":"","sources":["../../src/commands/migrate-generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"migrate-generate.js","sourceRoot":"","sources":["../../src/commands/migrate-generate.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/migrate.js
CHANGED
|
@@ -52,6 +52,54 @@ program
|
|
|
52
52
|
}
|
|
53
53
|
throw err;
|
|
54
54
|
}
|
|
55
|
+
// Safety net for #38: every admin-created `kywi_ct_*` table that exists in
|
|
56
|
+
// the live DB must be covered by the schema we just generated (a schema
|
|
57
|
+
// file) or explicitly excluded from the diff (negated in the generated
|
|
58
|
+
// drizzle.config.ts tablesFilter). If neither holds — e.g. a bug made
|
|
59
|
+
// migrate:generate silently fall back to a config-only schema — drizzle-kit
|
|
60
|
+
// would offer to DROP those tables with their rows. Abort instead.
|
|
61
|
+
let unprotected = [];
|
|
62
|
+
try {
|
|
63
|
+
const { listCustomContentTables } = await import('@kywi-software/core');
|
|
64
|
+
const liveTables = await listCustomContentTables(db);
|
|
65
|
+
const { readFileSync } = await import('node:fs');
|
|
66
|
+
const drizzleConfigText = existsSync(drizzleConfigPath)
|
|
67
|
+
? readFileSync(drizzleConfigPath, 'utf-8')
|
|
68
|
+
: '';
|
|
69
|
+
unprotected = liveTables.filter((t) => !existsSync(resolve(process.cwd(), 'kywi-generated', 'schema', `${t}.ts`)) &&
|
|
70
|
+
!drizzleConfigText.includes(`'!${t}'`) &&
|
|
71
|
+
!drizzleConfigText.includes(`"!${t}"`));
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
// The guard itself failing must not mask a working migrate — but say so.
|
|
75
|
+
console.warn(`Warning: could not verify admin-table coverage (${err.message}); proceeding.`);
|
|
76
|
+
}
|
|
77
|
+
if (unprotected.length > 0) {
|
|
78
|
+
console.error(`\n✖ Refusing to run drizzle-kit: ${unprotected.length} admin-created content-type ` +
|
|
79
|
+
`table(s) exist in the database but are missing from the generated schema:\n` +
|
|
80
|
+
unprotected.map((t) => ` ${t}`).join('\n') +
|
|
81
|
+
`\n Running the migration now would offer to DROP these tables and their rows (#38).` +
|
|
82
|
+
`\n Re-run 'kywi migrate' with a DATABASE_URL that can read kywi_content_types, or` +
|
|
83
|
+
`\n report this as a bug if the problem persists.`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
// Databases that predate the composite membership constraints (#40) can
|
|
87
|
+
// hold duplicate rows the new PKs would refuse to apply over. Dedupe
|
|
88
|
+
// before drizzle-kit runs; Postgres-only (the cleanup uses ctid/jsonb).
|
|
89
|
+
if ((config.db?.provider ?? 'postgresql') !== 'mysql') {
|
|
90
|
+
try {
|
|
91
|
+
const { dedupeMembershipRows } = await import('@kywi-software/core');
|
|
92
|
+
const deduped = await dedupeMembershipRows(db);
|
|
93
|
+
const total = deduped.userGroups + deduped.siteMemberships;
|
|
94
|
+
if (total > 0) {
|
|
95
|
+
console.log(`Removed ${total} duplicate membership row(s) (pre-0.2.2 bug #40) so the uniqueness constraints can apply.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.warn(`Warning: could not dedupe membership rows (${err.message}). ` +
|
|
100
|
+
'If drizzle-kit fails adding a primary key on kywi_user_groups/kywi_site_memberships, deduplicate those tables and re-run.');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
55
103
|
}
|
|
56
104
|
catch (err) {
|
|
57
105
|
// Only connection problems are converted above; anything else is a real
|
|
@@ -67,6 +115,13 @@ program
|
|
|
67
115
|
stdio: 'inherit',
|
|
68
116
|
env: process.env,
|
|
69
117
|
});
|
|
70
|
-
|
|
118
|
+
// A spawn failure (e.g. drizzle-kit not installed) leaves status null —
|
|
119
|
+
// that must be a loud error, not a silent success exit.
|
|
120
|
+
if (result.error) {
|
|
121
|
+
console.error(`\n✖ Could not run drizzle-kit (${result.error.message}).`);
|
|
122
|
+
console.error(" Is 'drizzle-kit' installed? It is a devDependency of the generated app — run 'pnpm install'.");
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
process.exit(result.status ?? 1);
|
|
71
126
|
});
|
|
72
127
|
//# sourceMappingURL=migrate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CACV,8GAA8G,CAC/G;KACA,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,EAAE,gBAAgB,CAAC;KACzE,MAAM,CAAC,QAAQ,EAAE,gFAAgF,EAAE,KAAK,CAAC;KACzG,MAAM,CAAC,KAAK,EAAE,OAA0C,EAAE,EAAE;IAC3D,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,mBAAmB,CAAC,CAAA;IAErE,mCAAmC;IACnC,4EAA4E;IAC5E,2EAA2E;IAC3E,2EAA2E;IAC3E,gDAAgD;IAChD,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;IACjD,MAAM,cAAc,GAAG,SAAS,CAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAE,EAChB,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAE,EAAE,kBAAkB,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,EACvF,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CACvC,CAAA;IACD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,IAAI,CAAC,CAAC,CAAA;IAC1C,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,kCAAkC,iBAAiB,EAAE,CAAC,CAAA;QACpE,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAA;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,4EAA4E;IAC5E,8EAA8E;IAC9E,6CAA6C;IAC7C,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QACzD,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAA;QACjD,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;QAC5F,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;QAC3C,IAAI,KAAa,CAAA;QACjB,IAAI,CAAC;YACH,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,oCAAoC,CAAC,CAAC,GAAG,CAAA;QACtF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,OAAQ,GAAa,CAAC,OAAO,IAAI,CAAC,CAAA;YAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QACD,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;QAC/C,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,UAAU,CAAC,CAAA;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAC3C,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,OAAO,QAAQ,IAAI,CAAC,CAAA;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,wCAAwC;QACxC,IAAK,GAAgC,EAAE,UAAU;YAAE,MAAM,GAAG,CAAA;IAC9D,CAAC;IAED,6BAA6B;IAC7B,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,CAAC,CAAA;IACnF,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAEpD,OAAO,CAAC,GAAG,CAAC,yBAAyB,UAAU,KAAK,CAAC,CAAA;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC,EAAE;QACpD,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAA;IAEF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAA;AAClC,CAAC,CAAC,CAAA"}
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CACV,8GAA8G,CAC/G;KACA,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,EAAE,gBAAgB,CAAC;KACzE,MAAM,CAAC,QAAQ,EAAE,gFAAgF,EAAE,KAAK,CAAC;KACzG,MAAM,CAAC,KAAK,EAAE,OAA0C,EAAE,EAAE;IAC3D,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,mBAAmB,CAAC,CAAA;IAErE,mCAAmC;IACnC,4EAA4E;IAC5E,2EAA2E;IAC3E,2EAA2E;IAC3E,gDAAgD;IAChD,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;IACjD,MAAM,cAAc,GAAG,SAAS,CAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAE,EAChB,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAE,EAAE,kBAAkB,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,EACvF,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CACvC,CAAA;IACD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,IAAI,CAAC,CAAC,CAAA;IAC1C,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,kCAAkC,iBAAiB,EAAE,CAAC,CAAA;QACpE,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAA;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,4EAA4E;IAC5E,8EAA8E;IAC9E,6CAA6C;IAC7C,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QACzD,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAA;QACjD,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;QAC5F,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;QAC3C,IAAI,KAAa,CAAA;QACjB,IAAI,CAAC;YACH,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,oCAAoC,CAAC,CAAC,GAAG,CAAA;QACtF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,OAAQ,GAAa,CAAC,OAAO,IAAI,CAAC,CAAA;YAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QACD,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;QAC/C,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,UAAU,CAAC,CAAA;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAC3C,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,OAAO,QAAQ,IAAI,CAAC,CAAA;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;QAED,2EAA2E;QAC3E,wEAAwE;QACxE,uEAAuE;QACvE,sEAAsE;QACtE,4EAA4E;QAC5E,mEAAmE;QACnE,IAAI,WAAW,GAAa,EAAE,CAAA;QAC9B,IAAI,CAAC;YACH,MAAM,EAAE,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;YACvE,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,EAAE,CAAC,CAAA;YACpD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;YAChD,MAAM,iBAAiB,GAAG,UAAU,CAAC,iBAAiB,CAAC;gBACrD,CAAC,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC;gBAC1C,CAAC,CAAC,EAAE,CAAA;YACN,WAAW,GAAG,UAAU,CAAC,MAAM,CAC7B,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC1E,CAAC,iBAAiB,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC;gBACtC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CACzC,CAAA;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,yEAAyE;YACzE,OAAO,CAAC,IAAI,CACV,mDAAoD,GAAa,CAAC,OAAO,gBAAgB,CAC1F,CAAA;QACH,CAAC;QACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CACX,oCAAoC,WAAW,CAAC,MAAM,8BAA8B;gBAClF,6EAA6E;gBAC7E,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC7C,sFAAsF;gBACtF,oFAAoF;gBACpF,mDAAmD,CACtD,CAAA;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,wEAAwE;QACxE,qEAAqE;QACrE,wEAAwE;QACxE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,IAAI,YAAY,CAAC,KAAK,OAAO,EAAE,CAAC;YACtD,IAAI,CAAC;gBACH,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;gBACpE,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,EAAE,CAAC,CAAA;gBAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,eAAe,CAAA;gBAC1D,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;oBACd,OAAO,CAAC,GAAG,CACT,WAAW,KAAK,2FAA2F,CAC5G,CAAA;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CACV,8CAA+C,GAAa,CAAC,OAAO,KAAK;oBACvE,2HAA2H,CAC9H,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,wCAAwC;QACxC,IAAK,GAAgC,EAAE,UAAU;YAAE,MAAM,GAAG,CAAA;IAC9D,CAAC;IAED,6BAA6B;IAC7B,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,CAAC,CAAA;IACnF,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAEpD,OAAO,CAAC,GAAG,CAAC,yBAAyB,UAAU,KAAK,CAAC,CAAA;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC,EAAE;QACpD,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAA;IAEF,wEAAwE;IACxE,wDAAwD;IACxD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,kCAAkC,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAA;QACzE,OAAO,CAAC,KAAK,CAAC,gGAAgG,CAAC,CAAA;QAC/G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAA;AAClC,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kywi-software/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Kywi CMS command-line tool — migrate, seed, and generate schema from a kywi.config.ts project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"commander": "^12.0.0",
|
|
37
37
|
"drizzle-orm": "^0.38.0",
|
|
38
38
|
"tsx": "^4.7.0",
|
|
39
|
-
"@kywi-software/core": "0.
|
|
39
|
+
"@kywi-software/core": "0.3.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^20.0.0",
|