@zintrust/core 0.4.41 → 0.4.43
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/package.json +3 -2
- package/src/boot/registry/runtime.d.ts.map +1 -1
- package/src/boot/registry/runtime.js +122 -0
- package/src/cache/Cache.d.ts.map +1 -1
- package/src/cache/Cache.js +25 -2
- package/src/cli/BaseCommand.d.ts.map +1 -1
- package/src/cli/BaseCommand.js +8 -0
- package/src/cli/CLI.d.ts.map +1 -1
- package/src/cli/CLI.js +2 -0
- package/src/cli/OptionalCliExtensions.d.ts.map +1 -1
- package/src/cli/OptionalCliExtensions.js +12 -0
- package/src/cli/cloudflare/CloudflareWranglerDevEnv.d.ts +24 -0
- package/src/cli/cloudflare/CloudflareWranglerDevEnv.d.ts.map +1 -0
- package/src/cli/cloudflare/CloudflareWranglerDevEnv.js +174 -0
- package/src/cli/commands/DebuggerCommand.d.ts +18 -0
- package/src/cli/commands/DebuggerCommand.d.ts.map +1 -0
- package/src/cli/commands/DebuggerCommand.js +6 -0
- package/src/cli/commands/DebuggerCommands.d.ts +25 -0
- package/src/cli/commands/DebuggerCommands.d.ts.map +1 -0
- package/src/cli/commands/DebuggerCommands.js +500 -0
- package/src/cli/commands/PrepareCommand.d.ts.map +1 -1
- package/src/cli/commands/PrepareCommand.js +56 -20
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +12 -94
- package/src/cli/commands/WranglerDevVarsCommand.d.ts +6 -0
- package/src/cli/commands/WranglerDevVarsCommand.d.ts.map +1 -0
- package/src/cli/commands/WranglerDevVarsCommand.js +52 -0
- package/src/cli/commands/index.d.ts +2 -0
- package/src/cli/commands/index.d.ts.map +1 -1
- package/src/cli/commands/index.js +2 -0
- package/src/cli/index.d.ts +1 -0
- package/src/cli/index.d.ts.map +1 -1
- package/src/cli/index.js +1 -0
- package/src/cli.d.ts +1 -0
- package/src/cli.d.ts.map +1 -1
- package/src/cli.js +1 -0
- package/src/config/database.d.ts.map +1 -1
- package/src/config/database.js +7 -1
- package/src/config/logger.d.ts +7 -0
- package/src/config/logger.d.ts.map +1 -1
- package/src/config/logger.js +37 -0
- package/src/debugger/SystemDebuggerBridge.d.ts +15 -0
- package/src/debugger/SystemDebuggerBridge.d.ts.map +1 -0
- package/src/debugger/SystemDebuggerBridge.js +109 -0
- package/src/events/EventDispatcher.d.ts.map +1 -1
- package/src/events/EventDispatcher.js +3 -0
- package/src/functions/cloudflare.d.ts.map +1 -1
- package/src/http/Kernel.d.ts.map +1 -1
- package/src/http/Kernel.js +8 -0
- package/src/http/RequestContext.d.ts +1 -0
- package/src/http/RequestContext.d.ts.map +1 -1
- package/src/http/RequestContext.js +9 -1
- package/src/index.d.ts +4 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +5 -3
- package/src/migrations/schema/SchemaCompiler.d.ts.map +1 -1
- package/src/migrations/schema/SchemaCompiler.js +2 -2
- package/src/orm/Database.d.ts +1 -0
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/Database.js +11 -16
- package/src/orm/DatabaseRuntimeRegistration.d.ts.map +1 -1
- package/src/orm/DatabaseRuntimeRegistration.js +9 -3
- package/src/orm/Model.d.ts +8 -2
- package/src/orm/Model.d.ts.map +1 -1
- package/src/orm/Model.js +193 -109
- package/src/orm/QueryBuilder.d.ts.map +1 -1
- package/src/orm/QueryBuilder.js +85 -1
- package/src/runtime/WorkerAdapterImports.d.ts.map +1 -1
- package/src/runtime/WorkerAdapterImports.js +1 -6
- package/src/runtime/WorkerProjectPlugins.d.ts +6 -0
- package/src/runtime/WorkerProjectPlugins.d.ts.map +1 -0
- package/src/runtime/WorkerProjectPlugins.js +5 -0
- package/src/runtime/plugins/system-debugger-runtime.d.ts +19 -0
- package/src/runtime/plugins/system-debugger-runtime.d.ts.map +1 -0
- package/src/runtime/plugins/system-debugger-runtime.js +19 -0
- package/src/runtime/plugins/system-debugger.d.ts +2 -0
- package/src/runtime/plugins/system-debugger.d.ts.map +1 -0
- package/src/runtime/plugins/system-debugger.js +14 -0
- package/src/security/JwtManager.d.ts.map +1 -1
- package/src/security/JwtManager.js +29 -0
- package/src/tools/http/Http.d.ts.map +1 -1
- package/src/tools/http/Http.js +2 -0
- package/src/tools/mail/index.d.ts.map +1 -1
- package/src/tools/mail/index.js +7 -1
- package/src/tools/notification/Service.d.ts.map +1 -1
- package/src/tools/notification/Service.js +18 -6
- package/src/tools/queue/Queue.d.ts.map +1 -1
- package/src/tools/queue/Queue.js +2 -0
- package/src/zintrust.plugins.d.ts +1 -0
- package/src/zintrust.plugins.d.ts.map +1 -1
- package/src/zintrust.plugins.js +3 -21
- package/src/zintrust.plugins.wg.d.ts +1 -0
- package/src/zintrust.plugins.wg.d.ts.map +1 -1
- package/src/zintrust.plugins.wg.js +3 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { BaseCommand } from '../BaseCommand.js';
|
|
2
|
+
import { D1SqlMigrations } from '../d1/D1SqlMigrations.js';
|
|
3
|
+
import { WranglerConfig } from '../d1/WranglerConfig.js';
|
|
4
|
+
import { WranglerD1 } from '../d1/WranglerD1.js';
|
|
5
|
+
import { confirmProductionRun, mapConnectionToOrmConfig, parseRollbackSteps, } from '../utils/DatabaseCliUtils.js';
|
|
6
|
+
import { readEnvString } from '../../common/ExternalServiceUtils.js';
|
|
7
|
+
import { databaseConfig } from '../../config/database.js';
|
|
8
|
+
import { Logger } from '../../config/logger.js';
|
|
9
|
+
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
10
|
+
import { isNonEmptyString } from '../../helper/index.js';
|
|
11
|
+
import { Migrator } from '../../migrations/Migrator.js';
|
|
12
|
+
import { createRequire } from '../../node-singletons/module.js';
|
|
13
|
+
import * as path from '../../node-singletons/path.js';
|
|
14
|
+
import { Database } from '../../orm/Database.js';
|
|
15
|
+
import { DatabaseAdapterRegistry } from '../../orm/DatabaseAdapterRegistry.js';
|
|
16
|
+
const loadDebuggerModule = async () => {
|
|
17
|
+
try {
|
|
18
|
+
return (await import('../../../packages/system-debugger/src/index.js'));
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
Logger.error('Failed to load optional package "@zintrust/system-debugger"', error);
|
|
22
|
+
throw ErrorFactory.createCliError('Package "@zintrust/system-debugger" is not installed. Add it to your project first.');
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const addPruneOptions = (command) => {
|
|
26
|
+
command
|
|
27
|
+
.option('--hours <number>', 'Remove entries older than N hours (default: from config)', '')
|
|
28
|
+
.option('--local', 'D1 only: run against local D1 database')
|
|
29
|
+
.option('--remote', 'D1 only: run against remote D1 database')
|
|
30
|
+
.option('--database <name>', 'D1 only: Wrangler D1 database binding name')
|
|
31
|
+
.option('--keep-exceptions', 'Keep exception entries regardless of age', false);
|
|
32
|
+
};
|
|
33
|
+
const addMigrateOptions = (command) => {
|
|
34
|
+
command
|
|
35
|
+
.option('--status', 'Display migration status (applied, pending, failed)')
|
|
36
|
+
.option('--fresh', 'Reset database: drop all tables and re-run all migrations')
|
|
37
|
+
.option('--reset', 'Rollback all migrations to initial state')
|
|
38
|
+
.option('--rollback', 'Rollback last migration batch')
|
|
39
|
+
.option('--step <number>', 'Number of batches to rollback (use with --rollback)', '1')
|
|
40
|
+
.option('--force', 'Skip production confirmation (allow unsafe operations in production)')
|
|
41
|
+
.option('--all', 'Run migrations for all configured database connections')
|
|
42
|
+
.option('--connection <name>', 'Use a specific database connection for debugger migrations')
|
|
43
|
+
.option('--local', 'D1 only: run against local D1 database')
|
|
44
|
+
.option('--remote', 'D1 only: run against remote D1 database')
|
|
45
|
+
.option('--database <name>', 'D1 only: Wrangler D1 database binding name')
|
|
46
|
+
.option('--no-interactive', 'Disable interactive prompts (useful for CI/CD)');
|
|
47
|
+
};
|
|
48
|
+
const resolveDashboardBasePath = () => {
|
|
49
|
+
const raw = readEnvString('DEBUGGER_BASE_PATH').trim();
|
|
50
|
+
if (raw === '')
|
|
51
|
+
return '/debugger';
|
|
52
|
+
return raw.startsWith('/') ? raw : `/${raw}`;
|
|
53
|
+
};
|
|
54
|
+
const resolveDashboardUrl = () => {
|
|
55
|
+
const host = readEnvString('HOST').trim() || '127.0.0.1';
|
|
56
|
+
const port = readEnvString('PORT').trim() || readEnvString('APP_PORT').trim() || '7777';
|
|
57
|
+
return `http://${host}:${port}${resolveDashboardBasePath()}`;
|
|
58
|
+
};
|
|
59
|
+
const resolveDebuggerMigrationDir = () => {
|
|
60
|
+
const requireFromProject = createRequire(path.join(process.cwd(), 'package.json'));
|
|
61
|
+
try {
|
|
62
|
+
const resolved = requireFromProject.resolve('@zintrust/system-debugger/migrations');
|
|
63
|
+
return path.dirname(resolved);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return path.join(process.cwd(), 'packages', 'system-debugger', 'migrations');
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const getD1DatabaseName = (options) => {
|
|
70
|
+
const optionValue = options['database'];
|
|
71
|
+
if (typeof optionValue === 'string' && optionValue.trim() !== '') {
|
|
72
|
+
return optionValue.trim();
|
|
73
|
+
}
|
|
74
|
+
const projectRoot = process.cwd();
|
|
75
|
+
const resolution = WranglerConfig.resolveD1Database(projectRoot);
|
|
76
|
+
if (resolution.status === 'resolved') {
|
|
77
|
+
return WranglerConfig.getDefaultD1DatabaseName(projectRoot) ?? 'zintrust_db';
|
|
78
|
+
}
|
|
79
|
+
if (resolution.status === 'ambiguous') {
|
|
80
|
+
throw ErrorFactory.createCliError('Multiple D1 targets are configured. Re-run with --database <database_name|binding> to choose the intended Wrangler D1 target.');
|
|
81
|
+
}
|
|
82
|
+
return 'zintrust_db';
|
|
83
|
+
};
|
|
84
|
+
const getInteractive = (options) => options['interactive'] !== false;
|
|
85
|
+
const resolveRuntimeDefaultConnectionName = () => {
|
|
86
|
+
const configuredDefault = String(databaseConfig.default ?? '').trim();
|
|
87
|
+
return configuredDefault === '' ? 'default' : configuredDefault;
|
|
88
|
+
};
|
|
89
|
+
const normalizeConnectionName = (value) => {
|
|
90
|
+
const normalized = value.trim();
|
|
91
|
+
if (normalized === '' || normalized === 'default') {
|
|
92
|
+
return resolveRuntimeDefaultConnectionName();
|
|
93
|
+
}
|
|
94
|
+
return normalized;
|
|
95
|
+
};
|
|
96
|
+
const resolveDebuggerConnectionName = (options) => {
|
|
97
|
+
if (isNonEmptyString(options['connection'])) {
|
|
98
|
+
return normalizeConnectionName(String(options['connection']));
|
|
99
|
+
}
|
|
100
|
+
return normalizeConnectionName(readEnvString('DEBUGGER_DB_CONNECTION').trim());
|
|
101
|
+
};
|
|
102
|
+
const withConfiguredDebuggerConnection = (options, configuredConnection) => {
|
|
103
|
+
if (isNonEmptyString(options['connection'])) {
|
|
104
|
+
return {
|
|
105
|
+
...options,
|
|
106
|
+
connection: resolveDebuggerConnectionName(options),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (isNonEmptyString(configuredConnection)) {
|
|
110
|
+
return {
|
|
111
|
+
...options,
|
|
112
|
+
connection: normalizeConnectionName(configuredConnection),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
...options,
|
|
117
|
+
connection: resolveDebuggerConnectionName(options),
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
const resolveDebuggerConnectionConfig = (options) => {
|
|
121
|
+
const selected = resolveDebuggerConnectionName(options);
|
|
122
|
+
const connections = databaseConfig.connections;
|
|
123
|
+
return connections[selected] ?? databaseConfig.getConnection();
|
|
124
|
+
};
|
|
125
|
+
const isD1ConnectionDriver = (driver) => driver === 'd1' || driver === 'd1-remote';
|
|
126
|
+
const resolveD1ExecutionMode = (options) => {
|
|
127
|
+
return options['local'] === true || options['remote'] !== true;
|
|
128
|
+
};
|
|
129
|
+
const ANSI_ESCAPE = String.fromCodePoint(27);
|
|
130
|
+
const stripAnsi = (value) => {
|
|
131
|
+
let output = '';
|
|
132
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
133
|
+
const char = value[index];
|
|
134
|
+
if (char !== ANSI_ESCAPE) {
|
|
135
|
+
output += char;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (value[index + 1] !== '[') {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
index += 2;
|
|
142
|
+
while (index < value.length && value[index] !== 'm') {
|
|
143
|
+
index += 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return output;
|
|
147
|
+
};
|
|
148
|
+
const extractWranglerJson = (output) => {
|
|
149
|
+
const normalized = stripAnsi(output);
|
|
150
|
+
const jsonStart = normalized.indexOf('[\n {');
|
|
151
|
+
if (jsonStart === -1)
|
|
152
|
+
return null;
|
|
153
|
+
try {
|
|
154
|
+
return JSON.parse(normalized.slice(jsonStart));
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
const parseWranglerTable = (output) => {
|
|
161
|
+
const lines = output.split('\n').map((line) => stripAnsi(line).trim());
|
|
162
|
+
const dataLines = lines.filter((line) => line.startsWith('│') && line.endsWith('│'));
|
|
163
|
+
if (dataLines.length < 2)
|
|
164
|
+
return [];
|
|
165
|
+
const toCells = (line) => {
|
|
166
|
+
return line
|
|
167
|
+
.split('│')
|
|
168
|
+
.slice(1, -1)
|
|
169
|
+
.map((cell) => cell.trim());
|
|
170
|
+
};
|
|
171
|
+
const headers = toCells(dataLines[0] ?? '');
|
|
172
|
+
const rows = dataLines.slice(1);
|
|
173
|
+
return rows.map((line) => {
|
|
174
|
+
const cells = toCells(line);
|
|
175
|
+
return Object.fromEntries(headers.map((header, index) => [header, cells[index] ?? '']));
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
const buildStatsFromJsonPayload = (payload) => {
|
|
179
|
+
const stats = {};
|
|
180
|
+
for (const row of payload[0]?.results ?? []) {
|
|
181
|
+
if (typeof row.type === 'string') {
|
|
182
|
+
stats[row.type] = typeof row.cnt === 'number' ? row.cnt : 0;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return stats;
|
|
186
|
+
};
|
|
187
|
+
const buildStatsFromTableRows = (rows) => {
|
|
188
|
+
const stats = {};
|
|
189
|
+
for (const row of rows) {
|
|
190
|
+
const key = row['type'] ?? '';
|
|
191
|
+
const count = Number.parseInt(row['cnt'] ?? '0', 10);
|
|
192
|
+
if (key !== '') {
|
|
193
|
+
stats[key] = Number.isNaN(count) ? 0 : count;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return stats;
|
|
197
|
+
};
|
|
198
|
+
const withSqlDebuggerStorage = async (options, callback) => {
|
|
199
|
+
const { DebuggerStorage } = await loadDebuggerModule();
|
|
200
|
+
const conn = resolveDebuggerConnectionConfig(options);
|
|
201
|
+
const db = Database.create(mapConnectionToOrmConfig(conn));
|
|
202
|
+
await db.connect();
|
|
203
|
+
try {
|
|
204
|
+
const storage = DebuggerStorage.resolveStorage(db);
|
|
205
|
+
return await callback(storage);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
await db.disconnect();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const executeD1Stats = (options) => {
|
|
212
|
+
const output = WranglerD1.executeSql({
|
|
213
|
+
dbName: getD1DatabaseName(options),
|
|
214
|
+
isLocal: resolveD1ExecutionMode(options),
|
|
215
|
+
sql: 'SELECT type, COUNT(*) as cnt FROM zin_debugger_entries GROUP BY type ORDER BY type',
|
|
216
|
+
});
|
|
217
|
+
const payload = extractWranglerJson(output);
|
|
218
|
+
if (payload !== null) {
|
|
219
|
+
return buildStatsFromJsonPayload(payload);
|
|
220
|
+
}
|
|
221
|
+
return buildStatsFromTableRows(parseWranglerTable(output));
|
|
222
|
+
};
|
|
223
|
+
const executeD1Delete = (options, sql) => {
|
|
224
|
+
const output = WranglerD1.executeSql({
|
|
225
|
+
dbName: getD1DatabaseName(options),
|
|
226
|
+
isLocal: resolveD1ExecutionMode(options),
|
|
227
|
+
sql: `${sql}; SELECT changes() as cnt`,
|
|
228
|
+
});
|
|
229
|
+
const payload = extractWranglerJson(output);
|
|
230
|
+
if (payload !== null) {
|
|
231
|
+
const count = payload.at(-1)?.results?.[0]?.cnt;
|
|
232
|
+
return typeof count === 'number' ? count : 0;
|
|
233
|
+
}
|
|
234
|
+
const rows = parseWranglerTable(output);
|
|
235
|
+
const count = Number.parseInt(rows.at(-1)?.['cnt'] ?? '0', 10);
|
|
236
|
+
return Number.isNaN(count) ? 0 : count;
|
|
237
|
+
};
|
|
238
|
+
const isBuiltInDriver = (driver) => driver === 'sqlite' ||
|
|
239
|
+
driver === 'mysql' ||
|
|
240
|
+
driver === 'postgresql' ||
|
|
241
|
+
driver === 'sqlserver' ||
|
|
242
|
+
driver === 'd1' ||
|
|
243
|
+
driver === 'd1-remote';
|
|
244
|
+
const isDestructiveAction = (options) => options['fresh'] === true || options['reset'] === true || options['rollback'] === true;
|
|
245
|
+
const executePrune = async (options) => {
|
|
246
|
+
const { DebuggerConfig } = await loadDebuggerModule();
|
|
247
|
+
const config = DebuggerConfig.merge();
|
|
248
|
+
const resolvedOptions = withConfiguredDebuggerConnection(options, config.connection);
|
|
249
|
+
const hours = typeof options['hours'] === 'string' && options['hours'] !== ''
|
|
250
|
+
? Number.parseInt(options['hours'], 10)
|
|
251
|
+
: config.pruneAfterHours;
|
|
252
|
+
const olderThanMs = hours * 60 * 60 * 1000;
|
|
253
|
+
const keepExceptions = options['keepExceptions'] === true;
|
|
254
|
+
const conn = resolveDebuggerConnectionConfig(resolvedOptions);
|
|
255
|
+
const threshold = Date.now() - olderThanMs;
|
|
256
|
+
const pruneSql = keepExceptions
|
|
257
|
+
? `DELETE FROM zin_debugger_entries WHERE created_at < ${String(threshold)} AND type != 'exception'`
|
|
258
|
+
: `DELETE FROM zin_debugger_entries WHERE created_at < ${String(threshold)}`;
|
|
259
|
+
Logger.info(`Pruning debugger entries older than ${hours}h...`);
|
|
260
|
+
const deleted = isD1ConnectionDriver(conn.driver)
|
|
261
|
+
? executeD1Delete(options, pruneSql)
|
|
262
|
+
: await withSqlDebuggerStorage(resolvedOptions, async (storage) => storage.prune(olderThanMs, keepExceptions));
|
|
263
|
+
Logger.info(`Done - removed ${deleted} entries.`);
|
|
264
|
+
};
|
|
265
|
+
const executeClear = async (options) => {
|
|
266
|
+
const { DebuggerConfig } = await loadDebuggerModule();
|
|
267
|
+
const config = DebuggerConfig.merge();
|
|
268
|
+
const resolvedOptions = withConfiguredDebuggerConnection(options, config.connection);
|
|
269
|
+
const conn = resolveDebuggerConnectionConfig(resolvedOptions);
|
|
270
|
+
Logger.info('Clearing all debugger entries...');
|
|
271
|
+
if (isD1ConnectionDriver(conn.driver)) {
|
|
272
|
+
executeD1Delete(options, 'DELETE FROM zin_debugger_entries');
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
await withSqlDebuggerStorage(resolvedOptions, async (storage) => storage.clear());
|
|
276
|
+
}
|
|
277
|
+
Logger.info('Done - all entries cleared.');
|
|
278
|
+
};
|
|
279
|
+
const executeStatus = async (options, cmd) => {
|
|
280
|
+
const { DebuggerConfig } = await loadDebuggerModule();
|
|
281
|
+
const config = DebuggerConfig.merge();
|
|
282
|
+
const resolvedOptions = withConfiguredDebuggerConnection(options, config.connection);
|
|
283
|
+
const connection = resolveDebuggerConnectionName(resolvedOptions);
|
|
284
|
+
const conn = resolveDebuggerConnectionConfig(resolvedOptions);
|
|
285
|
+
const stats = isD1ConnectionDriver(conn.driver)
|
|
286
|
+
? executeD1Stats(options)
|
|
287
|
+
: await withSqlDebuggerStorage(resolvedOptions, async (storage) => storage.stats());
|
|
288
|
+
cmd.info(`Debugger enabled via env: ${readEnvString('DEBUGGER_ENABLED').trim() || 'false'}`);
|
|
289
|
+
cmd.info(`Connection: ${connection}`);
|
|
290
|
+
cmd.info(`Prune after hours: ${String(config.pruneAfterHours)}`);
|
|
291
|
+
cmd.info(`Dashboard: ${resolveDashboardUrl()}`);
|
|
292
|
+
const keys = Object.keys(stats).sort((left, right) => left.localeCompare(right));
|
|
293
|
+
if (keys.length === 0) {
|
|
294
|
+
cmd.info('Stored entries: 0');
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
for (const key of keys) {
|
|
298
|
+
cmd.info(`${key}: ${String(stats[key] ?? 0)}`);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
const printMigrationStatus = async (migrator, cmd) => {
|
|
302
|
+
const rows = await migrator.status();
|
|
303
|
+
if (rows.length === 0) {
|
|
304
|
+
cmd.info('No debugger migrations found.');
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
for (const row of rows) {
|
|
308
|
+
const tag = row.status ?? (row.applied ? 'applied' : 'pending');
|
|
309
|
+
const extra = row.applied ? ` (batch=${row.batch ?? '?'}, at=${row.appliedAt ?? '?'})` : '';
|
|
310
|
+
cmd.info(`${tag}: ${row.name}${extra}`);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const applyDebuggerMigrations = async (migrator, cmd) => {
|
|
314
|
+
const result = await migrator.migrate();
|
|
315
|
+
if (result.appliedNames.length === 0) {
|
|
316
|
+
cmd.info('No pending debugger migrations.');
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
cmd.success('Debugger migrations applied.');
|
|
320
|
+
for (const name of result.appliedNames) {
|
|
321
|
+
cmd.info(`\u2713 ${name}`);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
const runMigrationActions = async (migrator, options, cmd, driver) => {
|
|
325
|
+
if (options['status'] === true) {
|
|
326
|
+
cmd.info(`Adapter: ${driver}`);
|
|
327
|
+
await printMigrationStatus(migrator, cmd);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (options['fresh'] === true) {
|
|
331
|
+
await migrator.fresh();
|
|
332
|
+
cmd.success('Debugger migrations applied (fresh).');
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (options['reset'] === true) {
|
|
336
|
+
await migrator.resetAll();
|
|
337
|
+
cmd.success('Debugger migrations reset.');
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (options['rollback'] === true) {
|
|
341
|
+
const steps = parseRollbackSteps(options);
|
|
342
|
+
const result = await migrator.rollbackLastBatch(steps);
|
|
343
|
+
cmd.success(`Debugger migrations rolled back (${result.rolledBack}).`);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
await applyDebuggerMigrations(migrator, cmd);
|
|
347
|
+
};
|
|
348
|
+
const runMigrationsForConnection = async (conn, options, cmd, interactive) => {
|
|
349
|
+
const destructive = isDestructiveAction(options);
|
|
350
|
+
const proceed = await confirmProductionRun({
|
|
351
|
+
cmd,
|
|
352
|
+
interactive,
|
|
353
|
+
destructive,
|
|
354
|
+
force: options['force'] === true,
|
|
355
|
+
message: 'NODE_ENV=production. Continue running debugger migrations?',
|
|
356
|
+
});
|
|
357
|
+
if (!proceed)
|
|
358
|
+
return;
|
|
359
|
+
if (!isBuiltInDriver(conn.driver) && !DatabaseAdapterRegistry.has(conn.driver)) {
|
|
360
|
+
cmd.warn(`Missing adapter for driver: ${conn.driver}`);
|
|
361
|
+
cmd.warn(`Install via 'zin plugin install adapter:${conn.driver}' (or 'zin add db:${conn.driver}').`);
|
|
362
|
+
}
|
|
363
|
+
const previousD1RemoteMode = typeof process === 'undefined' ? undefined : process.env['D1_REMOTE_MODE'];
|
|
364
|
+
if (conn.driver === 'd1' || conn.driver === 'd1-remote') {
|
|
365
|
+
if (options['status'] === true ||
|
|
366
|
+
options['fresh'] === true ||
|
|
367
|
+
options['reset'] === true ||
|
|
368
|
+
options['rollback'] === true) {
|
|
369
|
+
throw ErrorFactory.createCliError('D1-backed debugger migrations currently support apply only. Run `zin migrate:debugger --local|--remote` without status or rollback flags.');
|
|
370
|
+
}
|
|
371
|
+
const projectRoot = process.cwd();
|
|
372
|
+
const dbName = getD1DatabaseName(options);
|
|
373
|
+
const isLocal = options['local'] === true || options['remote'] !== true;
|
|
374
|
+
const outputDir = path.join(projectRoot, WranglerConfig.getD1MigrationsDir(projectRoot, dbName));
|
|
375
|
+
await D1SqlMigrations.compileAndWrite({
|
|
376
|
+
projectRoot,
|
|
377
|
+
globalDir: resolveDebuggerMigrationDir(),
|
|
378
|
+
extension: databaseConfig.migrations.extension,
|
|
379
|
+
includeGlobal: true,
|
|
380
|
+
outputDir,
|
|
381
|
+
});
|
|
382
|
+
const output = WranglerD1.applyMigrations({ cmd, dbName, isLocal });
|
|
383
|
+
if (output !== '') {
|
|
384
|
+
cmd.info(output);
|
|
385
|
+
}
|
|
386
|
+
cmd.success('Debugger D1 migrations applied.');
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const ormConfig = mapConnectionToOrmConfig(conn);
|
|
390
|
+
const db = Database.create(ormConfig);
|
|
391
|
+
await db.connect();
|
|
392
|
+
try {
|
|
393
|
+
const migrator = Migrator.create({
|
|
394
|
+
db,
|
|
395
|
+
projectRoot: process.cwd(),
|
|
396
|
+
globalDir: resolveDebuggerMigrationDir(),
|
|
397
|
+
extension: databaseConfig.migrations.extension,
|
|
398
|
+
separateTracking: true,
|
|
399
|
+
});
|
|
400
|
+
await runMigrationActions(migrator, options, cmd, conn.driver);
|
|
401
|
+
}
|
|
402
|
+
finally {
|
|
403
|
+
if (typeof process !== 'undefined') {
|
|
404
|
+
if (previousD1RemoteMode === undefined) {
|
|
405
|
+
delete process.env['D1_REMOTE_MODE'];
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
process.env['D1_REMOTE_MODE'] = previousD1RemoteMode;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
await db.disconnect();
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
const executeMigrateDebugger = async (options, cmd) => {
|
|
415
|
+
const interactive = getInteractive(options);
|
|
416
|
+
const targets = [];
|
|
417
|
+
if (options['all'] === true) {
|
|
418
|
+
for (const [name, config] of Object.entries(databaseConfig.connections)) {
|
|
419
|
+
targets.push({ name, config });
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
else if (isNonEmptyString(options['connection'])) {
|
|
423
|
+
const selected = String(options['connection']).trim();
|
|
424
|
+
const connections = databaseConfig.connections;
|
|
425
|
+
targets.push({
|
|
426
|
+
name: selected,
|
|
427
|
+
config: connections[selected] ?? databaseConfig.getConnection(),
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
const selected = readEnvString('DEBUGGER_DB_CONNECTION').trim() || 'default';
|
|
432
|
+
const connections = databaseConfig.connections;
|
|
433
|
+
targets.push({
|
|
434
|
+
name: selected,
|
|
435
|
+
config: connections[selected] ?? databaseConfig.getConnection(),
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
let sequence = Promise.resolve();
|
|
439
|
+
for (const { name, config } of targets) {
|
|
440
|
+
sequence = sequence.then(async () => {
|
|
441
|
+
if (targets.length > 1) {
|
|
442
|
+
cmd.info(`\n--- Connection: ${name} (${config.driver}) ---`);
|
|
443
|
+
}
|
|
444
|
+
await runMigrationsForConnection(config, options, cmd, interactive);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
await sequence;
|
|
448
|
+
};
|
|
449
|
+
const createProvider = (name, getCommand) => {
|
|
450
|
+
return Object.freeze({
|
|
451
|
+
name,
|
|
452
|
+
getCommand: () => getCommand().getCommand(),
|
|
453
|
+
});
|
|
454
|
+
};
|
|
455
|
+
export const DebuggerCommands = Object.freeze({
|
|
456
|
+
createDebuggerPruneCommand: () => BaseCommand.create({
|
|
457
|
+
name: 'debugger:prune',
|
|
458
|
+
description: 'Prune old entries from the debugger storage',
|
|
459
|
+
addOptions: addPruneOptions,
|
|
460
|
+
execute: executePrune,
|
|
461
|
+
}),
|
|
462
|
+
createDebuggerClearCommand: () => BaseCommand.create({
|
|
463
|
+
name: 'debugger:clear',
|
|
464
|
+
description: 'Clear all entries from the debugger storage',
|
|
465
|
+
addOptions: (command) => {
|
|
466
|
+
command
|
|
467
|
+
.option('--local', 'D1 only: run against local D1 database')
|
|
468
|
+
.option('--remote', 'D1 only: run against remote D1 database')
|
|
469
|
+
.option('--database <name>', 'D1 only: Wrangler D1 database binding name');
|
|
470
|
+
},
|
|
471
|
+
execute: async (options) => executeClear(options),
|
|
472
|
+
}),
|
|
473
|
+
createDebuggerStatusCommand: () => {
|
|
474
|
+
const cmd = BaseCommand.create({
|
|
475
|
+
name: 'debugger:status',
|
|
476
|
+
description: 'Show debugger storage stats and dashboard location',
|
|
477
|
+
addOptions: (command) => {
|
|
478
|
+
command
|
|
479
|
+
.option('--local', 'D1 only: run against local D1 database')
|
|
480
|
+
.option('--remote', 'D1 only: run against remote D1 database')
|
|
481
|
+
.option('--database <name>', 'D1 only: Wrangler D1 database binding name');
|
|
482
|
+
},
|
|
483
|
+
execute: async (options) => executeStatus(options, cmd),
|
|
484
|
+
});
|
|
485
|
+
return cmd;
|
|
486
|
+
},
|
|
487
|
+
createDebuggerMigrateCommand: () => {
|
|
488
|
+
const cmd = BaseCommand.create({
|
|
489
|
+
name: 'migrate:debugger',
|
|
490
|
+
description: 'Run debugger package migrations',
|
|
491
|
+
addOptions: addMigrateOptions,
|
|
492
|
+
execute: async (options) => executeMigrateDebugger(options, cmd),
|
|
493
|
+
});
|
|
494
|
+
return cmd;
|
|
495
|
+
},
|
|
496
|
+
createDebuggerPruneProvider: () => createProvider('debugger:prune', DebuggerCommands.createDebuggerPruneCommand),
|
|
497
|
+
createDebuggerClearProvider: () => createProvider('debugger:clear', DebuggerCommands.createDebuggerClearCommand),
|
|
498
|
+
createDebuggerStatusProvider: () => createProvider('debugger:status', DebuggerCommands.createDebuggerStatusCommand),
|
|
499
|
+
createDebuggerMigrateProvider: () => createProvider('migrate:debugger', DebuggerCommands.createDebuggerMigrateCommand),
|
|
500
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PrepareCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/PrepareCommand.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"PrepareCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/PrepareCommand.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAiFrD,eAAO,MAAM,cAAc,EAgCtB,YAAY,CAAC"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Makes the local dist/ folder installable via `file:/.../dist`.
|
|
4
4
|
* Usage: zintrust prepare
|
|
5
5
|
*/
|
|
6
|
+
import { materializeWranglerDevVars } from '../cloudflare/CloudflareWranglerDevEnv.js';
|
|
6
7
|
import { DistPackager } from '../utils/DistPackager.js';
|
|
7
8
|
import { SpawnUtil } from '../utils/spawn.js';
|
|
8
9
|
import { resolveNpmPath } from '../../common/index.js';
|
|
@@ -11,6 +12,56 @@ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
|
11
12
|
import * as path from '../../node-singletons/path.js';
|
|
12
13
|
import chalk from 'chalk';
|
|
13
14
|
import { Command } from 'commander';
|
|
15
|
+
const resolveDistPath = (options) => {
|
|
16
|
+
const distRel = typeof options.dist === 'string' && options.dist.trim() !== '' ? options.dist : 'dist';
|
|
17
|
+
return path.resolve(process.cwd(), distRel);
|
|
18
|
+
};
|
|
19
|
+
const logPreparedDist = () => {
|
|
20
|
+
Logger.info(chalk.green('✅ Dist prepared.'));
|
|
21
|
+
Logger.info('Docs roots:');
|
|
22
|
+
Logger.info(`- Production/new apps: ${chalk.cyan('dist/public')}`);
|
|
23
|
+
Logger.info(`- Framework dev: ${chalk.cyan('docs-website/public')}`);
|
|
24
|
+
};
|
|
25
|
+
const prepareWranglerDevVars = async (options) => {
|
|
26
|
+
if (options.devVars === undefined)
|
|
27
|
+
return;
|
|
28
|
+
const wranglerEnv = typeof options.devVars === 'string' ? options.devVars.trim() : '';
|
|
29
|
+
const result = await materializeWranglerDevVars({
|
|
30
|
+
cwd: process.cwd(),
|
|
31
|
+
projectRoot: process.cwd(),
|
|
32
|
+
...(wranglerEnv === '' ? {} : { envName: wranglerEnv }),
|
|
33
|
+
...(typeof options.envPath === 'string' ? { envPath: options.envPath } : {}),
|
|
34
|
+
...(typeof options.target === 'string' ? { target: options.target } : {}),
|
|
35
|
+
...(typeof options.config === 'string' ? { configPath: options.config } : {}),
|
|
36
|
+
requireSelection: true,
|
|
37
|
+
});
|
|
38
|
+
Logger.info(chalk.green(`✅ Wrangler dev vars prepared at ${path.basename(result.filePath)}.`));
|
|
39
|
+
Logger.info(`Selected keys: ${result.selectedKeys.length}`);
|
|
40
|
+
if (result.missingKeys.length > 0) {
|
|
41
|
+
Logger.info(`Missing keys: ${result.missingKeys.join(', ')}`);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const maybeLinkCli = async (options) => {
|
|
45
|
+
if (options.link !== true)
|
|
46
|
+
return;
|
|
47
|
+
Logger.info(chalk.bold('\nLinking CLI globally (npm link)...'));
|
|
48
|
+
const npm = resolveNpmPath();
|
|
49
|
+
const exitCode = await SpawnUtil.spawnAndWait({
|
|
50
|
+
command: npm,
|
|
51
|
+
args: ['link'],
|
|
52
|
+
cwd: process.cwd(),
|
|
53
|
+
});
|
|
54
|
+
if (exitCode !== 0) {
|
|
55
|
+
throw ErrorFactory.createCliError(`npm link exited with code ${exitCode}`);
|
|
56
|
+
}
|
|
57
|
+
Logger.info(chalk.green('✅ Linked. You can now run `zintrust` from your shell.'));
|
|
58
|
+
};
|
|
59
|
+
const executePrepare = async (options) => {
|
|
60
|
+
DistPackager.prepare(resolveDistPath(options), process.cwd());
|
|
61
|
+
logPreparedDist();
|
|
62
|
+
await prepareWranglerDevVars(options);
|
|
63
|
+
await maybeLinkCli(options);
|
|
64
|
+
};
|
|
14
65
|
export const PrepareCommand = {
|
|
15
66
|
name: 'prepare',
|
|
16
67
|
description: 'Prepare local dist/ for file: installs (simulate/fresh install workflow)',
|
|
@@ -18,29 +69,14 @@ export const PrepareCommand = {
|
|
|
18
69
|
return new Command('prepare')
|
|
19
70
|
.description('Prepare local dist/ so it can be installed via file:/.../dist')
|
|
20
71
|
.option('--dist <path>', 'Dist folder path (default: ./dist)')
|
|
72
|
+
.option('--dev-vars [env]', 'Generate Wrangler .dev.vars or .dev.vars.<env> from .zintrust.json cloudflare env groups')
|
|
73
|
+
.option('--env-path <path>', 'Env file used as source values for generated Wrangler dev vars', '.env')
|
|
74
|
+
.option('--target <id>', 'Cloudflare worker target key from .zintrust.json cloudflare.targets')
|
|
75
|
+
.option('-c, --config <path>', 'Wrangler config file used for target inference (optional)')
|
|
21
76
|
.option('--link', 'Also run `npm link` to expose zintrust/zin/z/zt on PATH (dev-only)')
|
|
22
77
|
.action(async (options) => {
|
|
23
78
|
try {
|
|
24
|
-
|
|
25
|
-
const distPath = path.resolve(process.cwd(), distRel);
|
|
26
|
-
DistPackager.prepare(distPath, process.cwd());
|
|
27
|
-
Logger.info(chalk.green('✅ Dist prepared.'));
|
|
28
|
-
Logger.info('Docs roots:');
|
|
29
|
-
Logger.info(`- Production/new apps: ${chalk.cyan('dist/public')}`);
|
|
30
|
-
Logger.info(`- Framework dev: ${chalk.cyan('docs-website/public')}`);
|
|
31
|
-
if (options.link === true) {
|
|
32
|
-
Logger.info(chalk.bold('\nLinking CLI globally (npm link)...'));
|
|
33
|
-
const npm = resolveNpmPath();
|
|
34
|
-
const exitCode = await SpawnUtil.spawnAndWait({
|
|
35
|
-
command: npm,
|
|
36
|
-
args: ['link'],
|
|
37
|
-
cwd: process.cwd(),
|
|
38
|
-
});
|
|
39
|
-
if (exitCode !== 0) {
|
|
40
|
-
throw ErrorFactory.createCliError(`npm link exited with code ${exitCode}`);
|
|
41
|
-
}
|
|
42
|
-
Logger.info(chalk.green('✅ Linked. You can now run `zintrust` from your shell.'));
|
|
43
|
-
}
|
|
79
|
+
await executePrepare(options);
|
|
44
80
|
}
|
|
45
81
|
catch (error) {
|
|
46
82
|
Logger.error('Failed to prepare dist', error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/StartCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"StartCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/StartCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA2+BvF,eAAO,MAAM,YAAY;cACb,YAAY;;mCAn7BU,MAAM,KAAG,OAAO;4CAaP,MAAM,KAAG,MAAM;4CA4Bf,MAAM,KAAG,OAAO;sCAetB,MAAM,WAAW,MAAM,KAAG,OAAO;oCAmBnC,MAAM,KAAG,OAAO;;EAm5BjD,CAAC"}
|