@geekmidas/cli 10.0.0-alpha.45 → 10.0.0-alpha.46
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/{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/{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 +395 -660
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +397 -662
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-BRklCm7b.mjs → migrate-B3opyC3o.mjs} +5 -5
- package/dist/{migrate-BRklCm7b.mjs.map → migrate-B3opyC3o.mjs.map} +1 -1
- package/dist/{migrate-PJi4b1ga.cjs → migrate-Dp5HFzuQ.cjs} +5 -5
- package/dist/{migrate-PJi4b1ga.cjs.map → migrate-Dp5HFzuQ.cjs.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-3RfHxdA0.cjs → ready-L7I68yXf.cjs} +67 -8
- package/dist/ready-L7I68yXf.cjs.map +1 -0
- package/dist/{ready-ZqOuNvKD.mjs → ready-V6Ou6-B6.mjs} +49 -8
- package/dist/ready-V6Ou6-B6.mjs.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-BKytVCzb.mjs → workspace-CHEC80sp.mjs} +6 -7
- package/dist/workspace-CHEC80sp.mjs.map +1 -0
- package/dist/{workspace-dV6f-3vv.cjs → workspace-D9z2ymBW.cjs} +11 -12
- package/dist/workspace-D9z2ymBW.cjs.map +1 -0
- 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/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.mjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
import { n as __require, t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { d as parseModuleConfig, f as appKey, l as loadWorkspaceConfig, n as NotABackendApp, o as loadAppConfig, p as derivedApps, r as NotInAnApp, s as loadConfig, t as ConfigNotFound, u as loadWorkspaceSettings } from "./config-
|
|
5
|
-
import { D as assertDeployedStage, E as TEST_STAGE, O as deployedProblems, T as InvalidStages, a as getAppBuildOrder, b as getDeployTargetError, k as stageProblems, m as stripPublicPrefix, o as getAppGkmConfig, p as getPublicEnvPrefix, t as allConstructGlobs, x as isDeployTargetSupported } from "./workspace-
|
|
3
|
+
import { i as ConstructGenerator, t as discover } from "./discover-Cf2jAcgF.mjs";
|
|
4
|
+
import { d as parseModuleConfig, f as appKey, l as loadWorkspaceConfig, n as NotABackendApp, o as loadAppConfig, p as derivedApps, r as NotInAnApp, s as loadConfig, t as ConfigNotFound, u as loadWorkspaceSettings } from "./config-D8J5rrTb.mjs";
|
|
5
|
+
import { D as assertDeployedStage, E as TEST_STAGE, O as deployedProblems, T as InvalidStages, a as getAppBuildOrder, b as getDeployTargetError, k as stageProblems, m as stripPublicPrefix, o as getAppGkmConfig, p as getPublicEnvPrefix, t as allConstructGlobs, x as isDeployTargetSupported } from "./workspace-DNzWgM1J.mjs";
|
|
6
6
|
import { a as withCustomSecret, i as toEmbeddableSecrets, n as maskPassword, t as initStageSecrets } from "./storage-BzaUxmqe.mjs";
|
|
7
7
|
import { a as getKeyPath, i as FileSecretsStore, n as secretsStoreFor } from "./store-DeGATCS-.mjs";
|
|
8
|
-
import { C as createEntryWrapper, D as loadSecretsForApp, E as loadEnvFiles, O as prepareEntryCredentials, S as createCredentialsPreload, T as isPortAvailable, _ as primaryPortKey, a as reconcileWorkspace, b as providerOf, c as LOCAL_CA_PATH, d as postgresDatabaseNames, f as quoteIdentifier, g as fakeKey, h as rootSite, i as derivedContainers, l as forgetState, m as resourceName, n as backendsOf, p as pgClient, r as constructGlobs, s as COMPOSE_PATH, t as FAKE_ENV, u as applyPostgres, v as cacheBackendFor, w as findAvailablePort, x as storageBackendFor, y as eventsBackendFor } from "./workspace-
|
|
9
|
-
import { n as EndpointGenerator, r as runtimeFor } from "./OpenApiTsGenerator-
|
|
8
|
+
import { C as createEntryWrapper, D as loadSecretsForApp, E as loadEnvFiles, O as prepareEntryCredentials, S as createCredentialsPreload, T as isPortAvailable, _ as primaryPortKey, a as reconcileWorkspace, b as providerOf, c as LOCAL_CA_PATH, d as postgresDatabaseNames, f as quoteIdentifier, g as fakeKey, h as rootSite, i as derivedContainers, l as forgetState, m as resourceName, n as backendsOf$1, p as pgClient, r as constructGlobs, s as COMPOSE_PATH, t as FAKE_ENV, u as applyPostgres, v as cacheBackendFor, w as findAvailablePort, x as storageBackendFor, y as eventsBackendFor } from "./workspace-CHEC80sp.mjs";
|
|
9
|
+
import { n as EndpointGenerator, r as runtimeFor } from "./OpenApiTsGenerator-BzIGy8KE.mjs";
|
|
10
10
|
import { generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi.mjs";
|
|
11
|
-
import { a as writeTestHarness, c as driversFor, i as TEST_MANIFEST_ENV, n as TEST_READY_FILE, o as SubscriberGenerator, s as cacheBackendsIn, t as TEST_READY_ENV } from "./ready-
|
|
12
|
-
import {
|
|
11
|
+
import { a as writeTestHarness, c as driversFor, i as TEST_MANIFEST_ENV, n as TEST_READY_FILE, o as SubscriberGenerator, s as cacheBackendsIn, t as TEST_READY_ENV } from "./ready-V6Ou6-B6.mjs";
|
|
12
|
+
import { n as withCompute, r as withRoutes, t as manifestModule } from "./emit-C1e8qD08.mjs";
|
|
13
13
|
import { createRequire } from "node:module";
|
|
14
14
|
import { Command } from "commander";
|
|
15
15
|
import { stdin, stdout } from "node:process";
|
|
16
16
|
import * as readline from "node:readline/promises";
|
|
17
17
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
18
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
18
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
19
19
|
import { homedir } from "node:os";
|
|
20
20
|
import { basename, dirname, isAbsolute, join, parse, relative, resolve } from "node:path";
|
|
21
21
|
import { execFile, execSync, spawn } from "node:child_process";
|
|
@@ -40,7 +40,7 @@ import { Queue } from "@geekmidas/constructs/queue";
|
|
|
40
40
|
import { Topic } from "@geekmidas/constructs/topic";
|
|
41
41
|
import { lookup } from "node:dns/promises";
|
|
42
42
|
//#region package.json
|
|
43
|
-
var version = "10.0.0-alpha.
|
|
43
|
+
var version = "10.0.0-alpha.46";
|
|
44
44
|
//#endregion
|
|
45
45
|
//#region src/auth/credentials.ts
|
|
46
46
|
/**
|
|
@@ -174,7 +174,7 @@ async function getHostingerToken(options) {
|
|
|
174
174
|
}
|
|
175
175
|
//#endregion
|
|
176
176
|
//#region src/auth/index.ts
|
|
177
|
-
const logger$
|
|
177
|
+
const logger$12 = console;
|
|
178
178
|
/**
|
|
179
179
|
* Validate Dokploy token by making a test API call
|
|
180
180
|
*/
|
|
@@ -241,52 +241,52 @@ async function prompt$1(message, hidden = false) {
|
|
|
241
241
|
async function loginCommand(options) {
|
|
242
242
|
const { provider, token: providedToken, endpoint: providedEndpoint } = options;
|
|
243
243
|
if (provider === "dokploy") {
|
|
244
|
-
logger$
|
|
244
|
+
logger$12.log("\n🔐 Logging in to Dokploy...\n");
|
|
245
245
|
let endpoint = providedEndpoint;
|
|
246
246
|
if (!endpoint) endpoint = await prompt$1("Dokploy URL (e.g., https://dokploy.example.com): ");
|
|
247
247
|
endpoint = endpoint.replace(/\/$/, "");
|
|
248
248
|
try {
|
|
249
249
|
new URL(endpoint);
|
|
250
250
|
} catch {
|
|
251
|
-
logger$
|
|
251
|
+
logger$12.error("Invalid URL format");
|
|
252
252
|
process.exit(1);
|
|
253
253
|
}
|
|
254
254
|
let token = providedToken;
|
|
255
255
|
if (!token) {
|
|
256
|
-
logger$
|
|
256
|
+
logger$12.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
|
|
257
257
|
token = await prompt$1("API Token: ", true);
|
|
258
258
|
}
|
|
259
259
|
if (!token) {
|
|
260
|
-
logger$
|
|
260
|
+
logger$12.error("Token is required");
|
|
261
261
|
process.exit(1);
|
|
262
262
|
}
|
|
263
|
-
logger$
|
|
263
|
+
logger$12.log("\nValidating credentials...");
|
|
264
264
|
if (!await validateDokployToken(endpoint, token)) {
|
|
265
|
-
logger$
|
|
265
|
+
logger$12.error("\n✗ Invalid credentials. Please check your token and try again.");
|
|
266
266
|
process.exit(1);
|
|
267
267
|
}
|
|
268
268
|
await storeDokployCredentials(token, endpoint);
|
|
269
|
-
logger$
|
|
270
|
-
logger$
|
|
271
|
-
logger$
|
|
272
|
-
logger$
|
|
269
|
+
logger$12.log("\n✓ Successfully logged in to Dokploy!");
|
|
270
|
+
logger$12.log(` Endpoint: ${endpoint}`);
|
|
271
|
+
logger$12.log(` Credentials stored in: ${getCredentialsPath()}`);
|
|
272
|
+
logger$12.log("\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.");
|
|
273
273
|
}
|
|
274
274
|
if (provider === "hostinger") {
|
|
275
|
-
logger$
|
|
275
|
+
logger$12.log("\n🔐 Logging in to Hostinger...\n");
|
|
276
276
|
let token = providedToken;
|
|
277
277
|
if (!token) {
|
|
278
|
-
logger$
|
|
278
|
+
logger$12.log("\nGenerate a token at: https://hpanel.hostinger.com/profile/api\n");
|
|
279
279
|
token = await prompt$1("API Token: ", true);
|
|
280
280
|
}
|
|
281
281
|
if (!token) {
|
|
282
|
-
logger$
|
|
282
|
+
logger$12.error("Token is required");
|
|
283
283
|
process.exit(1);
|
|
284
284
|
}
|
|
285
285
|
await storeHostingerToken(token);
|
|
286
|
-
logger$
|
|
287
|
-
logger$
|
|
288
|
-
logger$
|
|
289
|
-
logger$
|
|
286
|
+
logger$12.log("\n✓ Hostinger token stored.");
|
|
287
|
+
logger$12.log(` Credentials stored in: ${getCredentialsPath()}`);
|
|
288
|
+
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.");
|
|
289
|
+
logger$12.log("\nYou can now use it as a DNS provider without setting HOSTINGER_API_TOKEN.");
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
/**
|
|
@@ -295,27 +295,27 @@ async function loginCommand(options) {
|
|
|
295
295
|
async function logoutCommand(options) {
|
|
296
296
|
const { provider = "dokploy" } = options;
|
|
297
297
|
if (provider === "all") {
|
|
298
|
-
if (await removeDokployCredentials()) logger$
|
|
299
|
-
else logger$
|
|
298
|
+
if (await removeDokployCredentials()) logger$12.log("\n✓ Logged out from all services");
|
|
299
|
+
else logger$12.log("\nNo stored credentials found");
|
|
300
300
|
return;
|
|
301
301
|
}
|
|
302
302
|
if (provider === "dokploy") {
|
|
303
|
-
if (await removeDokployCredentials()) logger$
|
|
304
|
-
else logger$
|
|
303
|
+
if (await removeDokployCredentials()) logger$12.log("\n✓ Logged out from Dokploy");
|
|
304
|
+
else logger$12.log("\nNo Dokploy credentials found");
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
/**
|
|
308
308
|
* Show current login status
|
|
309
309
|
*/
|
|
310
310
|
async function whoamiCommand() {
|
|
311
|
-
logger$
|
|
311
|
+
logger$12.log("\n📋 Current credentials:\n");
|
|
312
312
|
const dokploy = await getDokployCredentials();
|
|
313
313
|
if (dokploy) {
|
|
314
|
-
logger$
|
|
315
|
-
logger$
|
|
316
|
-
logger$
|
|
317
|
-
} else logger$
|
|
318
|
-
logger$
|
|
314
|
+
logger$12.log(" Dokploy:");
|
|
315
|
+
logger$12.log(` Endpoint: ${dokploy.endpoint}`);
|
|
316
|
+
logger$12.log(` Token: ${maskToken(dokploy.token)}`);
|
|
317
|
+
} else logger$12.log(" Dokploy: Not logged in");
|
|
318
|
+
logger$12.log(`\n Credentials file: ${getCredentialsPath()}`);
|
|
319
319
|
}
|
|
320
320
|
/**
|
|
321
321
|
* Mask a token for display
|
|
@@ -325,85 +325,14 @@ function maskToken(token) {
|
|
|
325
325
|
return `${token.slice(0, 4)}...${token.slice(-4)}`;
|
|
326
326
|
}
|
|
327
327
|
//#endregion
|
|
328
|
-
//#region src/build/providerResolver.ts
|
|
329
|
-
/**
|
|
330
|
-
* Resolves provider configuration from the new simplified system
|
|
331
|
-
* to the internal legacy format for backward compatibility
|
|
332
|
-
*/
|
|
333
|
-
function resolveProviders(config, options) {
|
|
334
|
-
const providers = [];
|
|
335
|
-
let enableOpenApi = options.enableOpenApi || false;
|
|
336
|
-
if (options.providers) return {
|
|
337
|
-
providers: options.providers,
|
|
338
|
-
enableOpenApi
|
|
339
|
-
};
|
|
340
|
-
if (options.provider) {
|
|
341
|
-
const resolvedProviders = resolveMainProvider(options.provider, config.providers);
|
|
342
|
-
providers.push(...resolvedProviders.providers);
|
|
343
|
-
enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
|
|
344
|
-
} else if (config.providers) {
|
|
345
|
-
const resolvedProviders = resolveAllConfiguredProviders(config.providers);
|
|
346
|
-
providers.push(...resolvedProviders.providers);
|
|
347
|
-
enableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;
|
|
348
|
-
} else providers.push("aws-apigatewayv2", "aws-lambda");
|
|
349
|
-
return {
|
|
350
|
-
providers: [...new Set(providers)],
|
|
351
|
-
enableOpenApi
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
function resolveMainProvider(mainProvider, providersConfig) {
|
|
355
|
-
const providers = [];
|
|
356
|
-
let enableOpenApi = false;
|
|
357
|
-
if (mainProvider === "aws") {
|
|
358
|
-
const awsConfig = providersConfig?.aws;
|
|
359
|
-
if (awsConfig?.apiGateway) {
|
|
360
|
-
if (isEnabled(awsConfig.apiGateway.v1)) providers.push("aws-apigatewayv1");
|
|
361
|
-
if (isEnabled(awsConfig.apiGateway.v2)) providers.push("aws-apigatewayv2");
|
|
362
|
-
} else providers.push("aws-apigatewayv2");
|
|
363
|
-
if (awsConfig?.lambda) {
|
|
364
|
-
if (isEnabled(awsConfig.lambda.functions) || isEnabled(awsConfig.lambda.crons)) providers.push("aws-lambda");
|
|
365
|
-
} else providers.push("aws-lambda");
|
|
366
|
-
} else if (mainProvider === "server") {
|
|
367
|
-
providers.push("server");
|
|
368
|
-
const serverConfig = providersConfig?.server;
|
|
369
|
-
if (typeof serverConfig === "object" && serverConfig?.enableOpenApi) enableOpenApi = true;
|
|
370
|
-
}
|
|
371
|
-
return {
|
|
372
|
-
providers,
|
|
373
|
-
enableOpenApi
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
function resolveAllConfiguredProviders(providersConfig) {
|
|
377
|
-
const providers = [];
|
|
378
|
-
let enableOpenApi = false;
|
|
379
|
-
if (providersConfig.aws) {
|
|
380
|
-
const awsProviders = resolveMainProvider("aws", providersConfig);
|
|
381
|
-
providers.push(...awsProviders.providers);
|
|
382
|
-
}
|
|
383
|
-
if (providersConfig.server && isEnabled(providersConfig.server)) {
|
|
384
|
-
providers.push("server");
|
|
385
|
-
if (typeof providersConfig.server === "object" && providersConfig.server.enableOpenApi) enableOpenApi = true;
|
|
386
|
-
}
|
|
387
|
-
return {
|
|
388
|
-
providers,
|
|
389
|
-
enableOpenApi
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
function isEnabled(config) {
|
|
393
|
-
if (config === void 0) return false;
|
|
394
|
-
if (typeof config === "boolean") return config;
|
|
395
|
-
return config.enabled !== false;
|
|
396
|
-
}
|
|
397
|
-
//#endregion
|
|
398
328
|
//#region src/workspace/client-generator.ts
|
|
399
329
|
/**
|
|
400
330
|
* Normalize routes to an array of patterns.
|
|
401
|
-
* Handles
|
|
331
|
+
* Handles a glob or a list of them.
|
|
402
332
|
* @internal Exported for use in dev command
|
|
403
333
|
*/
|
|
404
334
|
function normalizeRoutes(routes) {
|
|
405
335
|
if (!routes) return [];
|
|
406
|
-
if (isPartitionedRoutes(routes)) return Array.isArray(routes.paths) ? routes.paths : [routes.paths];
|
|
407
336
|
return Array.isArray(routes) ? routes : [routes];
|
|
408
337
|
}
|
|
409
338
|
//#endregion
|
|
@@ -422,7 +351,7 @@ function normalizeRoutes(routes) {
|
|
|
422
351
|
* trade than one that tells you what to type. Caddy's own `caddy trust` draws
|
|
423
352
|
* the line in the same place.
|
|
424
353
|
*/
|
|
425
|
-
const logger$
|
|
354
|
+
const logger$11 = console;
|
|
426
355
|
const run = promisify(execFile);
|
|
427
356
|
/**
|
|
428
357
|
* How each platform is told about a new authority.
|
|
@@ -474,15 +403,15 @@ async function trustCommand(options = {}) {
|
|
|
474
403
|
const certificate = join(workspace.root, LOCAL_CA_PATH);
|
|
475
404
|
if (!existsSync(certificate)) throw new NoLocalAuthority(certificate);
|
|
476
405
|
const { describe, steps } = installation(process.platform, certificate);
|
|
477
|
-
logger$
|
|
478
|
-
logger$
|
|
406
|
+
logger$11.log(`\n🔐 Trusting the local authority in ${describe}`);
|
|
407
|
+
logger$11.log(` ${certificate}\n`);
|
|
479
408
|
if (options.dryRun) {
|
|
480
|
-
for (const [command, args] of steps) logger$
|
|
409
|
+
for (const [command, args] of steps) logger$11.log(` ${command} ${args.join(" ")}`);
|
|
481
410
|
return;
|
|
482
411
|
}
|
|
483
|
-
logger$
|
|
412
|
+
logger$11.log(" This needs an admin password.\n");
|
|
484
413
|
for (const [command, args] of steps) await run(command, args, { stdio: "inherit" });
|
|
485
|
-
logger$
|
|
414
|
+
logger$11.log("\n✅ Local https addresses are trusted. Restart your browser.\n");
|
|
486
415
|
}
|
|
487
416
|
/**
|
|
488
417
|
* Trust the authority if this machine lacks it and its owner agrees.
|
|
@@ -499,7 +428,7 @@ async function ensureTrusted(root, url, options = {}) {
|
|
|
499
428
|
if (await isTrusted(url)) return;
|
|
500
429
|
if (!options.assumeYes) {
|
|
501
430
|
if (!process.stdin.isTTY) {
|
|
502
|
-
logger$
|
|
431
|
+
logger$11.log(" Local https addresses are not trusted here. Run \"gkm trust\", or \"gkm setup --yes\".");
|
|
503
432
|
return;
|
|
504
433
|
}
|
|
505
434
|
if (await declined(root)) return;
|
|
@@ -511,7 +440,7 @@ async function ensureTrusted(root, url, options = {}) {
|
|
|
511
440
|
});
|
|
512
441
|
if (!install) {
|
|
513
442
|
await recordDeclined(root);
|
|
514
|
-
logger$
|
|
443
|
+
logger$11.log(" Skipped. Run \"gkm trust\" later.");
|
|
515
444
|
return;
|
|
516
445
|
}
|
|
517
446
|
}
|
|
@@ -1061,7 +990,7 @@ function closeFakes(served) {
|
|
|
1061
990
|
}
|
|
1062
991
|
//#endregion
|
|
1063
992
|
//#region src/exec/index.ts
|
|
1064
|
-
const logger$
|
|
993
|
+
const logger$10 = console;
|
|
1065
994
|
/** `gkm exec` was given nothing to run. */
|
|
1066
995
|
var NoCommandSpecified = class extends Error {
|
|
1067
996
|
constructor() {
|
|
@@ -1084,17 +1013,17 @@ async function execCommand(commandArgs, options = {}) {
|
|
|
1084
1013
|
const cwd = options.cwd ?? process.cwd();
|
|
1085
1014
|
if (!commandArgs[0]) throw new NoCommandSpecified();
|
|
1086
1015
|
const defaultEnv = loadEnvFiles(".env");
|
|
1087
|
-
if (defaultEnv.loaded.length > 0) logger$
|
|
1016
|
+
if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1088
1017
|
const { credentials, secretsJsonPath, appName } = await prepareEntryCredentials({ cwd });
|
|
1089
|
-
if (appName) logger$
|
|
1018
|
+
if (appName) logger$10.log(`📦 App: ${appName}`);
|
|
1090
1019
|
const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
|
|
1091
|
-
if (secretCount > 0) logger$
|
|
1020
|
+
if (secretCount > 0) logger$10.log(`🔐 Loaded ${secretCount} secret(s)`);
|
|
1092
1021
|
const preloadDir = join(cwd, ".gkm");
|
|
1093
1022
|
await mkdir(preloadDir, { recursive: true });
|
|
1094
1023
|
const preloadPath = join(preloadDir, "credentials-preload.mjs");
|
|
1095
1024
|
await createCredentialsPreload(preloadPath, secretsJsonPath);
|
|
1096
1025
|
const [cmd, ...args] = commandArgs;
|
|
1097
|
-
logger$
|
|
1026
|
+
logger$10.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
|
|
1098
1027
|
const nodeOptions = [(process.env.NODE_OPTIONS ?? "").replace(/--import[= ]\S+/g, "").trim(), `--import=${preloadPath}`].filter(Boolean).join(" ");
|
|
1099
1028
|
const child = spawn(cmd, args, {
|
|
1100
1029
|
cwd,
|
|
@@ -1108,7 +1037,7 @@ async function execCommand(commandArgs, options = {}) {
|
|
|
1108
1037
|
const exitCode = await new Promise((resolve) => {
|
|
1109
1038
|
child.on("close", (code) => resolve(code ?? 0));
|
|
1110
1039
|
child.on("error", (error) => {
|
|
1111
|
-
logger$
|
|
1040
|
+
logger$10.error(`Failed to run command: ${error.message}`);
|
|
1112
1041
|
resolve(1);
|
|
1113
1042
|
});
|
|
1114
1043
|
});
|
|
@@ -1116,7 +1045,7 @@ async function execCommand(commandArgs, options = {}) {
|
|
|
1116
1045
|
}
|
|
1117
1046
|
//#endregion
|
|
1118
1047
|
//#region src/dev/index.ts
|
|
1119
|
-
const logger$
|
|
1048
|
+
const logger$9 = console;
|
|
1120
1049
|
/**
|
|
1121
1050
|
* Normalize telescope configuration
|
|
1122
1051
|
* @internal Exported for testing
|
|
@@ -1181,39 +1110,36 @@ function normalizeHooksConfig(config, cwd = process.cwd()) {
|
|
|
1181
1110
|
return { serverHooksPath: resolve(cwd, serverPath) };
|
|
1182
1111
|
}
|
|
1183
1112
|
/**
|
|
1184
|
-
*
|
|
1113
|
+
* What a `--production` build is.
|
|
1114
|
+
*
|
|
1115
|
+
* A server runs its worker's background work itself — queues polled, crons
|
|
1116
|
+
* scheduled, subscribers drained — so the production entry wires all three.
|
|
1117
|
+
* The build writes their files on every server build, empty when there is
|
|
1118
|
+
* nothing, so including them costs an app without any nothing.
|
|
1119
|
+
*
|
|
1185
1120
|
* @internal Exported for testing
|
|
1186
1121
|
*/
|
|
1187
|
-
function normalizeProductionConfig(cliProduction
|
|
1122
|
+
function normalizeProductionConfig(cliProduction) {
|
|
1188
1123
|
if (!cliProduction) return;
|
|
1189
|
-
const config = configProduction ?? {};
|
|
1190
1124
|
return {
|
|
1191
1125
|
enabled: true,
|
|
1192
|
-
bundle:
|
|
1193
|
-
minify:
|
|
1194
|
-
healthCheck:
|
|
1195
|
-
gracefulShutdown:
|
|
1196
|
-
external:
|
|
1197
|
-
subscribers:
|
|
1198
|
-
openapi:
|
|
1199
|
-
optimizedHandlers:
|
|
1126
|
+
bundle: true,
|
|
1127
|
+
minify: true,
|
|
1128
|
+
healthCheck: "/health",
|
|
1129
|
+
gracefulShutdown: true,
|
|
1130
|
+
external: [],
|
|
1131
|
+
subscribers: "include",
|
|
1132
|
+
openapi: false,
|
|
1133
|
+
optimizedHandlers: true
|
|
1200
1134
|
};
|
|
1201
1135
|
}
|
|
1202
|
-
/**
|
|
1203
|
-
* Get production config from GkmConfig
|
|
1204
|
-
* @internal
|
|
1205
|
-
*/
|
|
1206
|
-
function getProductionConfigFromGkm(config) {
|
|
1207
|
-
const serverConfig = config.providers?.server;
|
|
1208
|
-
if (typeof serverConfig === "object") return serverConfig.production;
|
|
1209
|
-
}
|
|
1210
1136
|
/** Read by the generated server: no subscriber is subscribed or polled. */
|
|
1211
1137
|
const SUBSCRIBERS_ENV = "GKM_SUBSCRIBERS";
|
|
1212
1138
|
async function devCommand(options) {
|
|
1213
1139
|
if (options.subscribers === false) process.env[SUBSCRIBERS_ENV] = "off";
|
|
1214
1140
|
if (options.entry) return entryDevCommand(options);
|
|
1215
1141
|
const defaultEnv = loadEnvFiles(".env");
|
|
1216
|
-
if (defaultEnv.loaded.length > 0) logger$
|
|
1142
|
+
if (defaultEnv.loaded.length > 0) logger$9.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1217
1143
|
const appConfig = await loadAppConfig().catch((error) => {
|
|
1218
1144
|
if (error instanceof NotInAnApp || error instanceof NotABackendApp) return;
|
|
1219
1145
|
throw error;
|
|
@@ -1229,7 +1155,7 @@ async function devCommand(options) {
|
|
|
1229
1155
|
const workspaceAppPort = appConfig.app.port;
|
|
1230
1156
|
const workspace = appConfig.workspace;
|
|
1231
1157
|
if (appConfig.app.entry) {
|
|
1232
|
-
logger$
|
|
1158
|
+
logger$9.log(`📄 Using entry point: ${appConfig.app.entry}`);
|
|
1233
1159
|
return entryDevCommand({
|
|
1234
1160
|
...options,
|
|
1235
1161
|
entry: appConfig.app.entry,
|
|
@@ -1239,19 +1165,18 @@ async function devCommand(options) {
|
|
|
1239
1165
|
}
|
|
1240
1166
|
if (config.env) {
|
|
1241
1167
|
const { loaded, missing } = loadEnvFiles(config.env, appRoot);
|
|
1242
|
-
if (loaded.length > 0) logger$
|
|
1243
|
-
if (missing.length > 0) logger$
|
|
1168
|
+
if (loaded.length > 0) logger$9.log(`📦 Loaded env: ${loaded.join(", ")}`);
|
|
1169
|
+
if (missing.length > 0) logger$9.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
|
|
1244
1170
|
}
|
|
1245
|
-
const resolved = resolveProviders(config, { provider: "server" });
|
|
1246
1171
|
const telescope = normalizeTelescopeConfig(config.telescope);
|
|
1247
1172
|
const studio = normalizeStudioConfig(config.studio);
|
|
1248
1173
|
const hooks = normalizeHooksConfig(config.hooks, appRoot);
|
|
1249
|
-
const enableOpenApi = resolveOpenApiConfig(config).enabled
|
|
1174
|
+
const enableOpenApi = resolveOpenApiConfig(config).enabled;
|
|
1250
1175
|
const build = (bustCache = false) => quietly(() => buildApp({
|
|
1251
1176
|
config,
|
|
1252
1177
|
workspaceRoot: workspace?.root ?? secretsRoot,
|
|
1253
1178
|
appRoot,
|
|
1254
|
-
|
|
1179
|
+
target: "server",
|
|
1255
1180
|
enableOpenApi,
|
|
1256
1181
|
cacheBackend: cacheBackendFor(providerOf(workspace ?? config)),
|
|
1257
1182
|
telescope,
|
|
@@ -1272,8 +1197,8 @@ async function devCommand(options) {
|
|
|
1272
1197
|
...options.fake ? { fake: true } : {}
|
|
1273
1198
|
});
|
|
1274
1199
|
if (reconciled.changed && reconciled.plan.containers.length > 0) {
|
|
1275
|
-
logger$
|
|
1276
|
-
for (const [container, address] of Object.entries(reconciled.addresses)) logger$
|
|
1200
|
+
logger$9.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
|
|
1201
|
+
for (const [container, address] of Object.entries(reconciled.addresses)) logger$9.log(` ${container}: ${address}`);
|
|
1277
1202
|
}
|
|
1278
1203
|
Object.assign(appSecrets, reconciled.env);
|
|
1279
1204
|
const own = reconciled.plan.resources.find((r) => (r.kind === "rest-api" || r.kind === "site") && appKey(r.id) === workspaceAppName);
|
|
@@ -1286,7 +1211,7 @@ async function devCommand(options) {
|
|
|
1286
1211
|
secretsJsonPath = join(secretsDir, secretsFileName);
|
|
1287
1212
|
await writeFile(secretsJsonPath, JSON.stringify(appSecrets, null, 2));
|
|
1288
1213
|
}
|
|
1289
|
-
const devServer = new DevServer(
|
|
1214
|
+
const devServer = new DevServer(options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? workspaceAppPort !== void 0, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath, initial.selfServing !== void 0);
|
|
1290
1215
|
devServer.label = workspaceAppName ?? "server";
|
|
1291
1216
|
devServer.publicUrl = publicUrl;
|
|
1292
1217
|
await devServer.start();
|
|
@@ -1307,11 +1232,11 @@ async function devCommand(options) {
|
|
|
1307
1232
|
cwd: appRoot
|
|
1308
1233
|
});
|
|
1309
1234
|
watcher.on("error", (error) => {
|
|
1310
|
-
logger$
|
|
1235
|
+
logger$9.error("❌ Watcher error:", error);
|
|
1311
1236
|
});
|
|
1312
1237
|
let rebuildTimeout = null;
|
|
1313
1238
|
watcher.on("change", async (path) => {
|
|
1314
|
-
logger$
|
|
1239
|
+
logger$9.log(`🔄 ${path} changed — rebuilding`);
|
|
1315
1240
|
if (rebuildTimeout) clearTimeout(rebuildTimeout);
|
|
1316
1241
|
rebuildTimeout = setTimeout(async () => {
|
|
1317
1242
|
try {
|
|
@@ -1320,8 +1245,8 @@ async function devCommand(options) {
|
|
|
1320
1245
|
await devServer.restart();
|
|
1321
1246
|
} catch (error) {
|
|
1322
1247
|
const err = error;
|
|
1323
|
-
logger$
|
|
1324
|
-
if (err.stack) logger$
|
|
1248
|
+
logger$9.error(`❌ Rebuild failed: ${err.message}`);
|
|
1249
|
+
if (err.stack) logger$9.error(err.stack);
|
|
1325
1250
|
}
|
|
1326
1251
|
}, 300);
|
|
1327
1252
|
});
|
|
@@ -1329,9 +1254,9 @@ async function devCommand(options) {
|
|
|
1329
1254
|
const shutdown = () => {
|
|
1330
1255
|
if (isShuttingDown) return;
|
|
1331
1256
|
isShuttingDown = true;
|
|
1332
|
-
logger$
|
|
1257
|
+
logger$9.log("\n🛑 Shutting down...");
|
|
1333
1258
|
Promise.all([watcher.close(), devServer.stop()]).catch((err) => {
|
|
1334
|
-
logger$
|
|
1259
|
+
logger$9.error("Error during shutdown:", err);
|
|
1335
1260
|
}).finally(() => {
|
|
1336
1261
|
process.exit(0);
|
|
1337
1262
|
});
|
|
@@ -1533,7 +1458,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1533
1458
|
const frontendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "web");
|
|
1534
1459
|
const conflicts = checkPortConflicts(workspace);
|
|
1535
1460
|
if (conflicts.length > 0) {
|
|
1536
|
-
for (const conflict of conflicts) logger$
|
|
1461
|
+
for (const conflict of conflicts) logger$9.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
|
|
1537
1462
|
throw new Error("Port conflicts detected. Please assign unique ports to each app.");
|
|
1538
1463
|
}
|
|
1539
1464
|
if (frontendApps.length > 0) {
|
|
@@ -1542,10 +1467,10 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1542
1467
|
for (const result of validationResults) {
|
|
1543
1468
|
if (!result.valid) {
|
|
1544
1469
|
hasErrors = true;
|
|
1545
|
-
logger$
|
|
1546
|
-
for (const error of result.errors) logger$
|
|
1470
|
+
logger$9.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
|
|
1471
|
+
for (const error of result.errors) logger$9.error(` • ${error}`);
|
|
1547
1472
|
}
|
|
1548
|
-
for (const warning of result.warnings) logger$
|
|
1473
|
+
for (const warning of result.warnings) logger$9.warn(` ⚠️ ${result.appName}: ${warning}`);
|
|
1549
1474
|
}
|
|
1550
1475
|
if (hasErrors) throw new Error("Frontend app validation failed. Fix the issues above and try again.");
|
|
1551
1476
|
}
|
|
@@ -1555,20 +1480,20 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1555
1480
|
...options.fake ? { fake: true } : {}
|
|
1556
1481
|
});
|
|
1557
1482
|
if (reconciled.changed && reconciled.plan.containers.length > 0) {
|
|
1558
|
-
logger$
|
|
1559
|
-
for (const [container, address] of Object.entries(reconciled.addresses)) logger$
|
|
1483
|
+
logger$9.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
|
|
1484
|
+
for (const [container, address] of Object.entries(reconciled.addresses)) logger$9.log(` ${container}: ${address}`);
|
|
1560
1485
|
}
|
|
1561
1486
|
const secretsEnv = {
|
|
1562
1487
|
...rawSecrets,
|
|
1563
1488
|
...reconciled.env
|
|
1564
1489
|
};
|
|
1565
1490
|
const fakes = options.fake ? await serveFakes(reconciled.fakes, reconciled.ports) : [];
|
|
1566
|
-
for (const { id, port } of fakes) logger$
|
|
1491
|
+
for (const { id, port } of fakes) logger$9.log(`🎭 ${id} fake: http://localhost:${port}`);
|
|
1567
1492
|
if (options.migrate || options.seed) {
|
|
1568
|
-
const { prepareDevDatabases } = await import("./migrate-
|
|
1493
|
+
const { prepareDevDatabases } = await import("./migrate-B3opyC3o.mjs");
|
|
1569
1494
|
await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
|
|
1570
|
-
} else await import("./migrate-
|
|
1571
|
-
logger$
|
|
1495
|
+
} else await import("./migrate-B3opyC3o.mjs").then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
|
|
1496
|
+
logger$9.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
|
|
1572
1497
|
});
|
|
1573
1498
|
const appUrls = {};
|
|
1574
1499
|
for (const resource of reconciled.plan.resources) {
|
|
@@ -1589,11 +1514,11 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1589
1514
|
else {
|
|
1590
1515
|
const { filters, unpackaged } = turboFilters(workspace);
|
|
1591
1516
|
turboFilter = filters.flatMap((name) => ["--filter", name]);
|
|
1592
|
-
if (unpackaged.length > 0) logger$
|
|
1517
|
+
if (unpackaged.length > 0) logger$9.warn(`⚠️ No package.json with a name for: ${unpackaged.join(", ")} — turbo cannot run ${unpackaged.length === 1 ? "it" : "them"}.`);
|
|
1593
1518
|
}
|
|
1594
1519
|
const buildOrder = getAppBuildOrder(workspace);
|
|
1595
1520
|
const width = Math.max(...buildOrder.map((name) => name.length));
|
|
1596
|
-
logger$
|
|
1521
|
+
logger$9.log(`\n${workspace.name}: ${appCount} app(s)`);
|
|
1597
1522
|
for (const appName of buildOrder) {
|
|
1598
1523
|
const app = workspace.apps[appName];
|
|
1599
1524
|
if (!app) continue;
|
|
@@ -1601,14 +1526,14 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1601
1526
|
const own = reconciled.plan.resources.find((r) => r.kind === "mobile-app" && appKey(r.id) === appName);
|
|
1602
1527
|
const scheme = own ? reconciled.env[own.envKey] : void 0;
|
|
1603
1528
|
const device = Object.entries(reconciled.env).find(([key]) => key.endsWith("_DEVICE_URL"))?.[1];
|
|
1604
|
-
logger$
|
|
1529
|
+
logger$9.log(` ${appName.padEnd(width)} ${scheme ? `${scheme}://` : "mobile"}${device ? ` — devices reach ${new URL(device).hostname}` : ""}`);
|
|
1605
1530
|
continue;
|
|
1606
1531
|
}
|
|
1607
1532
|
const local = `http://localhost:${app.port}`;
|
|
1608
1533
|
const url = Object.entries(appUrls).find(([id]) => appKey(id) === appName)?.[1];
|
|
1609
|
-
logger$
|
|
1534
|
+
logger$9.log(` ${appName.padEnd(width)} ${url ? `${url} -> ${local}` : local}`);
|
|
1610
1535
|
}
|
|
1611
|
-
logger$
|
|
1536
|
+
logger$9.log("");
|
|
1612
1537
|
const configFiles = [
|
|
1613
1538
|
"gkm.config.ts",
|
|
1614
1539
|
"gkm.config.js",
|
|
@@ -1655,7 +1580,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1655
1580
|
const shutdown = () => {
|
|
1656
1581
|
if (isShuttingDown) return;
|
|
1657
1582
|
isShuttingDown = true;
|
|
1658
|
-
logger$
|
|
1583
|
+
logger$9.log("\n🛑 Shutting down workspace...");
|
|
1659
1584
|
closeFakes(fakes);
|
|
1660
1585
|
const pid = turboProcess.pid;
|
|
1661
1586
|
if (pid) try {
|
|
@@ -1680,7 +1605,7 @@ async function workspaceDevCommand(workspace, options) {
|
|
|
1680
1605
|
process.on("SIGTERM", shutdown);
|
|
1681
1606
|
return new Promise((resolve, reject) => {
|
|
1682
1607
|
turboProcess.on("error", (error) => {
|
|
1683
|
-
logger$
|
|
1608
|
+
logger$9.error("❌ Turbo error:", error);
|
|
1684
1609
|
reject(error);
|
|
1685
1610
|
});
|
|
1686
1611
|
turboProcess.on("exit", (code) => {
|
|
@@ -1699,11 +1624,11 @@ async function entryDevCommand(options) {
|
|
|
1699
1624
|
const entryPath = resolve(process.cwd(), entry);
|
|
1700
1625
|
if (!existsSync(entryPath)) throw new Error(`Entry file not found: ${entryPath}`);
|
|
1701
1626
|
const defaultEnv = loadEnvFiles(".env");
|
|
1702
|
-
if (defaultEnv.loaded.length > 0) logger$
|
|
1627
|
+
if (defaultEnv.loaded.length > 0) logger$9.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
|
|
1703
1628
|
const { credentials, resolvedPort, secretsJsonPath, appName } = await prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
|
|
1704
|
-
if (appName) logger$
|
|
1705
|
-
logger$
|
|
1706
|
-
if (Object.keys(credentials).length > 1) logger$
|
|
1629
|
+
if (appName) logger$9.log(`📦 App: ${appName} (port ${resolvedPort})`);
|
|
1630
|
+
logger$9.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
|
|
1631
|
+
if (Object.keys(credentials).length > 1) logger$9.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
|
|
1707
1632
|
const wrapperDir = join(process.cwd(), ".gkm");
|
|
1708
1633
|
await mkdir(wrapperDir, { recursive: true });
|
|
1709
1634
|
const wrapperPath = join(wrapperDir, "entry-wrapper.ts");
|
|
@@ -1714,7 +1639,7 @@ async function entryDevCommand(options) {
|
|
|
1714
1639
|
const shutdown = () => {
|
|
1715
1640
|
if (isShuttingDown) return;
|
|
1716
1641
|
isShuttingDown = true;
|
|
1717
|
-
logger$
|
|
1642
|
+
logger$9.log("\n🛑 Shutting down...");
|
|
1718
1643
|
runner.stop();
|
|
1719
1644
|
process.exit(0);
|
|
1720
1645
|
};
|
|
@@ -1750,14 +1675,14 @@ var EntryRunner = class {
|
|
|
1750
1675
|
});
|
|
1751
1676
|
let restartTimeout = null;
|
|
1752
1677
|
this.watcher.on("change", (path) => {
|
|
1753
|
-
logger$
|
|
1678
|
+
logger$9.log(`📝 File changed: ${path}`);
|
|
1754
1679
|
if (restartTimeout) clearTimeout(restartTimeout);
|
|
1755
1680
|
restartTimeout = setTimeout(async () => {
|
|
1756
|
-
logger$
|
|
1681
|
+
logger$9.log("🔄 Restarting...");
|
|
1757
1682
|
await this.restart();
|
|
1758
1683
|
}, 300);
|
|
1759
1684
|
});
|
|
1760
|
-
logger$
|
|
1685
|
+
logger$9.log(`👀 Watching for changes in: ${watchDir}`);
|
|
1761
1686
|
}
|
|
1762
1687
|
}
|
|
1763
1688
|
async runProcess() {
|
|
@@ -1772,17 +1697,17 @@ var EntryRunner = class {
|
|
|
1772
1697
|
});
|
|
1773
1698
|
this.isRunning = true;
|
|
1774
1699
|
this.childProcess.on("error", (error) => {
|
|
1775
|
-
logger$
|
|
1700
|
+
logger$9.error("❌ Process error:", error);
|
|
1776
1701
|
});
|
|
1777
1702
|
this.childProcess.on("exit", (code) => {
|
|
1778
|
-
if (code !== null && code !== 0 && code !== 143) logger$
|
|
1703
|
+
if (code !== null && code !== 0 && code !== 143) logger$9.error(`❌ Process exited with code ${code}`);
|
|
1779
1704
|
this.isRunning = false;
|
|
1780
1705
|
});
|
|
1781
1706
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1782
1707
|
if (this.isRunning) {
|
|
1783
|
-
logger$
|
|
1784
|
-
logger$
|
|
1785
|
-
logger$
|
|
1708
|
+
logger$9.log("");
|
|
1709
|
+
logger$9.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
|
|
1710
|
+
logger$9.log("");
|
|
1786
1711
|
}
|
|
1787
1712
|
}
|
|
1788
1713
|
async restart() {
|
|
@@ -1960,7 +1885,6 @@ function listenerOn(port) {
|
|
|
1960
1885
|
}
|
|
1961
1886
|
}
|
|
1962
1887
|
var DevServer = class {
|
|
1963
|
-
provider;
|
|
1964
1888
|
requestedPort;
|
|
1965
1889
|
portExplicit;
|
|
1966
1890
|
enableOpenApi;
|
|
@@ -1974,8 +1898,7 @@ var DevServer = class {
|
|
|
1974
1898
|
isRunning = false;
|
|
1975
1899
|
actualPort;
|
|
1976
1900
|
startTime = Date.now();
|
|
1977
|
-
constructor(
|
|
1978
|
-
this.provider = provider;
|
|
1901
|
+
constructor(requestedPort, portExplicit, enableOpenApi, telescope, studio, runtime = "node", appRoot = process.cwd(), secretsJsonPath, selfServing = false) {
|
|
1979
1902
|
this.requestedPort = requestedPort;
|
|
1980
1903
|
this.portExplicit = portExplicit;
|
|
1981
1904
|
this.enableOpenApi = enableOpenApi;
|
|
@@ -2002,9 +1925,9 @@ var DevServer = class {
|
|
|
2002
1925
|
this.actualPort = this.requestedPort;
|
|
2003
1926
|
} else {
|
|
2004
1927
|
this.actualPort = await findAvailablePort(this.requestedPort);
|
|
2005
|
-
if (this.actualPort !== this.requestedPort) logger$
|
|
1928
|
+
if (this.actualPort !== this.requestedPort) logger$9.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
|
|
2006
1929
|
}
|
|
2007
|
-
const serverEntryPath = join(this.appRoot, ".gkm",
|
|
1930
|
+
const serverEntryPath = join(this.appRoot, ".gkm", "server", "server.ts");
|
|
2008
1931
|
await this.createServerEntry();
|
|
2009
1932
|
this.serverProcess = spawn(...tsxCommand(this.appRoot, [
|
|
2010
1933
|
serverEntryPath,
|
|
@@ -2021,10 +1944,10 @@ var DevServer = class {
|
|
|
2021
1944
|
});
|
|
2022
1945
|
this.isRunning = true;
|
|
2023
1946
|
this.serverProcess.on("error", (error) => {
|
|
2024
|
-
logger$
|
|
1947
|
+
logger$9.error("❌ Server error:", error);
|
|
2025
1948
|
});
|
|
2026
1949
|
this.serverProcess.on("exit", (code, signal) => {
|
|
2027
|
-
if (code !== null && code !== 0 && signal !== "SIGTERM") logger$
|
|
1950
|
+
if (code !== null && code !== 0 && signal !== "SIGTERM") logger$9.error(`❌ Server exited with code ${code}`);
|
|
2028
1951
|
this.isRunning = false;
|
|
2029
1952
|
});
|
|
2030
1953
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
@@ -2032,13 +1955,13 @@ var DevServer = class {
|
|
|
2032
1955
|
const local = `http://localhost:${this.actualPort}`;
|
|
2033
1956
|
const address = this.publicUrl ? `${this.publicUrl} -> ${local}` : local;
|
|
2034
1957
|
const seconds = ((Date.now() - this.startTime) / 1e3).toFixed(1);
|
|
2035
|
-
logger$
|
|
1958
|
+
logger$9.log(`\x1b[32m✓\x1b[0m ${this.label} ready in ${seconds}s ${address}`);
|
|
2036
1959
|
const tools = this.selfServing ? [] : [
|
|
2037
1960
|
...this.enableOpenApi ? ["docs /__docs"] : [],
|
|
2038
1961
|
...this.telescope ? [`telescope ${this.telescope.path}`] : [],
|
|
2039
1962
|
...this.studio ? [`studio ${this.studio.path}`] : []
|
|
2040
1963
|
];
|
|
2041
|
-
if (tools.length > 0) logger$
|
|
1964
|
+
if (tools.length > 0) logger$9.log(` ${tools.join(" · ")}`);
|
|
2042
1965
|
}
|
|
2043
1966
|
}
|
|
2044
1967
|
async stop() {
|
|
@@ -2076,7 +1999,7 @@ var DevServer = class {
|
|
|
2076
1999
|
}
|
|
2077
2000
|
async createServerEntry() {
|
|
2078
2001
|
const { writeFile: fsWriteFile } = await import("node:fs/promises");
|
|
2079
|
-
await fsWriteFile(join(this.appRoot, ".gkm",
|
|
2002
|
+
await fsWriteFile(join(this.appRoot, ".gkm", "server", "server.ts"), generateServerEntryContent({
|
|
2080
2003
|
secretsJsonPath: this.secretsJsonPath,
|
|
2081
2004
|
runtime: this.runtime,
|
|
2082
2005
|
enableOpenApi: this.enableOpenApi,
|
|
@@ -2088,22 +2011,22 @@ var DevServer = class {
|
|
|
2088
2011
|
//#region src/generators/CronGenerator.ts
|
|
2089
2012
|
var CronGenerator = class extends ConstructGenerator {
|
|
2090
2013
|
async build(context, constructs, outputDir, options) {
|
|
2091
|
-
const
|
|
2014
|
+
const target = options?.target ?? "aws";
|
|
2092
2015
|
const logger = console;
|
|
2093
2016
|
const cronInfos = [];
|
|
2094
|
-
if (
|
|
2017
|
+
if (target === "server") {
|
|
2095
2018
|
await this.generateServerCronsFile(outputDir, constructs);
|
|
2096
2019
|
logger.log(`Generated server crons file with ${constructs.length} crons`);
|
|
2097
2020
|
return cronInfos;
|
|
2098
2021
|
}
|
|
2099
|
-
if (constructs.length === 0
|
|
2022
|
+
if (constructs.length === 0) return cronInfos;
|
|
2100
2023
|
const cronsDir = join(outputDir, "crons");
|
|
2101
2024
|
await mkdir(cronsDir, { recursive: true });
|
|
2102
2025
|
for (const { key, construct, path } of constructs) {
|
|
2103
2026
|
const handlerFile = await this.generateCronHandler(cronsDir, path.relative, key, context, construct.owner);
|
|
2104
2027
|
cronInfos.push({
|
|
2105
2028
|
name: key,
|
|
2106
|
-
handler: relative(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2029
|
+
handler: relative(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2107
2030
|
schedule: construct.schedule || "rate(1 hour)",
|
|
2108
2031
|
timeout: construct.timeout,
|
|
2109
2032
|
memorySize: construct.memorySize,
|
|
@@ -2293,17 +2216,17 @@ var FunctionGenerator = class extends ConstructGenerator {
|
|
|
2293
2216
|
return Function.isFunction(value);
|
|
2294
2217
|
}
|
|
2295
2218
|
async build(context, constructs, outputDir, options) {
|
|
2296
|
-
const
|
|
2219
|
+
const target = options?.target ?? "aws";
|
|
2297
2220
|
const logger = console;
|
|
2298
2221
|
const functionInfos = [];
|
|
2299
|
-
if (constructs.length === 0 ||
|
|
2222
|
+
if (constructs.length === 0 || target === "server") return functionInfos;
|
|
2300
2223
|
const functionsDir = join(outputDir, "functions");
|
|
2301
2224
|
await mkdir(functionsDir, { recursive: true });
|
|
2302
2225
|
for (const { key, construct, path } of constructs) {
|
|
2303
2226
|
const handlerFile = await this.generateFunctionHandler(functionsDir, path.relative, key, context, construct.owner);
|
|
2304
2227
|
functionInfos.push({
|
|
2305
2228
|
name: key,
|
|
2306
|
-
handler: relative(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2229
|
+
handler: relative(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2307
2230
|
timeout: construct.timeout,
|
|
2308
2231
|
memorySize: construct.memorySize,
|
|
2309
2232
|
environment: await construct.getEnvironment({ markOptional: context.markOptional }),
|
|
@@ -2347,22 +2270,22 @@ var QueueGenerator = class extends ConstructGenerator {
|
|
|
2347
2270
|
return Queue.isQueue(value);
|
|
2348
2271
|
}
|
|
2349
2272
|
async build(context, constructs, outputDir, options) {
|
|
2350
|
-
const
|
|
2273
|
+
const target = options?.target ?? "aws";
|
|
2351
2274
|
const logger = console;
|
|
2352
2275
|
const queueInfos = [];
|
|
2353
|
-
if (
|
|
2276
|
+
if (target === "server") {
|
|
2354
2277
|
await this.generateServerQueuesFile(outputDir, constructs);
|
|
2355
2278
|
logger.log(`Generated server queues file with ${constructs.length} queues (polling mode)`);
|
|
2356
2279
|
return queueInfos;
|
|
2357
2280
|
}
|
|
2358
|
-
if (constructs.length === 0
|
|
2281
|
+
if (constructs.length === 0) return queueInfos;
|
|
2359
2282
|
const queuesDir = join(outputDir, "queues");
|
|
2360
2283
|
await mkdir(queuesDir, { recursive: true });
|
|
2361
2284
|
for (const { key, construct, path } of constructs) {
|
|
2362
2285
|
const handlerFile = await this.generateQueueHandler(queuesDir, path.relative, key, context, construct.owner);
|
|
2363
2286
|
queueInfos.push({
|
|
2364
2287
|
name: construct.name,
|
|
2365
|
-
handler: relative(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2288
|
+
handler: relative(options?.root ?? process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
2366
2289
|
batchSize: construct.batchSize,
|
|
2367
2290
|
fifo: construct.fifo,
|
|
2368
2291
|
timeout: construct.timeout,
|
|
@@ -2528,217 +2451,6 @@ var TopicGenerator = class extends ConstructGenerator {
|
|
|
2528
2451
|
}
|
|
2529
2452
|
};
|
|
2530
2453
|
//#endregion
|
|
2531
|
-
//#region src/build/manifests.ts
|
|
2532
|
-
const logger$9 = console;
|
|
2533
|
-
function isPartitioned(field) {
|
|
2534
|
-
return !Array.isArray(field);
|
|
2535
|
-
}
|
|
2536
|
-
/**
|
|
2537
|
-
* Serialize a manifest field to a TypeScript string.
|
|
2538
|
-
* Flat arrays serialize as JSON arrays, partitioned fields as objects of arrays.
|
|
2539
|
-
*/
|
|
2540
|
-
function serializeField(field, indent = 2) {
|
|
2541
|
-
if (Array.isArray(field)) return JSON.stringify(field, null, indent);
|
|
2542
|
-
return `{\n${Object.entries(field).map(([key, value]) => ` ${JSON.stringify(key)}: ${JSON.stringify(value, null, indent)}`).join(",\n")},\n }`;
|
|
2543
|
-
}
|
|
2544
|
-
/**
|
|
2545
|
-
* Count total items across a manifest field (flat or partitioned).
|
|
2546
|
-
*/
|
|
2547
|
-
function countItems(field) {
|
|
2548
|
-
if (Array.isArray(field)) return field.length;
|
|
2549
|
-
return Object.values(field).reduce((sum, arr) => sum + arr.length, 0);
|
|
2550
|
-
}
|
|
2551
|
-
/**
|
|
2552
|
-
* Generate derived types for a construct field.
|
|
2553
|
-
* @param fieldName - The field name in the manifest (e.g., 'routes')
|
|
2554
|
-
* @param typeName - The exported type name (e.g., 'Route')
|
|
2555
|
-
* @param partitioned - Whether this field is partitioned
|
|
2556
|
-
*/
|
|
2557
|
-
function generateDerivedType(fieldName, typeName, partitioned) {
|
|
2558
|
-
if (partitioned) {
|
|
2559
|
-
const partitionTypeName = `${typeName}Partition`;
|
|
2560
|
-
return [`export type ${partitionTypeName} = keyof typeof manifest.${fieldName};`, `export type ${typeName}<P extends ${partitionTypeName} = ${partitionTypeName}> = (typeof manifest.${fieldName})[P][number];`].join("\n");
|
|
2561
|
-
}
|
|
2562
|
-
return `export type ${typeName} = (typeof manifest.${fieldName})[number];`;
|
|
2563
|
-
}
|
|
2564
|
-
/** A manifest field as a flat list, whether or not it is partitioned. */
|
|
2565
|
-
function flatten(field) {
|
|
2566
|
-
return Array.isArray(field) ? field : Object.values(field).flat();
|
|
2567
|
-
}
|
|
2568
|
-
async function generateAwsManifest(outputDir, routes, functions, crons, subscribers, queues = [], topics = [], constructs = {}, backends = {}) {
|
|
2569
|
-
const manifestDir = join(outputDir, "manifest");
|
|
2570
|
-
await mkdir(manifestDir, { recursive: true });
|
|
2571
|
-
const awsRoutes = filterAllRoutes(routes);
|
|
2572
|
-
const routesPartitioned = isPartitioned(awsRoutes);
|
|
2573
|
-
const functionsPartitioned = isPartitioned(functions);
|
|
2574
|
-
const cronsPartitioned = isPartitioned(crons);
|
|
2575
|
-
const subscribersPartitioned = isPartitioned(subscribers);
|
|
2576
|
-
const queuesPartitioned = isPartitioned(queues);
|
|
2577
|
-
const topicsPartitioned = isPartitioned(topics);
|
|
2578
|
-
const awsConstructs = withCompute(withRoutes(constructs, flatten(awsRoutes), { perRoute: true }), {
|
|
2579
|
-
functions: flatten(functions),
|
|
2580
|
-
crons: flatten(crons),
|
|
2581
|
-
queues: flatten(queues),
|
|
2582
|
-
subscribers: flatten(subscribers)
|
|
2583
|
-
});
|
|
2584
|
-
const content = `export const manifest = {
|
|
2585
|
-
routes: ${serializeField(awsRoutes)},
|
|
2586
|
-
functions: ${serializeField(functions)},
|
|
2587
|
-
crons: ${serializeField(crons)},
|
|
2588
|
-
subscribers: ${serializeField(subscribers)},
|
|
2589
|
-
queues: ${serializeField(queues)},
|
|
2590
|
-
topics: ${serializeField(topics)},
|
|
2591
|
-
} as const;
|
|
2592
|
-
|
|
2593
|
-
/**
|
|
2594
|
-
* What the application declares, as opposed to what this build generated.
|
|
2595
|
-
*
|
|
2596
|
-
* Discovery imports application code, so it runs once here rather than in every
|
|
2597
|
-
* consumer — a deploy config calling it would evaluate the whole runtime graph
|
|
2598
|
-
* inside its own toolchain.
|
|
2599
|
-
*/
|
|
2600
|
-
export const constructs = ${JSON.stringify(awsConstructs, null, 2)} as const;
|
|
2601
|
-
|
|
2602
|
-
/**
|
|
2603
|
-
* Where the backends that are config rather than declaration resolved to.
|
|
2604
|
-
*
|
|
2605
|
-
* Recorded because they were answered twice: once by the build, which registers
|
|
2606
|
-
* exactly one cache driver, and once by a deploy, which told the provisioner
|
|
2607
|
-
* something else — leaving the running code with a URL it had no driver for.
|
|
2608
|
-
*/
|
|
2609
|
-
export const backends = ${JSON.stringify(backends, null, 2)} as const;
|
|
2610
|
-
|
|
2611
|
-
// Derived types
|
|
2612
|
-
${generateDerivedType("routes", "Route", routesPartitioned)}
|
|
2613
|
-
${generateDerivedType("functions", "Function", functionsPartitioned)}
|
|
2614
|
-
${generateDerivedType("crons", "Cron", cronsPartitioned)}
|
|
2615
|
-
${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
|
|
2616
|
-
${generateDerivedType("queues", "Queue", queuesPartitioned)}
|
|
2617
|
-
${generateDerivedType("topics", "Topic", topicsPartitioned)}
|
|
2618
|
-
|
|
2619
|
-
export type ConstructId = keyof typeof constructs;
|
|
2620
|
-
export type Construct<Id extends ConstructId> = (typeof constructs)[Id];
|
|
2621
|
-
|
|
2622
|
-
// Useful union types
|
|
2623
|
-
export type Authorizer = Route['authorizer'];
|
|
2624
|
-
export type HttpMethod = Route['method'];
|
|
2625
|
-
export type RoutePath = Route['path'];
|
|
2626
|
-
`;
|
|
2627
|
-
const manifestPath = join(manifestDir, "aws.ts");
|
|
2628
|
-
await writeFile(manifestPath, content);
|
|
2629
|
-
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`);
|
|
2630
|
-
logger$9.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
|
|
2631
|
-
}
|
|
2632
|
-
async function generateServerManifest(outputDir, appInfo, routes, subscribers, queues = [], topics = [], constructs = {}, backends = {}) {
|
|
2633
|
-
const manifestDir = join(outputDir, "manifest");
|
|
2634
|
-
await mkdir(manifestDir, { recursive: true });
|
|
2635
|
-
const serverRoutes = mapRouteMetadata(filterAllRoutes(routes));
|
|
2636
|
-
const serverSubscribers = mapSubscriberMetadata(subscribers);
|
|
2637
|
-
const serverQueues = mapQueueMetadata(queues);
|
|
2638
|
-
const serverTopics = mapTopicMetadata(topics);
|
|
2639
|
-
const routesPartitioned = isPartitioned(serverRoutes);
|
|
2640
|
-
const subscribersPartitioned = isPartitioned(serverSubscribers);
|
|
2641
|
-
const queuesPartitioned = isPartitioned(serverQueues);
|
|
2642
|
-
const topicsPartitioned = isPartitioned(serverTopics);
|
|
2643
|
-
const content = `export const manifest = {
|
|
2644
|
-
app: ${JSON.stringify(appInfo, null, 2)},
|
|
2645
|
-
routes: ${serializeField(serverRoutes)},
|
|
2646
|
-
subscribers: ${serializeField(serverSubscribers)},
|
|
2647
|
-
queues: ${serializeField(serverQueues)},
|
|
2648
|
-
topics: ${serializeField(serverTopics)},
|
|
2649
|
-
} as const;
|
|
2650
|
-
|
|
2651
|
-
/**
|
|
2652
|
-
* What the application declares, as opposed to what this build generated.
|
|
2653
|
-
*
|
|
2654
|
-
* Discovery imports application code, so it runs once in the build rather than
|
|
2655
|
-
* in every consumer — a deploy config calling it would evaluate the whole
|
|
2656
|
-
* runtime graph inside its own toolchain.
|
|
2657
|
-
*/
|
|
2658
|
-
export const constructs = ${JSON.stringify(constructs, null, 2)} as const;
|
|
2659
|
-
|
|
2660
|
-
/**
|
|
2661
|
-
* Where the backends that are config rather than declaration resolved to.
|
|
2662
|
-
*
|
|
2663
|
-
* Recorded because they were answered twice: once by the build, which registers
|
|
2664
|
-
* exactly one cache driver, and once by a deploy, which told the provisioner
|
|
2665
|
-
* something else — leaving the running code with a URL it had no driver for.
|
|
2666
|
-
*/
|
|
2667
|
-
export const backends = ${JSON.stringify(backends, null, 2)} as const;
|
|
2668
|
-
|
|
2669
|
-
// Derived types
|
|
2670
|
-
${generateDerivedType("routes", "Route", routesPartitioned)}
|
|
2671
|
-
${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
|
|
2672
|
-
${generateDerivedType("queues", "Queue", queuesPartitioned)}
|
|
2673
|
-
${generateDerivedType("topics", "Topic", topicsPartitioned)}
|
|
2674
|
-
|
|
2675
|
-
export type ConstructId = keyof typeof constructs;
|
|
2676
|
-
export type Construct<Id extends ConstructId> = (typeof constructs)[Id];
|
|
2677
|
-
|
|
2678
|
-
// Useful union types
|
|
2679
|
-
export type Authorizer = Route['authorizer'];
|
|
2680
|
-
export type HttpMethod = Route['method'];
|
|
2681
|
-
export type RoutePath = Route['path'];
|
|
2682
|
-
`;
|
|
2683
|
-
const manifestPath = join(manifestDir, "server.ts");
|
|
2684
|
-
await writeFile(manifestPath, content);
|
|
2685
|
-
logger$9.log(`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers, ${countItems(serverQueues)} queues, ${countItems(serverTopics)} topics`);
|
|
2686
|
-
logger$9.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);
|
|
2687
|
-
}
|
|
2688
|
-
/**
|
|
2689
|
-
* Filter out 'ALL' method routes from a manifest field (flat or partitioned).
|
|
2690
|
-
*/
|
|
2691
|
-
function filterAllRoutes(routes) {
|
|
2692
|
-
if (Array.isArray(routes)) return routes.filter((r) => r.method !== "ALL");
|
|
2693
|
-
const result = {};
|
|
2694
|
-
for (const [partition, partitionRoutes] of Object.entries(routes)) result[partition] = partitionRoutes.filter((r) => r.method !== "ALL");
|
|
2695
|
-
return result;
|
|
2696
|
-
}
|
|
2697
|
-
/**
|
|
2698
|
-
* Map routes to server metadata (path, method, authorizer only).
|
|
2699
|
-
*/
|
|
2700
|
-
function mapRouteMetadata(routes) {
|
|
2701
|
-
const mapFn = (r) => ({
|
|
2702
|
-
path: r.path,
|
|
2703
|
-
method: r.method,
|
|
2704
|
-
authorizer: r.authorizer
|
|
2705
|
-
});
|
|
2706
|
-
if (Array.isArray(routes)) return routes.map(mapFn);
|
|
2707
|
-
const result = {};
|
|
2708
|
-
for (const [partition, partitionRoutes] of Object.entries(routes)) result[partition] = partitionRoutes.map(mapFn);
|
|
2709
|
-
return result;
|
|
2710
|
-
}
|
|
2711
|
-
/**
|
|
2712
|
-
* Map subscribers to server metadata (name, subscribedEvents only).
|
|
2713
|
-
*/
|
|
2714
|
-
function mapSubscriberMetadata(subscribers) {
|
|
2715
|
-
const mapFn = (s) => ({
|
|
2716
|
-
name: s.name,
|
|
2717
|
-
subscribedEvents: s.subscribedEvents
|
|
2718
|
-
});
|
|
2719
|
-
if (Array.isArray(subscribers)) return subscribers.map(mapFn);
|
|
2720
|
-
const result = {};
|
|
2721
|
-
for (const [partition, partitionSubs] of Object.entries(subscribers)) result[partition] = partitionSubs.map(mapFn);
|
|
2722
|
-
return result;
|
|
2723
|
-
}
|
|
2724
|
-
function mapQueueMetadata(queues) {
|
|
2725
|
-
const mapFn = (q) => ({ name: q.name });
|
|
2726
|
-
if (Array.isArray(queues)) return queues.map(mapFn);
|
|
2727
|
-
const result = {};
|
|
2728
|
-
for (const [partition, partitionQueues] of Object.entries(queues)) result[partition] = partitionQueues.map(mapFn);
|
|
2729
|
-
return result;
|
|
2730
|
-
}
|
|
2731
|
-
function mapTopicMetadata(topics) {
|
|
2732
|
-
const mapFn = (t) => ({
|
|
2733
|
-
name: t.name,
|
|
2734
|
-
events: t.events
|
|
2735
|
-
});
|
|
2736
|
-
if (Array.isArray(topics)) return topics.map(mapFn);
|
|
2737
|
-
const result = {};
|
|
2738
|
-
for (const [partition, partitionTopics] of Object.entries(topics)) result[partition] = partitionTopics.map(mapFn);
|
|
2739
|
-
return result;
|
|
2740
|
-
}
|
|
2741
|
-
//#endregion
|
|
2742
2454
|
//#region src/build/owners.ts
|
|
2743
2455
|
/**
|
|
2744
2456
|
* What a generated entry imports its runtime from, read off the discovered
|
|
@@ -2808,27 +2520,6 @@ function restApis(declared) {
|
|
|
2808
2520
|
function servedSurface(declared, workspaceRoot, appRoot) {
|
|
2809
2521
|
return restApis(declared).find((d) => resolve(workspaceRoot, d.path) === resolve(appRoot));
|
|
2810
2522
|
}
|
|
2811
|
-
/**
|
|
2812
|
-
* Check if any construct across the given arrays has a non-undefined partition.
|
|
2813
|
-
* When true, the manifest should use the partitioned shape for that construct type.
|
|
2814
|
-
*/
|
|
2815
|
-
function hasPartitions(constructs) {
|
|
2816
|
-
return constructs.some((c) => c.partition !== void 0);
|
|
2817
|
-
}
|
|
2818
|
-
/**
|
|
2819
|
-
* Group an info array by partition, using the partition values from
|
|
2820
|
-
* the corresponding construct array. Both arrays must be the same length
|
|
2821
|
-
* and in the same order.
|
|
2822
|
-
*/
|
|
2823
|
-
function groupInfosByPartition(infos, constructs) {
|
|
2824
|
-
const groups = {};
|
|
2825
|
-
for (let i = 0; i < infos.length; i++) {
|
|
2826
|
-
const partition = constructs[i]?.partition ?? "default";
|
|
2827
|
-
if (!groups[partition]) groups[partition] = [];
|
|
2828
|
-
groups[partition].push(infos[i]);
|
|
2829
|
-
}
|
|
2830
|
-
return groups;
|
|
2831
|
-
}
|
|
2832
2523
|
//#endregion
|
|
2833
2524
|
//#region src/build/surfaceEntry.ts
|
|
2834
2525
|
/** Whether a construct serves itself, asked of the construct. */
|
|
@@ -2905,6 +2596,24 @@ function rootGkmConfig(workspace) {
|
|
|
2905
2596
|
constructs: allConstructGlobs(workspace)
|
|
2906
2597
|
};
|
|
2907
2598
|
}
|
|
2599
|
+
/** Directories under `.gkm/` that the removed per-provider builds wrote. */
|
|
2600
|
+
const SUPERSEDED_OUTPUT = [
|
|
2601
|
+
"aws-apigatewayv1",
|
|
2602
|
+
"aws-apigatewayv2",
|
|
2603
|
+
"aws-lambda"
|
|
2604
|
+
];
|
|
2605
|
+
/** Whether `--provider` named something a build can target. */
|
|
2606
|
+
function isMainProvider(value) {
|
|
2607
|
+
return value === "aws" || value === "server";
|
|
2608
|
+
}
|
|
2609
|
+
var UnknownBuildProvider = class extends Error {
|
|
2610
|
+
provider;
|
|
2611
|
+
constructor(provider) {
|
|
2612
|
+
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.`);
|
|
2613
|
+
this.provider = provider;
|
|
2614
|
+
this.name = "UnknownBuildProvider";
|
|
2615
|
+
}
|
|
2616
|
+
};
|
|
2908
2617
|
async function buildCommand(options) {
|
|
2909
2618
|
const loadedConfig = await loadWorkspaceConfig();
|
|
2910
2619
|
if (loadedConfig.type === "workspace") {
|
|
@@ -2918,25 +2627,62 @@ async function buildCommand(options) {
|
|
|
2918
2627
|
}
|
|
2919
2628
|
}
|
|
2920
2629
|
const config = loadedConfig.type !== "workspace" ? await loadConfig() : resolve(process.cwd()) === resolve(loadedConfig.workspace.root) ? rootGkmConfig(loadedConfig.workspace) : (await loadAppConfig()).gkmConfig;
|
|
2921
|
-
const
|
|
2922
|
-
const
|
|
2923
|
-
const
|
|
2924
|
-
const
|
|
2630
|
+
const target = options.provider ?? providerOf(loadedConfig.workspace);
|
|
2631
|
+
const workspaceRoot = loadedConfig.workspace.root;
|
|
2632
|
+
const appRoot = process.cwd();
|
|
2633
|
+
const output = await buildOneApp({
|
|
2634
|
+
config,
|
|
2635
|
+
options,
|
|
2636
|
+
workspace: loadedConfig.workspace,
|
|
2637
|
+
appRoot,
|
|
2638
|
+
target
|
|
2639
|
+
});
|
|
2640
|
+
if (resolve(appRoot) === resolve(workspaceRoot)) await writeManifest({
|
|
2641
|
+
workspaceRoot,
|
|
2642
|
+
target,
|
|
2643
|
+
builds: output.built ? [output.built] : [],
|
|
2644
|
+
constructs: await declaredIn(config, workspaceRoot),
|
|
2645
|
+
backends: backendsOf(loadedConfig.workspace)
|
|
2646
|
+
});
|
|
2647
|
+
return output;
|
|
2648
|
+
}
|
|
2649
|
+
/** What the workspace declares, read through a config's globs. */
|
|
2650
|
+
async function declaredIn(config, cwd) {
|
|
2651
|
+
return discover({
|
|
2652
|
+
patterns: config.constructs,
|
|
2653
|
+
cwd
|
|
2654
|
+
});
|
|
2655
|
+
}
|
|
2656
|
+
/**
|
|
2657
|
+
* The backend choices the manifest records — answered by the deploy target,
|
|
2658
|
+
* the same place reconcile and the build's drivers read them.
|
|
2659
|
+
*/
|
|
2660
|
+
function backendsOf(workspace) {
|
|
2661
|
+
return {
|
|
2662
|
+
cache: cacheBackendFor(providerOf(workspace)),
|
|
2663
|
+
email: "ses"
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
/** One app's build, from its config and the command's options. */
|
|
2667
|
+
async function buildOneApp(input) {
|
|
2668
|
+
const { config, options, workspace, appRoot, target } = input;
|
|
2669
|
+
const cacheBackend = cacheBackendFor(providerOf(workspace));
|
|
2670
|
+
const production = normalizeProductionConfig(options.production ?? false);
|
|
2925
2671
|
if (production) logger$8.log(`🏭 Building for PRODUCTION`);
|
|
2926
|
-
logger$8.log(`Building
|
|
2672
|
+
logger$8.log(`Building for ${target}`);
|
|
2927
2673
|
logger$8.log(`Loading constructs from: ${formatRoutes(config.constructs)}`);
|
|
2928
2674
|
const telescope = production ? void 0 : normalizeTelescopeConfig(config.telescope);
|
|
2929
2675
|
if (telescope) logger$8.log(`🔭 Telescope enabled at ${telescope.path}`);
|
|
2930
2676
|
const studio = production ? void 0 : normalizeStudioConfig(config.studio);
|
|
2931
2677
|
if (studio) logger$8.log(`🗄️ Studio enabled at ${studio.path}`);
|
|
2932
|
-
const hooks = normalizeHooksConfig(config.hooks);
|
|
2678
|
+
const hooks = normalizeHooksConfig(config.hooks, appRoot);
|
|
2933
2679
|
if (hooks) logger$8.log(`🪝 Server hooks enabled`);
|
|
2934
2680
|
return buildApp({
|
|
2935
2681
|
config,
|
|
2936
|
-
workspaceRoot:
|
|
2937
|
-
appRoot
|
|
2938
|
-
|
|
2939
|
-
enableOpenApi:
|
|
2682
|
+
workspaceRoot: workspace.root,
|
|
2683
|
+
appRoot,
|
|
2684
|
+
target,
|
|
2685
|
+
enableOpenApi: options.enableOpenApi ?? false,
|
|
2940
2686
|
cacheBackend,
|
|
2941
2687
|
production,
|
|
2942
2688
|
telescope,
|
|
@@ -2948,6 +2694,33 @@ async function buildCommand(options) {
|
|
|
2948
2694
|
});
|
|
2949
2695
|
}
|
|
2950
2696
|
/**
|
|
2697
|
+
* Write the application's manifest: every declared construct, with what each
|
|
2698
|
+
* app generated folded into it.
|
|
2699
|
+
*
|
|
2700
|
+
* The manifest belongs to the whole application, so only the root writes it —
|
|
2701
|
+
* once, after every app has built, from the constructs the workspace declares.
|
|
2702
|
+
* An app's own build generates its handlers and nothing else.
|
|
2703
|
+
*/
|
|
2704
|
+
async function writeManifest(input) {
|
|
2705
|
+
const { workspaceRoot, target, builds, constructs, backends } = input;
|
|
2706
|
+
const manifestDir = join(workspaceRoot, ".gkm", "manifest");
|
|
2707
|
+
await mkdir(manifestDir, { recursive: true });
|
|
2708
|
+
await rm(join(manifestDir, `${target === "aws" ? "server" : "aws"}.ts`), { force: true });
|
|
2709
|
+
const withServed = builds.reduce((manifest, build) => withRoutes(manifest, build.routes.filter((route) => route.method !== "ALL"), {
|
|
2710
|
+
perRoute: true,
|
|
2711
|
+
...build.surface ? { surface: build.surface } : {}
|
|
2712
|
+
}), constructs);
|
|
2713
|
+
const folded = withCompute(withServed, {
|
|
2714
|
+
functions: builds.flatMap((build) => build.functions),
|
|
2715
|
+
crons: builds.flatMap((build) => build.crons),
|
|
2716
|
+
queues: builds.flatMap((build) => build.queues),
|
|
2717
|
+
subscribers: builds.flatMap((build) => build.subscribers)
|
|
2718
|
+
});
|
|
2719
|
+
const path = join(manifestDir, `${target}.ts`);
|
|
2720
|
+
await writeFile(path, manifestModule(folded, backends));
|
|
2721
|
+
logger$8.log(`Manifest: ${relative(process.cwd(), path)}`);
|
|
2722
|
+
}
|
|
2723
|
+
/**
|
|
2951
2724
|
* Turn one app's constructs into its generated entry.
|
|
2952
2725
|
*
|
|
2953
2726
|
* `gkm build` and `gkm dev` both run this. They used to be two copies of it,
|
|
@@ -2956,8 +2729,8 @@ async function buildCommand(options) {
|
|
|
2956
2729
|
* dev did not, and failed on exactly the apps the build had learned to handle.
|
|
2957
2730
|
*/
|
|
2958
2731
|
async function buildApp(input) {
|
|
2959
|
-
const { config, workspaceRoot, appRoot,
|
|
2960
|
-
const constructGlobs =
|
|
2732
|
+
const { config, workspaceRoot, appRoot, target, enableOpenApi, cacheBackend, production, telescope, studio, hooks, bustCache = false } = input;
|
|
2733
|
+
const constructGlobs = config.constructs;
|
|
2961
2734
|
const constructSources = {};
|
|
2962
2735
|
const declared = constructGlobs ? await discover({
|
|
2963
2736
|
patterns: constructGlobs,
|
|
@@ -3023,50 +2796,58 @@ async function buildApp(input) {
|
|
|
3023
2796
|
logger$8.log("No endpoints, functions, crons, subscribers, queues, or topics found to process");
|
|
3024
2797
|
return {};
|
|
3025
2798
|
}
|
|
3026
|
-
const
|
|
3027
|
-
await mkdir(rootOutputDir, { recursive: true });
|
|
3028
|
-
let result = {};
|
|
3029
|
-
for (const provider of providers) {
|
|
3030
|
-
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);
|
|
3031
|
-
if (providerResult.masterKey) result = providerResult;
|
|
3032
|
-
}
|
|
2799
|
+
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);
|
|
3033
2800
|
await generateOpenApi(allEndpoints.map(({ construct }) => construct), { openapi: config.openapi });
|
|
3034
2801
|
return result;
|
|
3035
2802
|
}
|
|
3036
|
-
async function
|
|
3037
|
-
const
|
|
3038
|
-
|
|
2803
|
+
async function buildForTarget(target, context, appRoot, workspaceRoot, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, endpoints, functions, crons, subscribers, queues, topics, enableOpenApi, skipBundle, stage) {
|
|
2804
|
+
const outputDir = join(appRoot, ".gkm", target);
|
|
2805
|
+
await Promise.all([...SUPERSEDED_OUTPUT.map((dir) => join(appRoot, ".gkm", dir)), ...appRoot === workspaceRoot ? [] : [join(appRoot, ".gkm", "manifest")]].map((dir) => rm(dir, {
|
|
2806
|
+
recursive: true,
|
|
2807
|
+
force: true
|
|
2808
|
+
})));
|
|
2809
|
+
if (target === "aws") await rm(outputDir, {
|
|
2810
|
+
recursive: true,
|
|
2811
|
+
force: true
|
|
2812
|
+
});
|
|
3039
2813
|
await mkdir(outputDir, { recursive: true });
|
|
3040
|
-
logger$8.log(`\nGenerating handlers for
|
|
2814
|
+
logger$8.log(`\nGenerating handlers for ${target}`);
|
|
2815
|
+
const options = {
|
|
2816
|
+
target,
|
|
2817
|
+
root: workspaceRoot
|
|
2818
|
+
};
|
|
3041
2819
|
const [routes, functionInfos, cronInfos, subscriberInfos, queueInfos, topicInfos] = await Promise.all([
|
|
3042
2820
|
endpointGenerator.build(context, endpoints, outputDir, {
|
|
3043
|
-
|
|
2821
|
+
...options,
|
|
3044
2822
|
enableOpenApi
|
|
3045
2823
|
}),
|
|
3046
|
-
functionGenerator.build(context, functions, outputDir,
|
|
3047
|
-
cronGenerator.build(context, crons, outputDir,
|
|
3048
|
-
subscriberGenerator.build(context, subscribers, outputDir,
|
|
3049
|
-
queueGenerator.build(context, queues, outputDir,
|
|
3050
|
-
topicGenerator.build(context, topics, outputDir,
|
|
2824
|
+
functionGenerator.build(context, functions, outputDir, options),
|
|
2825
|
+
cronGenerator.build(context, crons, outputDir, options),
|
|
2826
|
+
subscriberGenerator.build(context, subscribers, outputDir, options),
|
|
2827
|
+
queueGenerator.build(context, queues, outputDir, options),
|
|
2828
|
+
topicGenerator.build(context, topics, outputDir, options)
|
|
3051
2829
|
]);
|
|
3052
|
-
logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${
|
|
3053
|
-
const
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
2830
|
+
logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${target}`);
|
|
2831
|
+
const fields = {
|
|
2832
|
+
...context.surface ? { surface: context.surface.id } : {},
|
|
2833
|
+
functions: functionInfos,
|
|
2834
|
+
crons: cronInfos,
|
|
2835
|
+
queues: queueInfos,
|
|
2836
|
+
subscribers: subscriberInfos
|
|
2837
|
+
};
|
|
2838
|
+
if (target === "server") {
|
|
2839
|
+
const handler = relative(workspaceRoot, join(outputDir, "app.ts"));
|
|
2840
|
+
const built = {
|
|
2841
|
+
...fields,
|
|
2842
|
+
routes: await Promise.all(endpoints.map(async ({ construct }) => ({
|
|
2843
|
+
path: construct._path,
|
|
2844
|
+
method: construct.method,
|
|
2845
|
+
handler,
|
|
2846
|
+
environment: await construct.getEnvironment({ markOptional: context.markOptional }),
|
|
2847
|
+
dependencies: construct.constructs,
|
|
2848
|
+
authorizer: construct.authorizer?.name ?? "none"
|
|
2849
|
+
})))
|
|
2850
|
+
};
|
|
3070
2851
|
let masterKey;
|
|
3071
2852
|
if (context.production?.bundle && !skipBundle) {
|
|
3072
2853
|
logger$8.log(`\n📦 Bundling production server...`);
|
|
@@ -3093,12 +2874,15 @@ async function buildForProvider(provider, context, appRoot, discovered, endpoint
|
|
|
3093
2874
|
logger$8.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
|
|
3094
2875
|
}
|
|
3095
2876
|
}
|
|
3096
|
-
return {
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
}
|
|
3101
|
-
return {
|
|
2877
|
+
return {
|
|
2878
|
+
masterKey,
|
|
2879
|
+
built
|
|
2880
|
+
};
|
|
2881
|
+
}
|
|
2882
|
+
return { built: {
|
|
2883
|
+
...fields,
|
|
2884
|
+
routes
|
|
2885
|
+
} };
|
|
3102
2886
|
}
|
|
3103
2887
|
/**
|
|
3104
2888
|
* Detect available package manager.
|
|
@@ -3120,8 +2904,8 @@ function detectPackageManager$2() {
|
|
|
3120
2904
|
*
|
|
3121
2905
|
* @internal Exported for testing
|
|
3122
2906
|
*/
|
|
3123
|
-
function getTurboCommand(pm, filters = []) {
|
|
3124
|
-
const filterArgs = (typeof filters === "string" ? [filters] : filters).map((f) => ` --filter=${f}`).join("");
|
|
2907
|
+
function getTurboCommand(pm, filters = [], { only = false } = {}) {
|
|
2908
|
+
const filterArgs = (typeof filters === "string" ? [filters] : filters).map((f) => ` --filter=${f}`).join("") + (only ? " --only" : "");
|
|
3125
2909
|
switch (pm) {
|
|
3126
2910
|
case "pnpm": return `pnpm exec turbo run build${filterArgs}`;
|
|
3127
2911
|
case "yarn": return `yarn turbo run build${filterArgs}`;
|
|
@@ -3141,10 +2925,11 @@ function getTurboCommand(pm, filters = []) {
|
|
|
3141
2925
|
*
|
|
3142
2926
|
* @internal Exported for testing
|
|
3143
2927
|
*/
|
|
3144
|
-
function turboFilters(workspace) {
|
|
2928
|
+
function turboFilters(workspace, { exclude } = {}) {
|
|
3145
2929
|
const filters = [];
|
|
3146
2930
|
const unpackaged = [];
|
|
3147
|
-
for (const appName of Object.
|
|
2931
|
+
for (const [appName, app] of Object.entries(workspace.apps)) {
|
|
2932
|
+
if (app.type === exclude) continue;
|
|
3148
2933
|
const name = appPackageName(workspace, appName);
|
|
3149
2934
|
if (name) filters.push(name);
|
|
3150
2935
|
else unpackaged.push(appName);
|
|
@@ -3183,31 +2968,59 @@ async function workspaceBuildCommand(workspace, options) {
|
|
|
3183
2968
|
if (options.production) logger$8.log(` 🏭 Production mode enabled`);
|
|
3184
2969
|
const buildOrder = getAppBuildOrder(workspace);
|
|
3185
2970
|
logger$8.log(` Build order: ${buildOrder.join(" → ")}`);
|
|
3186
|
-
const pm = detectPackageManager$2();
|
|
3187
|
-
logger$8.log(`\n📦 Using ${pm} with Turbo for parallel builds...\n`);
|
|
3188
2971
|
try {
|
|
3189
|
-
const
|
|
3190
|
-
|
|
3191
|
-
const
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
});
|
|
3203
|
-
child.on("close", (code) => {
|
|
3204
|
-
if (code === 0) resolve();
|
|
3205
|
-
else reject(/* @__PURE__ */ new Error(`Turbo build failed with exit code ${code}`));
|
|
3206
|
-
});
|
|
3207
|
-
child.on("error", (err) => {
|
|
3208
|
-
reject(err);
|
|
2972
|
+
const target = options.provider ?? providerOf(workspace);
|
|
2973
|
+
const builds = [];
|
|
2974
|
+
for (const appName of buildOrder) {
|
|
2975
|
+
const app = workspace.apps[appName];
|
|
2976
|
+
const config = getAppGkmConfig(workspace, appName);
|
|
2977
|
+
if (!app || app.type !== "backend" || !config) continue;
|
|
2978
|
+
logger$8.log(`\n⚙️ ${appName}`);
|
|
2979
|
+
const output = await buildOneApp({
|
|
2980
|
+
config,
|
|
2981
|
+
options,
|
|
2982
|
+
workspace,
|
|
2983
|
+
appRoot: join(workspace.root, app.path),
|
|
2984
|
+
target
|
|
3209
2985
|
});
|
|
2986
|
+
if (output.built) builds.push(output.built);
|
|
2987
|
+
}
|
|
2988
|
+
await writeManifest({
|
|
2989
|
+
workspaceRoot: workspace.root,
|
|
2990
|
+
target,
|
|
2991
|
+
builds,
|
|
2992
|
+
constructs: await discover({
|
|
2993
|
+
patterns: allConstructGlobs(workspace),
|
|
2994
|
+
cwd: workspace.root
|
|
2995
|
+
}),
|
|
2996
|
+
backends: backendsOf(workspace)
|
|
3210
2997
|
});
|
|
2998
|
+
const { filters, unpackaged } = turboFilters(workspace, { exclude: "backend" });
|
|
2999
|
+
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.`);
|
|
3000
|
+
const pm = detectPackageManager$2();
|
|
3001
|
+
const turboCommand = getTurboCommand(pm, filters, { only: true });
|
|
3002
|
+
if (filters.length > 0) {
|
|
3003
|
+
logger$8.log(`\n📦 Using ${pm} with Turbo for the other apps...\n`);
|
|
3004
|
+
logger$8.log(`Running: ${turboCommand}`);
|
|
3005
|
+
await new Promise((resolve, reject) => {
|
|
3006
|
+
const child = spawn(turboCommand, {
|
|
3007
|
+
shell: true,
|
|
3008
|
+
cwd: workspace.root,
|
|
3009
|
+
stdio: "inherit",
|
|
3010
|
+
env: {
|
|
3011
|
+
...process.env,
|
|
3012
|
+
NODE_ENV: options.production ? "production" : "development"
|
|
3013
|
+
}
|
|
3014
|
+
});
|
|
3015
|
+
child.on("close", (code) => {
|
|
3016
|
+
if (code === 0) resolve();
|
|
3017
|
+
else reject(/* @__PURE__ */ new Error(`Turbo build failed with exit code ${code}`));
|
|
3018
|
+
});
|
|
3019
|
+
child.on("error", (err) => {
|
|
3020
|
+
reject(err);
|
|
3021
|
+
});
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3211
3024
|
for (const [appName, app] of apps) {
|
|
3212
3025
|
const outputPath = getAppOutputPath(workspace, appName, app);
|
|
3213
3026
|
results.push({
|
|
@@ -3250,23 +3063,11 @@ function getAppOutputPath(workspace, _appName, app) {
|
|
|
3250
3063
|
}
|
|
3251
3064
|
return join(appPath, ".gkm");
|
|
3252
3065
|
}
|
|
3253
|
-
/**
|
|
3254
|
-
* Format routes for logging, handling PartitionedRoutes.
|
|
3255
|
-
*/
|
|
3066
|
+
/** Format routes for logging. */
|
|
3256
3067
|
function formatRoutes(routes) {
|
|
3257
|
-
if (isPartitionedRoutes(routes)) return `${Array.isArray(routes.paths) ? routes.paths.join(", ") : routes.paths} (partitioned)`;
|
|
3258
3068
|
return Array.isArray(routes) ? routes.join(", ") : routes;
|
|
3259
3069
|
}
|
|
3260
3070
|
/**
|
|
3261
|
-
* Assemble a ManifestField from build infos and constructs.
|
|
3262
|
-
* If any construct has a partition, returns a Record<string, T[]>.
|
|
3263
|
-
* Otherwise, returns a flat T[].
|
|
3264
|
-
*/
|
|
3265
|
-
function assembleManifestField(infos, constructs) {
|
|
3266
|
-
if (!hasPartitions(constructs)) return infos;
|
|
3267
|
-
return groupInfosByPartition(infos, constructs);
|
|
3268
|
-
}
|
|
3269
|
-
/**
|
|
3270
3071
|
* Format a fatal error for display.
|
|
3271
3072
|
* Always includes the full stack trace since these are process-ending errors.
|
|
3272
3073
|
*/
|
|
@@ -5412,9 +5213,8 @@ async function dockerCommand(options) {
|
|
|
5412
5213
|
logger$6.log("📦 Detected workspace configuration");
|
|
5413
5214
|
return workspaceDockerCommand(loadedConfig.workspace);
|
|
5414
5215
|
}
|
|
5415
|
-
const
|
|
5416
|
-
const
|
|
5417
|
-
const healthCheckPath = (typeof config.providers?.server === "object" ? config.providers.server : void 0)?.production?.healthCheck ?? "/health";
|
|
5216
|
+
const dockerConfig = resolveDockerConfig(await loadConfig());
|
|
5217
|
+
const healthCheckPath = "/health";
|
|
5418
5218
|
const useSlim = options.slim === true;
|
|
5419
5219
|
if (useSlim) {
|
|
5420
5220
|
const distDir = join(process.cwd(), ".gkm", "server", "dist");
|
|
@@ -7420,6 +7220,10 @@ async function workspaceDeployCommand(configured, options) {
|
|
|
7420
7220
|
} else logger$4.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
|
|
7421
7221
|
const dokployApps = appsToDeployNames.filter((name) => {
|
|
7422
7222
|
const target = workspace.apps[name].resolvedDeployTarget;
|
|
7223
|
+
if (target === "sst") {
|
|
7224
|
+
logger$4.log(` ⚠️ Skipping ${name}: it deploys with SST — run \`gkm build && sst deploy --stage ${stage}\``);
|
|
7225
|
+
return false;
|
|
7226
|
+
}
|
|
7423
7227
|
if (!isDeployTargetSupported(target)) {
|
|
7424
7228
|
logger$4.log(` ⚠️ Skipping ${name}: ${getDeployTargetError(target, name)}`);
|
|
7425
7229
|
return false;
|
|
@@ -7940,66 +7744,6 @@ async function createApi(endpoint) {
|
|
|
7940
7744
|
});
|
|
7941
7745
|
}
|
|
7942
7746
|
/**
|
|
7943
|
-
* Update gkm.config.ts with Dokploy configuration
|
|
7944
|
-
*/
|
|
7945
|
-
/**
|
|
7946
|
-
* Whether the file's `dokploy` block is more than a flat literal.
|
|
7947
|
-
*
|
|
7948
|
-
* A spread, a `process.env`, a ternary or a nested object all defeat the
|
|
7949
|
-
* single-level regex below — the first two by being expressions it would
|
|
7950
|
-
* stringify away, the last by ending the match at the wrong brace.
|
|
7951
|
-
*/
|
|
7952
|
-
function unsafeToRewrite(content) {
|
|
7953
|
-
const start = content.indexOf("dokploy:");
|
|
7954
|
-
if (start === -1) return false;
|
|
7955
|
-
const block = content.slice(start, content.indexOf("\n },", start) + 1);
|
|
7956
|
-
return /\.\.\.|process\.env|\?\s|`|\{[^}]*\{/s.test(block);
|
|
7957
|
-
}
|
|
7958
|
-
async function updateConfig(config, cwd = process.cwd()) {
|
|
7959
|
-
const configPath = join(cwd, "gkm.config.ts");
|
|
7960
|
-
if (!existsSync(configPath)) {
|
|
7961
|
-
logger$3.warn("\n gkm.config.ts not found. Add this configuration manually:\n");
|
|
7962
|
-
logger$3.log(` providers: {`);
|
|
7963
|
-
logger$3.log(` dokploy: {`);
|
|
7964
|
-
logger$3.log(` endpoint: '${config.endpoint}',`);
|
|
7965
|
-
logger$3.log(` projectId: '${config.projectId}',`);
|
|
7966
|
-
logger$3.log(` applicationId: '${config.applicationId}',`);
|
|
7967
|
-
logger$3.log(` },`);
|
|
7968
|
-
logger$3.log(` },`);
|
|
7969
|
-
return;
|
|
7970
|
-
}
|
|
7971
|
-
const content = await readFile(configPath, "utf-8");
|
|
7972
|
-
if (unsafeToRewrite(content)) {
|
|
7973
|
-
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.");
|
|
7974
|
-
logger$3.log(`\n Discovered, if you want them written down:`);
|
|
7975
|
-
logger$3.log(` projectId: '${config.projectId}'`);
|
|
7976
|
-
logger$3.log(` applicationId: '${config.applicationId}'`);
|
|
7977
|
-
if (config.registryId) logger$3.log(` registryId: '${config.registryId}'`);
|
|
7978
|
-
return;
|
|
7979
|
-
}
|
|
7980
|
-
if (content.includes("dokploy:") && content.includes("applicationId:")) {
|
|
7981
|
-
logger$3.log("\n Dokploy config already exists in gkm.config.ts");
|
|
7982
|
-
logger$3.log(" Updating with new values...");
|
|
7983
|
-
}
|
|
7984
|
-
const registryLine = config.registryId ? `\n\t\t\tregistryId: '${config.registryId}',` : "";
|
|
7985
|
-
const dokployConfigStr = `dokploy: {
|
|
7986
|
-
endpoint: '${config.endpoint}',
|
|
7987
|
-
projectId: '${config.projectId}',
|
|
7988
|
-
applicationId: '${config.applicationId}',${registryLine}
|
|
7989
|
-
}`;
|
|
7990
|
-
let newContent;
|
|
7991
|
-
if (content.includes("providers:")) {
|
|
7992
|
-
if (content.includes("dokploy:")) newContent = content.replace(/dokploy:\s*\{[^}]*\}/s, dokployConfigStr);
|
|
7993
|
-
else newContent = content.replace(/providers:\s*\{/, `providers: {\n\t\t${dokployConfigStr},`);
|
|
7994
|
-
} else newContent = content.replace(/}\s*\)\s*;?\s*$/, `
|
|
7995
|
-
providers: {
|
|
7996
|
-
${dokployConfigStr},
|
|
7997
|
-
},
|
|
7998
|
-
});`);
|
|
7999
|
-
await writeFile(configPath, newContent);
|
|
8000
|
-
logger$3.log("\n ✓ Updated gkm.config.ts with Dokploy configuration");
|
|
8001
|
-
}
|
|
8002
|
-
/**
|
|
8003
7747
|
* Initialize Dokploy deployment configuration
|
|
8004
7748
|
*/
|
|
8005
7749
|
async function deployInitCommand(options) {
|
|
@@ -8052,7 +7796,6 @@ async function deployInitCommand(options) {
|
|
|
8052
7796
|
projectId,
|
|
8053
7797
|
applicationId: application.applicationId
|
|
8054
7798
|
};
|
|
8055
|
-
await updateConfig(config);
|
|
8056
7799
|
logger$3.log(`\n✅ Dokploy deployment initialized!`);
|
|
8057
7800
|
logger$3.log(`\n📋 Configuration:`);
|
|
8058
7801
|
logger$3.log(` Project ID: ${projectId}`);
|
|
@@ -9322,26 +9065,26 @@ function loadPackageJson() {
|
|
|
9322
9065
|
* Run: pnpm --filter @geekmidas/cli sync-versions
|
|
9323
9066
|
*/
|
|
9324
9067
|
const GEEKMIDAS_VERSIONS = {
|
|
9325
|
-
"@geekmidas/audit": "~10.0.0-alpha.
|
|
9326
|
-
"@geekmidas/auth": "~10.0.0-alpha.
|
|
9327
|
-
"@geekmidas/cache": "~10.0.0-alpha.
|
|
9328
|
-
"@geekmidas/client": "~10.0.0-alpha.
|
|
9329
|
-
"@geekmidas/cloud": "~10.0.0-alpha.
|
|
9330
|
-
"@geekmidas/constructs": "~10.0.0-alpha.
|
|
9331
|
-
"@geekmidas/db": "~10.0.0-alpha.
|
|
9332
|
-
"@geekmidas/emailkit": "~10.0.0-alpha.
|
|
9333
|
-
"@geekmidas/envkit": "~10.0.0-alpha.
|
|
9334
|
-
"@geekmidas/errors": "~10.0.0-alpha.
|
|
9335
|
-
"@geekmidas/events": "~10.0.0-alpha.
|
|
9336
|
-
"@geekmidas/logger": "~10.0.0-alpha.
|
|
9337
|
-
"@geekmidas/manifest": "~10.0.0-alpha.
|
|
9338
|
-
"@geekmidas/rate-limit": "~10.0.0-alpha.
|
|
9339
|
-
"@geekmidas/schema": "~10.0.0-alpha.
|
|
9340
|
-
"@geekmidas/services": "~10.0.0-alpha.
|
|
9341
|
-
"@geekmidas/storage": "~10.0.0-alpha.
|
|
9342
|
-
"@geekmidas/studio": "~10.0.0-alpha.
|
|
9343
|
-
"@geekmidas/telescope": "~10.0.0-alpha.
|
|
9344
|
-
"@geekmidas/testkit": "~10.0.0-alpha.
|
|
9068
|
+
"@geekmidas/audit": "~10.0.0-alpha.46",
|
|
9069
|
+
"@geekmidas/auth": "~10.0.0-alpha.46",
|
|
9070
|
+
"@geekmidas/cache": "~10.0.0-alpha.46",
|
|
9071
|
+
"@geekmidas/client": "~10.0.0-alpha.46",
|
|
9072
|
+
"@geekmidas/cloud": "~10.0.0-alpha.46",
|
|
9073
|
+
"@geekmidas/constructs": "~10.0.0-alpha.46",
|
|
9074
|
+
"@geekmidas/db": "~10.0.0-alpha.46",
|
|
9075
|
+
"@geekmidas/emailkit": "~10.0.0-alpha.46",
|
|
9076
|
+
"@geekmidas/envkit": "~10.0.0-alpha.46",
|
|
9077
|
+
"@geekmidas/errors": "~10.0.0-alpha.46",
|
|
9078
|
+
"@geekmidas/events": "~10.0.0-alpha.46",
|
|
9079
|
+
"@geekmidas/logger": "~10.0.0-alpha.46",
|
|
9080
|
+
"@geekmidas/manifest": "~10.0.0-alpha.46",
|
|
9081
|
+
"@geekmidas/rate-limit": "~10.0.0-alpha.46",
|
|
9082
|
+
"@geekmidas/schema": "~10.0.0-alpha.46",
|
|
9083
|
+
"@geekmidas/services": "~10.0.0-alpha.46",
|
|
9084
|
+
"@geekmidas/storage": "~10.0.0-alpha.46",
|
|
9085
|
+
"@geekmidas/studio": "~10.0.0-alpha.46",
|
|
9086
|
+
"@geekmidas/telescope": "~10.0.0-alpha.46",
|
|
9087
|
+
"@geekmidas/testkit": "~10.0.0-alpha.46",
|
|
9345
9088
|
"@geekmidas/cli": `~${loadPackageJson().version}`
|
|
9346
9089
|
};
|
|
9347
9090
|
//#endregion
|
|
@@ -10868,7 +10611,7 @@ function deployPackage(options) {
|
|
|
10868
10611
|
case "sst": {
|
|
10869
10612
|
const v = GEEKMIDAS_VERSIONS;
|
|
10870
10613
|
return {
|
|
10871
|
-
scripts: perStage(options, (stage) => `gkm build
|
|
10614
|
+
scripts: perStage(options, (stage) => `gkm build && sst deploy --stage ${stage}`),
|
|
10872
10615
|
dependencies: {
|
|
10873
10616
|
"@geekmidas/cloud": v["@geekmidas/cloud"],
|
|
10874
10617
|
"@geekmidas/db": v["@geekmidas/db"],
|
|
@@ -10933,7 +10676,7 @@ export default $config({
|
|
|
10933
10676
|
|
|
10934
10677
|
async run() {
|
|
10935
10678
|
const { App, fromManifest, Stack } = await import('@geekmidas/cloud/sst');
|
|
10936
|
-
// Written by \`gkm build
|
|
10679
|
+
// Written by \`gkm build\`. Imported rather than discovered,
|
|
10937
10680
|
// so SST's toolchain never evaluates the application's own modules.
|
|
10938
10681
|
const { backends, constructs } = await import('./.gkm/manifest/aws.js');
|
|
10939
10682
|
|
|
@@ -11171,8 +10914,11 @@ coverage/
|
|
|
11171
10914
|
${isSst ? "\n# SST\n.sst/\n" : ""}`;
|
|
11172
10915
|
const tsConfig = {
|
|
11173
10916
|
compilerOptions: {
|
|
10917
|
+
paths: {
|
|
10918
|
+
...isFullstack ? { [`@${options.name}/constructs/*`]: ["./constructs/*"] } : {},
|
|
10919
|
+
[`@${options.name}/manifest`]: [`./.gkm/manifest/${isSst ? "aws" : "server"}.ts`]
|
|
10920
|
+
},
|
|
11174
10921
|
...isFullstack ? {
|
|
11175
|
-
paths: { [`@${options.name}/constructs/*`]: ["./constructs/*"] },
|
|
11176
10922
|
allowImportingTsExtensions: true,
|
|
11177
10923
|
noEmit: true
|
|
11178
10924
|
} : {},
|
|
@@ -11313,7 +11059,7 @@ export default defineWorkspace({
|
|
|
11313
11059
|
// \`production-${options.name}-database\` on Dokploy and on AWS alike.
|
|
11314
11060
|
name: '${options.name}',
|
|
11315
11061
|
${stagesBlock(options.stages)}
|
|
11316
|
-
|
|
11062
|
+
${deployBlock(options)}
|
|
11317
11063
|
// Every kind, in every app. A declared database is why a Postgres exists, a
|
|
11318
11064
|
// declared bucket is why MinIO does, a declared topic is why a broker does —
|
|
11319
11065
|
// none of it listed here. It is also where the apps come from: a
|
|
@@ -11331,6 +11077,18 @@ ${workspaceConstructsGlobs(options.routesStructure, dirname(options.apiPath)).ma
|
|
|
11331
11077
|
`;
|
|
11332
11078
|
}
|
|
11333
11079
|
/**
|
|
11080
|
+
* Where it deploys, when that is not the default Dokploy: what a bare
|
|
11081
|
+
* `gkm build` builds for, and which backends a cache or a broker resolves to.
|
|
11082
|
+
*/
|
|
11083
|
+
function deployBlock(options) {
|
|
11084
|
+
if (options.deployTarget !== "sst") return "";
|
|
11085
|
+
return `
|
|
11086
|
+
// Deployed with \`sst deploy\`, from the manifest \`gkm build\` writes to
|
|
11087
|
+
// \`.gkm/manifest/aws.ts\`. Each construct becomes a managed AWS resource.
|
|
11088
|
+
deploy: { default: 'sst' },
|
|
11089
|
+
`;
|
|
11090
|
+
}
|
|
11091
|
+
/**
|
|
11334
11092
|
* Where a deployed stage's secrets live. On AWS that is SSM in the stage's own
|
|
11335
11093
|
* account, which the deploy job reaches with the role it already assumed; a
|
|
11336
11094
|
* server target keeps the encrypted local file, the default.
|
|
@@ -11356,7 +11114,7 @@ function secretsStore(options) {
|
|
|
11356
11114
|
*/
|
|
11357
11115
|
function generateRootConstructs(options) {
|
|
11358
11116
|
if (!options.monorepo || options.template !== "fullstack") return [];
|
|
11359
|
-
const {
|
|
11117
|
+
const { frontendFramework } = options;
|
|
11360
11118
|
const { cache, uploads, mail } = options.constructs;
|
|
11361
11119
|
const db = databaseFor();
|
|
11362
11120
|
const files = [];
|
|
@@ -12116,7 +11874,7 @@ const serverlessTemplate = {
|
|
|
12116
11874
|
},
|
|
12117
11875
|
scripts: {
|
|
12118
11876
|
dev: "gkm dev",
|
|
12119
|
-
build: "gkm build --provider aws
|
|
11877
|
+
build: "gkm build --provider aws",
|
|
12120
11878
|
test: "vitest",
|
|
12121
11879
|
"test:once": "vitest run",
|
|
12122
11880
|
typecheck: "tsc --noEmit",
|
|
@@ -12125,7 +11883,7 @@ const serverlessTemplate = {
|
|
|
12125
11883
|
"fmt:check": "biome format ."
|
|
12126
11884
|
},
|
|
12127
11885
|
files: (options) => {
|
|
12128
|
-
const { loggerType, routesStructure
|
|
11886
|
+
const { loggerType, routesStructure } = options;
|
|
12129
11887
|
const loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';
|
|
12130
11888
|
|
|
12131
11889
|
export const logger = createLogger();
|
|
@@ -12410,10 +12168,6 @@ export const telescope = new Telescope({
|
|
|
12410
12168
|
*/
|
|
12411
12169
|
const OPENAPI_OUTPUT_PATH = "./.gkm/openapi/api.ts";
|
|
12412
12170
|
/**
|
|
12413
|
-
* Endpoints output path (generated by gkm dev/build)
|
|
12414
|
-
*/
|
|
12415
|
-
const ENDPOINTS_OUTPUT_PATH = "./.gkm/server/endpoints.ts";
|
|
12416
|
-
/**
|
|
12417
12171
|
* All available templates
|
|
12418
12172
|
*/
|
|
12419
12173
|
const templates = {
|
|
@@ -12626,10 +12380,7 @@ function generatePackageJson(options, template) {
|
|
|
12626
12380
|
private: true,
|
|
12627
12381
|
type: "module",
|
|
12628
12382
|
...!monorepo && options.packageManager === "pnpm" ? { packageManager: PNPM_VERSION } : {},
|
|
12629
|
-
exports: {
|
|
12630
|
-
"./client": OPENAPI_OUTPUT_PATH,
|
|
12631
|
-
"./endpoints": ENDPOINTS_OUTPUT_PATH
|
|
12632
|
-
},
|
|
12383
|
+
exports: { "./client": OPENAPI_OUTPUT_PATH },
|
|
12633
12384
|
scripts,
|
|
12634
12385
|
dependencies: sortObject(dependencies),
|
|
12635
12386
|
devDependencies: sortObject(devDependencies)
|
|
@@ -15355,7 +15106,7 @@ function printNextSteps(projectName, options, pkgManager) {
|
|
|
15355
15106
|
}
|
|
15356
15107
|
if (options.deployTarget === "sst") {
|
|
15357
15108
|
console.log("🚀 Deployment (AWS, through SST):");
|
|
15358
|
-
for (const stage of deployed) console.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm build
|
|
15109
|
+
for (const stage of deployed) console.log(` ${getRunCommand(pkgManager, `deploy:${stage}`)} # gkm build, then sst deploy`);
|
|
15359
15110
|
console.log(` Uses your AWS credentials, in ${options.region}.`);
|
|
15360
15111
|
if (options.constructs.mail) console.log(" Set MAIL_FROM to a sender verified in SES first.");
|
|
15361
15112
|
console.log("");
|
|
@@ -16015,7 +15766,7 @@ async function testCommand(options = {}) {
|
|
|
16015
15766
|
root: workspace.root,
|
|
16016
15767
|
targets: [workspace.root, ...Object.values(workspace.apps).map((app) => isAbsolute(app.path) ? app.path : join(workspace.root, app.path))],
|
|
16017
15768
|
patterns: constructGlobs(workspace),
|
|
16018
|
-
cacheBackend: backendsOf(workspace).cache,
|
|
15769
|
+
cacheBackend: backendsOf$1(workspace).cache,
|
|
16019
15770
|
stage: TEST_STAGE,
|
|
16020
15771
|
env: finalCredentials,
|
|
16021
15772
|
factories: join(workspace.root, workspace.test.factories ?? "test/factories")
|
|
@@ -16090,8 +15841,8 @@ function testDatabases(reconciled) {
|
|
|
16090
15841
|
* starts without the reference data the app needs.
|
|
16091
15842
|
*/
|
|
16092
15843
|
async function migrateTestStage(workspace, env) {
|
|
16093
|
-
const { migrateAndSeed } = await import("./migrate-
|
|
16094
|
-
const { discover } = await import("./discover-
|
|
15844
|
+
const { migrateAndSeed } = await import("./migrate-B3opyC3o.mjs");
|
|
15845
|
+
const { discover } = await import("./discover-Cf2jAcgF.mjs").then((n) => n.n);
|
|
16095
15846
|
const sources = {};
|
|
16096
15847
|
const manifest = await discover({
|
|
16097
15848
|
patterns: constructGlobs(workspace),
|
|
@@ -16456,29 +16207,13 @@ program.command("setup").description("Reconcile declared constructs — containe
|
|
|
16456
16207
|
process.exit(1);
|
|
16457
16208
|
}
|
|
16458
16209
|
});
|
|
16459
|
-
program.command("build").description("Build handlers and the manifest from declared constructs").option("--provider <provider>", "
|
|
16210
|
+
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) => {
|
|
16460
16211
|
try {
|
|
16461
16212
|
const globalOptions = program.opts();
|
|
16462
16213
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16463
|
-
if (options.provider)
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
provider: options.provider,
|
|
16467
|
-
enableOpenApi: options.enableOpenapi || false,
|
|
16468
|
-
production: options.production || false,
|
|
16469
|
-
skipBundle: options.skipBundle || false,
|
|
16470
|
-
stage: options.stage,
|
|
16471
|
-
markOptional: options.markOptional || false
|
|
16472
|
-
});
|
|
16473
|
-
} else if (options.providers) await buildCommand({
|
|
16474
|
-
providers: [...new Set(options.providers.split(",").map((p) => p.trim()))],
|
|
16475
|
-
enableOpenApi: options.enableOpenapi || false,
|
|
16476
|
-
production: options.production || false,
|
|
16477
|
-
skipBundle: options.skipBundle || false,
|
|
16478
|
-
stage: options.stage,
|
|
16479
|
-
markOptional: options.markOptional || false
|
|
16480
|
-
});
|
|
16481
|
-
else await buildCommand({
|
|
16214
|
+
if (options.provider !== void 0 && !isMainProvider(options.provider)) throw new UnknownBuildProvider(options.provider);
|
|
16215
|
+
await buildCommand({
|
|
16216
|
+
...options.provider ? { provider: options.provider } : {},
|
|
16482
16217
|
enableOpenApi: options.enableOpenapi || false,
|
|
16483
16218
|
production: options.production || false,
|
|
16484
16219
|
skipBundle: options.skipBundle || false,
|
|
@@ -16537,7 +16272,7 @@ program.command("migrate").description("Apply each database construct's migratio
|
|
|
16537
16272
|
try {
|
|
16538
16273
|
const globalOptions = program.opts();
|
|
16539
16274
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16540
|
-
const { migrateCommand } = await import("./migrate-
|
|
16275
|
+
const { migrateCommand } = await import("./migrate-B3opyC3o.mjs");
|
|
16541
16276
|
await migrateCommand({
|
|
16542
16277
|
...options,
|
|
16543
16278
|
...construct ? { construct } : {}
|
|
@@ -16551,7 +16286,7 @@ program.command("seed").description("Migrate, then run each database construct's
|
|
|
16551
16286
|
try {
|
|
16552
16287
|
const globalOptions = program.opts();
|
|
16553
16288
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16554
|
-
const { seedCommand } = await import("./migrate-
|
|
16289
|
+
const { seedCommand } = await import("./migrate-B3opyC3o.mjs");
|
|
16555
16290
|
await seedCommand({
|
|
16556
16291
|
...options,
|
|
16557
16292
|
...construct ? { construct } : {}
|
|
@@ -16565,7 +16300,7 @@ program.command("migration").description("Write a construct's next migration: an
|
|
|
16565
16300
|
try {
|
|
16566
16301
|
const globalOptions = program.opts();
|
|
16567
16302
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16568
|
-
const { migrationCommand } = await import("./migrate-
|
|
16303
|
+
const { migrationCommand } = await import("./migrate-B3opyC3o.mjs");
|
|
16569
16304
|
await migrationCommand({
|
|
16570
16305
|
construct,
|
|
16571
16306
|
...name ? { name } : {}
|
|
@@ -16704,7 +16439,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
16704
16439
|
console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
16705
16440
|
process.exit(1);
|
|
16706
16441
|
}
|
|
16707
|
-
const { derivedContainers } = await import("./workspace-
|
|
16442
|
+
const { derivedContainers } = await import("./workspace-CHEC80sp.mjs").then((n) => n.o);
|
|
16708
16443
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
|
|
16709
16444
|
if (!result) {
|
|
16710
16445
|
console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
|
|
@@ -16763,7 +16498,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
|
|
|
16763
16498
|
try {
|
|
16764
16499
|
const globalOptions = program.opts();
|
|
16765
16500
|
if (globalOptions.cwd) process.chdir(globalOptions.cwd);
|
|
16766
|
-
const { deployGithubCommand } = await import("./github-
|
|
16501
|
+
const { deployGithubCommand } = await import("./github-BfpadQWQ.mjs");
|
|
16767
16502
|
await deployGithubCommand(options);
|
|
16768
16503
|
} catch (error) {
|
|
16769
16504
|
console.error(formatError(error));
|