@zintrust/core 0.4.76 → 0.4.79
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/bin/zintrust-main.d.ts +12 -0
- package/bin/zintrust-main.d.ts.map +1 -1
- package/bin/zintrust-main.js +149 -54
- package/package.json +1 -1
- package/src/boot/registry/runtime.d.ts.map +1 -1
- package/src/boot/registry/runtime.js +38 -4
- package/src/cli/commands/ProxyScaffoldUtils.d.ts +2 -0
- package/src/cli/commands/ProxyScaffoldUtils.d.ts.map +1 -1
- package/src/cli/commands/ProxyScaffoldUtils.js +147 -4
- package/src/cli/commands/TraceCommands.d.ts.map +1 -1
- package/src/cli/commands/TraceCommands.js +43 -51
- package/src/cli/commands/WranglerProxyCommandUtils.d.ts.map +1 -1
- package/src/cli/commands/WranglerProxyCommandUtils.js +14 -2
- package/src/config/logging/KvLogger.d.ts.map +1 -1
- package/src/config/logging/KvLogger.js +18 -6
- package/src/config/workers.d.ts.map +1 -1
- package/src/config/workers.js +52 -12
- package/src/functions/cloudflare.d.ts.map +1 -1
- package/src/functions/cloudflare.js +8 -0
- package/src/http/RequestContext.d.ts.map +1 -1
- package/src/http/RequestContext.js +5 -6
- package/src/index.d.ts +1 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +4 -3
- package/src/middleware/ErrorHandlerMiddleware.d.ts.map +1 -1
- package/src/middleware/ErrorHandlerMiddleware.js +14 -0
- package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.js +2 -1
- package/src/orm/migrations/MigrationStore.d.ts.map +1 -1
- package/src/orm/migrations/MigrationStore.js +383 -16
- package/src/proxy/d1/ZintrustD1Proxy.d.ts.map +1 -1
- package/src/proxy/d1/ZintrustD1Proxy.js +16 -9
- package/src/runtime/StartupConfigFileRegistry.d.ts +2 -1
- package/src/runtime/StartupConfigFileRegistry.d.ts.map +1 -1
- package/src/runtime/StartupConfigFileRegistry.js +1 -0
- package/src/runtime/plugins/trace-runtime.d.ts +10 -0
- package/src/runtime/plugins/trace-runtime.d.ts.map +1 -1
- package/src/runtime/plugins/trace-runtime.js +51 -7
- package/src/templates/project/basic/tsconfig.json.tpl +11 -12
- package/src/tools/queue/Queue.d.ts +1 -2
- package/src/tools/queue/Queue.d.ts.map +1 -1
- package/src/tools/queue/Queue.js +1 -2
- package/src/trace/SystemTraceBridge.js +1 -1
- package/src/zintrust.plugins.js +2 -2
- package/src/zintrust.plugins.wg.js +2 -2
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { Env } from '../../config/env.js';
|
|
2
2
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
3
3
|
import { QueryBuilder } from '../QueryBuilder.js';
|
|
4
|
+
const DEFAULT_LAYOUT = Object.freeze({
|
|
5
|
+
hasAppliedAt: true,
|
|
6
|
+
hasCreatedAt: true,
|
|
7
|
+
hasMigration: false,
|
|
8
|
+
hasName: true,
|
|
9
|
+
hasScope: true,
|
|
10
|
+
hasService: true,
|
|
11
|
+
hasStatus: true,
|
|
12
|
+
requiresCompatibilityMode: false,
|
|
13
|
+
});
|
|
14
|
+
const tableLayoutCache = new WeakMap();
|
|
4
15
|
function nowIso() {
|
|
5
16
|
// MySQL/MariaDB DATETIME does not accept ISO8601 with timezone (e.g. trailing 'Z').
|
|
6
17
|
// Use a portable UTC datetime string.
|
|
@@ -11,6 +22,261 @@ const toSafeService = (service) => {
|
|
|
11
22
|
return '';
|
|
12
23
|
return service.length > 0 ? service : '';
|
|
13
24
|
};
|
|
25
|
+
const isDefaultTrackingTarget = (scope, service) => {
|
|
26
|
+
return scope === 'global' && service === '';
|
|
27
|
+
};
|
|
28
|
+
const queryExists = async (db, sql, parameters) => {
|
|
29
|
+
const rows = await db.query(sql, parameters, true);
|
|
30
|
+
return rows.length > 0;
|
|
31
|
+
};
|
|
32
|
+
const schemaHasTable = async (db, tableName) => {
|
|
33
|
+
const driver = db.getType();
|
|
34
|
+
if (driver === 'sqlite' || driver === 'd1' || driver === 'd1-remote') {
|
|
35
|
+
return queryExists(db, "SELECT 1 FROM sqlite_master WHERE type='table' AND name=? LIMIT 1", [
|
|
36
|
+
tableName,
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
if (driver === 'postgresql') {
|
|
40
|
+
return queryExists(db, "SELECT 1 FROM information_schema.tables WHERE table_schema='public' AND table_name=? LIMIT 1", [tableName]);
|
|
41
|
+
}
|
|
42
|
+
if (driver === 'mysql') {
|
|
43
|
+
return queryExists(db, 'SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name=? LIMIT 1', [tableName]);
|
|
44
|
+
}
|
|
45
|
+
if (driver === 'sqlserver') {
|
|
46
|
+
return queryExists(db, 'SELECT 1 FROM sys.tables WHERE name=? LIMIT 1', [tableName]);
|
|
47
|
+
}
|
|
48
|
+
throw ErrorFactory.createCliError(`Unsupported DB driver: ${driver}`);
|
|
49
|
+
};
|
|
50
|
+
const schemaHasColumn = async (db, tableName, columnName) => {
|
|
51
|
+
const driver = db.getType();
|
|
52
|
+
if (driver === 'sqlite' || driver === 'd1' || driver === 'd1-remote') {
|
|
53
|
+
const rows = await db.query(`PRAGMA table_info("${tableName}")`, [], true);
|
|
54
|
+
return rows.some((row) => {
|
|
55
|
+
const record = row;
|
|
56
|
+
return typeof record.name === 'string' && record.name === columnName;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (driver === 'postgresql') {
|
|
60
|
+
return queryExists(db, "SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name=? AND column_name=? LIMIT 1", [tableName, columnName]);
|
|
61
|
+
}
|
|
62
|
+
if (driver === 'mysql') {
|
|
63
|
+
return queryExists(db, 'SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name=? AND column_name=? LIMIT 1', [tableName, columnName]);
|
|
64
|
+
}
|
|
65
|
+
if (driver === 'sqlserver') {
|
|
66
|
+
return queryExists(db, 'SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(?) AND name=?', [
|
|
67
|
+
tableName,
|
|
68
|
+
columnName,
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
throw ErrorFactory.createCliError(`Unsupported DB driver: ${driver}`);
|
|
72
|
+
};
|
|
73
|
+
const clearTableLayoutCache = (db) => {
|
|
74
|
+
tableLayoutCache.delete(db);
|
|
75
|
+
};
|
|
76
|
+
const ensureTrackingTable = async (db) => {
|
|
77
|
+
assertDbSupportsMigrations(db);
|
|
78
|
+
const adapter = db.getAdapterInstance(false);
|
|
79
|
+
const ensure = requireMigrationsTableSupport(adapter);
|
|
80
|
+
// getAdapterInstance(false) returns a raw adapter without going through Database.query()
|
|
81
|
+
// which auto-connects; ensure we're connected before creating the migrations table.
|
|
82
|
+
if (typeof db.connect === 'function') {
|
|
83
|
+
await db.connect();
|
|
84
|
+
}
|
|
85
|
+
else if (typeof adapter.connect === 'function') {
|
|
86
|
+
await adapter.connect();
|
|
87
|
+
}
|
|
88
|
+
clearTableLayoutCache(db);
|
|
89
|
+
await ensure();
|
|
90
|
+
clearTableLayoutCache(db);
|
|
91
|
+
};
|
|
92
|
+
const probeTableLayout = async (db) => {
|
|
93
|
+
const [hasTable, hasName, hasMigration, hasScope, hasService, hasStatus, hasAppliedAt, hasCreatedAt,] = await Promise.all([
|
|
94
|
+
schemaHasTable(db, 'migrations'),
|
|
95
|
+
schemaHasColumn(db, 'migrations', 'name'),
|
|
96
|
+
schemaHasColumn(db, 'migrations', 'migration'),
|
|
97
|
+
schemaHasColumn(db, 'migrations', 'scope'),
|
|
98
|
+
schemaHasColumn(db, 'migrations', 'service'),
|
|
99
|
+
schemaHasColumn(db, 'migrations', 'status'),
|
|
100
|
+
schemaHasColumn(db, 'migrations', 'applied_at'),
|
|
101
|
+
schemaHasColumn(db, 'migrations', 'created_at'),
|
|
102
|
+
]);
|
|
103
|
+
return {
|
|
104
|
+
hasAppliedAt,
|
|
105
|
+
hasCreatedAt,
|
|
106
|
+
hasMigration,
|
|
107
|
+
hasName,
|
|
108
|
+
hasScope,
|
|
109
|
+
hasService,
|
|
110
|
+
hasStatus,
|
|
111
|
+
hasTable,
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
const ensureProbeTableExists = async (db, probe, allowEnsure) => {
|
|
115
|
+
if (probe.hasTable || !allowEnsure)
|
|
116
|
+
return null;
|
|
117
|
+
await ensureTrackingTable(db);
|
|
118
|
+
return resolveTableLayout(db, false);
|
|
119
|
+
};
|
|
120
|
+
const assertProbeHasIdentityColumns = (probe) => {
|
|
121
|
+
if (probe.hasName || probe.hasMigration)
|
|
122
|
+
return;
|
|
123
|
+
throw ErrorFactory.createCliError('The migrations table is missing both `name` and `migration` columns. Update the tracking table before running migrations.');
|
|
124
|
+
};
|
|
125
|
+
const toTableLayout = (probe) => {
|
|
126
|
+
return {
|
|
127
|
+
hasAppliedAt: probe.hasAppliedAt,
|
|
128
|
+
hasCreatedAt: probe.hasCreatedAt,
|
|
129
|
+
hasMigration: probe.hasMigration,
|
|
130
|
+
hasName: probe.hasName,
|
|
131
|
+
hasScope: probe.hasScope,
|
|
132
|
+
hasService: probe.hasService,
|
|
133
|
+
hasStatus: probe.hasStatus,
|
|
134
|
+
requiresCompatibilityMode: probe.hasMigration ||
|
|
135
|
+
!probe.hasName ||
|
|
136
|
+
!probe.hasScope ||
|
|
137
|
+
!probe.hasService ||
|
|
138
|
+
!probe.hasStatus,
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
const loadTableLayout = async (db, allowEnsure) => {
|
|
142
|
+
if (typeof db.query !== 'function')
|
|
143
|
+
return DEFAULT_LAYOUT;
|
|
144
|
+
const probe = await probeTableLayout(db);
|
|
145
|
+
const ensuredLayout = await ensureProbeTableExists(db, probe, allowEnsure);
|
|
146
|
+
if (ensuredLayout !== null)
|
|
147
|
+
return ensuredLayout;
|
|
148
|
+
assertProbeHasIdentityColumns(probe);
|
|
149
|
+
return toTableLayout(probe);
|
|
150
|
+
};
|
|
151
|
+
const resolveTableLayout = async (db, allowEnsure = true) => {
|
|
152
|
+
const cached = tableLayoutCache.get(db);
|
|
153
|
+
if (cached !== undefined)
|
|
154
|
+
return cached;
|
|
155
|
+
const layoutPromise = loadTableLayout(db, allowEnsure);
|
|
156
|
+
tableLayoutCache.set(db, layoutPromise);
|
|
157
|
+
return layoutPromise.catch((error) => {
|
|
158
|
+
if (tableLayoutCache.get(db) === layoutPromise) {
|
|
159
|
+
clearTableLayoutCache(db);
|
|
160
|
+
}
|
|
161
|
+
throw error;
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
const assertCompatibleTrackingTarget = (layout, scope, service) => {
|
|
165
|
+
if ((layout.hasScope && layout.hasService) || isDefaultTrackingTarget(scope, service))
|
|
166
|
+
return;
|
|
167
|
+
throw ErrorFactory.createCliError('The existing migrations table uses the legacy schema and does not support scoped/service-specific migration tracking yet.');
|
|
168
|
+
};
|
|
169
|
+
const buildLegacyIdentity = (layout, name, scope, service) => {
|
|
170
|
+
const conditions = [];
|
|
171
|
+
const params = [];
|
|
172
|
+
if (layout.hasName && layout.hasMigration) {
|
|
173
|
+
conditions.push('(name = ? OR migration = ?)');
|
|
174
|
+
params.push(name, name);
|
|
175
|
+
}
|
|
176
|
+
else if (layout.hasName) {
|
|
177
|
+
conditions.push('name = ?');
|
|
178
|
+
params.push(name);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
conditions.push('migration = ?');
|
|
182
|
+
params.push(name);
|
|
183
|
+
}
|
|
184
|
+
if (layout.hasScope) {
|
|
185
|
+
conditions.push('scope = ?');
|
|
186
|
+
params.push(scope);
|
|
187
|
+
}
|
|
188
|
+
if (layout.hasService) {
|
|
189
|
+
conditions.push('service = ?');
|
|
190
|
+
params.push(service);
|
|
191
|
+
}
|
|
192
|
+
return { params, sql: conditions.join(' AND ') };
|
|
193
|
+
};
|
|
194
|
+
const normalizeLegacyName = (row) => {
|
|
195
|
+
if (typeof row['name'] === 'string' && row['name'].length > 0)
|
|
196
|
+
return row['name'];
|
|
197
|
+
if (typeof row['migration'] === 'string' && row['migration'].length > 0)
|
|
198
|
+
return row['migration'];
|
|
199
|
+
return '';
|
|
200
|
+
};
|
|
201
|
+
const getLegacyBatch = (row) => {
|
|
202
|
+
const value = row['batch'];
|
|
203
|
+
return typeof value === 'number' ? value : Number(value);
|
|
204
|
+
};
|
|
205
|
+
const getLegacyAppliedAt = (row) => {
|
|
206
|
+
return typeof row['applied_at'] === 'string' ? row['applied_at'] : null;
|
|
207
|
+
};
|
|
208
|
+
const getLegacyAppliedRows = async (db, layout, scope, service) => {
|
|
209
|
+
const normalizedService = toSafeService(service);
|
|
210
|
+
assertCompatibleTrackingTarget(layout, scope, normalizedService);
|
|
211
|
+
const selectColumns = [
|
|
212
|
+
...(layout.hasName ? ['name'] : []),
|
|
213
|
+
...(layout.hasMigration ? ['migration'] : []),
|
|
214
|
+
'batch',
|
|
215
|
+
...(layout.hasAppliedAt ? ['applied_at'] : []),
|
|
216
|
+
];
|
|
217
|
+
const conditions = [];
|
|
218
|
+
const params = [];
|
|
219
|
+
if (layout.hasStatus) {
|
|
220
|
+
conditions.push('status = ?');
|
|
221
|
+
params.push('completed');
|
|
222
|
+
}
|
|
223
|
+
if (layout.hasScope) {
|
|
224
|
+
conditions.push('scope = ?');
|
|
225
|
+
params.push(scope);
|
|
226
|
+
}
|
|
227
|
+
if (layout.hasService) {
|
|
228
|
+
conditions.push('service = ?');
|
|
229
|
+
params.push(normalizedService);
|
|
230
|
+
}
|
|
231
|
+
const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
|
|
232
|
+
return (await db.query(`SELECT ${selectColumns.join(', ')} FROM migrations${whereClause}`, params, true));
|
|
233
|
+
};
|
|
234
|
+
const findLegacyMigrationRecord = async (db, layout, params) => {
|
|
235
|
+
const identity = buildLegacyIdentity(layout, params.name, params.scope, params.service);
|
|
236
|
+
const existing = (await db.query(`SELECT id FROM migrations WHERE ${identity.sql} LIMIT 1`, identity.params, true));
|
|
237
|
+
return existing.length > 0;
|
|
238
|
+
};
|
|
239
|
+
const updateLegacyRunningRecord = async (db, layout, params) => {
|
|
240
|
+
const identity = buildLegacyIdentity(layout, params.name, params.scope, params.service);
|
|
241
|
+
const assignments = ['batch = ?'];
|
|
242
|
+
const updateParams = [params.batch];
|
|
243
|
+
if (layout.hasAppliedAt) {
|
|
244
|
+
assignments.push('applied_at = ?');
|
|
245
|
+
updateParams.push(null);
|
|
246
|
+
}
|
|
247
|
+
await db.execute(`UPDATE migrations SET ${assignments.join(', ')} WHERE ${identity.sql}`, [
|
|
248
|
+
...updateParams,
|
|
249
|
+
...identity.params,
|
|
250
|
+
]);
|
|
251
|
+
};
|
|
252
|
+
const buildLegacyInsertRunningPayload = (layout, params) => {
|
|
253
|
+
return {
|
|
254
|
+
columns: [
|
|
255
|
+
...(layout.hasName ? ['name'] : []),
|
|
256
|
+
...(layout.hasMigration ? ['migration'] : []),
|
|
257
|
+
...(layout.hasScope ? ['scope'] : []),
|
|
258
|
+
...(layout.hasService ? ['service'] : []),
|
|
259
|
+
'batch',
|
|
260
|
+
...(layout.hasStatus ? ['status'] : []),
|
|
261
|
+
...(layout.hasAppliedAt ? ['applied_at'] : []),
|
|
262
|
+
...(layout.hasCreatedAt ? ['created_at'] : []),
|
|
263
|
+
],
|
|
264
|
+
values: [
|
|
265
|
+
...(layout.hasName ? [params.name] : []),
|
|
266
|
+
...(layout.hasMigration ? [params.name] : []),
|
|
267
|
+
...(layout.hasScope ? [params.scope] : []),
|
|
268
|
+
...(layout.hasService ? [params.service] : []),
|
|
269
|
+
params.batch,
|
|
270
|
+
...(layout.hasStatus ? ['running'] : []),
|
|
271
|
+
...(layout.hasAppliedAt ? [null] : []),
|
|
272
|
+
...(layout.hasCreatedAt ? [nowIso()] : []),
|
|
273
|
+
],
|
|
274
|
+
};
|
|
275
|
+
};
|
|
276
|
+
const insertLegacyRunningRecord = async (db, layout, params) => {
|
|
277
|
+
const payload = buildLegacyInsertRunningPayload(layout, params);
|
|
278
|
+
await db.execute(`INSERT INTO migrations (${payload.columns.join(', ')}) VALUES (${payload.columns.map(() => '?').join(', ')})`, payload.values);
|
|
279
|
+
};
|
|
14
280
|
const assertDbSupportsMigrations = (db) => {
|
|
15
281
|
const t = db.getType();
|
|
16
282
|
if (t === 'd1') {
|
|
@@ -42,22 +308,22 @@ const requireMigrationsTableSupport = (adapter) => {
|
|
|
42
308
|
};
|
|
43
309
|
export const MigrationStore = Object.freeze({
|
|
44
310
|
async ensureTable(db) {
|
|
45
|
-
|
|
46
|
-
const adapter = db.getAdapterInstance(false);
|
|
47
|
-
const ensure = requireMigrationsTableSupport(adapter);
|
|
48
|
-
// getAdapterInstance(false) returns a raw adapter without going through Database.query()
|
|
49
|
-
// which auto-connects; ensure we're connected before creating the migrations table.
|
|
50
|
-
if (typeof db.connect === 'function') {
|
|
51
|
-
await db.connect();
|
|
52
|
-
}
|
|
53
|
-
else if (typeof adapter.connect === 'function') {
|
|
54
|
-
await adapter.connect();
|
|
55
|
-
}
|
|
56
|
-
await ensure();
|
|
311
|
+
await ensureTrackingTable(db);
|
|
57
312
|
},
|
|
58
313
|
async getLastCompletedBatch(db, scope = 'global', service = '') {
|
|
59
314
|
assertDbSupportsMigrations(db);
|
|
315
|
+
const layout = await resolveTableLayout(db);
|
|
60
316
|
const normalizedService = toSafeService(service);
|
|
317
|
+
if (layout.requiresCompatibilityMode) {
|
|
318
|
+
const rows = await getLegacyAppliedRows(db, layout, scope, normalizedService);
|
|
319
|
+
let maxBatch = 0;
|
|
320
|
+
for (const row of rows) {
|
|
321
|
+
const batch = getLegacyBatch(row);
|
|
322
|
+
if (Number.isFinite(batch) && batch > maxBatch)
|
|
323
|
+
maxBatch = batch;
|
|
324
|
+
}
|
|
325
|
+
return maxBatch;
|
|
326
|
+
}
|
|
61
327
|
const row = await QueryBuilder.create('migrations', db)
|
|
62
328
|
.max('batch', 'max_batch')
|
|
63
329
|
.where('status', '=', 'completed')
|
|
@@ -70,6 +336,28 @@ export const MigrationStore = Object.freeze({
|
|
|
70
336
|
async getAppliedMap(db, scope, service) {
|
|
71
337
|
assertDbSupportsMigrations(db);
|
|
72
338
|
const normalizedService = toSafeService(service);
|
|
339
|
+
const layout = await resolveTableLayout(db);
|
|
340
|
+
if (layout.requiresCompatibilityMode) {
|
|
341
|
+
const rows = await getLegacyAppliedRows(db, layout, scope, normalizedService);
|
|
342
|
+
const map = new Map();
|
|
343
|
+
for (const row of rows) {
|
|
344
|
+
const name = normalizeLegacyName(row);
|
|
345
|
+
const batch = getLegacyBatch(row);
|
|
346
|
+
if (name === '' || !Number.isFinite(batch))
|
|
347
|
+
continue;
|
|
348
|
+
map.set(name, {
|
|
349
|
+
name,
|
|
350
|
+
scope: layout.hasScope ? scope : 'global',
|
|
351
|
+
service: layout.hasService ? normalizedService : '',
|
|
352
|
+
batch,
|
|
353
|
+
status: typeof row['status'] === 'string'
|
|
354
|
+
? row['status']
|
|
355
|
+
: 'completed',
|
|
356
|
+
appliedAt: getLegacyAppliedAt(row),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return map;
|
|
360
|
+
}
|
|
73
361
|
const rows = await QueryBuilder.create('migrations', db)
|
|
74
362
|
.select('name', 'scope', 'service', 'batch', 'status')
|
|
75
363
|
.selectAs('applied_at', 'appliedAt')
|
|
@@ -90,6 +378,22 @@ export const MigrationStore = Object.freeze({
|
|
|
90
378
|
async insertRunning(db, params) {
|
|
91
379
|
assertDbSupportsMigrations(db);
|
|
92
380
|
const normalizedService = toSafeService(params.service);
|
|
381
|
+
const layout = await resolveTableLayout(db);
|
|
382
|
+
if (layout.requiresCompatibilityMode) {
|
|
383
|
+
assertCompatibleTrackingTarget(layout, params.scope, normalizedService);
|
|
384
|
+
const legacyParams = {
|
|
385
|
+
name: params.name,
|
|
386
|
+
scope: params.scope,
|
|
387
|
+
service: normalizedService,
|
|
388
|
+
batch: params.batch,
|
|
389
|
+
};
|
|
390
|
+
if (await findLegacyMigrationRecord(db, layout, legacyParams)) {
|
|
391
|
+
await updateLegacyRunningRecord(db, layout, legacyParams);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
await insertLegacyRunningRecord(db, layout, legacyParams);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
93
397
|
const existing = await QueryBuilder.create('migrations', db)
|
|
94
398
|
.select('id')
|
|
95
399
|
.where('name', '=', params.name)
|
|
@@ -122,10 +426,37 @@ export const MigrationStore = Object.freeze({
|
|
|
122
426
|
},
|
|
123
427
|
async markStatus(db, params) {
|
|
124
428
|
assertDbSupportsMigrations(db);
|
|
429
|
+
const normalizedService = toSafeService(params.service);
|
|
430
|
+
const layout = await resolveTableLayout(db);
|
|
431
|
+
if (layout.requiresCompatibilityMode) {
|
|
432
|
+
assertCompatibleTrackingTarget(layout, params.scope, normalizedService);
|
|
433
|
+
const identity = buildLegacyIdentity(layout, params.name, params.scope, normalizedService);
|
|
434
|
+
if (!layout.hasStatus && params.status === 'failed') {
|
|
435
|
+
await db.execute(`DELETE FROM migrations WHERE ${identity.sql}`, identity.params);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
const assignments = [];
|
|
439
|
+
const updateParams = [];
|
|
440
|
+
if (layout.hasStatus) {
|
|
441
|
+
assignments.push('status = ?');
|
|
442
|
+
updateParams.push(params.status);
|
|
443
|
+
}
|
|
444
|
+
if (params.appliedAt !== undefined && layout.hasAppliedAt) {
|
|
445
|
+
assignments.push('applied_at = ?');
|
|
446
|
+
updateParams.push(params.appliedAt);
|
|
447
|
+
}
|
|
448
|
+
if (assignments.length === 0)
|
|
449
|
+
return;
|
|
450
|
+
await db.execute(`UPDATE migrations SET ${assignments.join(', ')} WHERE ${identity.sql}`, [
|
|
451
|
+
...updateParams,
|
|
452
|
+
...identity.params,
|
|
453
|
+
]);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
125
456
|
const builder = QueryBuilder.create('migrations', db)
|
|
126
457
|
.where('name', '=', params.name)
|
|
127
458
|
.andWhere('scope', '=', params.scope)
|
|
128
|
-
.andWhere('service', '=',
|
|
459
|
+
.andWhere('service', '=', normalizedService);
|
|
129
460
|
if (params.appliedAt !== undefined) {
|
|
130
461
|
await builder.update({ status: params.status, applied_at: params.appliedAt });
|
|
131
462
|
return;
|
|
@@ -134,11 +465,30 @@ export const MigrationStore = Object.freeze({
|
|
|
134
465
|
},
|
|
135
466
|
async listCompletedInBatchesGte(db, params) {
|
|
136
467
|
assertDbSupportsMigrations(db);
|
|
468
|
+
const normalizedService = toSafeService(params.service);
|
|
469
|
+
const layout = await resolveTableLayout(db);
|
|
470
|
+
if (layout.requiresCompatibilityMode) {
|
|
471
|
+
const rows = await getLegacyAppliedRows(db, layout, params.scope, normalizedService);
|
|
472
|
+
const out = [];
|
|
473
|
+
for (const row of rows) {
|
|
474
|
+
const name = normalizeLegacyName(row);
|
|
475
|
+
const batch = getLegacyBatch(row);
|
|
476
|
+
if (name === '' || !Number.isFinite(batch) || batch < params.minBatch)
|
|
477
|
+
continue;
|
|
478
|
+
out.push({ name, batch });
|
|
479
|
+
}
|
|
480
|
+
out.sort((left, right) => {
|
|
481
|
+
if (left.batch !== right.batch)
|
|
482
|
+
return right.batch - left.batch;
|
|
483
|
+
return right.name.localeCompare(left.name);
|
|
484
|
+
});
|
|
485
|
+
return out;
|
|
486
|
+
}
|
|
137
487
|
const rows = await QueryBuilder.create('migrations', db)
|
|
138
488
|
.select('name', 'batch')
|
|
139
489
|
.where('status', '=', 'completed')
|
|
140
490
|
.andWhere('scope', '=', params.scope)
|
|
141
|
-
.andWhere('service', '=',
|
|
491
|
+
.andWhere('service', '=', normalizedService)
|
|
142
492
|
.andWhere('batch', '>=', params.minBatch)
|
|
143
493
|
.orderBy('batch', 'DESC')
|
|
144
494
|
.orderBy('id', 'DESC')
|
|
@@ -157,11 +507,20 @@ export const MigrationStore = Object.freeze({
|
|
|
157
507
|
},
|
|
158
508
|
async listAllCompletedNames(db, params) {
|
|
159
509
|
assertDbSupportsMigrations(db);
|
|
510
|
+
const normalizedService = toSafeService(params.service);
|
|
511
|
+
const layout = await resolveTableLayout(db);
|
|
512
|
+
if (layout.requiresCompatibilityMode) {
|
|
513
|
+
const rows = await getLegacyAppliedRows(db, layout, params.scope, normalizedService);
|
|
514
|
+
return rows
|
|
515
|
+
.map(normalizeLegacyName)
|
|
516
|
+
.filter((name) => name.length > 0)
|
|
517
|
+
.sort((left, right) => right.localeCompare(left));
|
|
518
|
+
}
|
|
160
519
|
const rows = await QueryBuilder.create('migrations', db)
|
|
161
520
|
.select('name')
|
|
162
521
|
.where('status', '=', 'completed')
|
|
163
522
|
.andWhere('scope', '=', params.scope)
|
|
164
|
-
.andWhere('service', '=',
|
|
523
|
+
.andWhere('service', '=', normalizedService)
|
|
165
524
|
.orderBy('batch', 'DESC')
|
|
166
525
|
.orderBy('id', 'DESC')
|
|
167
526
|
.get();
|
|
@@ -169,10 +528,18 @@ export const MigrationStore = Object.freeze({
|
|
|
169
528
|
},
|
|
170
529
|
async deleteRecord(db, params) {
|
|
171
530
|
assertDbSupportsMigrations(db);
|
|
531
|
+
const normalizedService = toSafeService(params.service);
|
|
532
|
+
const layout = await resolveTableLayout(db);
|
|
533
|
+
if (layout.requiresCompatibilityMode) {
|
|
534
|
+
assertCompatibleTrackingTarget(layout, params.scope, normalizedService);
|
|
535
|
+
const identity = buildLegacyIdentity(layout, params.name, params.scope, normalizedService);
|
|
536
|
+
await db.execute(`DELETE FROM migrations WHERE ${identity.sql}`, identity.params);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
172
539
|
await QueryBuilder.create('migrations', db)
|
|
173
540
|
.where('name', '=', params.name)
|
|
174
541
|
.andWhere('scope', '=', params.scope)
|
|
175
|
-
.andWhere('service', '=',
|
|
542
|
+
.andWhere('service', '=', normalizedService)
|
|
176
543
|
.delete();
|
|
177
544
|
},
|
|
178
545
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZintrustD1Proxy.d.ts","sourceRoot":"","sources":["../../../../src/proxy/d1/ZintrustD1Proxy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ZintrustD1Proxy.d.ts","sourceRoot":"","sources":["../../../../src/proxy/d1/ZintrustD1Proxy.ts"],"names":[],"mappings":"AASA,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC;AAEjD,KAAK,qBAAqB,GAAG;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,GAAG,EAAE;QACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QACtC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QACrE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;QAChE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC;KAChG,CAAC;IACF,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrF,CAAC;AAEF,KAAK,WAAW,CAAC,CAAC,IAAI;IACpB,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;CACf,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,mBAAmB,CAAC;IACpD,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,OAAO,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAC,GAAG,OAAO,OAAO,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5C,GAAG,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;CACjC,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,mBAAmB,CAAC;CAC/C,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAyRF,eAAO,MAAM,eAAe;;;mBAGL,OAAO,OAAO,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC;EAqB5D,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { Logger } from '../../config/logger.js';
|
|
2
|
-
import { isArray, isObject, isString } from '../../helper/index.js';
|
|
3
1
|
import { getEnvInt, json, normalizeBindingName, readAndVerifyJson, toErrorResponse, } from '../CloudflareProxyShared.js';
|
|
4
2
|
import { RequestValidator } from '../RequestValidator.js';
|
|
5
3
|
const DEFAULT_SIGNING_WINDOW_MS = 60_000;
|
|
6
4
|
const DEFAULT_MAX_BODY_BYTES = 128 * 1024;
|
|
7
5
|
const DEFAULT_MAX_SQL_BYTES = 32 * 1024;
|
|
8
6
|
const DEFAULT_MAX_PARAMS = 256;
|
|
7
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
8
|
+
const isString = (value) => typeof value === 'string';
|
|
9
|
+
const isArray = (value) => Array.isArray(value);
|
|
9
10
|
const isDebugEnabled = (env) => {
|
|
10
11
|
const raw = env.ZT_PROXY_DEBUG;
|
|
11
12
|
if (!isString(raw))
|
|
@@ -28,10 +29,16 @@ const safeErrorMessage = (error) => {
|
|
|
28
29
|
const logProxyError = (env, context, error) => {
|
|
29
30
|
if (!isDebugEnabled(env))
|
|
30
31
|
return;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
try {
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.error('[ZintrustD1Proxy] error', {
|
|
35
|
+
...context,
|
|
36
|
+
message: safeErrorMessage(error).slice(0, 800),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// ignore logging failures in Workers proxy mode
|
|
41
|
+
}
|
|
35
42
|
};
|
|
36
43
|
const resolveD1Binding = (env) => {
|
|
37
44
|
const candidates = ['DB', 'zintrust_db', normalizeBindingName(env.D1_BINDING)].filter((value, index, values) => isString(value) && value.trim() !== '' && values.indexOf(value) === index);
|
|
@@ -50,7 +57,7 @@ const loadStatements = (env) => {
|
|
|
50
57
|
return null;
|
|
51
58
|
try {
|
|
52
59
|
const parsed = JSON.parse(raw);
|
|
53
|
-
if (!
|
|
60
|
+
if (!isRecord(parsed))
|
|
54
61
|
return null;
|
|
55
62
|
return parsed;
|
|
56
63
|
}
|
|
@@ -80,7 +87,7 @@ const toD1ExceptionResponse = (error) => {
|
|
|
80
87
|
return toErrorResponse(500, 'D1_ERROR', message);
|
|
81
88
|
};
|
|
82
89
|
const parseSqlPayload = (payload) => {
|
|
83
|
-
if (!
|
|
90
|
+
if (!isRecord(payload)) {
|
|
84
91
|
return { ok: false, response: toErrorResponse(400, 'VALIDATION_ERROR', 'Invalid body') };
|
|
85
92
|
}
|
|
86
93
|
const sql = payload['sql'];
|
|
@@ -181,7 +188,7 @@ const handleExec = async (request, env) => {
|
|
|
181
188
|
}
|
|
182
189
|
};
|
|
183
190
|
const parseStatementPayload = (payload) => {
|
|
184
|
-
if (!
|
|
191
|
+
if (!isRecord(payload)) {
|
|
185
192
|
return { ok: false, response: toErrorResponse(400, 'VALIDATION_ERROR', 'Invalid body') };
|
|
186
193
|
}
|
|
187
194
|
const statementId = payload['statementId'];
|
|
@@ -3,13 +3,14 @@ export declare const StartupConfigFile: {
|
|
|
3
3
|
readonly Cache: "config/cache.ts";
|
|
4
4
|
readonly Database: "config/database.ts";
|
|
5
5
|
readonly Mail: "config/mail.ts";
|
|
6
|
+
readonly Trace: "config/trace.ts";
|
|
6
7
|
readonly Middleware: "config/middleware.ts";
|
|
7
8
|
readonly Notification: "config/notification.ts";
|
|
8
9
|
readonly Queue: "config/queue.ts";
|
|
9
10
|
readonly Storage: "config/storage.ts";
|
|
10
11
|
readonly Workers: "config/workers.ts";
|
|
11
12
|
};
|
|
12
|
-
export type StartupConfigFileTypes = typeof StartupConfigFile.Broadcast | typeof StartupConfigFile.Cache | typeof StartupConfigFile.Database | typeof StartupConfigFile.Mail | typeof StartupConfigFile.Middleware | typeof StartupConfigFile.Notification | typeof StartupConfigFile.Queue | typeof StartupConfigFile.Storage | typeof StartupConfigFile.Workers;
|
|
13
|
+
export type StartupConfigFileTypes = typeof StartupConfigFile.Broadcast | typeof StartupConfigFile.Cache | typeof StartupConfigFile.Database | typeof StartupConfigFile.Mail | typeof StartupConfigFile.Trace | typeof StartupConfigFile.Middleware | typeof StartupConfigFile.Notification | typeof StartupConfigFile.Queue | typeof StartupConfigFile.Storage | typeof StartupConfigFile.Workers;
|
|
13
14
|
export declare const StartupConfigFileRegistry: Readonly<{
|
|
14
15
|
preload(files: readonly StartupConfigFileTypes[]): Promise<void>;
|
|
15
16
|
isPreloaded(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartupConfigFileRegistry.d.ts","sourceRoot":"","sources":["../../../src/runtime/StartupConfigFileRegistry.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"StartupConfigFileRegistry.d.ts","sourceRoot":"","sources":["../../../src/runtime/StartupConfigFileRegistry.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,iBAAiB;;;;;;;;;;;CAWpB,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAC9B,OAAO,iBAAiB,CAAC,SAAS,GAClC,OAAO,iBAAiB,CAAC,KAAK,GAC9B,OAAO,iBAAiB,CAAC,QAAQ,GACjC,OAAO,iBAAiB,CAAC,IAAI,GAC7B,OAAO,iBAAiB,CAAC,KAAK,GAC9B,OAAO,iBAAiB,CAAC,UAAU,GACnC,OAAO,iBAAiB,CAAC,YAAY,GACrC,OAAO,iBAAiB,CAAC,KAAK,GAC9B,OAAO,iBAAiB,CAAC,OAAO,GAChC,OAAO,iBAAiB,CAAC,OAAO,CAAC;AAiDrC,eAAO,MAAM,yBAAyB;mBACf,SAAS,sBAAsB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;mBAcvD,OAAO;QAIlB,CAAC,QAAQ,sBAAsB,GAAG,CAAC,GAAG,SAAS;cAIzC,sBAAsB,GAAG,OAAO;IAI1C,+BAA+B;aACtB,IAAI;EAIb,CAAC;AAEH,eAAe,yBAAyB,CAAC"}
|
|
@@ -10,10 +10,20 @@ type TraceStorageApi = {
|
|
|
10
10
|
export declare const isAvailable: () => boolean;
|
|
11
11
|
export declare const TraceConfig: TraceConfigApi;
|
|
12
12
|
export declare const TraceStorage: TraceStorageApi;
|
|
13
|
+
export declare const registerTraceDashboard: (router: unknown, options?: {
|
|
14
|
+
basePath?: string;
|
|
15
|
+
middleware?: ReadonlyArray<string>;
|
|
16
|
+
}) => void;
|
|
13
17
|
export declare const registerTraceRoutes: (router: unknown, storage: unknown, options?: {
|
|
14
18
|
basePath?: string;
|
|
15
19
|
middleware?: ReadonlyArray<string>;
|
|
16
20
|
}) => void;
|
|
21
|
+
export declare const captureTraceException: (error: unknown, context?: {
|
|
22
|
+
batchId?: string;
|
|
23
|
+
hostname?: string;
|
|
24
|
+
path?: string;
|
|
25
|
+
userId?: string;
|
|
26
|
+
}) => void;
|
|
17
27
|
export declare const ensureSystemTraceRegistered: () => Promise<void>;
|
|
18
28
|
export {};
|
|
19
29
|
//# sourceMappingURL=trace-runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime/plugins/trace-runtime.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC;CACtC,CAAC;
|
|
1
|
+
{"version":3,"file":"trace-runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime/plugins/trace-runtime.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC;CACtC,CAAC;AAwEF,eAAO,MAAM,WAAW,QAAO,OAA0C,CAAC;AAE1E,eAAO,MAAM,WAAW,EAAE,cAIxB,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,eAIzB,CAAC;AAEH,eAAO,MAAM,sBAAsB,GACjC,QAAQ,OAAO,EACf,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,KAClE,IAEF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,OAAO,EACf,SAAS,OAAO,EAChB,UAAU;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,KAClE,IAEF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,OAAO,OAAO,EACd,UAAU;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAChF,IASF,CAAC;AAEF,eAAO,MAAM,2BAA2B,QAAa,OAAO,CAAC,IAAI,CAIhE,CAAC"}
|