@geekmidas/cli 10.0.0-alpha.45 → 10.0.0-alpha.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -183
- package/dist/{OpenApiTsGenerator-B4Kj_qNU.cjs → OpenApiTsGenerator-BN0PIZxd.cjs} +17 -71
- package/dist/OpenApiTsGenerator-BN0PIZxd.cjs.map +1 -0
- package/dist/{OpenApiTsGenerator-CEh3EKN3.mjs → OpenApiTsGenerator-BzIGy8KE.mjs} +17 -71
- package/dist/OpenApiTsGenerator-BzIGy8KE.mjs.map +1 -0
- package/dist/backends-B9V2XD2M.cjs +82 -0
- package/dist/backends-B9V2XD2M.cjs.map +1 -0
- package/dist/backends-CSuLl0YP.mjs +59 -0
- package/dist/backends-CSuLl0YP.mjs.map +1 -0
- package/dist/{config-CJ-PAb7M.cjs → config-CsYSyUya.cjs} +3 -3
- package/dist/{config-CJ-PAb7M.cjs.map → config-CsYSyUya.cjs.map} +1 -1
- package/dist/{config-5watB1D0.mjs → config-D8J5rrTb.mjs} +3 -3
- package/dist/{config-5watB1D0.mjs.map → config-D8J5rrTb.mjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +2 -2
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +2 -2
- package/dist/{discover-BLhf7V_J.mjs → discover-Cf2jAcgF.mjs} +4 -56
- package/dist/discover-Cf2jAcgF.mjs.map +1 -0
- package/dist/{discover-B0f_kuNN.cjs → discover-DXNviAh-.cjs} +3 -79
- package/dist/discover-DXNviAh-.cjs.map +1 -0
- package/dist/{emit-Bzq7JsMP.mjs → emit-C1e8qD08.mjs} +12 -43
- package/dist/emit-C1e8qD08.mjs.map +1 -0
- package/dist/{emit-BdoPFjZf.cjs → emit-Dmc1nvdS.cjs} +11 -54
- package/dist/emit-Dmc1nvdS.cjs.map +1 -0
- package/dist/encryption-C7OGMve_.cjs +91 -0
- package/dist/encryption-C7OGMve_.cjs.map +1 -0
- package/dist/encryption-DyQnPsZN.mjs +90 -0
- package/dist/encryption-DyQnPsZN.mjs.map +1 -0
- package/dist/{github-D5MthUlR.mjs → github-BfpadQWQ.mjs} +3 -3
- package/dist/{github-D5MthUlR.mjs.map → github-BfpadQWQ.mjs.map} +1 -1
- package/dist/{github-BAr8WGkR.cjs → github-BrI1tv6u.cjs} +3 -3
- package/dist/{github-BAr8WGkR.cjs.map → github-BrI1tv6u.cjs.map} +1 -1
- package/dist/{index-B3PeGOQp.d.cts → index-BQhJXpaQ.d.mts} +2 -2
- package/dist/{index-B3PeGOQp.d.cts.map → index-BQhJXpaQ.d.mts.map} +1 -1
- package/dist/{index-BOyaGcCm.d.mts → index-DHJePE0y.d.cts} +2 -2
- package/dist/{index-BOyaGcCm.d.mts.map → index-DHJePE0y.d.cts.map} +1 -1
- package/dist/index.cjs +444 -670
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +442 -668
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-PJi4b1ga.cjs → migrate-BgEY9pdP.cjs} +5 -5
- package/dist/{migrate-PJi4b1ga.cjs.map → migrate-BgEY9pdP.cjs.map} +1 -1
- package/dist/{migrate-BRklCm7b.mjs → migrate-DhxTIA0z.mjs} +5 -5
- package/dist/{migrate-BRklCm7b.mjs.map → migrate-DhxTIA0z.mjs.map} +1 -1
- package/dist/openapi.cjs +2 -2
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +2 -2
- package/dist/{ready-ZqOuNvKD.mjs → ready-WfT-eWlm.mjs} +50 -8
- package/dist/ready-WfT-eWlm.mjs.map +1 -0
- package/dist/{ready-3RfHxdA0.cjs → ready-lr2Fm-ep.cjs} +68 -8
- package/dist/ready-lr2Fm-ep.cjs.map +1 -0
- package/dist/reconcile/public.cjs +2 -4
- package/dist/reconcile/public.d.cts +6 -10
- package/dist/reconcile/public.d.cts.map +1 -1
- package/dist/reconcile/public.d.mts +6 -10
- package/dist/reconcile/public.d.mts.map +1 -1
- package/dist/reconcile/public.mjs +3 -3
- package/dist/{types-0R124hrY.d.mts → types-BbrNu83u.d.mts} +14 -109
- package/dist/{types-0R124hrY.d.mts.map → types-BbrNu83u.d.mts.map} +1 -1
- package/dist/{types-DfdYe31u.d.cts → types-DNqEsctD.d.cts} +14 -109
- package/dist/{types-DfdYe31u.d.cts.map → types-DNqEsctD.d.cts.map} +1 -1
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-RYSYtHP7.cjs → workspace-DEibcoBe.cjs} +11 -25
- package/dist/{workspace-RYSYtHP7.cjs.map → workspace-DEibcoBe.cjs.map} +1 -1
- package/dist/{workspace-DOmIhiau.mjs → workspace-DNzWgM1J.mjs} +11 -25
- package/dist/{workspace-DOmIhiau.mjs.map → workspace-DNzWgM1J.mjs.map} +1 -1
- package/dist/{workspace-BKytVCzb.mjs → workspace-cb6U29EL.mjs} +59 -81
- package/dist/workspace-cb6U29EL.mjs.map +1 -0
- package/dist/{workspace-dV6f-3vv.cjs → workspace-vafrzZTC.cjs} +65 -105
- package/dist/workspace-vafrzZTC.cjs.map +1 -0
- package/package.json +14 -14
- package/dist/OpenApiTsGenerator-B4Kj_qNU.cjs.map +0 -1
- package/dist/OpenApiTsGenerator-CEh3EKN3.mjs.map +0 -1
- package/dist/discover-B0f_kuNN.cjs.map +0 -1
- package/dist/discover-BLhf7V_J.mjs.map +0 -1
- package/dist/emit-BdoPFjZf.cjs.map +0 -1
- package/dist/emit-Bzq7JsMP.mjs.map +0 -1
- package/dist/ready-3RfHxdA0.cjs.map +0 -1
- package/dist/ready-ZqOuNvKD.mjs.map +0 -1
- package/dist/workspace-BKytVCzb.mjs.map +0 -1
- package/dist/workspace-dV6f-3vv.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
4
|
-
const require_discover = require("./discover-
|
|
5
|
-
const require_config = require("./config-
|
|
6
|
-
const require_workspace = require("./workspace-
|
|
4
|
+
const require_discover = require("./discover-DXNviAh-.cjs");
|
|
5
|
+
const require_config = require("./config-CsYSyUya.cjs");
|
|
6
|
+
const require_workspace = require("./workspace-DEibcoBe.cjs");
|
|
7
7
|
const require_storage = require("./storage-CSGoC3bK.cjs");
|
|
8
8
|
const require_store = require("./store-DQgxT_WR.cjs");
|
|
9
|
-
const require_workspace$1 = require("./workspace-
|
|
10
|
-
const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-
|
|
9
|
+
const require_workspace$1 = require("./workspace-vafrzZTC.cjs");
|
|
10
|
+
const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-BN0PIZxd.cjs");
|
|
11
11
|
const require_openapi = require("./openapi.cjs");
|
|
12
|
-
const require_ready = require("./ready-
|
|
13
|
-
const
|
|
12
|
+
const require_ready = require("./ready-lr2Fm-ep.cjs");
|
|
13
|
+
const require_backends = require("./backends-B9V2XD2M.cjs");
|
|
14
|
+
const require_emit = require("./emit-Dmc1nvdS.cjs");
|
|
14
15
|
let commander = require("commander");
|
|
15
16
|
let node_process = require("node:process");
|
|
16
17
|
let node_readline_promises = require("node:readline/promises");
|
|
@@ -28,6 +29,7 @@ let chokidar = require("chokidar");
|
|
|
28
29
|
chokidar = require_rolldown_runtime.__toESM(chokidar, 1);
|
|
29
30
|
let node_crypto = require("node:crypto");
|
|
30
31
|
let node_url = require("node:url");
|
|
32
|
+
let _geekmidas_constructs_encryption = require("@geekmidas/constructs/encryption");
|
|
31
33
|
let _geekmidas_db_pg_roles = require("@geekmidas/db/pg/roles");
|
|
32
34
|
let pg = require("pg");
|
|
33
35
|
let yaml = require("yaml");
|
|
@@ -46,7 +48,7 @@ let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
|
|
|
46
48
|
let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
|
|
47
49
|
let node_dns_promises = require("node:dns/promises");
|
|
48
50
|
//#region package.json
|
|
49
|
-
var version = "10.0.0-alpha.
|
|
51
|
+
var version = "10.0.0-alpha.47";
|
|
50
52
|
//#endregion
|
|
51
53
|
//#region src/auth/credentials.ts
|
|
52
54
|
/**
|
|
@@ -180,7 +182,7 @@ async function getHostingerToken(options) {
|
|
|
180
182
|
}
|
|
181
183
|
//#endregion
|
|
182
184
|
//#region src/auth/index.ts
|
|
183
|
-
const logger$
|
|
185
|
+
const logger$12 = console;
|
|
184
186
|
/**
|
|
185
187
|
* Validate Dokploy token by making a test API call
|
|
186
188
|
*/
|
|
@@ -247,52 +249,52 @@ async function prompt$1(message, hidden = false) {
|
|
|
247
249
|
async function loginCommand(options) {
|
|
248
250
|
const { provider, token: providedToken, endpoint: providedEndpoint } = options;
|
|
249
251
|
if (provider === "dokploy") {
|
|
250
|
-
logger$
|
|
252
|
+
logger$12.log("\n🔐 Logging in to Dokploy...\n");
|
|
251
253
|
let endpoint = providedEndpoint;
|
|
252
254
|
if (!endpoint) endpoint = await prompt$1("Dokploy URL (e.g., https://dokploy.example.com): ");
|
|
253
255
|
endpoint = endpoint.replace(/\/$/, "");
|
|
254
256
|
try {
|
|
255
257
|
new URL(endpoint);
|
|
256
258
|
} catch {
|
|
257
|
-
logger$
|
|
259
|
+
logger$12.error("Invalid URL format");
|
|
258
260
|
process.exit(1);
|
|
259
261
|
}
|
|
260
262
|
let token = providedToken;
|
|
261
263
|
if (!token) {
|
|
262
|
-
logger$
|
|
264
|
+
logger$12.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
|
|
263
265
|
token = await prompt$1("API Token: ", true);
|
|
264
266
|
}
|
|
265
267
|
if (!token) {
|
|
266
|
-
logger$
|
|
268
|
+
logger$12.error("Token is required");
|
|
267
269
|
process.exit(1);
|
|
268
270
|
}
|
|
269
|
-
logger$
|
|
271
|
+
logger$12.log("\nValidating credentials...");
|
|
270
272
|
if (!await validateDokployToken(endpoint, token)) {
|
|
271
|
-
logger$
|
|
273
|
+
logger$12.error("\n✗ Invalid credentials. Please check your token and try again.");
|
|
272
274
|
process.exit(1);
|
|
273
275
|
}
|
|
274
276
|
await storeDokployCredentials(token, endpoint);
|
|
275
|
-
logger$
|
|
276
|
-
logger$
|
|
277
|
-
logger$
|
|
278
|
-
logger$
|
|
277
|
+
logger$12.log("\n✓ Successfully logged in to Dokploy!");
|
|
278
|
+
logger$12.log(` Endpoint: ${endpoint}`);
|
|
279
|
+
logger$12.log(` Credentials stored in: ${getCredentialsPath()}`);
|
|
280
|
+
logger$12.log("\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.");
|
|
279
281
|
}
|
|
280
282
|
if (provider === "hostinger") {
|
|
281
|
-
logger$
|
|
283
|
+
logger$12.log("\n🔐 Logging in to Hostinger...\n");
|
|
282
284
|
let token = providedToken;
|
|
283
285
|
if (!token) {
|
|
284
|
-
logger$
|
|
286
|
+
logger$12.log("\nGenerate a token at: https://hpanel.hostinger.com/profile/api\n");
|
|
285
287
|
token = await prompt$1("API Token: ", true);
|
|
286
288
|
}
|
|
287
289
|
if (!token) {
|
|
288
|
-
logger$
|
|
290
|
+
logger$12.error("Token is required");
|
|
289
291
|
process.exit(1);
|
|
290
292
|
}
|
|
291
293
|
await storeHostingerToken(token);
|
|
292
|
-
logger$
|
|
293
|
-
logger$
|
|
294
|
-
logger$
|
|
295
|
-
logger$
|
|
294
|
+
logger$12.log("\n✓ Hostinger token stored.");
|
|
295
|
+
logger$12.log(` Credentials stored in: ${getCredentialsPath()}`);
|
|
296
|
+
logger$12.log(" Not validated here: every DNS endpoint is scoped to a domain, so the\n first deploy that touches DNS is where a bad token reports itself.");
|
|
297
|
+
logger$12.log("\nYou can now use it as a DNS provider without setting HOSTINGER_API_TOKEN.");
|
|
296
298
|
}
|
|
297
299
|
}
|
|
298
300
|
/**
|
|
@@ -301,27 +303,27 @@ async function loginCommand(options) {
|
|
|
301
303
|
async function logoutCommand(options) {
|
|
302
304
|
const { provider = "dokploy" } = options;
|
|
303
305
|
if (provider === "all") {
|
|
304
|
-
if (await removeDokployCredentials()) logger$
|
|
305
|
-
else logger$
|
|
306
|
+
if (await removeDokployCredentials()) logger$12.log("\n✓ Logged out from all services");
|
|
307
|
+
else logger$12.log("\nNo stored credentials found");
|
|
306
308
|
return;
|
|
307
309
|
}
|
|
308
310
|
if (provider === "dokploy") {
|
|
309
|
-
if (await removeDokployCredentials()) logger$
|
|
310
|
-
else logger$
|
|
311
|
+
if (await removeDokployCredentials()) logger$12.log("\n✓ Logged out from Dokploy");
|
|
312
|
+
else logger$12.log("\nNo Dokploy credentials found");
|
|
311
313
|
}
|
|
312
314
|
}
|
|
313
315
|
/**
|
|
314
316
|
* Show current login status
|
|
315
317
|
*/
|
|
316
318
|
async function whoamiCommand() {
|
|
317
|
-
logger$
|
|
319
|
+
logger$12.log("\n📋 Current credentials:\n");
|
|
318
320
|
const dokploy = await getDokployCredentials();
|
|
319
321
|
if (dokploy) {
|
|
320
|
-
logger$
|
|
321
|
-
logger$
|
|
322
|
-
logger$
|
|
323
|
-
} else logger$
|
|
324
|
-
logger$
|
|
322
|
+
logger$12.log(" Dokploy:");
|
|
323
|
+
logger$12.log(` Endpoint: ${dokploy.endpoint}`);
|
|
324
|
+
logger$12.log(` Token: ${maskToken(dokploy.token)}`);
|
|
325
|
+
} else logger$12.log(" Dokploy: Not logged in");
|
|
326
|
+
logger$12.log(`\n Credentials file: ${getCredentialsPath()}`);
|
|
325
327
|
}
|
|
326
328
|
/**
|
|
327
329
|
* Mask a token for display
|
|
@@ -331,85 +333,14 @@ function maskToken(token) {
|
|
|
331
333
|
return `${token.slice(0, 4)}...${token.slice(-4)}`;
|
|
332
334
|
}
|
|
333
335
|
//#endregion
|
|
334
|
-
//#region src/build/providerResolver.ts
|
|
335
|
-
/**
|
|
336
|
-
* Resolves provider configuration from the new simplified system
|
|
337
|
-
* to the internal legacy format for backward compatibility
|
|
338
|
-
*/
|
|
339
|
-
function resolveProviders(config, options) {
|
|
340
|
-
const providers = [];
|
|
341
|
-
let enableOpenApi = options.enableOpenApi || false;
|
|
342
|
-
if (options.providers) return {
|
|
343
|
-
providers: options.providers,
|
|
344
|
-
enableOpenApi
|
|
345
|
-
};
|
|
346
|
-
if (options.provider) {
|
|
347
|
-
const resolvedProviders = resolveMainProvider(options.provider, config.providers);
|
|
348
|
-
providers.push(...resolvedProviders.providers);
|
|
349
|
-
enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
|
|
350
|
-
} else if (config.providers) {
|
|
351
|
-
const resolvedProviders = resolveAllConfiguredProviders(config.providers);
|
|
352
|
-
providers.push(...resolvedProviders.providers);
|
|
353
|
-
enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
|
|
354
|
-
} else providers.push("aws-apigatewayv2", "aws-lambda");
|
|
355
|
-
return {
|
|
356
|
-
providers: [...new Set(providers)],
|
|
357
|
-
enableOpenApi
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
function resolveMainProvider(mainProvider, providersConfig) {
|
|
361
|
-
const providers = [];
|
|
362
|
-
let enableOpenApi = false;
|
|
363
|
-
if (mainProvider === "aws") {
|
|
364
|
-
const awsConfig = providersConfig?.aws;
|
|
365
|
-
if (awsConfig?.apiGateway) {
|
|
366
|
-
if (isEnabled(awsConfig.apiGateway.v1)) providers.push("aws-apigatewayv1");
|
|
367
|
-
if (isEnabled(awsConfig.apiGateway.v2)) providers.push("aws-apigatewayv2");
|
|
368
|
-
} else providers.push("aws-apigatewayv2");
|
|
369
|
-
if (awsConfig?.lambda) {
|
|
370
|
-
if (isEnabled(awsConfig.lambda.functions) || isEnabled(awsConfig.lambda.crons)) providers.push("aws-lambda");
|
|
371
|
-
} else providers.push("aws-lambda");
|
|
372
|
-
} else if (mainProvider === "server") {
|
|
373
|
-
providers.push("server");
|
|
374
|
-
const serverConfig = providersConfig?.server;
|
|
375
|
-
if (typeof serverConfig === "object" && serverConfig?.enableOpenApi) enableOpenApi = true;
|
|
376
|
-
}
|
|
377
|
-
return {
|
|
378
|
-
providers,
|
|
379
|
-
enableOpenApi
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
function resolveAllConfiguredProviders(providersConfig) {
|
|
383
|
-
const providers = [];
|
|
384
|
-
let enableOpenApi = false;
|
|
385
|
-
if (providersConfig.aws) {
|
|
386
|
-
const awsProviders = resolveMainProvider("aws", providersConfig);
|
|
387
|
-
providers.push(...awsProviders.providers);
|
|
388
|
-
}
|
|
389
|
-
if (providersConfig.server && isEnabled(providersConfig.server)) {
|
|
390
|
-
providers.push("server");
|
|
391
|
-
if (typeof providersConfig.server === "object" && providersConfig.server.enableOpenApi) enableOpenApi = true;
|
|
392
|
-
}
|
|
393
|
-
return {
|
|
394
|
-
providers,
|
|
395
|
-
enableOpenApi
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
function isEnabled(config) {
|
|
399
|
-
if (config === void 0) return false;
|
|
400
|
-
if (typeof config === "boolean") return config;
|
|
401
|
-
return config.enabled !== false;
|
|
402
|
-
}
|
|
403
|
-
//#endregion
|
|
404
336
|
//#region src/workspace/client-generator.ts
|
|
405
337
|
/**
|
|
406
338
|
* Normalize routes to an array of patterns.
|
|
407
|
-
* Handles
|
|
339
|
+
* Handles a glob or a list of them.
|
|
408
340
|
* @internal Exported for use in dev command
|
|
409
341
|
*/
|
|
410
342
|
function normalizeRoutes(routes) {
|
|
411
343
|
if (!routes) return [];
|
|
412
|
-
if (require_discover.isPartitionedRoutes(routes)) return Array.isArray(routes.paths) ? routes.paths : [routes.paths];
|
|
413
344
|
return Array.isArray(routes) ? routes : [routes];
|
|
414
345
|
}
|
|
415
346
|
//#endregion
|
|
@@ -428,7 +359,7 @@ function normalizeRoutes(routes) {
|
|
|
428
359
|
* trade than one that tells you what to type. Caddy's own `caddy trust` draws
|
|
429
360
|
* the line in the same place.
|
|
430
361
|
*/
|
|
431
|
-
const logger$
|
|
362
|
+
const logger$11 = console;
|
|
432
363
|
const run = (0, node_util.promisify)(node_child_process.execFile);
|
|
433
364
|
/**
|
|
434
365
|
* How each platform is told about a new authority.
|
|
@@ -480,15 +411,15 @@ async function trustCommand(options = {}) {
|
|
|
480
411
|
const certificate = (0, node_path.join)(workspace.root, require_workspace$1.LOCAL_CA_PATH);
|
|
481
412
|
if (!(0, node_fs.existsSync)(certificate)) throw new NoLocalAuthority(certificate);
|
|
482
413
|
const { describe, steps } = installation(process.platform, certificate);
|
|
483
|
-
logger$
|
|
484
|
-
logger$
|
|
414
|
+
logger$11.log(`\n🔐 Trusting the local authority in ${describe}`);
|
|
415
|
+
logger$11.log(` ${certificate}\n`);
|
|
485
416
|
if (options.dryRun) {
|
|
486
|
-
for (const [command, args] of steps) logger$
|
|
417
|
+
for (const [command, args] of steps) logger$11.log(` ${command} ${args.join(" ")}`);
|
|
487
418
|
return;
|
|
488
419
|
}
|
|
489
|
-
logger$
|
|
420
|
+
logger$11.log(" This needs an admin password.\n");
|
|
490
421
|
for (const [command, args] of steps) await run(command, args, { stdio: "inherit" });
|
|
491
|
-
logger$
|
|
422
|
+
logger$11.log("\n✅ Local https addresses are trusted. Restart your browser.\n");
|
|
492
423
|
}
|
|
493
424
|
/**
|
|
494
425
|
* Trust the authority if this machine lacks it and its owner agrees.
|
|
@@ -505,7 +436,7 @@ async function ensureTrusted(root, url, options = {}) {
|
|
|
505
436
|
if (await isTrusted(url)) return;
|
|
506
437
|
if (!options.assumeYes) {
|
|
507
438
|
if (!process.stdin.isTTY) {
|
|
508
|
-
logger$
|
|
439
|
+
logger$11.log(" Local https addresses are not trusted here. Run \"gkm trust\", or \"gkm setup --yes\".");
|
|
509
440
|
return;
|
|
510
441
|
}
|
|
511
442
|
if (await declined(root)) return;
|
|
@@ -517,7 +448,7 @@ async function ensureTrusted(root, url, options = {}) {
|
|
|
517
448
|
});
|
|
518
449
|
if (!install) {
|
|
519
450
|
await recordDeclined(root);
|
|
520
|
-
logger$
|
|
451
|
+
logger$11.log(" Skipped. Run \"gkm trust\" later.");
|
|
521
452
|
return;
|
|
522
453
|
}
|
|
523
454
|
}
|
|
@@ -1067,7 +998,7 @@ function closeFakes(served) {
|
|
|
1067
998
|
}
|
|
1068
999
|
//#endregion
|
|
1069
1000
|
//#region src/exec/index.ts
|
|
1070
|
-
const logger$
|
|
1001
|
+
const logger$10 = console;
|
|
1071
1002
|
/** `gkm exec` was given nothing to run. */
|
|
1072
1003
|
var NoCommandSpecified = class extends Error {
|
|
1073
1004
|
constructor() {
|
|
@@ -1090,17 +1021,17 @@ async function execCommand(commandArgs, options = {}) {
|
|
|
1090
1021
|
const cwd = options.cwd ?? process.cwd();
|
|
1091
1022
|
if (!commandArgs[0]) throw new NoCommandSpecified();
|
|
1092
1023
|
const defaultEnv = require_workspace$1.loadEnvFiles(".env");
|
|
1093
|
-
if (defaultEnv.loaded.length > 0) logger$
|
|
1024
|
+
if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1094
1025
|
const { credentials, secretsJsonPath, appName } = await require_workspace$1.prepareEntryCredentials({ cwd });
|
|
1095
|
-
if (appName) logger$
|
|
1026
|
+
if (appName) logger$10.log(`📦 App: ${appName}`);
|
|
1096
1027
|
const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
|
|
1097
|
-
if (secretCount > 0) logger$
|
|
1028
|
+
if (secretCount > 0) logger$10.log(`🔐 Loaded ${secretCount} secret(s)`);
|
|
1098
1029
|
const preloadDir = (0, node_path.join)(cwd, ".gkm");
|
|
1099
1030
|
await (0, node_fs_promises.mkdir)(preloadDir, { recursive: true });
|
|
1100
1031
|
const preloadPath = (0, node_path.join)(preloadDir, "credentials-preload.mjs");
|
|
1101
1032
|
await require_workspace$1.createCredentialsPreload(preloadPath, secretsJsonPath);
|
|
1102
1033
|
const [cmd, ...args] = commandArgs;
|
|
1103
|
-
logger$
|
|
1034
|
+
logger$10.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
|
|
1104
1035
|
const nodeOptions = [(process.env.NODE_OPTIONS ?? "").replace(/--import[= ]\S+/g, "").trim(), `--import=${preloadPath}`].filter(Boolean).join(" ");
|
|
1105
1036
|
const child = (0, node_child_process.spawn)(cmd, args, {
|
|
1106
1037
|
cwd,
|
|
@@ -1114,7 +1045,7 @@ async function execCommand(commandArgs, options = {}) {
|
|
|
1114
1045
|
const exitCode = await new Promise((resolve) => {
|
|
1115
1046
|
child.on("close", (code) => resolve(code ?? 0));
|
|
1116
1047
|
child.on("error", (error) => {
|
|
1117
|
-
logger$
|
|
1048
|
+
logger$10.error(`Failed to run command: ${error.message}`);
|
|
1118
1049
|
resolve(1);
|
|
1119
1050
|
});
|
|
1120
1051
|
});
|
|
@@ -1122,7 +1053,7 @@ async function execCommand(commandArgs, options = {}) {
|
|
|
1122
1053
|
}
|
|
1123
1054
|
//#endregion
|
|
1124
1055
|
//#region src/dev/index.ts
|
|
1125
|
-
const logger$
|
|
1056
|
+
const logger$9 = console;
|
|
1126
1057
|
/**
|
|
1127
1058
|
* Normalize telescope configuration
|
|
1128
1059
|
* @internal Exported for testing
|
|
@@ -1187,39 +1118,36 @@ function normalizeHooksConfig(config, cwd = process.cwd()) {
|
|
|
1187
1118
|
return { serverHooksPath: (0, node_path.resolve)(cwd, serverPath) };
|
|
1188
1119
|
}
|
|
1189
1120
|
/**
|
|
1190
|
-
*
|
|
1121
|
+
* What a `--production` build is.
|
|
1122
|
+
*
|
|
1123
|
+
* A server runs its worker's background work itself — queues polled, crons
|
|
1124
|
+
* scheduled, subscribers drained — so the production entry wires all three.
|
|
1125
|
+
* The build writes their files on every server build, empty when there is
|
|
1126
|
+
* nothing, so including them costs an app without any nothing.
|
|
1127
|
+
*
|
|
1191
1128
|
* @internal Exported for testing
|
|
1192
1129
|
*/
|
|
1193
|
-
function normalizeProductionConfig(cliProduction
|
|
1130
|
+
function normalizeProductionConfig(cliProduction) {
|
|
1194
1131
|
if (!cliProduction) return;
|
|
1195
|
-
const config = configProduction ?? {};
|
|
1196
1132
|
return {
|
|
1197
1133
|
enabled: true,
|
|
1198
|
-
bundle:
|
|
1199
|
-
minify:
|
|
1200
|
-
healthCheck:
|
|
1201
|
-
gracefulShutdown:
|
|
1202
|
-
external:
|
|
1203
|
-
subscribers:
|
|
1204
|
-
openapi:
|
|
1205
|
-
optimizedHandlers:
|
|
1134
|
+
bundle: true,
|
|
1135
|
+
minify: true,
|
|
1136
|
+
healthCheck: "/health",
|
|
1137
|
+
gracefulShutdown: true,
|
|
1138
|
+
external: [],
|
|
1139
|
+
subscribers: "include",
|
|
1140
|
+
openapi: false,
|
|
1141
|
+
optimizedHandlers: true
|
|
1206
1142
|
};
|
|
1207
1143
|
}
|
|
1208
|
-
/**
|
|
1209
|
-
* Get production config from GkmConfig
|
|
1210
|
-
* @internal
|
|
1211
|
-
*/
|
|
1212
|
-
function getProductionConfigFromGkm(config) {
|
|
1213
|
-
const serverConfig = config.providers?.server;
|
|
1214
|
-
if (typeof serverConfig === "object") return serverConfig.production;
|
|
1215
|
-
}
|
|
1216
1144
|
/** Read by the generated server: no subscriber is subscribed or polled. */
|
|
1217
1145
|
const SUBSCRIBERS_ENV = "GKM_SUBSCRIBERS";
|
|
1218
1146
|
async function devCommand(options) {
|
|
1219
1147
|
if (options.subscribers === false) process.env[SUBSCRIBERS_ENV] = "off";
|
|
1220
1148
|
if (options.entry) return entryDevCommand(options);
|
|
1221
1149
|
const defaultEnv = require_workspace$1.loadEnvFiles(".env");
|
|
1222
|
-
if (defaultEnv.loaded.length > 0) logger$
|
|
1150
|
+
if (defaultEnv.loaded.length > 0) logger$9.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1223
1151
|
const appConfig = await require_config.loadAppConfig().catch((error) => {
|
|
1224
1152
|
if (error instanceof require_config.NotInAnApp || error instanceof require_config.NotABackendApp) return;
|
|
1225
1153
|
throw error;
|
|
@@ -1235,7 +1163,7 @@ async function devCommand(options) {
|
|
|
1235
1163
|
const workspaceAppPort = appConfig.app.port;
|
|
1236
1164
|
const workspace = appConfig.workspace;
|
|
1237
1165
|
if (appConfig.app.entry) {
|
|
1238
|
-
logger$
|
|
1166
|
+
logger$9.log(`📄 Using entry point: ${appConfig.app.entry}`);
|
|
1239
1167
|
return entryDevCommand({
|
|
1240
1168
|
...options,
|
|
1241
1169
|
entry: appConfig.app.entry,
|
|
@@ -1245,21 +1173,20 @@ async function devCommand(options) {
|
|
|
1245
1173
|
}
|
|
1246
1174
|
if (config.env) {
|
|
1247
1175
|
const { loaded, missing } = require_workspace$1.loadEnvFiles(config.env, appRoot);
|
|
1248
|
-
if (loaded.length > 0) logger$
|
|
1249
|
-
if (missing.length > 0) logger$
|
|
1176
|
+
if (loaded.length > 0) logger$9.log(`📦 Loaded env: ${loaded.join(", ")}`);
|
|
1177
|
+
if (missing.length > 0) logger$9.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
|
|
1250
1178
|
}
|
|
1251
|
-
const resolved = resolveProviders(config, { provider: "server" });
|
|
1252
1179
|
const telescope = normalizeTelescopeConfig(config.telescope);
|
|
1253
1180
|
const studio = normalizeStudioConfig(config.studio);
|
|
1254
1181
|
const hooks = normalizeHooksConfig(config.hooks, appRoot);
|
|
1255
|
-
const enableOpenApi = require_openapi.resolveOpenApiConfig(config).enabled
|
|
1182
|
+
const enableOpenApi = require_openapi.resolveOpenApiConfig(config).enabled;
|
|
1256
1183
|
const build = (bustCache = false) => quietly(() => buildApp({
|
|
1257
1184
|
config,
|
|
1258
1185
|
workspaceRoot: workspace?.root ?? secretsRoot,
|
|
1259
1186
|
appRoot,
|
|
1260
|
-
|
|
1187
|
+
target: "server",
|
|
1261
1188
|
enableOpenApi,
|
|
1262
|
-
cacheBackend:
|
|
1189
|
+
cacheBackend: require_backends.cacheBackendFor(require_backends.providerOf(workspace ?? config)),
|
|
1263
1190
|
telescope,
|
|
1264
1191
|
studio,
|
|
1265
1192
|
hooks,
|
|
@@ -1277,9 +1204,9 @@ async function devCommand(options) {
|
|
|
1277
1204
|
stage: workspace.stages.local,
|
|
1278
1205
|
...options.fake ? { fake: true } : {}
|
|
1279
1206
|
});
|
|
1280
|
-
if (reconciled.
|
|
1281
|
-
logger$
|
|
1282
|
-
for (const
|
|
1207
|
+
if (reconciled.services.length > 0) {
|
|
1208
|
+
logger$9.log("🐳 Services");
|
|
1209
|
+
for (const line of require_workspace$1.describeServices(reconciled.services)) logger$9.log(line);
|
|
1283
1210
|
}
|
|
1284
1211
|
Object.assign(appSecrets, reconciled.env);
|
|
1285
1212
|
const own = reconciled.plan.resources.find((r) => (r.kind === "rest-api" || r.kind === "site") && require_config.appKey(r.id) === workspaceAppName);
|
|
@@ -1292,7 +1219,7 @@ async function devCommand(options) {
|
|
|
1292
1219
|
secretsJsonPath = (0, node_path.join)(secretsDir, secretsFileName);
|
|
1293
1220
|
await (0, node_fs_promises.writeFile)(secretsJsonPath, JSON.stringify(appSecrets, null, 2));
|
|
1294
1221
|
}
|
|
1295
|
-
const devServer = new DevServer(
|
|
1222
|
+
const devServer = new DevServer(options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? workspaceAppPort !== void 0, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath, initial.selfServing !== void 0);
|
|
1296
1223
|
devServer.label = workspaceAppName ?? "server";
|
|
1297
1224
|
devServer.publicUrl = publicUrl;
|
|
1298
1225
|
await devServer.start();
|
|
@@ -1313,11 +1240,11 @@ async function devCommand(options) {
|
|
|
1313
1240
|
cwd: appRoot
|
|
1314
1241
|
});
|
|
1315
1242
|
watcher.on("error", (error) => {
|
|
1316
|
-
logger$
|
|
1243
|
+
logger$9.error("❌ Watcher error:", error);
|
|
1317
1244
|
});
|
|
1318
1245
|
let rebuildTimeout = null;
|
|
1319
1246
|
watcher.on("change", async (path) => {
|
|
1320
|
-
logger$
|
|
1247
|
+
logger$9.log(`🔄 ${path} changed — rebuilding`);
|
|
1321
1248
|
if (rebuildTimeout) clearTimeout(rebuildTimeout);
|
|
1322
1249
|
rebuildTimeout = setTimeout(async () => {
|
|
1323
1250
|
try {
|
|
@@ -1326,8 +1253,8 @@ async function devCommand(options) {
|
|
|
1326
1253
|
await devServer.restart();
|
|
1327
1254
|
} catch (error) {
|
|
1328
1255
|
const err = error;
|
|
1329
|
-
logger$
|
|
1330
|
-
if (err.stack) logger$
|
|
1256
|
+
logger$9.error(`❌ Rebuild failed: ${err.message}`);
|
|
1257
|
+
if (err.stack) logger$9.error(err.stack);
|
|
1331
1258
|
}
|
|
1332
1259
|
}, 300);
|
|
1333
1260
|
});
|
|
@@ -1335,9 +1262,9 @@ async function devCommand(options) {
|
|
|
1335
1262
|
const shutdown = () => {
|
|
1336
1263
|
if (isShuttingDown) return;
|
|
1337
1264
|
isShuttingDown = true;
|
|
1338
|
-
logger$
|
|
1265
|
+
logger$9.log("\n🛑 Shutting down...");
|
|
1339
1266
|
Promise.all([watcher.close(), devServer.stop()]).catch((err) => {
|
|
1340
|
-
logger$
|
|
1267
|
+
logger$9.error("Error during shutdown:", err);
|
|
1341
1268
|
}).finally(() => {
|
|
1342
1269
|
process.exit(0);
|
|
1343
1270
|
});
|
|
@@ -1539,7 +1466,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1539
1466
|
const frontendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "web");
|
|
1540
1467
|
const conflicts = checkPortConflicts(workspace);
|
|
1541
1468
|
if (conflicts.length > 0) {
|
|
1542
|
-
for (const conflict of conflicts) logger$
|
|
1469
|
+
for (const conflict of conflicts) logger$9.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
|
|
1543
1470
|
throw new Error("Port conflicts detected. Please assign unique ports to each app.");
|
|
1544
1471
|
}
|
|
1545
1472
|
if (frontendApps.length > 0) {
|
|
@@ -1548,10 +1475,10 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1548
1475
|
for (const result of validationResults) {
|
|
1549
1476
|
if (!result.valid) {
|
|
1550
1477
|
hasErrors = true;
|
|
1551
|
-
logger$
|
|
1552
|
-
for (const error of result.errors) logger$
|
|
1478
|
+
logger$9.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
|
|
1479
|
+
for (const error of result.errors) logger$9.error(` • ${error}`);
|
|
1553
1480
|
}
|
|
1554
|
-
for (const warning of result.warnings) logger$
|
|
1481
|
+
for (const warning of result.warnings) logger$9.warn(` ⚠️ ${result.appName}: ${warning}`);
|
|
1555
1482
|
}
|
|
1556
1483
|
if (hasErrors) throw new Error("Frontend app validation failed. Fix the issues above and try again.");
|
|
1557
1484
|
}
|
|
@@ -1560,21 +1487,21 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1560
1487
|
stage: workspace.stages.local,
|
|
1561
1488
|
...options.fake ? { fake: true } : {}
|
|
1562
1489
|
});
|
|
1563
|
-
if (reconciled.
|
|
1564
|
-
logger$
|
|
1565
|
-
for (const
|
|
1490
|
+
if (reconciled.services.length > 0) {
|
|
1491
|
+
logger$9.log("🐳 Services");
|
|
1492
|
+
for (const line of require_workspace$1.describeServices(reconciled.services)) logger$9.log(line);
|
|
1566
1493
|
}
|
|
1567
1494
|
const secretsEnv = {
|
|
1568
1495
|
...rawSecrets,
|
|
1569
1496
|
...reconciled.env
|
|
1570
1497
|
};
|
|
1571
1498
|
const fakes = options.fake ? await serveFakes(reconciled.fakes, reconciled.ports) : [];
|
|
1572
|
-
for (const { id, port } of fakes) logger$
|
|
1499
|
+
for (const { id, port } of fakes) logger$9.log(`🎭 ${id} fake: http://localhost:${port}`);
|
|
1573
1500
|
if (options.migrate || options.seed) {
|
|
1574
|
-
const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-
|
|
1501
|
+
const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
|
|
1575
1502
|
await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
|
|
1576
|
-
} else await Promise.resolve().then(() => require("./migrate-
|
|
1577
|
-
logger$
|
|
1503
|
+
} else await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
|
|
1504
|
+
logger$9.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
|
|
1578
1505
|
});
|
|
1579
1506
|
const appUrls = {};
|
|
1580
1507
|
for (const resource of reconciled.plan.resources) {
|
|
@@ -1595,11 +1522,11 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1595
1522
|
else {
|
|
1596
1523
|
const { filters, unpackaged } = turboFilters(workspace);
|
|
1597
1524
|
turboFilter = filters.flatMap((name) => ["--filter", name]);
|
|
1598
|
-
if (unpackaged.length > 0) logger$
|
|
1525
|
+
if (unpackaged.length > 0) logger$9.warn(`⚠️ No package.json with a name for: ${unpackaged.join(", ")} — turbo cannot run ${unpackaged.length === 1 ? "it" : "them"}.`);
|
|
1599
1526
|
}
|
|
1600
1527
|
const buildOrder = require_workspace.getAppBuildOrder(workspace);
|
|
1601
1528
|
const width = Math.max(...buildOrder.map((name) => name.length));
|
|
1602
|
-
logger$
|
|
1529
|
+
logger$9.log(`\n${workspace.name}: ${appCount} app(s)`);
|
|
1603
1530
|
for (const appName of buildOrder) {
|
|
1604
1531
|
const app = workspace.apps[appName];
|
|
1605
1532
|
if (!app) continue;
|
|
@@ -1607,14 +1534,14 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1607
1534
|
const own = reconciled.plan.resources.find((r) => r.kind === "mobile-app" && require_config.appKey(r.id) === appName);
|
|
1608
1535
|
const scheme = own ? reconciled.env[own.envKey] : void 0;
|
|
1609
1536
|
const device = Object.entries(reconciled.env).find(([key]) => key.endsWith("_DEVICE_URL"))?.[1];
|
|
1610
|
-
logger$
|
|
1537
|
+
logger$9.log(` ${appName.padEnd(width)} ${scheme ? `${scheme}://` : "mobile"}${device ? ` — devices reach ${new URL(device).hostname}` : ""}`);
|
|
1611
1538
|
continue;
|
|
1612
1539
|
}
|
|
1613
1540
|
const local = `http://localhost:${app.port}`;
|
|
1614
1541
|
const url = Object.entries(appUrls).find(([id]) => require_config.appKey(id) === appName)?.[1];
|
|
1615
|
-
logger$
|
|
1542
|
+
logger$9.log(` ${appName.padEnd(width)} ${url ? `${url} -> ${local}` : local}`);
|
|
1616
1543
|
}
|
|
1617
|
-
logger$
|
|
1544
|
+
logger$9.log("");
|
|
1618
1545
|
const configFiles = [
|
|
1619
1546
|
"gkm.config.ts",
|
|
1620
1547
|
"gkm.config.js",
|
|
@@ -1661,7 +1588,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1661
1588
|
const shutdown = () => {
|
|
1662
1589
|
if (isShuttingDown) return;
|
|
1663
1590
|
isShuttingDown = true;
|
|
1664
|
-
logger$
|
|
1591
|
+
logger$9.log("\n🛑 Shutting down workspace...");
|
|
1665
1592
|
closeFakes(fakes);
|
|
1666
1593
|
const pid = turboProcess.pid;
|
|
1667
1594
|
if (pid) try {
|
|
@@ -1686,7 +1613,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1686
1613
|
process.on("SIGTERM", shutdown);
|
|
1687
1614
|
return new Promise((resolve, reject) => {
|
|
1688
1615
|
turboProcess.on("error", (error) => {
|
|
1689
|
-
logger$
|
|
1616
|
+
logger$9.error("❌ Turbo error:", error);
|
|
1690
1617
|
reject(error);
|
|
1691
1618
|
});
|
|
1692
1619
|
turboProcess.on("exit", (code) => {
|
|
@@ -1705,11 +1632,11 @@ async function entryDevCommand(options) {
|
|
|
1705
1632
|
const entryPath = (0, node_path.resolve)(process.cwd(), entry);
|
|
1706
1633
|
if (!(0, node_fs.existsSync)(entryPath)) throw new Error(`Entry file not found: ${entryPath}`);
|
|
1707
1634
|
const defaultEnv = require_workspace$1.loadEnvFiles(".env");
|
|
1708
|
-
if (defaultEnv.loaded.length > 0) logger$
|
|
1635
|
+
if (defaultEnv.loaded.length > 0) logger$9.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1709
1636
|
const { credentials, resolvedPort, secretsJsonPath, appName } = await require_workspace$1.prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
|
|
1710
|
-
if (appName) logger$
|
|
1711
|
-
logger$
|
|
1712
|
-
if (Object.keys(credentials).length > 1) logger$
|
|
1637
|
+
if (appName) logger$9.log(`📦 App: ${appName} (port ${resolvedPort})`);
|
|
1638
|
+
logger$9.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
|
|
1639
|
+
if (Object.keys(credentials).length > 1) logger$9.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
|
|
1713
1640
|
const wrapperDir = (0, node_path.join)(process.cwd(), ".gkm");
|
|
1714
1641
|
await (0, node_fs_promises.mkdir)(wrapperDir, { recursive: true });
|
|
1715
1642
|
const wrapperPath = (0, node_path.join)(wrapperDir, "entry-wrapper.ts");
|
|
@@ -1720,7 +1647,7 @@ async function entryDevCommand(options) {
|
|
|
1720
1647
|
const shutdown = () => {
|
|
1721
1648
|
if (isShuttingDown) return;
|
|
1722
1649
|
isShuttingDown = true;
|
|
1723
|
-
logger$
|
|
1650
|
+
logger$9.log("\n🛑 Shutting down...");
|
|
1724
1651
|
runner.stop();
|
|
1725
1652
|
process.exit(0);
|
|
1726
1653
|
};
|
|
@@ -1756,14 +1683,14 @@ var EntryRunner = class {
|
|
|
1756
1683
|
});
|
|
1757
1684
|
let restartTimeout = null;
|
|
1758
1685
|
this.watcher.on("change", (path) => {
|
|
1759
|
-
logger$
|
|
1686
|
+
logger$9.log(`📝 File changed: ${path}`);
|
|
1760
1687
|
if (restartTimeout) clearTimeout(restartTimeout);
|
|
1761
1688
|
restartTimeout = setTimeout(async () => {
|
|
1762
|
-
logger$
|
|
1689
|
+
logger$9.log("🔄 Restarting...");
|
|
1763
1690
|
await this.restart();
|
|
1764
1691
|
}, 300);
|
|
1765
1692
|
});
|
|
1766
|
-
logger$
|
|
1693
|
+
logger$9.log(`👀 Watching for changes in: ${watchDir}`);
|
|
1767
1694
|
}
|
|
1768
1695
|
}
|
|
1769
1696
|
async runProcess() {
|
|
@@ -1778,17 +1705,17 @@ var EntryRunner = class {
|
|
|
1778
1705
|
});
|
|
1779
1706
|
this.isRunning = true;
|
|
1780
1707
|
this.childProcess.on("error", (error) => {
|
|
1781
|
-
logger$
|
|
1708
|
+
logger$9.error("❌ Process error:", error);
|
|
1782
1709
|
});
|
|
1783
1710
|
this.childProcess.on("exit", (code) => {
|
|
1784
|
-
if (code !== null && code !== 0 && code !== 143) logger$
|
|
1711
|
+
if (code !== null && code !== 0 && code !== 143) logger$9.error(`❌ Process exited with code ${code}`);
|
|
1785
1712
|
this.isRunning = false;
|
|
1786
1713
|
});
|
|
1787
1714
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1788
1715
|
if (this.isRunning) {
|
|
1789
|
-
logger$
|
|
1790
|
-
logger$
|
|
1791
|
-
logger$
|
|
1716
|
+
logger$9.log("");
|
|
1717
|
+
logger$9.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
|
|
1718
|
+
logger$9.log("");
|
|
1792
1719
|
}
|
|
1793
1720
|
}
|
|
1794
1721
|
async restart() {
|
|
@@ -1966,7 +1893,6 @@ function listenerOn(port) {
|
|
|
1966
1893
|
}
|
|
1967
1894
|
}
|
|
1968
1895
|
var DevServer = class {
|
|
1969
|
-
provider;
|
|
1970
1896
|
requestedPort;
|
|
1971
1897
|
portExplicit;
|
|
1972
1898
|
enableOpenApi;
|
|
@@ -1980,8 +1906,7 @@ var DevServer = class {
|
|
|
1980
1906
|
isRunning = false;
|
|
1981
1907
|
actualPort;
|
|
1982
1908
|
startTime = Date.now();
|
|
1983
|
-
constructor(
|
|
1984
|
-
this.provider = provider;
|
|
1909
|
+
constructor(requestedPort, portExplicit, enableOpenApi, telescope, studio, runtime = "node", appRoot = process.cwd(), secretsJsonPath, selfServing = false) {
|
|
1985
1910
|
this.requestedPort = requestedPort;
|
|
1986
1911
|
this.portExplicit = portExplicit;
|
|
1987
1912
|
this.enableOpenApi = enableOpenApi;
|
|
@@ -2008,9 +1933,9 @@ var DevServer = class {
|
|
|
2008
1933
|
this.actualPort = this.requestedPort;
|
|
2009
1934
|
} else {
|
|
2010
1935
|
this.actualPort = await require_workspace$1.findAvailablePort(this.requestedPort);
|
|
2011
|
-
if (this.actualPort !== this.requestedPort) logger$
|
|
1936
|
+
if (this.actualPort !== this.requestedPort) logger$9.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
|
|
2012
1937
|
}
|
|
2013
|
-
const serverEntryPath = (0, node_path.join)(this.appRoot, ".gkm",
|
|
1938
|
+
const serverEntryPath = (0, node_path.join)(this.appRoot, ".gkm", "server", "server.ts");
|
|
2014
1939
|
await this.createServerEntry();
|
|
2015
1940
|
this.serverProcess = (0, node_child_process.spawn)(...tsxCommand(this.appRoot, [
|
|
2016
1941
|
serverEntryPath,
|
|
@@ -2027,10 +1952,10 @@ var DevServer = class {
|
|
|
2027
1952
|
});
|
|
2028
1953
|
this.isRunning = true;
|
|
2029
1954
|
this.serverProcess.on("error", (error) => {
|
|
2030
|
-
logger$
|
|
1955
|
+
logger$9.error("❌ Server error:", error);
|
|
2031
1956
|
});
|
|
2032
1957
|
this.serverProcess.on("exit", (code, signal) => {
|
|
2033
|
-
if (code !== null && code !== 0 && signal !== "SIGTERM") logger$
|
|
1958
|
+
if (code !== null && code !== 0 && signal !== "SIGTERM") logger$9.error(`❌ Server exited with code ${code}`);
|
|
2034
1959
|
this.isRunning = false;
|
|
2035
1960
|
});
|
|
2036
1961
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
@@ -2038,13 +1963,13 @@ var DevServer = class {
|
|
|
2038
1963
|
const local = `http://localhost:${this.actualPort}`;
|
|
2039
1964
|
const address = this.publicUrl ? `${this.publicUrl} -> ${local}` : local;
|
|
2040
1965
|
const seconds = ((Date.now() - this.startTime) / 1e3).toFixed(1);
|
|
2041
|
-
logger$
|
|
1966
|
+
logger$9.log(`\x1b[32m✓\x1b[0m ${this.label} ready in ${seconds}s ${address}`);
|
|
2042
1967
|
const tools = this.selfServing ? [] : [
|
|
2043
1968
|
...this.enableOpenApi ? ["docs /__docs"] : [],
|
|
2044
1969
|
...this.telescope ? [`telescope ${this.telescope.path}`] : [],
|
|
2045
1970
|
...this.studio ? [`studio ${this.studio.path}`] : []
|
|
2046
1971
|
];
|
|
2047
|
-
if (tools.length > 0) logger$
|
|
1972
|
+
if (tools.length > 0) logger$9.log(` ${tools.join(" · ")}`);
|
|
2048
1973
|
}
|
|
2049
1974
|
}
|
|
2050
1975
|
async stop() {
|
|
@@ -2082,7 +2007,7 @@ var DevServer = class {
|
|
|
2082
2007
|
}
|
|
2083
2008
|
async createServerEntry() {
|
|
2084
2009
|
const { writeFile: fsWriteFile } = await import("node:fs/promises");
|
|
2085
|
-
await fsWriteFile((0, node_path.join)(this.appRoot, ".gkm",
|
|
2010
|
+
await fsWriteFile((0, node_path.join)(this.appRoot, ".gkm", "server", "server.ts"), generateServerEntryContent({
|
|
2086
2011
|
secretsJsonPath: this.secretsJsonPath,
|
|
2087
2012
|
runtime: this.runtime,
|
|
2088
2013
|
enableOpenApi: this.enableOpenApi,
|
|
@@ -2094,22 +2019,22 @@ var DevServer = class {
|
|
|
2094
2019
|
//#region src/generators/CronGenerator.ts
|
|
2095
2020
|
var CronGenerator = class extends require_discover.ConstructGenerator {
|
|
2096
2021
|
async build(context, constructs, outputDir, options) {
|
|
2097
|
-
const
|
|
2022
|
+
const target = options?.target ?? "aws";
|
|
2098
2023
|
const logger = console;
|
|
2099
2024
|
const cronInfos = [];
|
|
2100
|
-
if (
|
|
2025
|
+
if (target === "server") {
|
|
2101
2026
|
await this.generateServerCronsFile(outputDir, constructs);
|
|
2102
2027
|
logger.log(`Generated server crons file with ${constructs.length} crons`);
|
|
2103
2028
|
return cronInfos;
|
|
2104
2029
|
}
|
|
2105
|
-
if (constructs.length === 0
|
|
2030
|
+
if (constructs.length === 0) return cronInfos;
|
|
2106
2031
|
const cronsDir = (0, node_path.join)(outputDir, "crons");
|
|
2107
2032
|
await (0, node_fs_promises.mkdir)(cronsDir, { recursive: true });
|
|
2108
2033
|
for (const { key, construct, path } of constructs) {
|
|
2109
2034
|
const handlerFile = await this.generateCronHandler(cronsDir, path.relative, key, context, construct.owner);
|
|
2110
2035
|
cronInfos.push({
|
|
2111
2036
|
name: key,
|
|
2112
|
-
handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2037
|
+
handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2113
2038
|
schedule: construct.schedule || "rate(1 hour)",
|
|
2114
2039
|
timeout: construct.timeout,
|
|
2115
2040
|
memorySize: construct.memorySize,
|
|
@@ -2299,17 +2224,17 @@ var FunctionGenerator = class extends require_discover.ConstructGenerator {
|
|
|
2299
2224
|
return _geekmidas_constructs_functions.Function.isFunction(value);
|
|
2300
2225
|
}
|
|
2301
2226
|
async build(context, constructs, outputDir, options) {
|
|
2302
|
-
const
|
|
2227
|
+
const target = options?.target ?? "aws";
|
|
2303
2228
|
const logger = console;
|
|
2304
2229
|
const functionInfos = [];
|
|
2305
|
-
if (constructs.length === 0 ||
|
|
2230
|
+
if (constructs.length === 0 || target === "server") return functionInfos;
|
|
2306
2231
|
const functionsDir = (0, node_path.join)(outputDir, "functions");
|
|
2307
2232
|
await (0, node_fs_promises.mkdir)(functionsDir, { recursive: true });
|
|
2308
2233
|
for (const { key, construct, path } of constructs) {
|
|
2309
2234
|
const handlerFile = await this.generateFunctionHandler(functionsDir, path.relative, key, context, construct.owner);
|
|
2310
2235
|
functionInfos.push({
|
|
2311
2236
|
name: key,
|
|
2312
|
-
handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2237
|
+
handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2313
2238
|
timeout: construct.timeout,
|
|
2314
2239
|
memorySize: construct.memorySize,
|
|
2315
2240
|
environment: await construct.getEnvironment({ markOptional: context.markOptional }),
|
|
@@ -2353,22 +2278,22 @@ var QueueGenerator = class extends require_discover.ConstructGenerator {
|
|
|
2353
2278
|
return _geekmidas_constructs_queue.Queue.isQueue(value);
|
|
2354
2279
|
}
|
|
2355
2280
|
async build(context, constructs, outputDir, options) {
|
|
2356
|
-
const
|
|
2281
|
+
const target = options?.target ?? "aws";
|
|
2357
2282
|
const logger = console;
|
|
2358
2283
|
const queueInfos = [];
|
|
2359
|
-
if (
|
|
2284
|
+
if (target === "server") {
|
|
2360
2285
|
await this.generateServerQueuesFile(outputDir, constructs);
|
|
2361
2286
|
logger.log(`Generated server queues file with ${constructs.length} queues (polling mode)`);
|
|
2362
2287
|
return queueInfos;
|
|
2363
2288
|
}
|
|
2364
|
-
if (constructs.length === 0
|
|
2289
|
+
if (constructs.length === 0) return queueInfos;
|
|
2365
2290
|
const queuesDir = (0, node_path.join)(outputDir, "queues");
|
|
2366
2291
|
await (0, node_fs_promises.mkdir)(queuesDir, { recursive: true });
|
|
2367
2292
|
for (const { key, construct, path } of constructs) {
|
|
2368
2293
|
const handlerFile = await this.generateQueueHandler(queuesDir, path.relative, key, context, construct.owner);
|
|
2369
2294
|
queueInfos.push({
|
|
2370
2295
|
name: construct.name,
|
|
2371
|
-
handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2296
|
+
handler: (0, node_path.relative)(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2372
2297
|
batchSize: construct.batchSize,
|
|
2373
2298
|
fifo: construct.fifo,
|
|
2374
2299
|
timeout: construct.timeout,
|
|
@@ -2534,217 +2459,6 @@ var TopicGenerator = class extends require_discover.ConstructGenerator {
|
|
|
2534
2459
|
}
|
|
2535
2460
|
};
|
|
2536
2461
|
//#endregion
|
|
2537
|
-
//#region src/build/manifests.ts
|
|
2538
|
-
const logger$9 = console;
|
|
2539
|
-
function isPartitioned(field) {
|
|
2540
|
-
return !Array.isArray(field);
|
|
2541
|
-
}
|
|
2542
|
-
/**
|
|
2543
|
-
* Serialize a manifest field to a TypeScript string.
|
|
2544
|
-
* Flat arrays serialize as JSON arrays, partitioned fields as objects of arrays.
|
|
2545
|
-
*/
|
|
2546
|
-
function serializeField(field, indent = 2) {
|
|
2547
|
-
if (Array.isArray(field)) return JSON.stringify(field, null, indent);
|
|
2548
|
-
return `{\n${Object.entries(field).map(([key, value]) => ` ${JSON.stringify(key)}: ${JSON.stringify(value, null, indent)}`).join(",\n")},\n }`;
|
|
2549
|
-
}
|
|
2550
|
-
/**
|
|
2551
|
-
* Count total items across a manifest field (flat or partitioned).
|
|
2552
|
-
*/
|
|
2553
|
-
function countItems(field) {
|
|
2554
|
-
if (Array.isArray(field)) return field.length;
|
|
2555
|
-
return Object.values(field).reduce((sum, arr) => sum + arr.length, 0);
|
|
2556
|
-
}
|
|
2557
|
-
/**
|
|
2558
|
-
* Generate derived types for a construct field.
|
|
2559
|
-
* @param fieldName - The field name in the manifest (e.g., 'routes')
|
|
2560
|
-
* @param typeName - The exported type name (e.g., 'Route')
|
|
2561
|
-
* @param partitioned - Whether this field is partitioned
|
|
2562
|
-
*/
|
|
2563
|
-
function generateDerivedType(fieldName, typeName, partitioned) {
|
|
2564
|
-
if (partitioned) {
|
|
2565
|
-
const partitionTypeName = `${typeName}Partition`;
|
|
2566
|
-
return [`export type ${partitionTypeName} = keyof typeof manifest.${fieldName};`, `export type ${typeName}<P extends ${partitionTypeName} = ${partitionTypeName}> = (typeof manifest.${fieldName})[P][number];`].join("\n");
|
|
2567
|
-
}
|
|
2568
|
-
return `export type ${typeName} = (typeof manifest.${fieldName})[number];`;
|
|
2569
|
-
}
|
|
2570
|
-
/** A manifest field as a flat list, whether or not it is partitioned. */
|
|
2571
|
-
function flatten(field) {
|
|
2572
|
-
return Array.isArray(field) ? field : Object.values(field).flat();
|
|
2573
|
-
}
|
|
2574
|
-
async function generateAwsManifest(outputDir, routes, functions, crons, subscribers, queues = [], topics = [], constructs = {}, backends = {}) {
|
|
2575
|
-
const manifestDir = (0, node_path.join)(outputDir, "manifest");
|
|
2576
|
-
await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
|
|
2577
|
-
const awsRoutes = filterAllRoutes(routes);
|
|
2578
|
-
const routesPartitioned = isPartitioned(awsRoutes);
|
|
2579
|
-
const functionsPartitioned = isPartitioned(functions);
|
|
2580
|
-
const cronsPartitioned = isPartitioned(crons);
|
|
2581
|
-
const subscribersPartitioned = isPartitioned(subscribers);
|
|
2582
|
-
const queuesPartitioned = isPartitioned(queues);
|
|
2583
|
-
const topicsPartitioned = isPartitioned(topics);
|
|
2584
|
-
const awsConstructs = require_emit.withCompute(require_emit.withRoutes(constructs, flatten(awsRoutes), { perRoute: true }), {
|
|
2585
|
-
functions: flatten(functions),
|
|
2586
|
-
crons: flatten(crons),
|
|
2587
|
-
queues: flatten(queues),
|
|
2588
|
-
subscribers: flatten(subscribers)
|
|
2589
|
-
});
|
|
2590
|
-
const content = `export const manifest = {
|
|
2591
|
-
routes: ${serializeField(awsRoutes)},
|
|
2592
|
-
functions: ${serializeField(functions)},
|
|
2593
|
-
crons: ${serializeField(crons)},
|
|
2594
|
-
subscribers: ${serializeField(subscribers)},
|
|
2595
|
-
queues: ${serializeField(queues)},
|
|
2596
|
-
topics: ${serializeField(topics)},
|
|
2597
|
-
} as const;
|
|
2598
|
-
|
|
2599
|
-
/**
|
|
2600
|
-
* What the application declares, as opposed to what this build generated.
|
|
2601
|
-
*
|
|
2602
|
-
* Discovery imports application code, so it runs once here rather than in every
|
|
2603
|
-
* consumer — a deploy config calling it would evaluate the whole runtime graph
|
|
2604
|
-
* inside its own toolchain.
|
|
2605
|
-
*/
|
|
2606
|
-
export const constructs = ${JSON.stringify(awsConstructs, null, 2)} as const;
|
|
2607
|
-
|
|
2608
|
-
/**
|
|
2609
|
-
* Where the backends that are config rather than declaration resolved to.
|
|
2610
|
-
*
|
|
2611
|
-
* Recorded because they were answered twice: once by the build, which registers
|
|
2612
|
-
* exactly one cache driver, and once by a deploy, which told the provisioner
|
|
2613
|
-
* something else — leaving the running code with a URL it had no driver for.
|
|
2614
|
-
*/
|
|
2615
|
-
export const backends = ${JSON.stringify(backends, null, 2)} as const;
|
|
2616
|
-
|
|
2617
|
-
// Derived types
|
|
2618
|
-
${generateDerivedType("routes", "Route", routesPartitioned)}
|
|
2619
|
-
${generateDerivedType("functions", "Function", functionsPartitioned)}
|
|
2620
|
-
${generateDerivedType("crons", "Cron", cronsPartitioned)}
|
|
2621
|
-
${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
|
|
2622
|
-
${generateDerivedType("queues", "Queue", queuesPartitioned)}
|
|
2623
|
-
${generateDerivedType("topics", "Topic", topicsPartitioned)}
|
|
2624
|
-
|
|
2625
|
-
export type ConstructId = keyof typeof constructs;
|
|
2626
|
-
export type Construct<Id extends ConstructId> = (typeof constructs)[Id];
|
|
2627
|
-
|
|
2628
|
-
// Useful union types
|
|
2629
|
-
export type Authorizer = Route['authorizer'];
|
|
2630
|
-
export type HttpMethod = Route['method'];
|
|
2631
|
-
export type RoutePath = Route['path'];
|
|
2632
|
-
`;
|
|
2633
|
-
const manifestPath = (0, node_path.join)(manifestDir, "aws.ts");
|
|
2634
|
-
await (0, node_fs_promises.writeFile)(manifestPath, content);
|
|
2635
|
-
logger$9.log(`Generated AWS manifest with ${countItems(awsRoutes)} routes, ${countItems(functions)} functions, ${countItems(crons)} crons, ${countItems(subscribers)} subscribers, ${countItems(queues)} queues, ${countItems(topics)} topics`);
|
|
2636
|
-
logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
|
|
2637
|
-
}
|
|
2638
|
-
async function generateServerManifest(outputDir, appInfo, routes, subscribers, queues = [], topics = [], constructs = {}, backends = {}) {
|
|
2639
|
-
const manifestDir = (0, node_path.join)(outputDir, "manifest");
|
|
2640
|
-
await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
|
|
2641
|
-
const serverRoutes = mapRouteMetadata(filterAllRoutes(routes));
|
|
2642
|
-
const serverSubscribers = mapSubscriberMetadata(subscribers);
|
|
2643
|
-
const serverQueues = mapQueueMetadata(queues);
|
|
2644
|
-
const serverTopics = mapTopicMetadata(topics);
|
|
2645
|
-
const routesPartitioned = isPartitioned(serverRoutes);
|
|
2646
|
-
const subscribersPartitioned = isPartitioned(serverSubscribers);
|
|
2647
|
-
const queuesPartitioned = isPartitioned(serverQueues);
|
|
2648
|
-
const topicsPartitioned = isPartitioned(serverTopics);
|
|
2649
|
-
const content = `export const manifest = {
|
|
2650
|
-
app: ${JSON.stringify(appInfo, null, 2)},
|
|
2651
|
-
routes: ${serializeField(serverRoutes)},
|
|
2652
|
-
subscribers: ${serializeField(serverSubscribers)},
|
|
2653
|
-
queues: ${serializeField(serverQueues)},
|
|
2654
|
-
topics: ${serializeField(serverTopics)},
|
|
2655
|
-
} as const;
|
|
2656
|
-
|
|
2657
|
-
/**
|
|
2658
|
-
* What the application declares, as opposed to what this build generated.
|
|
2659
|
-
*
|
|
2660
|
-
* Discovery imports application code, so it runs once in the build rather than
|
|
2661
|
-
* in every consumer — a deploy config calling it would evaluate the whole
|
|
2662
|
-
* runtime graph inside its own toolchain.
|
|
2663
|
-
*/
|
|
2664
|
-
export const constructs = ${JSON.stringify(constructs, null, 2)} as const;
|
|
2665
|
-
|
|
2666
|
-
/**
|
|
2667
|
-
* Where the backends that are config rather than declaration resolved to.
|
|
2668
|
-
*
|
|
2669
|
-
* Recorded because they were answered twice: once by the build, which registers
|
|
2670
|
-
* exactly one cache driver, and once by a deploy, which told the provisioner
|
|
2671
|
-
* something else — leaving the running code with a URL it had no driver for.
|
|
2672
|
-
*/
|
|
2673
|
-
export const backends = ${JSON.stringify(backends, null, 2)} as const;
|
|
2674
|
-
|
|
2675
|
-
// Derived types
|
|
2676
|
-
${generateDerivedType("routes", "Route", routesPartitioned)}
|
|
2677
|
-
${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
|
|
2678
|
-
${generateDerivedType("queues", "Queue", queuesPartitioned)}
|
|
2679
|
-
${generateDerivedType("topics", "Topic", topicsPartitioned)}
|
|
2680
|
-
|
|
2681
|
-
export type ConstructId = keyof typeof constructs;
|
|
2682
|
-
export type Construct<Id extends ConstructId> = (typeof constructs)[Id];
|
|
2683
|
-
|
|
2684
|
-
// Useful union types
|
|
2685
|
-
export type Authorizer = Route['authorizer'];
|
|
2686
|
-
export type HttpMethod = Route['method'];
|
|
2687
|
-
export type RoutePath = Route['path'];
|
|
2688
|
-
`;
|
|
2689
|
-
const manifestPath = (0, node_path.join)(manifestDir, "server.ts");
|
|
2690
|
-
await (0, node_fs_promises.writeFile)(manifestPath, content);
|
|
2691
|
-
logger$9.log(`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers, ${countItems(serverQueues)} queues, ${countItems(serverTopics)} topics`);
|
|
2692
|
-
logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
|
|
2693
|
-
}
|
|
2694
|
-
/**
|
|
2695
|
-
* Filter out 'ALL' method routes from a manifest field (flat or partitioned).
|
|
2696
|
-
*/
|
|
2697
|
-
function filterAllRoutes(routes) {
|
|
2698
|
-
if (Array.isArray(routes)) return routes.filter((r) => r.method !== "ALL");
|
|
2699
|
-
const result = {};
|
|
2700
|
-
for (const [partition, partitionRoutes] of Object.entries(routes)) result[partition] = partitionRoutes.filter((r) => r.method !== "ALL");
|
|
2701
|
-
return result;
|
|
2702
|
-
}
|
|
2703
|
-
/**
|
|
2704
|
-
* Map routes to server metadata (path, method, authorizer only).
|
|
2705
|
-
*/
|
|
2706
|
-
function mapRouteMetadata(routes) {
|
|
2707
|
-
const mapFn = (r) => ({
|
|
2708
|
-
path: r.path,
|
|
2709
|
-
method: r.method,
|
|
2710
|
-
authorizer: r.authorizer
|
|
2711
|
-
});
|
|
2712
|
-
if (Array.isArray(routes)) return routes.map(mapFn);
|
|
2713
|
-
const result = {};
|
|
2714
|
-
for (const [partition, partitionRoutes] of Object.entries(routes)) result[partition] = partitionRoutes.map(mapFn);
|
|
2715
|
-
return result;
|
|
2716
|
-
}
|
|
2717
|
-
/**
|
|
2718
|
-
* Map subscribers to server metadata (name, subscribedEvents only).
|
|
2719
|
-
*/
|
|
2720
|
-
function mapSubscriberMetadata(subscribers) {
|
|
2721
|
-
const mapFn = (s) => ({
|
|
2722
|
-
name: s.name,
|
|
2723
|
-
subscribedEvents: s.subscribedEvents
|
|
2724
|
-
});
|
|
2725
|
-
if (Array.isArray(subscribers)) return subscribers.map(mapFn);
|
|
2726
|
-
const result = {};
|
|
2727
|
-
for (const [partition, partitionSubs] of Object.entries(subscribers)) result[partition] = partitionSubs.map(mapFn);
|
|
2728
|
-
return result;
|
|
2729
|
-
}
|
|
2730
|
-
function mapQueueMetadata(queues) {
|
|
2731
|
-
const mapFn = (q) => ({ name: q.name });
|
|
2732
|
-
if (Array.isArray(queues)) return queues.map(mapFn);
|
|
2733
|
-
const result = {};
|
|
2734
|
-
for (const [partition, partitionQueues] of Object.entries(queues)) result[partition] = partitionQueues.map(mapFn);
|
|
2735
|
-
return result;
|
|
2736
|
-
}
|
|
2737
|
-
function mapTopicMetadata(topics) {
|
|
2738
|
-
const mapFn = (t) => ({
|
|
2739
|
-
name: t.name,
|
|
2740
|
-
events: t.events
|
|
2741
|
-
});
|
|
2742
|
-
if (Array.isArray(topics)) return topics.map(mapFn);
|
|
2743
|
-
const result = {};
|
|
2744
|
-
for (const [partition, partitionTopics] of Object.entries(topics)) result[partition] = partitionTopics.map(mapFn);
|
|
2745
|
-
return result;
|
|
2746
|
-
}
|
|
2747
|
-
//#endregion
|
|
2748
2462
|
//#region src/build/owners.ts
|
|
2749
2463
|
/**
|
|
2750
2464
|
* What a generated entry imports its runtime from, read off the discovered
|
|
@@ -2814,27 +2528,6 @@ function restApis(declared) {
|
|
|
2814
2528
|
function servedSurface(declared, workspaceRoot, appRoot) {
|
|
2815
2529
|
return restApis(declared).find((d) => (0, node_path.resolve)(workspaceRoot, d.path) === (0, node_path.resolve)(appRoot));
|
|
2816
2530
|
}
|
|
2817
|
-
/**
|
|
2818
|
-
* Check if any construct across the given arrays has a non-undefined partition.
|
|
2819
|
-
* When true, the manifest should use the partitioned shape for that construct type.
|
|
2820
|
-
*/
|
|
2821
|
-
function hasPartitions(constructs) {
|
|
2822
|
-
return constructs.some((c) => c.partition !== void 0);
|
|
2823
|
-
}
|
|
2824
|
-
/**
|
|
2825
|
-
* Group an info array by partition, using the partition values from
|
|
2826
|
-
* the corresponding construct array. Both arrays must be the same length
|
|
2827
|
-
* and in the same order.
|
|
2828
|
-
*/
|
|
2829
|
-
function groupInfosByPartition(infos, constructs) {
|
|
2830
|
-
const groups = {};
|
|
2831
|
-
for (let i = 0; i < infos.length; i++) {
|
|
2832
|
-
const partition = constructs[i]?.partition ?? "default";
|
|
2833
|
-
if (!groups[partition]) groups[partition] = [];
|
|
2834
|
-
groups[partition].push(infos[i]);
|
|
2835
|
-
}
|
|
2836
|
-
return groups;
|
|
2837
|
-
}
|
|
2838
2531
|
//#endregion
|
|
2839
2532
|
//#region src/build/surfaceEntry.ts
|
|
2840
2533
|
/** Whether a construct serves itself, asked of the construct. */
|
|
@@ -2911,6 +2604,24 @@ function rootGkmConfig(workspace) {
|
|
|
2911
2604
|
constructs: require_workspace.allConstructGlobs(workspace)
|
|
2912
2605
|
};
|
|
2913
2606
|
}
|
|
2607
|
+
/** Directories under `.gkm/` that the removed per-provider builds wrote. */
|
|
2608
|
+
const SUPERSEDED_OUTPUT = [
|
|
2609
|
+
"aws-apigatewayv1",
|
|
2610
|
+
"aws-apigatewayv2",
|
|
2611
|
+
"aws-lambda"
|
|
2612
|
+
];
|
|
2613
|
+
/** Whether `--provider` named something a build can target. */
|
|
2614
|
+
function isMainProvider(value) {
|
|
2615
|
+
return value === "aws" || value === "server";
|
|
2616
|
+
}
|
|
2617
|
+
var UnknownBuildProvider = class extends Error {
|
|
2618
|
+
provider;
|
|
2619
|
+
constructor(provider) {
|
|
2620
|
+
super(`'${provider}' is not a build target. Pass --provider aws or --provider server, or leave it out to build for where gkm.config.ts deploys.`);
|
|
2621
|
+
this.provider = provider;
|
|
2622
|
+
this.name = "UnknownBuildProvider";
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2914
2625
|
async function buildCommand(options) {
|
|
2915
2626
|
const loadedConfig = await require_config.loadWorkspaceConfig();
|
|
2916
2627
|
if (loadedConfig.type === "workspace") {
|
|
@@ -2924,25 +2635,62 @@ async function buildCommand(options) {
|
|
|
2924
2635
|
}
|
|
2925
2636
|
}
|
|
2926
2637
|
const config = loadedConfig.type !== "workspace" ? await require_config.loadConfig() : (0, node_path.resolve)(process.cwd()) === (0, node_path.resolve)(loadedConfig.workspace.root) ? rootGkmConfig(loadedConfig.workspace) : (await require_config.loadAppConfig()).gkmConfig;
|
|
2927
|
-
const
|
|
2928
|
-
const
|
|
2929
|
-
const
|
|
2930
|
-
const
|
|
2638
|
+
const target = options.provider ?? require_backends.providerOf(loadedConfig.workspace);
|
|
2639
|
+
const workspaceRoot = loadedConfig.workspace.root;
|
|
2640
|
+
const appRoot = process.cwd();
|
|
2641
|
+
const output = await buildOneApp({
|
|
2642
|
+
config,
|
|
2643
|
+
options,
|
|
2644
|
+
workspace: loadedConfig.workspace,
|
|
2645
|
+
appRoot,
|
|
2646
|
+
target
|
|
2647
|
+
});
|
|
2648
|
+
if ((0, node_path.resolve)(appRoot) === (0, node_path.resolve)(workspaceRoot)) await writeManifest({
|
|
2649
|
+
workspaceRoot,
|
|
2650
|
+
target,
|
|
2651
|
+
builds: output.built ? [output.built] : [],
|
|
2652
|
+
constructs: await declaredIn(config, workspaceRoot),
|
|
2653
|
+
backends: backendsOf(loadedConfig.workspace)
|
|
2654
|
+
});
|
|
2655
|
+
return output;
|
|
2656
|
+
}
|
|
2657
|
+
/** What the workspace declares, read through a config's globs. */
|
|
2658
|
+
async function declaredIn(config, cwd) {
|
|
2659
|
+
return require_discover.discover({
|
|
2660
|
+
patterns: config.constructs,
|
|
2661
|
+
cwd
|
|
2662
|
+
});
|
|
2663
|
+
}
|
|
2664
|
+
/**
|
|
2665
|
+
* The backend choices the manifest records — answered by the deploy target,
|
|
2666
|
+
* the same place reconcile and the build's drivers read them.
|
|
2667
|
+
*/
|
|
2668
|
+
function backendsOf(workspace) {
|
|
2669
|
+
return {
|
|
2670
|
+
cache: require_backends.cacheBackendFor(require_backends.providerOf(workspace)),
|
|
2671
|
+
email: "ses"
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
/** One app's build, from its config and the command's options. */
|
|
2675
|
+
async function buildOneApp(input) {
|
|
2676
|
+
const { config, options, workspace, appRoot, target } = input;
|
|
2677
|
+
const cacheBackend = require_backends.cacheBackendFor(require_backends.providerOf(workspace));
|
|
2678
|
+
const production = normalizeProductionConfig(options.production ?? false);
|
|
2931
2679
|
if (production) logger$8.log(`🏭 Building for PRODUCTION`);
|
|
2932
|
-
logger$8.log(`Building
|
|
2680
|
+
logger$8.log(`Building for ${target}`);
|
|
2933
2681
|
logger$8.log(`Loading constructs from: ${formatRoutes(config.constructs)}`);
|
|
2934
2682
|
const telescope = production ? void 0 : normalizeTelescopeConfig(config.telescope);
|
|
2935
2683
|
if (telescope) logger$8.log(`🔭 Telescope enabled at ${telescope.path}`);
|
|
2936
2684
|
const studio = production ? void 0 : normalizeStudioConfig(config.studio);
|
|
2937
2685
|
if (studio) logger$8.log(`🗄️ Studio enabled at ${studio.path}`);
|
|
2938
|
-
const hooks = normalizeHooksConfig(config.hooks);
|
|
2686
|
+
const hooks = normalizeHooksConfig(config.hooks, appRoot);
|
|
2939
2687
|
if (hooks) logger$8.log(`🪝 Server hooks enabled`);
|
|
2940
2688
|
return buildApp({
|
|
2941
2689
|
config,
|
|
2942
|
-
workspaceRoot:
|
|
2943
|
-
appRoot
|
|
2944
|
-
|
|
2945
|
-
enableOpenApi:
|
|
2690
|
+
workspaceRoot: workspace.root,
|
|
2691
|
+
appRoot,
|
|
2692
|
+
target,
|
|
2693
|
+
enableOpenApi: options.enableOpenApi ?? false,
|
|
2946
2694
|
cacheBackend,
|
|
2947
2695
|
production,
|
|
2948
2696
|
telescope,
|
|
@@ -2954,6 +2702,33 @@ async function buildCommand(options) {
|
|
|
2954
2702
|
});
|
|
2955
2703
|
}
|
|
2956
2704
|
/**
|
|
2705
|
+
* Write the application's manifest: every declared construct, with what each
|
|
2706
|
+
* app generated folded into it.
|
|
2707
|
+
*
|
|
2708
|
+
* The manifest belongs to the whole application, so only the root writes it —
|
|
2709
|
+
* once, after every app has built, from the constructs the workspace declares.
|
|
2710
|
+
* An app's own build generates its handlers and nothing else.
|
|
2711
|
+
*/
|
|
2712
|
+
async function writeManifest(input) {
|
|
2713
|
+
const { workspaceRoot, target, builds, constructs, backends } = input;
|
|
2714
|
+
const manifestDir = (0, node_path.join)(workspaceRoot, ".gkm", "manifest");
|
|
2715
|
+
await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
|
|
2716
|
+
await (0, node_fs_promises.rm)((0, node_path.join)(manifestDir, `${target === "aws" ? "server" : "aws"}.ts`), { force: true });
|
|
2717
|
+
const withServed = builds.reduce((manifest, build) => require_emit.withRoutes(manifest, build.routes.filter((route) => route.method !== "ALL"), {
|
|
2718
|
+
perRoute: true,
|
|
2719
|
+
...build.surface ? { surface: build.surface } : {}
|
|
2720
|
+
}), constructs);
|
|
2721
|
+
const folded = require_emit.withCompute(withServed, {
|
|
2722
|
+
functions: builds.flatMap((build) => build.functions),
|
|
2723
|
+
crons: builds.flatMap((build) => build.crons),
|
|
2724
|
+
queues: builds.flatMap((build) => build.queues),
|
|
2725
|
+
subscribers: builds.flatMap((build) => build.subscribers)
|
|
2726
|
+
});
|
|
2727
|
+
const path = (0, node_path.join)(manifestDir, `${target}.ts`);
|
|
2728
|
+
await (0, node_fs_promises.writeFile)(path, require_emit.manifestModule(folded, backends));
|
|
2729
|
+
logger$8.log(`Manifest: ${(0, node_path.relative)(process.cwd(), path)}`);
|
|
2730
|
+
}
|
|
2731
|
+
/**
|
|
2957
2732
|
* Turn one app's constructs into its generated entry.
|
|
2958
2733
|
*
|
|
2959
2734
|
* `gkm build` and `gkm dev` both run this. They used to be two copies of it,
|
|
@@ -2962,8 +2737,8 @@ async function buildCommand(options) {
|
|
|
2962
2737
|
* dev did not, and failed on exactly the apps the build had learned to handle.
|
|
2963
2738
|
*/
|
|
2964
2739
|
async function buildApp(input) {
|
|
2965
|
-
const { config, workspaceRoot, appRoot,
|
|
2966
|
-
const constructGlobs =
|
|
2740
|
+
const { config, workspaceRoot, appRoot, target, enableOpenApi, cacheBackend, production, telescope, studio, hooks, bustCache = false } = input;
|
|
2741
|
+
const constructGlobs = config.constructs;
|
|
2967
2742
|
const constructSources = {};
|
|
2968
2743
|
const declared = constructGlobs ? await require_discover.discover({
|
|
2969
2744
|
patterns: constructGlobs,
|
|
@@ -3029,50 +2804,58 @@ async function buildApp(input) {
|
|
|
3029
2804
|
logger$8.log("No endpoints, functions, crons, subscribers, queues, or topics found to process");
|
|
3030
2805
|
return {};
|
|
3031
2806
|
}
|
|
3032
|
-
const
|
|
3033
|
-
await (0, node_fs_promises.mkdir)(rootOutputDir, { recursive: true });
|
|
3034
|
-
let result = {};
|
|
3035
|
-
for (const provider of providers) {
|
|
3036
|
-
const providerResult = await buildForProvider(provider, buildContext, appRoot, declared, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, allQueues, allTopics, enableOpenApi, input.skipBundle ?? false, input.stage);
|
|
3037
|
-
if (providerResult.masterKey) result = providerResult;
|
|
3038
|
-
}
|
|
2807
|
+
const result = await buildForTarget(target, buildContext, appRoot, workspaceRoot, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, allQueues, allTopics, enableOpenApi, input.skipBundle ?? false, input.stage);
|
|
3039
2808
|
await require_openapi.generateOpenApi(allEndpoints.map(({ construct }) => construct), { openapi: config.openapi });
|
|
3040
2809
|
return result;
|
|
3041
2810
|
}
|
|
3042
|
-
async function
|
|
3043
|
-
const
|
|
3044
|
-
|
|
2811
|
+
async function buildForTarget(target, context, appRoot, workspaceRoot, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, endpoints, functions, crons, subscribers, queues, topics, enableOpenApi, skipBundle, stage) {
|
|
2812
|
+
const outputDir = (0, node_path.join)(appRoot, ".gkm", target);
|
|
2813
|
+
await Promise.all([...SUPERSEDED_OUTPUT.map((dir) => (0, node_path.join)(appRoot, ".gkm", dir)), ...appRoot === workspaceRoot ? [] : [(0, node_path.join)(appRoot, ".gkm", "manifest")]].map((dir) => (0, node_fs_promises.rm)(dir, {
|
|
2814
|
+
recursive: true,
|
|
2815
|
+
force: true
|
|
2816
|
+
})));
|
|
2817
|
+
if (target === "aws") await (0, node_fs_promises.rm)(outputDir, {
|
|
2818
|
+
recursive: true,
|
|
2819
|
+
force: true
|
|
2820
|
+
});
|
|
3045
2821
|
await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
|
|
3046
|
-
logger$8.log(`\nGenerating handlers for
|
|
2822
|
+
logger$8.log(`\nGenerating handlers for ${target}`);
|
|
2823
|
+
const options = {
|
|
2824
|
+
target,
|
|
2825
|
+
root: workspaceRoot
|
|
2826
|
+
};
|
|
3047
2827
|
const [routes, functionInfos, cronInfos, subscriberInfos, queueInfos, topicInfos] = await Promise.all([
|
|
3048
2828
|
endpointGenerator.build(context, endpoints, outputDir, {
|
|
3049
|
-
|
|
2829
|
+
...options,
|
|
3050
2830
|
enableOpenApi
|
|
3051
2831
|
}),
|
|
3052
|
-
functionGenerator.build(context, functions, outputDir,
|
|
3053
|
-
cronGenerator.build(context, crons, outputDir,
|
|
3054
|
-
subscriberGenerator.build(context, subscribers, outputDir,
|
|
3055
|
-
queueGenerator.build(context, queues, outputDir,
|
|
3056
|
-
topicGenerator.build(context, topics, outputDir,
|
|
2832
|
+
functionGenerator.build(context, functions, outputDir, options),
|
|
2833
|
+
cronGenerator.build(context, crons, outputDir, options),
|
|
2834
|
+
subscriberGenerator.build(context, subscribers, outputDir, options),
|
|
2835
|
+
queueGenerator.build(context, queues, outputDir, options),
|
|
2836
|
+
topicGenerator.build(context, topics, outputDir, options)
|
|
3057
2837
|
]);
|
|
3058
|
-
logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${
|
|
3059
|
-
const
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
2838
|
+
logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${target}`);
|
|
2839
|
+
const fields = {
|
|
2840
|
+
...context.surface ? { surface: context.surface.id } : {},
|
|
2841
|
+
functions: functionInfos,
|
|
2842
|
+
crons: cronInfos,
|
|
2843
|
+
queues: queueInfos,
|
|
2844
|
+
subscribers: subscriberInfos
|
|
2845
|
+
};
|
|
2846
|
+
if (target === "server") {
|
|
2847
|
+
const handler = (0, node_path.relative)(workspaceRoot, (0, node_path.join)(outputDir, "app.ts"));
|
|
2848
|
+
const built = {
|
|
2849
|
+
...fields,
|
|
2850
|
+
routes: await Promise.all(endpoints.map(async ({ construct }) => ({
|
|
2851
|
+
path: construct._path,
|
|
2852
|
+
method: construct.method,
|
|
2853
|
+
handler,
|
|
2854
|
+
environment: await construct.getEnvironment({ markOptional: context.markOptional }),
|
|
2855
|
+
dependencies: construct.constructs,
|
|
2856
|
+
authorizer: construct.authorizer?.name ?? "none"
|
|
2857
|
+
})))
|
|
2858
|
+
};
|
|
3076
2859
|
let masterKey;
|
|
3077
2860
|
if (context.production?.bundle && !skipBundle) {
|
|
3078
2861
|
logger$8.log(`\n📦 Bundling production server...`);
|
|
@@ -3099,12 +2882,15 @@ async function buildForProvider(provider, context, appRoot, discovered, endpoint
|
|
|
3099
2882
|
logger$8.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
|
|
3100
2883
|
}
|
|
3101
2884
|
}
|
|
3102
|
-
return {
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
}
|
|
3107
|
-
return {
|
|
2885
|
+
return {
|
|
2886
|
+
masterKey,
|
|
2887
|
+
built
|
|
2888
|
+
};
|
|
2889
|
+
}
|
|
2890
|
+
return { built: {
|
|
2891
|
+
...fields,
|
|
2892
|
+
routes
|
|
2893
|
+
} };
|
|
3108
2894
|
}
|
|
3109
2895
|
/**
|
|
3110
2896
|
* Detect available package manager.
|
|
@@ -3126,8 +2912,8 @@ function detectPackageManager$2() {
|
|
|
3126
2912
|
*
|
|
3127
2913
|
* @internal Exported for testing
|
|
3128
2914
|
*/
|
|
3129
|
-
function getTurboCommand(pm, filters = []) {
|
|
3130
|
-
const filterArgs = (typeof filters === "string" ? [filters] : filters).map((f) => ` --filter=${f}`).join("");
|
|
2915
|
+
function getTurboCommand(pm, filters = [], { only = false } = {}) {
|
|
2916
|
+
const filterArgs = (typeof filters === "string" ? [filters] : filters).map((f) => ` --filter=${f}`).join("") + (only ? " --only" : "");
|
|
3131
2917
|
switch (pm) {
|
|
3132
2918
|
case "pnpm": return `pnpm exec turbo run build${filterArgs}`;
|
|
3133
2919
|
case "yarn": return `yarn turbo run build${filterArgs}`;
|
|
@@ -3147,10 +2933,11 @@ function getTurboCommand(pm, filters = []) {
|
|
|
3147
2933
|
*
|
|
3148
2934
|
* @internal Exported for testing
|
|
3149
2935
|
*/
|
|
3150
|
-
function turboFilters(workspace) {
|
|
2936
|
+
function turboFilters(workspace, { exclude } = {}) {
|
|
3151
2937
|
const filters = [];
|
|
3152
2938
|
const unpackaged = [];
|
|
3153
|
-
for (const appName of Object.
|
|
2939
|
+
for (const [appName, app] of Object.entries(workspace.apps)) {
|
|
2940
|
+
if (app.type === exclude) continue;
|
|
3154
2941
|
const name = appPackageName(workspace, appName);
|
|
3155
2942
|
if (name) filters.push(name);
|
|
3156
2943
|
else unpackaged.push(appName);
|
|
@@ -3189,31 +2976,59 @@ async function workspaceBuildCommand(workspace, options) {
|
|
|
3189
2976
|
if (options.production) logger$8.log(` 🏭 Production mode enabled`);
|
|
3190
2977
|
const buildOrder = require_workspace.getAppBuildOrder(workspace);
|
|
3191
2978
|
logger$8.log(` Build order: ${buildOrder.join(" → ")}`);
|
|
3192
|
-
const pm = detectPackageManager$2();
|
|
3193
|
-
logger$8.log(`\n📦 Using ${pm} with Turbo for parallel builds...\n`);
|
|
3194
2979
|
try {
|
|
3195
|
-
const
|
|
3196
|
-
|
|
3197
|
-
const
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
});
|
|
3209
|
-
child.on("close", (code) => {
|
|
3210
|
-
if (code === 0) resolve();
|
|
3211
|
-
else reject(/* @__PURE__ */ new Error(`Turbo build failed with exit code ${code}`));
|
|
3212
|
-
});
|
|
3213
|
-
child.on("error", (err) => {
|
|
3214
|
-
reject(err);
|
|
2980
|
+
const target = options.provider ?? require_backends.providerOf(workspace);
|
|
2981
|
+
const builds = [];
|
|
2982
|
+
for (const appName of buildOrder) {
|
|
2983
|
+
const app = workspace.apps[appName];
|
|
2984
|
+
const config = require_workspace.getAppGkmConfig(workspace, appName);
|
|
2985
|
+
if (!app || app.type !== "backend" || !config) continue;
|
|
2986
|
+
logger$8.log(`\n⚙️ ${appName}`);
|
|
2987
|
+
const output = await buildOneApp({
|
|
2988
|
+
config,
|
|
2989
|
+
options,
|
|
2990
|
+
workspace,
|
|
2991
|
+
appRoot: (0, node_path.join)(workspace.root, app.path),
|
|
2992
|
+
target
|
|
3215
2993
|
});
|
|
2994
|
+
if (output.built) builds.push(output.built);
|
|
2995
|
+
}
|
|
2996
|
+
await writeManifest({
|
|
2997
|
+
workspaceRoot: workspace.root,
|
|
2998
|
+
target,
|
|
2999
|
+
builds,
|
|
3000
|
+
constructs: await require_discover.discover({
|
|
3001
|
+
patterns: require_workspace.allConstructGlobs(workspace),
|
|
3002
|
+
cwd: workspace.root
|
|
3003
|
+
}),
|
|
3004
|
+
backends: backendsOf(workspace)
|
|
3216
3005
|
});
|
|
3006
|
+
const { filters, unpackaged } = turboFilters(workspace, { exclude: "backend" });
|
|
3007
|
+
if (unpackaged.length > 0) throw new Error(`No package.json for workspace app(s): ${unpackaged.join(", ")}. Each app needs one — turbo builds packages, and gkm reads the name back to know which app it is building.`);
|
|
3008
|
+
const pm = detectPackageManager$2();
|
|
3009
|
+
const turboCommand = getTurboCommand(pm, filters, { only: true });
|
|
3010
|
+
if (filters.length > 0) {
|
|
3011
|
+
logger$8.log(`\n📦 Using ${pm} with Turbo for the other apps...\n`);
|
|
3012
|
+
logger$8.log(`Running: ${turboCommand}`);
|
|
3013
|
+
await new Promise((resolve, reject) => {
|
|
3014
|
+
const child = (0, node_child_process.spawn)(turboCommand, {
|
|
3015
|
+
shell: true,
|
|
3016
|
+
cwd: workspace.root,
|
|
3017
|
+
stdio: "inherit",
|
|
3018
|
+
env: {
|
|
3019
|
+
...process.env,
|
|
3020
|
+
NODE_ENV: options.production ? "production" : "development"
|
|
3021
|
+
}
|
|
3022
|
+
});
|
|
3023
|
+
child.on("close", (code) => {
|
|
3024
|
+
if (code === 0) resolve();
|
|
3025
|
+
else reject(/* @__PURE__ */ new Error(`Turbo build failed with exit code ${code}`));
|
|
3026
|
+
});
|
|
3027
|
+
child.on("error", (err) => {
|
|
3028
|
+
reject(err);
|
|
3029
|
+
});
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3217
3032
|
for (const [appName, app] of apps) {
|
|
3218
3033
|
const outputPath = getAppOutputPath(workspace, appName, app);
|
|
3219
3034
|
results.push({
|
|
@@ -3256,23 +3071,11 @@ function getAppOutputPath(workspace, _appName, app) {
|
|
|
3256
3071
|
}
|
|
3257
3072
|
return (0, node_path.join)(appPath, ".gkm");
|
|
3258
3073
|
}
|
|
3259
|
-
/**
|
|
3260
|
-
* Format routes for logging, handling PartitionedRoutes.
|
|
3261
|
-
*/
|
|
3074
|
+
/** Format routes for logging. */
|
|
3262
3075
|
function formatRoutes(routes) {
|
|
3263
|
-
if (require_discover.isPartitionedRoutes(routes)) return `${Array.isArray(routes.paths) ? routes.paths.join(", ") : routes.paths} (partitioned)`;
|
|
3264
3076
|
return Array.isArray(routes) ? routes.join(", ") : routes;
|
|
3265
3077
|
}
|
|
3266
3078
|
/**
|
|
3267
|
-
* Assemble a ManifestField from build infos and constructs.
|
|
3268
|
-
* If any construct has a partition, returns a Record<string, T[]>.
|
|
3269
|
-
* Otherwise, returns a flat T[].
|
|
3270
|
-
*/
|
|
3271
|
-
function assembleManifestField(infos, constructs) {
|
|
3272
|
-
if (!hasPartitions(constructs)) return infos;
|
|
3273
|
-
return groupInfosByPartition(infos, constructs);
|
|
3274
|
-
}
|
|
3275
|
-
/**
|
|
3276
3079
|
* Format a fatal error for display.
|
|
3277
3080
|
* Always includes the full stack trace since these are process-ending errors.
|
|
3278
3081
|
*/
|
|
@@ -3575,6 +3378,19 @@ const PROVISIONERS = {
|
|
|
3575
3378
|
return { provides: { [key]: supplied(declaration.id, key, context) } };
|
|
3576
3379
|
},
|
|
3577
3380
|
/**
|
|
3381
|
+
* The keyring the stage keeps in its secrets.
|
|
3382
|
+
*
|
|
3383
|
+
* Generated on the first deploy (`withGeneratedSecrets`) and rotated only
|
|
3384
|
+
* by `gkm encryption:rotate`, so a redeploy never changes a key and nothing
|
|
3385
|
+
* written becomes unreadable. Nothing is created in Dokploy: the process
|
|
3386
|
+
* holds the keyring.
|
|
3387
|
+
*/
|
|
3388
|
+
encryption: async (declaration, context) => {
|
|
3389
|
+
if (declaration.kind !== "encryption") throw new WrongKind(declaration.kind);
|
|
3390
|
+
const key = (0, _geekmidas_manifest.provideKey)(declaration.id, "url");
|
|
3391
|
+
return { provides: { [key]: supplied(declaration.id, key, context) } };
|
|
3392
|
+
},
|
|
3393
|
+
/**
|
|
3578
3394
|
* A third party's credentials, as the stage was given them.
|
|
3579
3395
|
*
|
|
3580
3396
|
* Nothing is created and nothing derived: the value was issued by somebody
|
|
@@ -3944,9 +3760,9 @@ async function provisionDeclared(options) {
|
|
|
3944
3760
|
environmentId: options.environmentId,
|
|
3945
3761
|
stage: options.stage,
|
|
3946
3762
|
project: workspace.name,
|
|
3947
|
-
cache:
|
|
3948
|
-
events:
|
|
3949
|
-
storage:
|
|
3763
|
+
cache: require_backends.cacheBackendFor(require_backends.providerOf(workspace)),
|
|
3764
|
+
events: require_backends.eventsBackendFor(require_backends.providerOf(workspace)),
|
|
3765
|
+
storage: require_backends.storageBackendFor(require_backends.providerOf(workspace)),
|
|
3950
3766
|
addresses: surfaceAddresses(workspace, manifest, options.appUrls),
|
|
3951
3767
|
seed: options.seed,
|
|
3952
3768
|
...options.supplied ? { supplied: options.supplied } : {},
|
|
@@ -5424,9 +5240,8 @@ async function dockerCommand(options) {
|
|
|
5424
5240
|
logger$6.log("📦 Detected workspace configuration");
|
|
5425
5241
|
return workspaceDockerCommand(loadedConfig.workspace);
|
|
5426
5242
|
}
|
|
5427
|
-
const
|
|
5428
|
-
const
|
|
5429
|
-
const healthCheckPath = (typeof config.providers?.server === "object" ? config.providers.server : void 0)?.production?.healthCheck ?? "/health";
|
|
5243
|
+
const dockerConfig = resolveDockerConfig(await require_config.loadConfig());
|
|
5244
|
+
const healthCheckPath = "/health";
|
|
5430
5245
|
const useSlim = options.slim === true;
|
|
5431
5246
|
if (useSlim) {
|
|
5432
5247
|
const distDir = (0, node_path.join)(process.cwd(), ".gkm", "server", "dist");
|
|
@@ -6585,6 +6400,8 @@ function validateEnvVars(requiredVars, context) {
|
|
|
6585
6400
|
* who could read the repo.
|
|
6586
6401
|
* - **Each `secret` construct's value** — an auth server's signing secret —
|
|
6587
6402
|
* random, rather than derived.
|
|
6403
|
+
* - **Each `encryption` construct's keyring** — one random key and an index
|
|
6404
|
+
* key. Later keys are added by `gkm encryption:rotate`, never by a deploy.
|
|
6588
6405
|
*
|
|
6589
6406
|
* Both are generated on the first deploy that needs them and written to the
|
|
6590
6407
|
* stage's store, so every later deploy reads the same values: sessions survive
|
|
@@ -6600,10 +6417,10 @@ function withGeneratedSecrets(secrets, manifest) {
|
|
|
6600
6417
|
const generated = [];
|
|
6601
6418
|
const custom = { ...secrets.custom };
|
|
6602
6419
|
for (const declaration of Object.values(manifest)) {
|
|
6603
|
-
if (declaration?.kind !== "secret") continue;
|
|
6420
|
+
if (declaration?.kind !== "secret" && declaration?.kind !== "encryption") continue;
|
|
6604
6421
|
const key = declaration.provides?.[0];
|
|
6605
6422
|
if (!key || custom[key]) continue;
|
|
6606
|
-
custom[key] = random();
|
|
6423
|
+
custom[key] = declaration.kind === "encryption" ? (0, _geekmidas_constructs_encryption.generateKeyring)() : random();
|
|
6607
6424
|
generated.push(key);
|
|
6608
6425
|
}
|
|
6609
6426
|
const seed = secrets.seed ?? random();
|
|
@@ -7432,6 +7249,10 @@ async function workspaceDeployCommand(configured, options) {
|
|
|
7432
7249
|
} else logger$4.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
|
|
7433
7250
|
const dokployApps = appsToDeployNames.filter((name) => {
|
|
7434
7251
|
const target = workspace.apps[name].resolvedDeployTarget;
|
|
7252
|
+
if (target === "sst") {
|
|
7253
|
+
logger$4.log(` ⚠️ Skipping ${name}: it deploys with SST — run \`gkm build && sst deploy --stage ${stage}\``);
|
|
7254
|
+
return false;
|
|
7255
|
+
}
|
|
7435
7256
|
if (!require_workspace.isDeployTargetSupported(target)) {
|
|
7436
7257
|
logger$4.log(` ⚠️ Skipping ${name}: ${require_workspace.getDeployTargetError(target, name)}`);
|
|
7437
7258
|
return false;
|
|
@@ -7952,66 +7773,6 @@ async function createApi(endpoint) {
|
|
|
7952
7773
|
});
|
|
7953
7774
|
}
|
|
7954
7775
|
/**
|
|
7955
|
-
* Update gkm.config.ts with Dokploy configuration
|
|
7956
|
-
*/
|
|
7957
|
-
/**
|
|
7958
|
-
* Whether the file's `dokploy` block is more than a flat literal.
|
|
7959
|
-
*
|
|
7960
|
-
* A spread, a `process.env`, a ternary or a nested object all defeat the
|
|
7961
|
-
* single-level regex below — the first two by being expressions it would
|
|
7962
|
-
* stringify away, the last by ending the match at the wrong brace.
|
|
7963
|
-
*/
|
|
7964
|
-
function unsafeToRewrite(content) {
|
|
7965
|
-
const start = content.indexOf("dokploy:");
|
|
7966
|
-
if (start === -1) return false;
|
|
7967
|
-
const block = content.slice(start, content.indexOf("\n },", start) + 1);
|
|
7968
|
-
return /\.\.\.|process\.env|\?\s|`|\{[^}]*\{/s.test(block);
|
|
7969
|
-
}
|
|
7970
|
-
async function updateConfig(config, cwd = process.cwd()) {
|
|
7971
|
-
const configPath = (0, node_path.join)(cwd, "gkm.config.ts");
|
|
7972
|
-
if (!(0, node_fs.existsSync)(configPath)) {
|
|
7973
|
-
logger$3.warn("\n gkm.config.ts not found. Add this configuration manually:\n");
|
|
7974
|
-
logger$3.log(` providers: {`);
|
|
7975
|
-
logger$3.log(` dokploy: {`);
|
|
7976
|
-
logger$3.log(` endpoint: '${config.endpoint}',`);
|
|
7977
|
-
logger$3.log(` projectId: '${config.projectId}',`);
|
|
7978
|
-
logger$3.log(` applicationId: '${config.applicationId}',`);
|
|
7979
|
-
logger$3.log(` },`);
|
|
7980
|
-
logger$3.log(` },`);
|
|
7981
|
-
return;
|
|
7982
|
-
}
|
|
7983
|
-
const content = await (0, node_fs_promises.readFile)(configPath, "utf-8");
|
|
7984
|
-
if (unsafeToRewrite(content)) {
|
|
7985
|
-
logger$3.warn("\n gkm.config.ts holds a dokploy block this cannot safely rewrite —\n it contains an expression or a nested object. Leaving it alone.");
|
|
7986
|
-
logger$3.log(`\n Discovered, if you want them written down:`);
|
|
7987
|
-
logger$3.log(` projectId: '${config.projectId}'`);
|
|
7988
|
-
logger$3.log(` applicationId: '${config.applicationId}'`);
|
|
7989
|
-
if (config.registryId) logger$3.log(` registryId: '${config.registryId}'`);
|
|
7990
|
-
return;
|
|
7991
|
-
}
|
|
7992
|
-
if (content.includes("dokploy:") && content.includes("applicationId:")) {
|
|
7993
|
-
logger$3.log("\n Dokploy config already exists in gkm.config.ts");
|
|
7994
|
-
logger$3.log(" Updating with new values...");
|
|
7995
|
-
}
|
|
7996
|
-
const registryLine = config.registryId ? `\n\t\t\tregistryId: '${config.registryId}',` : "";
|
|
7997
|
-
const dokployConfigStr = `dokploy: {
|
|
7998
|
-
endpoint: '${config.endpoint}',
|
|
7999
|
-
projectId: '${config.projectId}',
|
|
8000
|
-
applicationId: '${config.applicationId}',${registryLine}
|
|
8001
|
-
}`;
|
|
8002
|
-
let newContent;
|
|
8003
|
-
if (content.includes("providers:")) {
|
|
8004
|
-
if (content.includes("dokploy:")) newContent = content.replace(/dokploy:\s*\{[^}]*\}/s, dokployConfigStr);
|
|
8005
|
-
else newContent = content.replace(/providers:\s*\{/, `providers: {\n\t\t${dokployConfigStr},`);
|
|
8006
|
-
} else newContent = content.replace(/}\s*\)\s*;?\s*$/, `
|
|
8007
|
-
providers: {
|
|
8008
|
-
${dokployConfigStr},
|
|
8009
|
-
},
|
|
8010
|
-
});`);
|
|
8011
|
-
await (0, node_fs_promises.writeFile)(configPath, newContent);
|
|
8012
|
-
logger$3.log("\n ✓ Updated gkm.config.ts with Dokploy configuration");
|
|
8013
|
-
}
|
|
8014
|
-
/**
|
|
8015
7776
|
* Initialize Dokploy deployment configuration
|
|
8016
7777
|
*/
|
|
8017
7778
|
async function deployInitCommand(options) {
|
|
@@ -8064,7 +7825,6 @@ async function deployInitCommand(options) {
|
|
|
8064
7825
|
projectId,
|
|
8065
7826
|
applicationId: application.applicationId
|
|
8066
7827
|
};
|
|
8067
|
-
await updateConfig(config);
|
|
8068
7828
|
logger$3.log(`\n✅ Dokploy deployment initialized!`);
|
|
8069
7829
|
logger$3.log(`\n📋 Configuration:`);
|
|
8070
7830
|
logger$3.log(` Project ID: ${projectId}`);
|
|
@@ -9334,26 +9094,26 @@ function loadPackageJson() {
|
|
|
9334
9094
|
* Run: pnpm --filter @geekmidas/cli sync-versions
|
|
9335
9095
|
*/
|
|
9336
9096
|
const GEEKMIDAS_VERSIONS = {
|
|
9337
|
-
"@geekmidas/audit": "~10.0.0-alpha.
|
|
9338
|
-
"@geekmidas/auth": "~10.0.0-alpha.
|
|
9339
|
-
"@geekmidas/cache": "~10.0.0-alpha.
|
|
9340
|
-
"@geekmidas/client": "~10.0.0-alpha.
|
|
9341
|
-
"@geekmidas/cloud": "~10.0.0-alpha.
|
|
9342
|
-
"@geekmidas/constructs": "~10.0.0-alpha.
|
|
9343
|
-
"@geekmidas/db": "~10.0.0-alpha.
|
|
9344
|
-
"@geekmidas/emailkit": "~10.0.0-alpha.
|
|
9345
|
-
"@geekmidas/envkit": "~10.0.0-alpha.
|
|
9346
|
-
"@geekmidas/errors": "~10.0.0-alpha.
|
|
9347
|
-
"@geekmidas/events": "~10.0.0-alpha.
|
|
9348
|
-
"@geekmidas/logger": "~10.0.0-alpha.
|
|
9349
|
-
"@geekmidas/manifest": "~10.0.0-alpha.
|
|
9350
|
-
"@geekmidas/rate-limit": "~10.0.0-alpha.
|
|
9351
|
-
"@geekmidas/schema": "~10.0.0-alpha.
|
|
9352
|
-
"@geekmidas/services": "~10.0.0-alpha.
|
|
9353
|
-
"@geekmidas/storage": "~10.0.0-alpha.
|
|
9354
|
-
"@geekmidas/studio": "~10.0.0-alpha.
|
|
9355
|
-
"@geekmidas/telescope": "~10.0.0-alpha.
|
|
9356
|
-
"@geekmidas/testkit": "~10.0.0-alpha.
|
|
9097
|
+
"@geekmidas/audit": "~10.0.0-alpha.47",
|
|
9098
|
+
"@geekmidas/auth": "~10.0.0-alpha.47",
|
|
9099
|
+
"@geekmidas/cache": "~10.0.0-alpha.47",
|
|
9100
|
+
"@geekmidas/client": "~10.0.0-alpha.47",
|
|
9101
|
+
"@geekmidas/cloud": "~10.0.0-alpha.47",
|
|
9102
|
+
"@geekmidas/constructs": "~10.0.0-alpha.47",
|
|
9103
|
+
"@geekmidas/db": "~10.0.0-alpha.47",
|
|
9104
|
+
"@geekmidas/emailkit": "~10.0.0-alpha.47",
|
|
9105
|
+
"@geekmidas/envkit": "~10.0.0-alpha.47",
|
|
9106
|
+
"@geekmidas/errors": "~10.0.0-alpha.47",
|
|
9107
|
+
"@geekmidas/events": "~10.0.0-alpha.47",
|
|
9108
|
+
"@geekmidas/logger": "~10.0.0-alpha.47",
|
|
9109
|
+
"@geekmidas/manifest": "~10.0.0-alpha.47",
|
|
9110
|
+
"@geekmidas/rate-limit": "~10.0.0-alpha.47",
|
|
9111
|
+
"@geekmidas/schema": "~10.0.0-alpha.47",
|
|
9112
|
+
"@geekmidas/services": "~10.0.0-alpha.47",
|
|
9113
|
+
"@geekmidas/storage": "~10.0.0-alpha.47",
|
|
9114
|
+
"@geekmidas/studio": "~10.0.0-alpha.47",
|
|
9115
|
+
"@geekmidas/telescope": "~10.0.0-alpha.47",
|
|
9116
|
+
"@geekmidas/testkit": "~10.0.0-alpha.47",
|
|
9357
9117
|
"@geekmidas/cli": `~${loadPackageJson().version}`
|
|
9358
9118
|
};
|
|
9359
9119
|
//#endregion
|
|
@@ -10880,7 +10640,7 @@ function deployPackage(options) {
|
|
|
10880
10640
|
case "sst": {
|
|
10881
10641
|
const v = GEEKMIDAS_VERSIONS;
|
|
10882
10642
|
return {
|
|
10883
|
-
scripts: perStage(options, (stage) => `gkm build
|
|
10643
|
+
scripts: perStage(options, (stage) => `gkm build && sst deploy --stage ${stage}`),
|
|
10884
10644
|
dependencies: {
|
|
10885
10645
|
"@geekmidas/cloud": v["@geekmidas/cloud"],
|
|
10886
10646
|
"@geekmidas/db": v["@geekmidas/db"],
|
|
@@ -10945,7 +10705,7 @@ export default $config({
|
|
|
10945
10705
|
|
|
10946
10706
|
async run() {
|
|
10947
10707
|
const { App, fromManifest, Stack } = await import('@geekmidas/cloud/sst');
|
|
10948
|
-
// Written by \`gkm build
|
|
10708
|
+
// Written by \`gkm build\`. Imported rather than discovered,
|
|
10949
10709
|
// so SST's toolchain never evaluates the application's own modules.
|
|
10950
10710
|
const { backends, constructs } = await import('./.gkm/manifest/aws.js');
|
|
10951
10711
|
|
|
@@ -11183,8 +10943,11 @@ coverage/
|
|
|
11183
10943
|
${isSst ? "\n# SST\n.sst/\n" : ""}`;
|
|
11184
10944
|
const tsConfig = {
|
|
11185
10945
|
compilerOptions: {
|
|
10946
|
+
paths: {
|
|
10947
|
+
...isFullstack ? { [`@${options.name}/constructs/*`]: ["./constructs/*"] } : {},
|
|
10948
|
+
[`@${options.name}/manifest`]: [`./.gkm/manifest/${isSst ? "aws" : "server"}.ts`]
|
|
10949
|
+
},
|
|
11186
10950
|
...isFullstack ? {
|
|
11187
|
-
paths: { [`@${options.name}/constructs/*`]: ["./constructs/*"] },
|
|
11188
10951
|
allowImportingTsExtensions: true,
|
|
11189
10952
|
noEmit: true
|
|
11190
10953
|
} : {},
|
|
@@ -11325,7 +11088,7 @@ export default defineWorkspace({
|
|
|
11325
11088
|
// \`production-${options.name}-database\` on Dokploy and on AWS alike.
|
|
11326
11089
|
name: '${options.name}',
|
|
11327
11090
|
${stagesBlock(options.stages)}
|
|
11328
|
-
|
|
11091
|
+
${deployBlock(options)}
|
|
11329
11092
|
// Every kind, in every app. A declared database is why a Postgres exists, a
|
|
11330
11093
|
// declared bucket is why MinIO does, a declared topic is why a broker does —
|
|
11331
11094
|
// none of it listed here. It is also where the apps come from: a
|
|
@@ -11343,6 +11106,18 @@ ${workspaceConstructsGlobs(options.routesStructure, (0, node_path.dirname)(optio
|
|
|
11343
11106
|
`;
|
|
11344
11107
|
}
|
|
11345
11108
|
/**
|
|
11109
|
+
* Where it deploys, when that is not the default Dokploy: what a bare
|
|
11110
|
+
* `gkm build` builds for, and which backends a cache or a broker resolves to.
|
|
11111
|
+
*/
|
|
11112
|
+
function deployBlock(options) {
|
|
11113
|
+
if (options.deployTarget !== "sst") return "";
|
|
11114
|
+
return `
|
|
11115
|
+
// Deployed with \`sst deploy\`, from the manifest \`gkm build\` writes to
|
|
11116
|
+
// \`.gkm/manifest/aws.ts\`. Each construct becomes a managed AWS resource.
|
|
11117
|
+
deploy: { default: 'sst' },
|
|
11118
|
+
`;
|
|
11119
|
+
}
|
|
11120
|
+
/**
|
|
11346
11121
|
* Where a deployed stage's secrets live. On AWS that is SSM in the stage's own
|
|
11347
11122
|
* account, which the deploy job reaches with the role it already assumed; a
|
|
11348
11123
|
* server target keeps the encrypted local file, the default.
|
|
@@ -11368,7 +11143,7 @@ function secretsStore(options) {
|
|
|
11368
11143
|
*/
|
|
11369
11144
|
function generateRootConstructs(options) {
|
|
11370
11145
|
if (!options.monorepo || options.template !== "fullstack") return [];
|
|
11371
|
-
const {
|
|
11146
|
+
const { frontendFramework } = options;
|
|
11372
11147
|
const { cache, uploads, mail } = options.constructs;
|
|
11373
11148
|
const db = databaseFor();
|
|
11374
11149
|
const files = [];
|
|
@@ -12128,7 +11903,7 @@ const serverlessTemplate = {
|
|
|
12128
11903
|
},
|
|
12129
11904
|
scripts: {
|
|
12130
11905
|
dev: "gkm dev",
|
|
12131
|
-
build: "gkm build --provider aws
|
|
11906
|
+
build: "gkm build --provider aws",
|
|
12132
11907
|
test: "vitest",
|
|
12133
11908
|
"test:once": "vitest run",
|
|
12134
11909
|
typecheck: "tsc --noEmit",
|
|
@@ -12137,7 +11912,7 @@ const serverlessTemplate = {
|
|
|
12137
11912
|
"fmt:check": "biome format ."
|
|
12138
11913
|
},
|
|
12139
11914
|
files: (options) => {
|
|
12140
|
-
const { loggerType, routesStructure
|
|
11915
|
+
const { loggerType, routesStructure } = options;
|
|
12141
11916
|
const loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';
|
|
12142
11917
|
|
|
12143
11918
|
export const logger = createLogger();
|
|
@@ -12422,10 +12197,6 @@ export const telescope = new Telescope({
|
|
|
12422
12197
|
*/
|
|
12423
12198
|
const OPENAPI_OUTPUT_PATH = "./.gkm/openapi/api.ts";
|
|
12424
12199
|
/**
|
|
12425
|
-
* Endpoints output path (generated by gkm dev/build)
|
|
12426
|
-
*/
|
|
12427
|
-
const ENDPOINTS_OUTPUT_PATH = "./.gkm/server/endpoints.ts";
|
|
12428
|
-
/**
|
|
12429
12200
|
* All available templates
|
|
12430
12201
|
*/
|
|
12431
12202
|
const templates = {
|
|
@@ -12638,10 +12409,7 @@ function generatePackageJson(options, template) {
|
|
|
12638
12409
|
private: true,
|
|
12639
12410
|
type: "module",
|
|
12640
12411
|
...!monorepo && options.packageManager === "pnpm" ? { packageManager: PNPM_VERSION } : {},
|
|
12641
|
-
exports: {
|
|
12642
|
-
"./client": OPENAPI_OUTPUT_PATH,
|
|
12643
|
-
"./endpoints": ENDPOINTS_OUTPUT_PATH
|
|
12644
|
-
},
|
|
12412
|
+
exports: { "./client": OPENAPI_OUTPUT_PATH },
|
|
12645
12413
|
scripts,
|
|
12646
12414
|
dependencies: sortObject(dependencies),
|
|
12647
12415
|
devDependencies: sortObject(devDependencies)
|
|
@@ -15367,7 +15135,7 @@ function printNextSteps(projectName, options, pkgManager) {
|
|
|
15367
15135
|
}
|
|
15368
15136
|
if (options.deployTarget === "sst") {
|
|
15369
15137
|
console.log("🚀 Deployment (AWS, through SST):");
|
|
15370
|
-
for (const stage of deployed) console.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm build
|
|
15138
|
+
for (const stage of deployed) console.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm build, then sst deploy`);
|
|
15371
15139
|
console.log(` Uses your AWS credentials, in ${options.region}.`);
|
|
15372
15140
|
if (options.constructs.mail) console.log(" Set MAIL_FROM to a sender verified in SES first.");
|
|
15373
15141
|
console.log("");
|
|
@@ -15754,8 +15522,8 @@ async function reconcileLocal(workspace, stage, options) {
|
|
|
15754
15522
|
logger$1.log("🐳 Services already up to date");
|
|
15755
15523
|
return;
|
|
15756
15524
|
}
|
|
15757
|
-
logger$1.log(
|
|
15758
|
-
for (const
|
|
15525
|
+
logger$1.log("🐳 Services");
|
|
15526
|
+
for (const line of require_workspace$1.describeServices(result.services)) logger$1.log(line);
|
|
15759
15527
|
const url = result.plan.resources.filter((r) => r.kind === "rest-api" || r.kind === "site" || r.kind === "file-server").map((r) => result.env[r.envKey]).find((address) => address?.startsWith("https://"));
|
|
15760
15528
|
if (url) await ensureTrusted(workspace.root, url, { ...options.yes ? { assumeYes: true } : {} });
|
|
15761
15529
|
}
|
|
@@ -16102,8 +15870,8 @@ function testDatabases(reconciled) {
|
|
|
16102
15870
|
* starts without the reference data the app needs.
|
|
16103
15871
|
*/
|
|
16104
15872
|
async function migrateTestStage(workspace, env) {
|
|
16105
|
-
const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-
|
|
16106
|
-
const { discover } = await Promise.resolve().then(() => require("./discover-
|
|
15873
|
+
const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
|
|
15874
|
+
const { discover } = await Promise.resolve().then(() => require("./discover-DXNviAh-.cjs")).then((n) => n.discover_exports);
|
|
16107
15875
|
const sources = {};
|
|
16108
15876
|
const manifest = await discover({
|
|
16109
15877
|
patterns: require_workspace$1.constructGlobs(workspace),
|
|
@@ -16468,29 +16236,13 @@ program.command("setup").description("Reconcile declared constructs — containe
|
|
|
16468
16236
|
process.exit(1);
|
|
16469
16237
|
}
|
|
16470
16238
|
});
|
|
16471
|
-
program.command("build").description("Build handlers and the manifest from declared constructs").option("--provider <provider>", "
|
|
16239
|
+
program.command("build").description("Build handlers and the manifest from declared constructs").option("--provider <provider>", "Build for aws or server (default: where gkm.config.ts deploys)").option("--enable-openapi", "Enable OpenAPI documentation generation for server builds").option("--production", "Build for production (no dev tools, bundled output)").option("--skip-bundle", "Skip bundling step in production build").option("--stage <stage>", "Inject encrypted secrets for deployment stage").option("--mark-optional", "Suffix optional env vars with ? in manifest envVars field (e.g. PORT?)").action(async (options) => {
|
|
16472
16240
|
try {
|
|
16473
16241
|
const globalOptions = program.opts();
|
|
16474
16242
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16475
|
-
if (options.provider)
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
provider: options.provider,
|
|
16479
|
-
enableOpenApi: options.enableOpenapi || false,
|
|
16480
|
-
production: options.production || false,
|
|
16481
|
-
skipBundle: options.skipBundle || false,
|
|
16482
|
-
stage: options.stage,
|
|
16483
|
-
markOptional: options.markOptional || false
|
|
16484
|
-
});
|
|
16485
|
-
} else if (options.providers) await buildCommand({
|
|
16486
|
-
providers: [...new Set(options.providers.split(",").map((p) => p.trim()))],
|
|
16487
|
-
enableOpenApi: options.enableOpenapi || false,
|
|
16488
|
-
production: options.production || false,
|
|
16489
|
-
skipBundle: options.skipBundle || false,
|
|
16490
|
-
stage: options.stage,
|
|
16491
|
-
markOptional: options.markOptional || false
|
|
16492
|
-
});
|
|
16493
|
-
else await buildCommand({
|
|
16243
|
+
if (options.provider !== void 0 && !isMainProvider(options.provider)) throw new UnknownBuildProvider(options.provider);
|
|
16244
|
+
await buildCommand({
|
|
16245
|
+
...options.provider ? { provider: options.provider } : {},
|
|
16494
16246
|
enableOpenApi: options.enableOpenapi || false,
|
|
16495
16247
|
production: options.production || false,
|
|
16496
16248
|
skipBundle: options.skipBundle || false,
|
|
@@ -16549,7 +16301,7 @@ program.command("migrate").description("Apply each database construct's migratio
|
|
|
16549
16301
|
try {
|
|
16550
16302
|
const globalOptions = program.opts();
|
|
16551
16303
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16552
|
-
const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
16304
|
+
const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
|
|
16553
16305
|
await migrateCommand({
|
|
16554
16306
|
...options,
|
|
16555
16307
|
...construct ? { construct } : {}
|
|
@@ -16563,7 +16315,7 @@ program.command("seed").description("Migrate, then run each database construct's
|
|
|
16563
16315
|
try {
|
|
16564
16316
|
const globalOptions = program.opts();
|
|
16565
16317
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16566
|
-
const { seedCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
16318
|
+
const { seedCommand } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
|
|
16567
16319
|
await seedCommand({
|
|
16568
16320
|
...options,
|
|
16569
16321
|
...construct ? { construct } : {}
|
|
@@ -16577,7 +16329,7 @@ program.command("migration").description("Write a construct's next migration: an
|
|
|
16577
16329
|
try {
|
|
16578
16330
|
const globalOptions = program.opts();
|
|
16579
16331
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16580
|
-
const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-
|
|
16332
|
+
const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-BgEY9pdP.cjs"));
|
|
16581
16333
|
await migrationCommand({
|
|
16582
16334
|
construct,
|
|
16583
16335
|
...name ? { name } : {}
|
|
@@ -16671,6 +16423,28 @@ program.command("secrets:set").description("Set a custom secret for a stage").ar
|
|
|
16671
16423
|
process.exit(1);
|
|
16672
16424
|
}
|
|
16673
16425
|
});
|
|
16426
|
+
program.command("encryption:rotate").description("Add a new current key to an Encryption construct's keyring on a server stage").argument("<construct>", "The Encryption construct (e.g. Pii)").requiredOption("--stage <stage>", "A deployed stage").action(async (construct, options) => {
|
|
16427
|
+
try {
|
|
16428
|
+
const globalOptions = program.opts();
|
|
16429
|
+
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16430
|
+
const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-C7OGMve_.cjs"));
|
|
16431
|
+
await encryptionRotateCommand(construct, options);
|
|
16432
|
+
} catch (error) {
|
|
16433
|
+
console.error(formatError(error));
|
|
16434
|
+
process.exit(1);
|
|
16435
|
+
}
|
|
16436
|
+
});
|
|
16437
|
+
program.command("encryption:retire").description("Remove an old key from an Encryption construct's keyring, once nothing is under it").argument("<construct>", "The Encryption construct (e.g. Pii)").argument("<key>", "The key to retire (e.g. k1)").requiredOption("--stage <stage>", "A deployed stage").action(async (construct, key, options) => {
|
|
16438
|
+
try {
|
|
16439
|
+
const globalOptions = program.opts();
|
|
16440
|
+
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16441
|
+
const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-C7OGMve_.cjs"));
|
|
16442
|
+
await encryptionRetireCommand(construct, key, options);
|
|
16443
|
+
} catch (error) {
|
|
16444
|
+
console.error(formatError(error));
|
|
16445
|
+
process.exit(1);
|
|
16446
|
+
}
|
|
16447
|
+
});
|
|
16674
16448
|
program.command("secrets:show").description("Show secrets for a stage").requiredOption("--stage <stage>", "Stage name").option("--reveal", "Show actual secret values (not masked)").action(async (options) => {
|
|
16675
16449
|
try {
|
|
16676
16450
|
const globalOptions = program.opts();
|
|
@@ -16716,7 +16490,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
16716
16490
|
console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
16717
16491
|
process.exit(1);
|
|
16718
16492
|
}
|
|
16719
|
-
const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-
|
|
16493
|
+
const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-vafrzZTC.cjs")).then((n) => n.workspace_exports);
|
|
16720
16494
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
|
|
16721
16495
|
if (!result) {
|
|
16722
16496
|
console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
|
|
@@ -16775,7 +16549,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
|
|
|
16775
16549
|
try {
|
|
16776
16550
|
const globalOptions = program.opts();
|
|
16777
16551
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16778
|
-
const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-
|
|
16552
|
+
const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BrI1tv6u.cjs"));
|
|
16779
16553
|
await deployGithubCommand(options);
|
|
16780
16554
|
} catch (error) {
|
|
16781
16555
|
console.error(formatError(error));
|