@meetploy/cli 1.14.0 → 1.14.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/dist/index.js
CHANGED
|
@@ -54,30 +54,22 @@ async function detectMonorepo(projectDir) {
|
|
|
54
54
|
const hasLerna = await fileExists(join(projectDir, "lerna.json"));
|
|
55
55
|
if (hasLerna) {
|
|
56
56
|
indicators.push("lerna.json");
|
|
57
|
-
|
|
58
|
-
type = "lerna";
|
|
59
|
-
}
|
|
57
|
+
type ??= "lerna";
|
|
60
58
|
}
|
|
61
59
|
const hasNx = await fileExists(join(projectDir, "nx.json"));
|
|
62
60
|
if (hasNx) {
|
|
63
61
|
indicators.push("nx.json");
|
|
64
|
-
|
|
65
|
-
type = "nx";
|
|
66
|
-
}
|
|
62
|
+
type ??= "nx";
|
|
67
63
|
}
|
|
68
64
|
const hasTurbo = await fileExists(join(projectDir, "turbo.json"));
|
|
69
65
|
if (hasTurbo) {
|
|
70
66
|
indicators.push("turbo.json");
|
|
71
|
-
|
|
72
|
-
type = "turbo";
|
|
73
|
-
}
|
|
67
|
+
type ??= "turbo";
|
|
74
68
|
}
|
|
75
69
|
const hasRush = await fileExists(join(projectDir, "rush.json"));
|
|
76
70
|
if (hasRush) {
|
|
77
71
|
indicators.push("rush.json");
|
|
78
|
-
|
|
79
|
-
type = "rush";
|
|
80
|
-
}
|
|
72
|
+
type ??= "rush";
|
|
81
73
|
}
|
|
82
74
|
return {
|
|
83
75
|
isMonorepo: indicators.length > 0,
|
|
@@ -271,7 +263,7 @@ function readAndValidatePloyConfigSync(projectDir, configPath, validationOptions
|
|
|
271
263
|
return validatePloyConfig(config, configFile, validationOptions);
|
|
272
264
|
}
|
|
273
265
|
function hasBindings(config) {
|
|
274
|
-
return !!(config.db
|
|
266
|
+
return !!(config.db ?? config.queue ?? config.cache ?? config.state ?? config.workflow ?? config.ai ?? config.auth);
|
|
275
267
|
}
|
|
276
268
|
function getWorkerEntryPoint(projectDir, config) {
|
|
277
269
|
if (config.main) {
|
|
@@ -1352,16 +1344,15 @@ function createFileWatcher(srcDir, onRebuild) {
|
|
|
1352
1344
|
if (debounceTimer) {
|
|
1353
1345
|
clearTimeout(debounceTimer);
|
|
1354
1346
|
}
|
|
1355
|
-
debounceTimer = setTimeout(
|
|
1347
|
+
debounceTimer = setTimeout(() => {
|
|
1356
1348
|
if (isRebuilding) {
|
|
1357
1349
|
return;
|
|
1358
1350
|
}
|
|
1359
1351
|
isRebuilding = true;
|
|
1360
|
-
|
|
1361
|
-
await onRebuild();
|
|
1362
|
-
} finally {
|
|
1352
|
+
onRebuild().finally(() => {
|
|
1363
1353
|
isRebuilding = false;
|
|
1364
|
-
}
|
|
1354
|
+
}).catch(() => {
|
|
1355
|
+
});
|
|
1365
1356
|
}, 100);
|
|
1366
1357
|
}
|
|
1367
1358
|
return {
|
|
@@ -1402,7 +1393,7 @@ function createFileWatcher(srcDir, onRebuild) {
|
|
|
1402
1393
|
debounceTimer = null;
|
|
1403
1394
|
}
|
|
1404
1395
|
if (watcher) {
|
|
1405
|
-
watcher.close();
|
|
1396
|
+
void watcher.close();
|
|
1406
1397
|
watcher = null;
|
|
1407
1398
|
}
|
|
1408
1399
|
}
|
|
@@ -1425,10 +1416,10 @@ var init_watcher = __esm({
|
|
|
1425
1416
|
function readPloyConfig2(projectDir, configPath) {
|
|
1426
1417
|
const config = readPloyConfigSync(projectDir, configPath);
|
|
1427
1418
|
if (!config.kind) {
|
|
1428
|
-
throw new Error(`Missing required field 'kind' in ${configPath
|
|
1419
|
+
throw new Error(`Missing required field 'kind' in ${configPath ?? "ploy.yaml"}`);
|
|
1429
1420
|
}
|
|
1430
1421
|
if (config.kind !== "dynamic" && config.kind !== "worker") {
|
|
1431
|
-
throw new Error(`Invalid kind '${config.kind}' in ${configPath
|
|
1422
|
+
throw new Error(`Invalid kind '${config.kind}' in ${configPath ?? "ploy.yaml"}. Must be 'dynamic' or 'worker'`);
|
|
1432
1423
|
}
|
|
1433
1424
|
return config;
|
|
1434
1425
|
}
|
|
@@ -1444,7 +1435,7 @@ function generateWorkerdConfig(options) {
|
|
|
1444
1435
|
const { port, mockServicePort } = options;
|
|
1445
1436
|
const services = [
|
|
1446
1437
|
'(name = "main", worker = .worker)',
|
|
1447
|
-
`(name = "mock", external = (address = "localhost:${mockServicePort}", http = ()))`,
|
|
1438
|
+
`(name = "mock", external = (address = "localhost:${String(mockServicePort)}", http = ()))`,
|
|
1448
1439
|
'(name = "internet", network = (allow = ["public", "private", "local"], tlsOptions = (trustBrowserCas = true)))'
|
|
1449
1440
|
];
|
|
1450
1441
|
const bindings = [
|
|
@@ -1458,7 +1449,7 @@ const config :Workerd.Config = (
|
|
|
1458
1449
|
${services.join(",\n ")}
|
|
1459
1450
|
],
|
|
1460
1451
|
sockets = [
|
|
1461
|
-
(name = "http", address = "*:${port}", http = (), service = "main")
|
|
1452
|
+
(name = "http", address = "*:${String(port)}", http = (), service = "main")
|
|
1462
1453
|
]
|
|
1463
1454
|
);
|
|
1464
1455
|
|
|
@@ -1664,7 +1655,7 @@ function createAuthHandlers(db) {
|
|
|
1664
1655
|
return c.json({ error: message }, 500);
|
|
1665
1656
|
}
|
|
1666
1657
|
};
|
|
1667
|
-
const meHandler =
|
|
1658
|
+
const meHandler = (c) => {
|
|
1668
1659
|
try {
|
|
1669
1660
|
const cookieToken = getCookie(c, "ploy_session");
|
|
1670
1661
|
const authHeader = c.req.header("Authorization");
|
|
@@ -1708,7 +1699,7 @@ function createAuthHandlers(db) {
|
|
|
1708
1699
|
return c.json({ error: message }, 500);
|
|
1709
1700
|
}
|
|
1710
1701
|
};
|
|
1711
|
-
const signoutHandler =
|
|
1702
|
+
const signoutHandler = (c) => {
|
|
1712
1703
|
try {
|
|
1713
1704
|
const sessionToken = getCookie(c, "ploy_session");
|
|
1714
1705
|
if (sessionToken) {
|
|
@@ -1823,8 +1814,8 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
1823
1814
|
if (tableName !== "auth_users" && tableName !== "auth_sessions") {
|
|
1824
1815
|
return c.json({ error: "Table not found" }, 404);
|
|
1825
1816
|
}
|
|
1826
|
-
const limit = parseInt(c.req.query("limit")
|
|
1827
|
-
const offset = parseInt(c.req.query("offset")
|
|
1817
|
+
const limit = parseInt(c.req.query("limit") ?? "50", 10);
|
|
1818
|
+
const offset = parseInt(c.req.query("offset") ?? "0", 10);
|
|
1828
1819
|
try {
|
|
1829
1820
|
const db = dbManager2.emulatorDb;
|
|
1830
1821
|
const columnsResult = db.prepare(`PRAGMA table_info("${tableName}")`).all();
|
|
@@ -2036,8 +2027,8 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
2036
2027
|
return c.json({ error: `Database binding '${binding}' not found` }, 404);
|
|
2037
2028
|
}
|
|
2038
2029
|
const tableName = c.req.param("tableName");
|
|
2039
|
-
const limit = parseInt(c.req.query("limit")
|
|
2040
|
-
const offset = parseInt(c.req.query("offset")
|
|
2030
|
+
const limit = parseInt(c.req.query("limit") ?? "50", 10);
|
|
2031
|
+
const offset = parseInt(c.req.query("offset") ?? "0", 10);
|
|
2041
2032
|
try {
|
|
2042
2033
|
const db = dbManager2.getD1Database(resourceName);
|
|
2043
2034
|
const columnsResult = db.prepare(`PRAGMA table_info("${tableName}")`).all();
|
|
@@ -2118,7 +2109,7 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
2118
2109
|
app.get("/api/queue/:binding/messages", (c) => {
|
|
2119
2110
|
const binding = c.req.param("binding");
|
|
2120
2111
|
const queueName = config.queue?.[binding];
|
|
2121
|
-
const limit = parseInt(c.req.query("limit")
|
|
2112
|
+
const limit = parseInt(c.req.query("limit") ?? "10", 10);
|
|
2122
2113
|
if (!queueName) {
|
|
2123
2114
|
return c.json({ error: "Queue not found" }, 404);
|
|
2124
2115
|
}
|
|
@@ -2145,8 +2136,8 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
2145
2136
|
app.get("/api/cache/:binding/entries", (c) => {
|
|
2146
2137
|
const binding = c.req.param("binding");
|
|
2147
2138
|
const cacheName = config.cache?.[binding];
|
|
2148
|
-
const limit = parseInt(c.req.query("limit")
|
|
2149
|
-
const offset = parseInt(c.req.query("offset")
|
|
2139
|
+
const limit = parseInt(c.req.query("limit") ?? "20", 10);
|
|
2140
|
+
const offset = parseInt(c.req.query("offset") ?? "0", 10);
|
|
2150
2141
|
const now = Math.floor(Date.now() / 1e3);
|
|
2151
2142
|
if (!cacheName) {
|
|
2152
2143
|
return c.json({ error: "Cache binding not found" }, 404);
|
|
@@ -2178,9 +2169,9 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
2178
2169
|
app.get("/api/state/:binding/entries", (c) => {
|
|
2179
2170
|
const binding = c.req.param("binding");
|
|
2180
2171
|
const stateName = config.state?.[binding];
|
|
2181
|
-
const limit = parseInt(c.req.query("limit")
|
|
2182
|
-
const offset = parseInt(c.req.query("offset")
|
|
2183
|
-
const search = c.req.query("search")
|
|
2172
|
+
const limit = parseInt(c.req.query("limit") ?? "20", 10);
|
|
2173
|
+
const offset = parseInt(c.req.query("offset") ?? "0", 10);
|
|
2174
|
+
const search = c.req.query("search") ?? "";
|
|
2184
2175
|
if (!stateName) {
|
|
2185
2176
|
return c.json({ error: "State binding not found" }, 404);
|
|
2186
2177
|
}
|
|
@@ -2210,7 +2201,7 @@ function createDashboardRoutes(app, dbManager2, config) {
|
|
|
2210
2201
|
app.get("/api/workflow/:binding/executions", (c) => {
|
|
2211
2202
|
const binding = c.req.param("binding");
|
|
2212
2203
|
const workflowConfig = config.workflow?.[binding];
|
|
2213
|
-
const limit = parseInt(c.req.query("limit")
|
|
2204
|
+
const limit = parseInt(c.req.query("limit") ?? "20", 10);
|
|
2214
2205
|
if (!workflowConfig) {
|
|
2215
2206
|
return c.json({ error: "Workflow not found" }, 404);
|
|
2216
2207
|
}
|
|
@@ -2473,7 +2464,7 @@ function createQueueHandlers(db) {
|
|
|
2473
2464
|
const transaction = db.transaction(() => {
|
|
2474
2465
|
for (const msg of messages) {
|
|
2475
2466
|
const id = randomUUID();
|
|
2476
|
-
const visibleAt = now + (msg.delaySeconds
|
|
2467
|
+
const visibleAt = now + (msg.delaySeconds ?? 0);
|
|
2477
2468
|
insert.run(id, queueName, JSON.stringify(msg.payload), visibleAt);
|
|
2478
2469
|
messageIds.push(id);
|
|
2479
2470
|
}
|
|
@@ -3141,15 +3132,15 @@ var init_emulator = __esm({
|
|
|
3141
3132
|
debug(`Temp dir: ${this.tempDir}`, this.options.verbose);
|
|
3142
3133
|
this.dbManager = initializeDatabases(this.projectDir);
|
|
3143
3134
|
debug("Initialized databases", this.options.verbose);
|
|
3144
|
-
const workerUrl = `http://${this.options.host}:${this.options.port}`;
|
|
3135
|
+
const workerUrl = `http://${this.options.host}:${String(this.options.port)}`;
|
|
3145
3136
|
const dashboardPort = this.options.dashboardPort;
|
|
3146
3137
|
this.mockServer = await startMockServer(this.dbManager, this.config, {
|
|
3147
3138
|
workerUrl,
|
|
3148
3139
|
port: dashboardPort,
|
|
3149
3140
|
dashboardEnabled: true
|
|
3150
3141
|
});
|
|
3151
|
-
debug(`Mock server started on port ${this.mockServer.port}`, this.options.verbose);
|
|
3152
|
-
const mockServiceUrl = `http://localhost:${this.mockServer.port}`;
|
|
3142
|
+
debug(`Mock server started on port ${String(this.mockServer.port)}`, this.options.verbose);
|
|
3143
|
+
const mockServiceUrl = `http://localhost:${String(this.mockServer.port)}`;
|
|
3153
3144
|
const entryPoint = getWorkerEntryPoint2(this.projectDir, this.config);
|
|
3154
3145
|
debug(`Entry point: ${entryPoint}`, this.options.verbose);
|
|
3155
3146
|
await this.bundle(entryPoint, mockServiceUrl);
|
|
@@ -3176,13 +3167,13 @@ var init_emulator = __esm({
|
|
|
3176
3167
|
debug(`Watching ${srcDir} for changes`, this.options.verbose);
|
|
3177
3168
|
}
|
|
3178
3169
|
if (this.config.queue) {
|
|
3179
|
-
const workerUrl2 = `http://${this.options.host}:${this.options.port}`;
|
|
3170
|
+
const workerUrl2 = `http://${this.options.host}:${String(this.options.port)}`;
|
|
3180
3171
|
this.queueProcessor = createQueueProcessor(this.dbManager.emulatorDb, this.config.queue, workerUrl2);
|
|
3181
3172
|
this.queueProcessor.start();
|
|
3182
3173
|
debug("Queue processor started", this.options.verbose);
|
|
3183
3174
|
}
|
|
3184
|
-
success(`Emulator running at http://${this.options.host}:${this.options.port}`);
|
|
3185
|
-
log(` Dashboard: http://${this.options.host}:${this.mockServer.port}`);
|
|
3175
|
+
success(`Emulator running at http://${this.options.host}:${String(this.options.port)}`);
|
|
3176
|
+
log(` Dashboard: http://${this.options.host}:${String(this.mockServer.port)}`);
|
|
3186
3177
|
if (this.config.db) {
|
|
3187
3178
|
log(` DB bindings: ${Object.keys(this.config.db).join(", ")}`);
|
|
3188
3179
|
}
|
|
@@ -3230,7 +3221,7 @@ var init_emulator = __esm({
|
|
|
3230
3221
|
shell: true,
|
|
3231
3222
|
env: {
|
|
3232
3223
|
...process.env,
|
|
3233
|
-
PATH: `${workerdBinDir}:${process.env.PATH
|
|
3224
|
+
PATH: `${workerdBinDir}:${process.env.PATH ?? ""}`
|
|
3234
3225
|
}
|
|
3235
3226
|
});
|
|
3236
3227
|
let started = false;
|
|
@@ -3267,13 +3258,13 @@ var init_emulator = __esm({
|
|
|
3267
3258
|
});
|
|
3268
3259
|
this.workerdProcess.on("exit", (code) => {
|
|
3269
3260
|
if (code !== 0 && code !== null) {
|
|
3270
|
-
error(`workerd exited with code ${code}`);
|
|
3261
|
+
error(`workerd exited with code ${String(code)}`);
|
|
3271
3262
|
if (stderrOutput) {
|
|
3272
3263
|
error(`workerd stderr: ${stderrOutput.trim()}`);
|
|
3273
3264
|
}
|
|
3274
3265
|
}
|
|
3275
3266
|
if (!started) {
|
|
3276
|
-
reject(new Error(`workerd exited with code ${code}`));
|
|
3267
|
+
reject(new Error(`workerd exited with code ${String(code)}`));
|
|
3277
3268
|
}
|
|
3278
3269
|
});
|
|
3279
3270
|
setTimeout(() => {
|
|
@@ -3310,10 +3301,11 @@ var init_emulator = __esm({
|
|
|
3310
3301
|
return this.projectDir;
|
|
3311
3302
|
}
|
|
3312
3303
|
setupSignalHandlers() {
|
|
3313
|
-
const handler =
|
|
3304
|
+
const handler = () => {
|
|
3314
3305
|
log("\nShutting down...");
|
|
3315
|
-
|
|
3316
|
-
|
|
3306
|
+
void this.stop().then(() => {
|
|
3307
|
+
process.exit(0);
|
|
3308
|
+
});
|
|
3317
3309
|
};
|
|
3318
3310
|
process.on("SIGINT", handler);
|
|
3319
3311
|
process.on("SIGTERM", handler);
|
|
@@ -3428,7 +3420,7 @@ function createDevD1(databaseId, apiUrl) {
|
|
|
3428
3420
|
async batch(statements) {
|
|
3429
3421
|
const stmts = statements.map((s) => {
|
|
3430
3422
|
const data = s.__db_data;
|
|
3431
|
-
return data
|
|
3423
|
+
return data ?? s;
|
|
3432
3424
|
});
|
|
3433
3425
|
const response = await fetch(`${apiUrl}/db`, {
|
|
3434
3426
|
method: "POST",
|
|
@@ -3488,7 +3480,7 @@ async function initPloyForDev(config) {
|
|
|
3488
3480
|
globalThis.__PLOY_DEV_INITIALIZED__ = true;
|
|
3489
3481
|
const cliMockServerUrl = process.env.PLOY_MOCK_SERVER_URL;
|
|
3490
3482
|
if (cliMockServerUrl) {
|
|
3491
|
-
const configPath2 = config?.configPath
|
|
3483
|
+
const configPath2 = config?.configPath ?? "./ploy.yaml";
|
|
3492
3484
|
const projectDir2 = process.cwd();
|
|
3493
3485
|
let ployConfig2;
|
|
3494
3486
|
try {
|
|
@@ -3536,7 +3528,7 @@ async function initPloyForDev(config) {
|
|
|
3536
3528
|
console.log(`[Ploy] Using CLI mock server at ${cliMockServerUrl} (${features2.join(", ")})`);
|
|
3537
3529
|
return;
|
|
3538
3530
|
}
|
|
3539
|
-
const configPath = config?.configPath
|
|
3531
|
+
const configPath = config?.configPath ?? "./ploy.yaml";
|
|
3540
3532
|
const projectDir = process.cwd();
|
|
3541
3533
|
let ployConfig;
|
|
3542
3534
|
try {
|
|
@@ -3559,7 +3551,7 @@ async function initPloyForDev(config) {
|
|
|
3559
3551
|
ensureDataDir(projectDir);
|
|
3560
3552
|
dbManager = initializeDatabases(projectDir);
|
|
3561
3553
|
mockServer = await startMockServer(dbManager, ployConfig, {});
|
|
3562
|
-
const apiUrl = `http://localhost:${mockServer.port}`;
|
|
3554
|
+
const apiUrl = `http://localhost:${String(mockServer.port)}`;
|
|
3563
3555
|
const env = {};
|
|
3564
3556
|
if (hasDbBindings && ployConfig.db) {
|
|
3565
3557
|
for (const [bindingName, databaseId] of Object.entries(ployConfig.db)) {
|
|
@@ -3607,13 +3599,15 @@ async function initPloyForDev(config) {
|
|
|
3607
3599
|
dbManager.close();
|
|
3608
3600
|
}
|
|
3609
3601
|
});
|
|
3610
|
-
process.on("SIGINT",
|
|
3611
|
-
|
|
3612
|
-
|
|
3602
|
+
process.on("SIGINT", () => {
|
|
3603
|
+
void cleanup().then(() => {
|
|
3604
|
+
process.exit(0);
|
|
3605
|
+
});
|
|
3613
3606
|
});
|
|
3614
|
-
process.on("SIGTERM",
|
|
3615
|
-
|
|
3616
|
-
|
|
3607
|
+
process.on("SIGTERM", () => {
|
|
3608
|
+
void cleanup().then(() => {
|
|
3609
|
+
process.exit(0);
|
|
3610
|
+
});
|
|
3617
3611
|
});
|
|
3618
3612
|
}
|
|
3619
3613
|
var PLOY_CONTEXT_SYMBOL, mockServer, dbManager;
|
|
@@ -3650,7 +3644,7 @@ async function startDevDashboard(options = {}) {
|
|
|
3650
3644
|
port,
|
|
3651
3645
|
dashboardEnabled: true
|
|
3652
3646
|
});
|
|
3653
|
-
debug(`Mock server started on port ${mockServer2.port}`, verbose);
|
|
3647
|
+
debug(`Mock server started on port ${String(mockServer2.port)}`, verbose);
|
|
3654
3648
|
if (config.db) {
|
|
3655
3649
|
log(` DB bindings: ${Object.keys(config.db).join(", ")}`);
|
|
3656
3650
|
}
|
|
@@ -3945,8 +3939,8 @@ async function listTables(options) {
|
|
|
3945
3939
|
);
|
|
3946
3940
|
if (error2 || !data) {
|
|
3947
3941
|
throw new ApiClientError(
|
|
3948
|
-
error2?.message
|
|
3949
|
-
response
|
|
3942
|
+
error2?.message ?? "Failed to fetch tables",
|
|
3943
|
+
response.status
|
|
3950
3944
|
);
|
|
3951
3945
|
}
|
|
3952
3946
|
const tablesResult = data;
|
|
@@ -3967,13 +3961,13 @@ async function listTables(options) {
|
|
|
3967
3961
|
});
|
|
3968
3962
|
if (schemaError || !schemaData) {
|
|
3969
3963
|
throw new ApiClientError(
|
|
3970
|
-
schemaError?.message
|
|
3971
|
-
schemaResponse
|
|
3964
|
+
schemaError?.message ?? "Failed to fetch schema",
|
|
3965
|
+
schemaResponse.status
|
|
3972
3966
|
);
|
|
3973
3967
|
}
|
|
3974
3968
|
const schemaResult = schemaData;
|
|
3975
3969
|
for (const table of schemaResult.tables) {
|
|
3976
|
-
console.log(`Table: ${table.name}`);
|
|
3970
|
+
console.log(`Table: ${String(table.name)}`);
|
|
3977
3971
|
console.log("-".repeat(40));
|
|
3978
3972
|
console.log(
|
|
3979
3973
|
" " + "COLUMN".padEnd(20) + "TYPE".padEnd(15) + "NULLABLE".padEnd(10) + "PK"
|
|
@@ -3983,7 +3977,7 @@ async function listTables(options) {
|
|
|
3983
3977
|
const nullable = col.notNull ? "NO" : "YES";
|
|
3984
3978
|
const pk = col.primaryKey ? "YES" : "";
|
|
3985
3979
|
console.log(
|
|
3986
|
-
" " + col.name.padEnd(20) + col.type.padEnd(15) + nullable.padEnd(10) + pk
|
|
3980
|
+
" " + String(col.name).padEnd(20) + String(col.type).padEnd(15) + nullable.padEnd(10) + pk
|
|
3987
3981
|
);
|
|
3988
3982
|
}
|
|
3989
3983
|
console.log("");
|
|
@@ -3992,7 +3986,7 @@ async function listTables(options) {
|
|
|
3992
3986
|
console.log("NAME".padEnd(30) + "ROWS".padEnd(12) + "SIZE");
|
|
3993
3987
|
console.log("-".repeat(55));
|
|
3994
3988
|
for (const table of tablesResult.tables) {
|
|
3995
|
-
console.log(table.name.padEnd(30) + "-".padEnd(12) + "-");
|
|
3989
|
+
console.log(String(table.name).padEnd(30) + "-".padEnd(12) + "-");
|
|
3996
3990
|
}
|
|
3997
3991
|
}
|
|
3998
3992
|
console.log("");
|
|
@@ -4044,23 +4038,23 @@ async function viewAnalytics(options) {
|
|
|
4044
4038
|
);
|
|
4045
4039
|
if (error2 || !data) {
|
|
4046
4040
|
throw new ApiClientError(
|
|
4047
|
-
error2?.message
|
|
4048
|
-
response
|
|
4041
|
+
error2?.message ?? "Failed to fetch analytics",
|
|
4042
|
+
response.status
|
|
4049
4043
|
);
|
|
4050
4044
|
}
|
|
4051
4045
|
const insightsResult = data;
|
|
4052
4046
|
console.log("Database Analytics");
|
|
4053
4047
|
console.log("==================");
|
|
4054
4048
|
console.log("");
|
|
4055
|
-
console.log(` Period: ${insightsResult.timeRange}`);
|
|
4049
|
+
console.log(` Period: ${String(insightsResult.timeRange)}`);
|
|
4056
4050
|
console.log(
|
|
4057
|
-
` Total Queries: ${insightsResult.summary.totalQueries.toLocaleString()}`
|
|
4051
|
+
` Total Queries: ${String(insightsResult.summary.totalQueries.toLocaleString())}`
|
|
4058
4052
|
);
|
|
4059
4053
|
console.log(
|
|
4060
|
-
` Total Rows Read: ${insightsResult.summary.totalRowsRead.toLocaleString()}`
|
|
4054
|
+
` Total Rows Read: ${String(insightsResult.summary.totalRowsRead.toLocaleString())}`
|
|
4061
4055
|
);
|
|
4062
4056
|
console.log(
|
|
4063
|
-
` Total Rows Written: ${insightsResult.summary.totalRowsWritten.toLocaleString()}`
|
|
4057
|
+
` Total Rows Written: ${String(insightsResult.summary.totalRowsWritten.toLocaleString())}`
|
|
4064
4058
|
);
|
|
4065
4059
|
const avgDuration = insightsResult.summary.totalQueries > 0 ? insightsResult.summary.totalDurationMs / insightsResult.summary.totalQueries : 0;
|
|
4066
4060
|
console.log(` Avg Query Duration: ${avgDuration.toFixed(2)}ms`);
|
|
@@ -4071,15 +4065,21 @@ async function viewAnalytics(options) {
|
|
|
4071
4065
|
console.log("");
|
|
4072
4066
|
for (let i = 0; i < insightsResult.topQueries.length; i++) {
|
|
4073
4067
|
const insight = insightsResult.topQueries[i];
|
|
4074
|
-
console.log(`${i + 1}. ${truncateQuery(insight.queryText, 60)}`);
|
|
4075
|
-
console.log(` Calls: ${insight.totalCalls.toLocaleString()}`);
|
|
4076
|
-
console.log(` Avg Duration: ${insight.avgDurationMs.toFixed(2)}ms`);
|
|
4077
4068
|
console.log(
|
|
4078
|
-
|
|
4069
|
+
`${String(i + 1)}. ${truncateQuery(String(insight.queryText), 60)}`
|
|
4079
4070
|
);
|
|
4080
|
-
console.log(`
|
|
4071
|
+
console.log(` Calls: ${String(insight.totalCalls.toLocaleString())}`);
|
|
4081
4072
|
console.log(
|
|
4082
|
-
`
|
|
4073
|
+
` Avg Duration: ${String(insight.avgDurationMs.toFixed(2))}ms`
|
|
4074
|
+
);
|
|
4075
|
+
console.log(
|
|
4076
|
+
` Total Duration: ${String(insight.totalDurationMs.toFixed(2))}ms`
|
|
4077
|
+
);
|
|
4078
|
+
console.log(
|
|
4079
|
+
` Rows Read: ${String(insight.totalRowsRead.toLocaleString())}`
|
|
4080
|
+
);
|
|
4081
|
+
console.log(
|
|
4082
|
+
` Rows Written: ${String(insight.totalRowsWritten.toLocaleString())}`
|
|
4083
4083
|
);
|
|
4084
4084
|
console.log("");
|
|
4085
4085
|
}
|
|
@@ -4118,8 +4118,8 @@ async function listDatabases(options) {
|
|
|
4118
4118
|
);
|
|
4119
4119
|
if (error2 || !data) {
|
|
4120
4120
|
throw new ApiClientError(
|
|
4121
|
-
error2?.message
|
|
4122
|
-
response
|
|
4121
|
+
error2?.message ?? "Failed to list databases",
|
|
4122
|
+
response.status
|
|
4123
4123
|
);
|
|
4124
4124
|
}
|
|
4125
4125
|
const databases = data.databases;
|
|
@@ -4136,10 +4136,10 @@ async function listDatabases(options) {
|
|
|
4136
4136
|
);
|
|
4137
4137
|
console.log("-".repeat(80));
|
|
4138
4138
|
for (const db of databases) {
|
|
4139
|
-
const id = db.id.substring(0, Math.min(24, db.id.length));
|
|
4140
|
-
const name = db.name.substring(0, Math.min(23, db.name.length)).padEnd(25);
|
|
4141
|
-
const region = (db.region || "-").padEnd(15);
|
|
4142
|
-
const created = db.createdAt ? new Date(db.createdAt).toLocaleDateString() : "-";
|
|
4139
|
+
const id = String(db.id).substring(0, Math.min(24, String(db.id).length));
|
|
4140
|
+
const name = String(db.name).substring(0, Math.min(23, String(db.name).length)).padEnd(25);
|
|
4141
|
+
const region = (String(db.region) || "-").padEnd(15);
|
|
4142
|
+
const created = db.createdAt ? new Date(String(db.createdAt)).toLocaleDateString() : "-";
|
|
4143
4143
|
console.log(`${id} ${name}${region}${created}`);
|
|
4144
4144
|
}
|
|
4145
4145
|
console.log("");
|
|
@@ -4286,8 +4286,8 @@ async function retryDeployment(deploymentId) {
|
|
|
4286
4286
|
);
|
|
4287
4287
|
if (error2 || !data) {
|
|
4288
4288
|
throw new ApiClientError(
|
|
4289
|
-
error2?.message
|
|
4290
|
-
response
|
|
4289
|
+
error2?.message ?? "Failed to retry deployment",
|
|
4290
|
+
response.status
|
|
4291
4291
|
);
|
|
4292
4292
|
}
|
|
4293
4293
|
const retryResult = data;
|
|
@@ -4325,8 +4325,8 @@ async function viewDeploymentLogs(deploymentId, _options) {
|
|
|
4325
4325
|
);
|
|
4326
4326
|
if (error2 || !data) {
|
|
4327
4327
|
throw new ApiClientError(
|
|
4328
|
-
error2?.message
|
|
4329
|
-
response
|
|
4328
|
+
error2?.message ?? "Failed to fetch logs",
|
|
4329
|
+
response.status
|
|
4330
4330
|
);
|
|
4331
4331
|
}
|
|
4332
4332
|
const logsResult = data;
|
|
@@ -4363,8 +4363,8 @@ async function viewDeployment(deploymentId, _options) {
|
|
|
4363
4363
|
);
|
|
4364
4364
|
if (error2 || !data) {
|
|
4365
4365
|
throw new ApiClientError(
|
|
4366
|
-
error2?.message
|
|
4367
|
-
response
|
|
4366
|
+
error2?.message ?? "Failed to fetch deployment",
|
|
4367
|
+
response.status
|
|
4368
4368
|
);
|
|
4369
4369
|
}
|
|
4370
4370
|
const deployment = data.deployment;
|
|
@@ -4426,14 +4426,14 @@ async function listDeployments(options) {
|
|
|
4426
4426
|
query: {
|
|
4427
4427
|
projectId: options.projectId,
|
|
4428
4428
|
branch: options.branch,
|
|
4429
|
-
limit: options.limit?.toString()
|
|
4429
|
+
limit: options.limit?.toString() ?? "20"
|
|
4430
4430
|
}
|
|
4431
4431
|
}
|
|
4432
4432
|
});
|
|
4433
4433
|
if (error2 || !data) {
|
|
4434
4434
|
throw new ApiClientError(
|
|
4435
|
-
error2?.message
|
|
4436
|
-
response
|
|
4435
|
+
error2?.message ?? "Failed to list deployments",
|
|
4436
|
+
response.status
|
|
4437
4437
|
);
|
|
4438
4438
|
}
|
|
4439
4439
|
const deployments = data.deployments;
|
|
@@ -4452,7 +4452,7 @@ async function listDeployments(options) {
|
|
|
4452
4452
|
for (const d of deployments) {
|
|
4453
4453
|
const id = d.id.substring(0, Math.min(10, d.id.length));
|
|
4454
4454
|
const status = d.status.padEnd(10);
|
|
4455
|
-
const branchSource = d.branch
|
|
4455
|
+
const branchSource = d.branch ?? "-";
|
|
4456
4456
|
const branch = branchSource.substring(0, Math.min(18, branchSource.length)).padEnd(20);
|
|
4457
4457
|
const commit = d.commitSha ? d.commitSha.substring(0, Math.min(8, d.commitSha.length)) : "-";
|
|
4458
4458
|
const created = new Date(d.createdAt).toLocaleDateString();
|
|
@@ -4705,7 +4705,9 @@ async function exchangeCodeForToken(apiUrl, code, redirectUri) {
|
|
|
4705
4705
|
});
|
|
4706
4706
|
if (!response.ok) {
|
|
4707
4707
|
const errorBody = await response.text();
|
|
4708
|
-
throw new Error(
|
|
4708
|
+
throw new Error(
|
|
4709
|
+
`Token exchange failed: ${String(response.status)} - ${errorBody}`
|
|
4710
|
+
);
|
|
4709
4711
|
}
|
|
4710
4712
|
return await response.json();
|
|
4711
4713
|
}
|
|
@@ -4729,43 +4731,46 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4729
4731
|
},
|
|
4730
4732
|
5 * 60 * 1e3
|
|
4731
4733
|
);
|
|
4732
|
-
server = createServer(
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4734
|
+
server = createServer((req, res) => {
|
|
4735
|
+
void (async () => {
|
|
4736
|
+
const reqUrl = new URL(
|
|
4737
|
+
req.url ?? "/",
|
|
4738
|
+
`http://${CALLBACK_HOST}:${String(CALLBACK_PORT)}`
|
|
4739
|
+
);
|
|
4740
|
+
if (reqUrl.pathname !== "/callback") {
|
|
4741
|
+
res.writeHead(404);
|
|
4742
|
+
res.end("Not found");
|
|
4743
|
+
return;
|
|
4744
|
+
}
|
|
4745
|
+
const code = reqUrl.searchParams.get("code");
|
|
4746
|
+
const state = reqUrl.searchParams.get("state");
|
|
4747
|
+
const error2 = reqUrl.searchParams.get("error");
|
|
4748
|
+
const errorDescription = reqUrl.searchParams.get("error_description");
|
|
4749
|
+
if (error2) {
|
|
4750
|
+
clearTimeout(timeout);
|
|
4751
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
4752
|
+
res.end(`
|
|
4750
4753
|
<!DOCTYPE html>
|
|
4751
4754
|
<html>
|
|
4752
4755
|
<head><title>Login Failed</title></head>
|
|
4753
4756
|
<body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
4754
4757
|
<h1>Login Failed</h1>
|
|
4755
4758
|
<p>Error: ${error2}</p>
|
|
4756
|
-
<p>${errorDescription
|
|
4759
|
+
<p>${errorDescription ?? ""}</p>
|
|
4757
4760
|
<p>You can close this window.</p>
|
|
4758
4761
|
</body>
|
|
4759
4762
|
</html>
|
|
4760
4763
|
`);
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4764
|
+
server?.close();
|
|
4765
|
+
reject(
|
|
4766
|
+
new Error(`OAuth error: ${error2} - ${errorDescription ?? ""}`)
|
|
4767
|
+
);
|
|
4768
|
+
return;
|
|
4769
|
+
}
|
|
4770
|
+
if (!code) {
|
|
4771
|
+
clearTimeout(timeout);
|
|
4772
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
4773
|
+
res.end(`
|
|
4769
4774
|
<!DOCTYPE html>
|
|
4770
4775
|
<html>
|
|
4771
4776
|
<head><title>Login Failed</title></head>
|
|
@@ -4776,14 +4781,14 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4776
4781
|
</body>
|
|
4777
4782
|
</html>
|
|
4778
4783
|
`);
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4784
|
+
server?.close();
|
|
4785
|
+
reject(new Error("No authorization code received"));
|
|
4786
|
+
return;
|
|
4787
|
+
}
|
|
4788
|
+
if (state !== expectedState) {
|
|
4789
|
+
clearTimeout(timeout);
|
|
4790
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
4791
|
+
res.end(`
|
|
4787
4792
|
<!DOCTYPE html>
|
|
4788
4793
|
<html>
|
|
4789
4794
|
<head><title>Login Failed</title></head>
|
|
@@ -4794,20 +4799,20 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4794
4799
|
</body>
|
|
4795
4800
|
</html>
|
|
4796
4801
|
`);
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4802
|
+
server?.close();
|
|
4803
|
+
reject(new Error("State mismatch - possible CSRF attack"));
|
|
4804
|
+
return;
|
|
4805
|
+
}
|
|
4806
|
+
try {
|
|
4807
|
+
const redirectUri = `http://${CALLBACK_HOST}:${String(CALLBACK_PORT)}/callback`;
|
|
4808
|
+
const tokenResponse = await exchangeCodeForToken(
|
|
4809
|
+
apiUrl,
|
|
4810
|
+
code,
|
|
4811
|
+
redirectUri
|
|
4812
|
+
);
|
|
4813
|
+
clearTimeout(timeout);
|
|
4814
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
4815
|
+
res.end(`
|
|
4811
4816
|
<!DOCTYPE html>
|
|
4812
4817
|
<html>
|
|
4813
4818
|
<head><title>Login Successful</title></head>
|
|
@@ -4818,12 +4823,12 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4818
4823
|
</body>
|
|
4819
4824
|
</html>
|
|
4820
4825
|
`);
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4826
|
+
server?.close();
|
|
4827
|
+
resolve(tokenResponse);
|
|
4828
|
+
} catch (err) {
|
|
4829
|
+
clearTimeout(timeout);
|
|
4830
|
+
res.writeHead(500, { "Content-Type": "text/html" });
|
|
4831
|
+
res.end(`
|
|
4827
4832
|
<!DOCTYPE html>
|
|
4828
4833
|
<html>
|
|
4829
4834
|
<head><title>Login Failed</title></head>
|
|
@@ -4835,15 +4840,16 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4835
4840
|
</body>
|
|
4836
4841
|
</html>
|
|
4837
4842
|
`);
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4843
|
+
server?.close();
|
|
4844
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4845
|
+
}
|
|
4846
|
+
})();
|
|
4841
4847
|
});
|
|
4842
4848
|
server.on("error", (err) => {
|
|
4843
4849
|
clearTimeout(timeout);
|
|
4844
4850
|
if (err.code === "EADDRINUSE") {
|
|
4845
4851
|
const portError = new Error(
|
|
4846
|
-
`Port ${CALLBACK_PORT} is already in use. Please close any other process using this port and try again.`
|
|
4852
|
+
`Port ${String(CALLBACK_PORT)} is already in use. Please close any other process using this port and try again.`
|
|
4847
4853
|
);
|
|
4848
4854
|
reject(portError);
|
|
4849
4855
|
rejectListening(portError);
|
|
@@ -4862,9 +4868,9 @@ function createCallbackServer(expectedState, apiUrl) {
|
|
|
4862
4868
|
return { tokenPromise, waitForListening };
|
|
4863
4869
|
}
|
|
4864
4870
|
async function loginCommand(options = {}) {
|
|
4865
|
-
const apiUrl = options.apiUrl
|
|
4871
|
+
const apiUrl = options.apiUrl ?? await getApiUrl();
|
|
4866
4872
|
const state = generateState();
|
|
4867
|
-
const redirectUri = `http://${CALLBACK_HOST}:${CALLBACK_PORT}/callback`;
|
|
4873
|
+
const redirectUri = `http://${CALLBACK_HOST}:${String(CALLBACK_PORT)}/callback`;
|
|
4868
4874
|
console.log("Starting login flow...");
|
|
4869
4875
|
console.log("");
|
|
4870
4876
|
const authUrl = new URL(`${apiUrl}/oauth/authorize`);
|