@geekmidas/cli 10.0.0-alpha.0 → 10.0.0-alpha.2
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 +0 -7
- package/dist/{config-DbPE1KXF.cjs → config-BholeD-0.cjs} +5 -5
- package/dist/config-BholeD-0.cjs.map +1 -0
- package/dist/{config-D8o6I_7Z.mjs → config-CzWnfcXM.mjs} +5 -5
- package/dist/config-CzWnfcXM.mjs.map +1 -0
- package/dist/config.cjs +1 -1
- package/dist/config.mjs +1 -1
- package/dist/{credentials-Dh0Q6HzY.mjs → credentials-BZcp3CGx.mjs} +3 -3
- package/dist/{credentials-Dh0Q6HzY.mjs.map → credentials-BZcp3CGx.mjs.map} +1 -1
- package/dist/{credentials-K961ThG3.cjs → credentials-DQmbRnr1.cjs} +3 -3
- package/dist/{credentials-K961ThG3.cjs.map → credentials-DQmbRnr1.cjs.map} +1 -1
- package/dist/index.cjs +248 -273
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +248 -273
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-CgpMWMmM.mjs → openapi-CY9xFkTH.mjs} +2 -2
- package/dist/{openapi-CgpMWMmM.mjs.map → openapi-CY9xFkTH.mjs.map} +1 -1
- package/dist/{openapi-CljONd_M.cjs → openapi-c9bpieI5.cjs} +2 -2
- package/dist/{openapi-CljONd_M.cjs.map → openapi-c9bpieI5.cjs.map} +1 -1
- package/dist/openapi.cjs +2 -2
- package/dist/openapi.mjs +2 -2
- package/dist/{setup-DOsYueeQ.mjs → setup-Bc73t0ve.mjs} +3 -3
- package/dist/{setup-DOsYueeQ.mjs.map → setup-Bc73t0ve.mjs.map} +1 -1
- package/dist/{setup-CJiQM2pX.cjs → setup-C48C9hto.cjs} +3 -3
- package/dist/{setup-CJiQM2pX.cjs.map → setup-C48C9hto.cjs.map} +1 -1
- package/dist/{setup-DSutDAlt.mjs → setup-DCuudnCl.mjs} +3 -3
- package/dist/{setup-DMtU3p41.cjs → setup-fG_ivuxO.cjs} +3 -3
- package/dist/{workspace-8acupeaI.cjs → workspace-BO_KWohI.cjs} +2 -2
- package/dist/{workspace-yP5AHnrn.mjs → workspace-DK4WWJIn.mjs} +2 -2
- package/package.json +11 -11
- package/dist/config-D8o6I_7Z.mjs.map +0 -1
- package/dist/config-DbPE1KXF.cjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
import { __require } from "./chunk-Duj1WY3L.mjs";
|
|
3
3
|
import { ConstructGenerator, DEFAULT_CACHE, discover, isPartitionedRoutes } from "./discover-CAlFgYec.mjs";
|
|
4
|
-
import { derivedApps, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig, resolveAppSpec } from "./config-
|
|
4
|
+
import { derivedApps, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig, resolveAppSpec } from "./config-CzWnfcXM.mjs";
|
|
5
5
|
import { allConstructGlobs, getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, getPublicEnvPrefix, isDeployTargetSupported, stripPublicPrefix } from "./workspace-7FqprxuJ.mjs";
|
|
6
6
|
import { getCredentialsPath, getDokployCredentials, getDokployRegistryId, getDokployToken, removeDokployCredentials, storeDokployCredentials, storeDokployRegistryId, storeHostingerToken } from "./credentials-B5zRHdAl.mjs";
|
|
7
|
-
import { applyPostgres, cacheBackendOf, constructGlobs, createCredentialsPreload, createEntryWrapper, derivedContainers, emailBackendOf, findAvailablePort, isPortAvailable, loadEnvFiles, loadSecretsForApp, prepareEntryCredentials, providerOf, reconcileWorkspace, resolveServicePorts, resourceName, rewriteUrlsWithPorts, startWorkspaceServices, storageBackendOf, usesConstructs } from "./credentials-
|
|
7
|
+
import { applyPostgres, cacheBackendOf, constructGlobs, createCredentialsPreload, createEntryWrapper, derivedContainers, emailBackendOf, findAvailablePort, isPortAvailable, loadEnvFiles, loadSecretsForApp, prepareEntryCredentials, providerOf, reconcileWorkspace, resolveServicePorts, resourceName, rewriteUrlsWithPorts, startWorkspaceServices, storageBackendOf, usesConstructs } from "./credentials-BZcp3CGx.mjs";
|
|
8
8
|
import { createStageSecrets, rotateServicePassword } from "./generator-VE2JrFlY.mjs";
|
|
9
9
|
import { getKeyPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-Bi24WfoW.mjs";
|
|
10
|
-
import { EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, normalizeRoutes, openapiCommand, resolveOpenApiConfig } from "./openapi-
|
|
10
|
+
import { EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, normalizeRoutes, openapiCommand, resolveOpenApiConfig } from "./openapi-CY9xFkTH.mjs";
|
|
11
11
|
import { withCompute, withRoutes } from "./emit-CiZS_5Ub.mjs";
|
|
12
12
|
import { DokployApi } from "./dokploy-api-aTFPz7_4.mjs";
|
|
13
13
|
import { encryptSecrets } from "./encryption-D-abyhZx.mjs";
|
|
@@ -15,7 +15,7 @@ import { CachedStateProvider } from "./CachedStateProvider-DTniehMP.mjs";
|
|
|
15
15
|
import { generateDbPassword, generateDbUrl, generateFullstackCustomSecrets } from "./fullstack-secrets-D1o9-G5l.mjs";
|
|
16
16
|
import { generateReactQueryCommand } from "./openapi-react-query-Byltvm_7.mjs";
|
|
17
17
|
import "./sync-CmEuNZsB.mjs";
|
|
18
|
-
import { setupCommand, trustCommand } from "./setup-
|
|
18
|
+
import { setupCommand, trustCommand } from "./setup-Bc73t0ve.mjs";
|
|
19
19
|
import { createRequire } from "node:module";
|
|
20
20
|
import { copyFileSync, existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
21
21
|
import { basename, dirname, isAbsolute, join, parse, relative, resolve } from "node:path";
|
|
@@ -43,7 +43,7 @@ import prompts from "prompts";
|
|
|
43
43
|
|
|
44
44
|
//#region package.json
|
|
45
45
|
var name = "@geekmidas/cli";
|
|
46
|
-
var version = "
|
|
46
|
+
var version = "10.0.0-alpha.1";
|
|
47
47
|
var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
|
|
48
48
|
var private$1 = false;
|
|
49
49
|
var type = "module";
|
|
@@ -443,7 +443,7 @@ var CronGenerator = class extends ConstructGenerator {
|
|
|
443
443
|
const importPath = relativePath.replace(/\.ts$/, ".js");
|
|
444
444
|
const relativeEnvParserPath = relative(dirname(handlerPath), context.envParserPath);
|
|
445
445
|
const relativeLoggerPath = relative(dirname(handlerPath), context.loggerPath);
|
|
446
|
-
const content = `import { AWSScheduledFunction } from '@geekmidas/constructs/
|
|
446
|
+
const content = `import { AWSScheduledFunction } from '@geekmidas/constructs/aws';
|
|
447
447
|
import { ${exportName} } from '${importPath}';
|
|
448
448
|
import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
|
|
449
449
|
import ${context.loggerImportPattern} from '${relativeLoggerPath}';
|
|
@@ -7364,26 +7364,26 @@ const CLI_VERSION = `~${pkg.version}`;
|
|
|
7364
7364
|
* Run: pnpm --filter @geekmidas/cli sync-versions
|
|
7365
7365
|
*/
|
|
7366
7366
|
const GEEKMIDAS_VERSIONS = {
|
|
7367
|
-
"@geekmidas/audit": "~
|
|
7368
|
-
"@geekmidas/auth": "~
|
|
7369
|
-
"@geekmidas/cache": "~
|
|
7370
|
-
"@geekmidas/client": "~
|
|
7371
|
-
"@geekmidas/cloud": "~
|
|
7372
|
-
"@geekmidas/constructs": "~
|
|
7373
|
-
"@geekmidas/db": "~
|
|
7374
|
-
"@geekmidas/emailkit": "~
|
|
7375
|
-
"@geekmidas/envkit": "~
|
|
7376
|
-
"@geekmidas/errors": "~
|
|
7377
|
-
"@geekmidas/events": "~
|
|
7378
|
-
"@geekmidas/logger": "~
|
|
7379
|
-
"@geekmidas/manifest": "~
|
|
7380
|
-
"@geekmidas/rate-limit": "~
|
|
7381
|
-
"@geekmidas/schema": "~
|
|
7382
|
-
"@geekmidas/services": "~
|
|
7383
|
-
"@geekmidas/storage": "~
|
|
7384
|
-
"@geekmidas/studio": "~
|
|
7385
|
-
"@geekmidas/telescope": "~
|
|
7386
|
-
"@geekmidas/testkit": "~
|
|
7367
|
+
"@geekmidas/audit": "~10.0.0-alpha.1",
|
|
7368
|
+
"@geekmidas/auth": "~10.0.0-alpha.1",
|
|
7369
|
+
"@geekmidas/cache": "~10.0.0-alpha.1",
|
|
7370
|
+
"@geekmidas/client": "~10.0.0-alpha.1",
|
|
7371
|
+
"@geekmidas/cloud": "~10.0.0-alpha.1",
|
|
7372
|
+
"@geekmidas/constructs": "~10.0.0-alpha.1",
|
|
7373
|
+
"@geekmidas/db": "~10.0.0-alpha.1",
|
|
7374
|
+
"@geekmidas/emailkit": "~10.0.0-alpha.1",
|
|
7375
|
+
"@geekmidas/envkit": "~10.0.0-alpha.1",
|
|
7376
|
+
"@geekmidas/errors": "~10.0.0-alpha.1",
|
|
7377
|
+
"@geekmidas/events": "~10.0.0-alpha.1",
|
|
7378
|
+
"@geekmidas/logger": "~10.0.0-alpha.1",
|
|
7379
|
+
"@geekmidas/manifest": "~10.0.0-alpha.1",
|
|
7380
|
+
"@geekmidas/rate-limit": "~10.0.0-alpha.1",
|
|
7381
|
+
"@geekmidas/schema": "~10.0.0-alpha.1",
|
|
7382
|
+
"@geekmidas/services": "~10.0.0-alpha.1",
|
|
7383
|
+
"@geekmidas/storage": "~10.0.0-alpha.1",
|
|
7384
|
+
"@geekmidas/studio": "~10.0.0-alpha.1",
|
|
7385
|
+
"@geekmidas/telescope": "~10.0.0-alpha.1",
|
|
7386
|
+
"@geekmidas/testkit": "~10.0.0-alpha.1",
|
|
7387
7387
|
"@geekmidas/cli": CLI_VERSION
|
|
7388
7388
|
};
|
|
7389
7389
|
|
|
@@ -7442,119 +7442,6 @@ function generateAuthAppFiles(options) {
|
|
|
7442
7442
|
include: ["src/**/*.ts"],
|
|
7443
7443
|
exclude: ["node_modules", "dist"]
|
|
7444
7444
|
};
|
|
7445
|
-
const envTs = `import { Credentials } from '@geekmidas/envkit/credentials';
|
|
7446
|
-
import { EnvironmentParser } from '@geekmidas/envkit';
|
|
7447
|
-
|
|
7448
|
-
export const envParser = new EnvironmentParser({ ...process.env, ...Credentials });
|
|
7449
|
-
|
|
7450
|
-
// Global config - only minimal shared values
|
|
7451
|
-
// Service-specific config should be parsed where needed
|
|
7452
|
-
export const config = envParser
|
|
7453
|
-
.create((get) => ({
|
|
7454
|
-
nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),
|
|
7455
|
-
stage: get('STAGE').enum(['development', 'staging', 'production']).default('development'),
|
|
7456
|
-
}))
|
|
7457
|
-
.parse();
|
|
7458
|
-
`;
|
|
7459
|
-
const loggerTs = `import { createLogger } from '@geekmidas/logger/${options.loggerType}';
|
|
7460
|
-
|
|
7461
|
-
export const logger = createLogger();
|
|
7462
|
-
`;
|
|
7463
|
-
const authTs = `import { betterAuth } from 'better-auth';
|
|
7464
|
-
import { magicLink } from 'better-auth/plugins';
|
|
7465
|
-
import pg from 'pg';
|
|
7466
|
-
import { envParser } from './config/env.ts';
|
|
7467
|
-
import { logger } from './config/logger.ts';
|
|
7468
|
-
|
|
7469
|
-
// Parse auth-specific config (no defaults - values from secrets)
|
|
7470
|
-
const authConfig = envParser
|
|
7471
|
-
.create((get) => ({
|
|
7472
|
-
databaseUrl: get('DATABASE_URL').string(),
|
|
7473
|
-
baseUrl: get('BETTER_AUTH_URL').string(),
|
|
7474
|
-
trustedOrigins: get('BETTER_AUTH_TRUSTED_ORIGINS').string(),
|
|
7475
|
-
secret: get('BETTER_AUTH_SECRET').string(),
|
|
7476
|
-
}))
|
|
7477
|
-
.parse();
|
|
7478
|
-
|
|
7479
|
-
export const auth = betterAuth({
|
|
7480
|
-
database: new pg.Pool({
|
|
7481
|
-
connectionString: authConfig.databaseUrl,
|
|
7482
|
-
}),
|
|
7483
|
-
baseURL: authConfig.baseUrl,
|
|
7484
|
-
trustedOrigins: authConfig.trustedOrigins.split(','),
|
|
7485
|
-
secret: authConfig.secret,
|
|
7486
|
-
plugins: [
|
|
7487
|
-
magicLink({
|
|
7488
|
-
sendMagicLink: async ({ email, url }) => {
|
|
7489
|
-
// TODO: Implement email sending using @geekmidas/emailkit
|
|
7490
|
-
// For development, log the magic link
|
|
7491
|
-
logger.info({ email, url }, 'Magic link generated');
|
|
7492
|
-
console.log('\\n================================');
|
|
7493
|
-
console.log('MAGIC LINK FOR:', email);
|
|
7494
|
-
console.log(url);
|
|
7495
|
-
console.log('================================\\n');
|
|
7496
|
-
},
|
|
7497
|
-
expiresIn: 300, // 5 minutes
|
|
7498
|
-
}),
|
|
7499
|
-
],
|
|
7500
|
-
emailAndPassword: {
|
|
7501
|
-
enabled: false, // Only magic link for now
|
|
7502
|
-
},
|
|
7503
|
-
});
|
|
7504
|
-
|
|
7505
|
-
export type Auth = typeof auth;
|
|
7506
|
-
`;
|
|
7507
|
-
const indexTs = `import { Hono } from 'hono';
|
|
7508
|
-
import { cors } from 'hono/cors';
|
|
7509
|
-
import { serve } from '@hono/node-server';
|
|
7510
|
-
import { auth } from './auth.ts';
|
|
7511
|
-
import { envParser } from './config/env.ts';
|
|
7512
|
-
import { logger } from './config/logger.ts';
|
|
7513
|
-
|
|
7514
|
-
// Parse server config (no defaults - values from secrets)
|
|
7515
|
-
const serverConfig = envParser
|
|
7516
|
-
.create((get) => ({
|
|
7517
|
-
port: get('PORT').string().transform(Number),
|
|
7518
|
-
trustedOrigins: get('BETTER_AUTH_TRUSTED_ORIGINS').string(),
|
|
7519
|
-
}))
|
|
7520
|
-
.parse();
|
|
7521
|
-
|
|
7522
|
-
const app = new Hono();
|
|
7523
|
-
|
|
7524
|
-
// CORS must be registered before routes
|
|
7525
|
-
app.use(
|
|
7526
|
-
'/api/auth/*',
|
|
7527
|
-
cors({
|
|
7528
|
-
origin: serverConfig.trustedOrigins.split(','),
|
|
7529
|
-
allowHeaders: ['Content-Type', 'Authorization'],
|
|
7530
|
-
allowMethods: ['POST', 'GET', 'OPTIONS'],
|
|
7531
|
-
credentials: true,
|
|
7532
|
-
}),
|
|
7533
|
-
);
|
|
7534
|
-
|
|
7535
|
-
// Health check endpoint
|
|
7536
|
-
app.get('/health', (c) => {
|
|
7537
|
-
return c.json({
|
|
7538
|
-
status: 'ok',
|
|
7539
|
-
service: 'auth',
|
|
7540
|
-
timestamp: new Date().toISOString(),
|
|
7541
|
-
});
|
|
7542
|
-
});
|
|
7543
|
-
|
|
7544
|
-
// Mount better-auth handler
|
|
7545
|
-
app.on(['POST', 'GET'], '/api/auth/*', (c) => {
|
|
7546
|
-
return auth.handler(c.req.raw);
|
|
7547
|
-
});
|
|
7548
|
-
|
|
7549
|
-
logger.info({ port: serverConfig.port }, 'Starting auth server');
|
|
7550
|
-
|
|
7551
|
-
serve({
|
|
7552
|
-
fetch: app.fetch,
|
|
7553
|
-
port: serverConfig.port,
|
|
7554
|
-
}, (info) => {
|
|
7555
|
-
logger.info({ port: info.port }, 'Auth server running');
|
|
7556
|
-
});
|
|
7557
|
-
`;
|
|
7558
7445
|
const gitignore = `node_modules/
|
|
7559
7446
|
dist/
|
|
7560
7447
|
.env.local
|
|
@@ -7569,22 +7456,6 @@ dist/
|
|
|
7569
7456
|
path: "apps/auth/tsconfig.json",
|
|
7570
7457
|
content: `${JSON.stringify(tsConfig, null, 2)}\n`
|
|
7571
7458
|
},
|
|
7572
|
-
{
|
|
7573
|
-
path: "apps/auth/src/config/env.ts",
|
|
7574
|
-
content: envTs
|
|
7575
|
-
},
|
|
7576
|
-
{
|
|
7577
|
-
path: "apps/auth/src/config/logger.ts",
|
|
7578
|
-
content: loggerTs
|
|
7579
|
-
},
|
|
7580
|
-
{
|
|
7581
|
-
path: "apps/auth/src/auth.ts",
|
|
7582
|
-
content: authTs
|
|
7583
|
-
},
|
|
7584
|
-
{
|
|
7585
|
-
path: "apps/auth/src/index.ts",
|
|
7586
|
-
content: indexTs
|
|
7587
|
-
},
|
|
7588
7459
|
{
|
|
7589
7460
|
path: "apps/auth/.gitignore",
|
|
7590
7461
|
content: gitignore
|
|
@@ -7797,6 +7668,7 @@ export default defineConfig({${options.monorepo ? "" : `
|
|
|
7797
7668
|
baseUrl: ".",
|
|
7798
7669
|
paths: {
|
|
7799
7670
|
"~/*": ["./src/*"],
|
|
7671
|
+
[`@${options.name}/constructs/*`]: ["../../constructs/*"],
|
|
7800
7672
|
[`@${options.name}/*`]: ["../../packages/*/src"]
|
|
7801
7673
|
}
|
|
7802
7674
|
},
|
|
@@ -9191,6 +9063,10 @@ coverage/
|
|
|
9191
9063
|
`;
|
|
9192
9064
|
const tsConfig = {
|
|
9193
9065
|
compilerOptions: {
|
|
9066
|
+
...isFullstack ? {
|
|
9067
|
+
baseUrl: ".",
|
|
9068
|
+
paths: { [`@${options.name}/constructs/*`]: ["./constructs/*"] }
|
|
9069
|
+
} : {},
|
|
9194
9070
|
target: "ES2022",
|
|
9195
9071
|
module: "NodeNext",
|
|
9196
9072
|
moduleResolution: "NodeNext",
|
|
@@ -9300,124 +9176,212 @@ export default defineConfig({
|
|
|
9300
9176
|
return files$1;
|
|
9301
9177
|
}
|
|
9302
9178
|
/**
|
|
9303
|
-
*
|
|
9304
|
-
*
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
dependencies: ['api', 'auth'],
|
|
9314
|
-
config: {
|
|
9315
|
-
client: './src/config/client.ts',
|
|
9316
|
-
server: './src/config/server.ts',
|
|
9317
|
-
},
|
|
9318
|
-
},`;
|
|
9319
|
-
case "expo": return `app: {
|
|
9320
|
-
type: 'mobile',
|
|
9321
|
-
framework: 'expo',
|
|
9322
|
-
path: 'apps/app',
|
|
9323
|
-
port: 8081,
|
|
9324
|
-
dependencies: ['api', 'auth'],
|
|
9325
|
-
},`;
|
|
9326
|
-
default: return `web: {
|
|
9327
|
-
type: 'web',
|
|
9328
|
-
framework: 'nextjs',
|
|
9329
|
-
path: 'apps/web',
|
|
9330
|
-
port: 3001,
|
|
9331
|
-
dependencies: ['api', 'auth'],
|
|
9332
|
-
config: {
|
|
9333
|
-
client: './src/config/client.ts',
|
|
9334
|
-
server: './src/config/server.ts',
|
|
9335
|
-
},
|
|
9336
|
-
},`;
|
|
9337
|
-
}
|
|
9338
|
-
}
|
|
9339
|
-
/**
|
|
9340
|
-
* Generate gkm.config.ts with defineWorkspace for fullstack template
|
|
9179
|
+
* `gkm.config.ts` for the fullstack workspace.
|
|
9180
|
+
*
|
|
9181
|
+
* What is *not* here is the point. There is no `apps` block: the apps are the
|
|
9182
|
+
* constructs that said they have a process — a `RestApi`, a `BetterAuth`, a
|
|
9183
|
+
* `StaticSite` — and naming them again here would be the same sentence written
|
|
9184
|
+
* twice with only one copy checked.
|
|
9185
|
+
*
|
|
9186
|
+
* There is no `services` block either unless something non-default was picked.
|
|
9187
|
+
* Every key defaults from the deploy target: on a server target a cache is a
|
|
9188
|
+
* table in the database that is already there, storage is MinIO, mail is SES.
|
|
9341
9189
|
*/
|
|
9342
9190
|
function generateWorkspaceConfig(options) {
|
|
9343
|
-
const { telescope, services, deployTarget, routesStructure } = options;
|
|
9344
|
-
const getRoutesGlob = () => {
|
|
9345
|
-
switch (routesStructure) {
|
|
9346
|
-
case "centralized-endpoints": return "./src/endpoints/**/*.ts";
|
|
9347
|
-
case "centralized-routes": return "./src/routes/**/*.ts";
|
|
9348
|
-
case "domain-based": return "./src/**/routes/*.ts";
|
|
9349
|
-
}
|
|
9350
|
-
};
|
|
9351
9191
|
let config = `import { defineWorkspace } from '@geekmidas/cli/config';
|
|
9352
9192
|
|
|
9353
9193
|
export default defineWorkspace({
|
|
9194
|
+
// The scope every physical name is built from: \`Database\` becomes
|
|
9195
|
+
// \`production-${options.name}-database\` on Dokploy and on AWS alike.
|
|
9354
9196
|
name: '${options.name}',
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
logger: './src/config/logger#logger',
|
|
9363
|
-
dependencies: ['auth'],`;
|
|
9364
|
-
if (telescope) config += `
|
|
9365
|
-
telescope: {
|
|
9366
|
-
enabled: true,
|
|
9367
|
-
path: '/__telescope',
|
|
9368
|
-
},`;
|
|
9369
|
-
config += `
|
|
9370
|
-
openapi: {
|
|
9371
|
-
enabled: true,
|
|
9372
|
-
},
|
|
9373
|
-
},
|
|
9374
|
-
auth: {
|
|
9375
|
-
type: 'backend',
|
|
9376
|
-
path: 'apps/auth',
|
|
9377
|
-
port: 3002,
|
|
9378
|
-
entry: './src/index.ts',
|
|
9379
|
-
framework: 'better-auth',
|
|
9380
|
-
envParser: './src/config/env#envParser',
|
|
9381
|
-
logger: './src/config/logger#logger',
|
|
9382
|
-
},
|
|
9383
|
-
${generateFrontendAppEntry(options)}
|
|
9384
|
-
},
|
|
9385
|
-
shared: {
|
|
9386
|
-
packages: ['packages/*'],
|
|
9387
|
-
models: {
|
|
9388
|
-
path: 'packages/models',
|
|
9389
|
-
schema: 'zod',
|
|
9390
|
-
},
|
|
9391
|
-
},`;
|
|
9392
|
-
if (services.db || services.cache || services.mail || services.storage || services.events) {
|
|
9393
|
-
config += `
|
|
9394
|
-
services: {`;
|
|
9395
|
-
if (services.db) config += `
|
|
9396
|
-
db: true,`;
|
|
9397
|
-
if (services.cache) config += `
|
|
9398
|
-
cache: true,`;
|
|
9399
|
-
if (services.mail) config += `
|
|
9400
|
-
mail: true,`;
|
|
9401
|
-
if (services.storage) config += `
|
|
9402
|
-
storage: true,`;
|
|
9403
|
-
if (services.events) config += `
|
|
9404
|
-
events: '${services.events}',`;
|
|
9405
|
-
config += `
|
|
9406
|
-
},`;
|
|
9407
|
-
}
|
|
9408
|
-
if (deployTarget === "dokploy") config += `
|
|
9409
|
-
deploy: {
|
|
9410
|
-
default: 'dokploy',
|
|
9411
|
-
},`;
|
|
9412
|
-
config += `
|
|
9197
|
+
|
|
9198
|
+
// One glob, every kind. A declared database is why a Postgres exists, a
|
|
9199
|
+
// declared bucket is why MinIO does, a declared topic is why a broker does —
|
|
9200
|
+
// none of it listed here. It is also where the apps come from: a
|
|
9201
|
+
// \`StaticSite\` is an app, and so is every \`RestApi\`.
|
|
9202
|
+
constructs: './constructs/**/*.ts',
|
|
9203
|
+
|
|
9413
9204
|
secrets: {
|
|
9414
9205
|
enabled: true,
|
|
9415
|
-
}
|
|
9416
|
-
config += `
|
|
9206
|
+
},
|
|
9417
9207
|
});
|
|
9418
9208
|
`;
|
|
9209
|
+
if (options.services.events && options.services.events !== "pgboss") config = config.replace(" secrets: {", ` services: {
|
|
9210
|
+
events: '${options.services.events}',
|
|
9211
|
+
},
|
|
9212
|
+
|
|
9213
|
+
secrets: {`);
|
|
9419
9214
|
return config;
|
|
9420
9215
|
}
|
|
9216
|
+
/**
|
|
9217
|
+
* The workspace's constructs, at its root rather than inside an app.
|
|
9218
|
+
*
|
|
9219
|
+
* They outlive the app that used them first: a site depending on the API is a
|
|
9220
|
+
* fact about the workspace, and a construct reaching across into a sibling
|
|
9221
|
+
* app's `src/` to state it is the shape this layout removes. Apps import them
|
|
9222
|
+
* through the `@<name>/constructs/*` path the root tsconfig maps.
|
|
9223
|
+
*
|
|
9224
|
+
* Every one of these is also an answer config used to give: the database is
|
|
9225
|
+
* why a Postgres exists, the surface and the site are the apps, and the edges
|
|
9226
|
+
* between them are the CORS origins and the build order.
|
|
9227
|
+
*/
|
|
9228
|
+
function generateRootConstructs(options) {
|
|
9229
|
+
if (!options.monorepo || options.template !== "fullstack") return [];
|
|
9230
|
+
const { name: name$1, services, frontendFramework } = options;
|
|
9231
|
+
const db = databaseFor(name$1);
|
|
9232
|
+
const files$1 = [];
|
|
9233
|
+
files$1.push({
|
|
9234
|
+
path: "constructs/logger.ts",
|
|
9235
|
+
content: `import { createLogger } from '@geekmidas/logger/${options.loggerType}';
|
|
9236
|
+
|
|
9237
|
+
/**
|
|
9238
|
+
* The logger every endpoint runs with.
|
|
9239
|
+
*
|
|
9240
|
+
* Named once, here, because the surface carries it. It used to be
|
|
9241
|
+
* \`logger: './src/config/logger#logger'\` in config — a module path the build
|
|
9242
|
+
* printed into each generated handler, checked by nothing and wrong the moment
|
|
9243
|
+
* the file moved.
|
|
9244
|
+
*/
|
|
9245
|
+
export const logger = createLogger();
|
|
9246
|
+
`
|
|
9247
|
+
});
|
|
9248
|
+
files$1.push({
|
|
9249
|
+
path: "constructs/database.ts",
|
|
9250
|
+
content: `import { KyselyDatabase } from '@geekmidas/constructs/database/kysely';
|
|
9251
|
+
import type { Generated } from 'kysely';
|
|
9252
|
+
|
|
9253
|
+
/** Your database schema. Add tables here. */
|
|
9254
|
+
export interface Database {
|
|
9255
|
+
users: {
|
|
9256
|
+
id: Generated<string>;
|
|
9257
|
+
name: string;
|
|
9258
|
+
email: string;
|
|
9259
|
+
created_at: Generated<Date>;
|
|
9260
|
+
};
|
|
9261
|
+
}
|
|
9262
|
+
|
|
9263
|
+
/**
|
|
9264
|
+
* The database, declared once.
|
|
9265
|
+
*
|
|
9266
|
+
* The container, the database inside it, its roles and schema, and
|
|
9267
|
+
* \`${db.urlKey}\` all derive from this line — which is why nothing lists
|
|
9268
|
+
* \`postgres\` anywhere.
|
|
9269
|
+
*/
|
|
9270
|
+
export const database = new KyselyDatabase<Database, '${db.id}'>('${db.id}');
|
|
9271
|
+
|
|
9272
|
+
/**
|
|
9273
|
+
* The auth server's own schema in that same Postgres, with its own role.
|
|
9274
|
+
*
|
|
9275
|
+
* A schema tenant rather than a second database: one container, and a role
|
|
9276
|
+
* whose \`search_path\` is pinned, so Better Auth's tables cannot collide with
|
|
9277
|
+
* the application's.
|
|
9278
|
+
*/
|
|
9279
|
+
export const authDb = database.schema<Record<string, never>, 'AuthDb'>('AuthDb');
|
|
9280
|
+
`
|
|
9281
|
+
});
|
|
9282
|
+
files$1.push({
|
|
9283
|
+
path: "constructs/auth.ts",
|
|
9284
|
+
content: `import { BetterAuth } from '@geekmidas/constructs/auth';
|
|
9285
|
+
import { authDb } from './database.ts';
|
|
9286
|
+
|
|
9287
|
+
/**
|
|
9288
|
+
* The auth server.
|
|
9289
|
+
*
|
|
9290
|
+
* There is no \`src/index.ts\` to go with this, and that is the point: the
|
|
9291
|
+
* routes are a wildcard, so no glob finds them and the build generates the
|
|
9292
|
+
* entry from this declaration instead. CORS, the trusted origins and the
|
|
9293
|
+
* cookie domain come from whatever declared an edge to it — nobody writes an
|
|
9294
|
+
* origin down.
|
|
9295
|
+
*/
|
|
9296
|
+
export const auth = new BetterAuth('Auth', {
|
|
9297
|
+
database: authDb,
|
|
9298
|
+
basePath: '/api/auth',
|
|
9299
|
+
});
|
|
9300
|
+
`
|
|
9301
|
+
});
|
|
9302
|
+
files$1.push({
|
|
9303
|
+
path: "constructs/api.ts",
|
|
9304
|
+
content: `import { RestApi } from '@geekmidas/constructs/rest-api';
|
|
9305
|
+
import { auth } from './auth.ts';
|
|
9306
|
+
import { logger } from './logger.ts';
|
|
9307
|
+
|
|
9308
|
+
/**
|
|
9309
|
+
* The application's HTTP surface — one RestApi, one container.
|
|
9310
|
+
*
|
|
9311
|
+
* No \`app\`: \`Api\` means \`apps/api\`, which the id already said. The
|
|
9312
|
+
* \`code\` glob is here only because this scaffold puts its endpoints under
|
|
9313
|
+
* \`src/\`, where the conventional layout has them at the app root.
|
|
9314
|
+
*/
|
|
9315
|
+
export const api = new RestApi('Api', {
|
|
9316
|
+
// Typed out rather than omitted: an API that ships open because a field was
|
|
9317
|
+
// left off is the one default worth refusing to have.
|
|
9318
|
+
defaultAuthorizer: 'none',
|
|
9319
|
+
|
|
9320
|
+
// The actual logger, not a path to one.
|
|
9321
|
+
logger,
|
|
9322
|
+
|
|
9323
|
+
app: {
|
|
9324
|
+
code: './src/{endpoints,functions,crons,queues,topics,subscribers}/**/*.ts',
|
|
9325
|
+
},
|
|
9326
|
+
}).auth(auth);
|
|
9327
|
+
`
|
|
9328
|
+
});
|
|
9329
|
+
const variant = frontendFramework === "tanstack-start" ? "{ variant: 'tanstack' }" : frontendFramework === "expo" ? void 0 : "{ variant: 'next' }";
|
|
9330
|
+
if (variant !== void 0) files$1.push({
|
|
9331
|
+
path: "constructs/site.ts",
|
|
9332
|
+
content: `import { StaticSite } from '@geekmidas/constructs/site';
|
|
9333
|
+
import { api } from './api.ts';
|
|
9334
|
+
import { auth } from './auth.ts';
|
|
9335
|
+
|
|
9336
|
+
/**
|
|
9337
|
+
* The frontend — a construct like any other, which is what makes it an app.
|
|
9338
|
+
*
|
|
9339
|
+
* No \`path\`: \`Web\` means \`apps/web\`. \`.dependsOn()\` is the single fact
|
|
9340
|
+
* behind four things that are hand-maintained otherwise: this site's
|
|
9341
|
+
* build-time API URL, the API's CORS origins, the auth server's trusted
|
|
9342
|
+
* origins, and which generated client lands here.
|
|
9343
|
+
*/
|
|
9344
|
+
export const web = new StaticSite('Web', ${variant}).dependsOn([api, auth]);
|
|
9345
|
+
`
|
|
9346
|
+
});
|
|
9347
|
+
if (services.storage) {
|
|
9348
|
+
const bucket = storageFor(name$1);
|
|
9349
|
+
files$1.push({
|
|
9350
|
+
path: "constructs/storage.ts",
|
|
9351
|
+
content: `import { ObjectStorage } from '@geekmidas/constructs/object-storage';
|
|
9352
|
+
|
|
9353
|
+
/** A bucket — MinIO locally, S3 deployed, one declaration for both. */
|
|
9354
|
+
export const uploads = new ObjectStorage('${bucket.id}');
|
|
9355
|
+
`
|
|
9356
|
+
});
|
|
9357
|
+
}
|
|
9358
|
+
if (services.mail) {
|
|
9359
|
+
const mail = emailFor(name$1);
|
|
9360
|
+
files$1.push({
|
|
9361
|
+
path: "constructs/email.ts",
|
|
9362
|
+
content: `import { Email } from '@geekmidas/constructs/email';
|
|
9363
|
+
|
|
9364
|
+
/** Outbound mail — Mailpit locally, SES deployed. */
|
|
9365
|
+
export const email = new Email('${mail.id}', { templates: {} });
|
|
9366
|
+
`
|
|
9367
|
+
});
|
|
9368
|
+
}
|
|
9369
|
+
if (services.cache) {
|
|
9370
|
+
const kv = cacheFor(name$1);
|
|
9371
|
+
files$1.push({
|
|
9372
|
+
path: "constructs/cache.ts",
|
|
9373
|
+
content: `import { Cache } from '@geekmidas/constructs/cache';
|
|
9374
|
+
|
|
9375
|
+
/**
|
|
9376
|
+
* A cache. Which backend serves it follows the deploy target — a table in the
|
|
9377
|
+
* database on a server, Upstash on AWS — so nothing here says where it lives.
|
|
9378
|
+
*/
|
|
9379
|
+
export const cache = new Cache('${kv.id}');
|
|
9380
|
+
`
|
|
9381
|
+
});
|
|
9382
|
+
}
|
|
9383
|
+
return files$1;
|
|
9384
|
+
}
|
|
9421
9385
|
|
|
9422
9386
|
//#endregion
|
|
9423
9387
|
//#region src/init/templates/api.ts
|
|
@@ -9484,9 +9448,16 @@ export const logger = createLogger();
|
|
|
9484
9448
|
}
|
|
9485
9449
|
}
|
|
9486
9450
|
};
|
|
9487
|
-
|
|
9451
|
+
/**
|
|
9452
|
+
* Where a file at the app's `src/` root reaches a construct.
|
|
9453
|
+
*
|
|
9454
|
+
* A workspace keeps them at its own root, so the app goes through the
|
|
9455
|
+
* `@<name>/constructs/*` alias rather than climbing out with `../../`.
|
|
9456
|
+
*/
|
|
9457
|
+
const constructsImport = (file) => monorepo ? `@${name$1}/constructs/${file}.ts` : `./constructs/${file}.ts`;
|
|
9458
|
+
const apiImport = monorepo ? `@${name$1}/constructs/api.ts` : routesStructure === "domain-based" ? "../../constructs/api.js" : "../constructs/api.js";
|
|
9488
9459
|
const files$1 = [
|
|
9489
|
-
{
|
|
9460
|
+
...declares ? [{
|
|
9490
9461
|
path: "src/constructs/api.ts",
|
|
9491
9462
|
content: `import { RestApi } from '@geekmidas/constructs/rest-api';
|
|
9492
9463
|
import { logger } from '../config/logger.ts';
|
|
@@ -9501,7 +9472,7 @@ export const api = new RestApi('Api', {
|
|
|
9501
9472
|
logger,
|
|
9502
9473
|
});
|
|
9503
9474
|
`
|
|
9504
|
-
},
|
|
9475
|
+
}] : [],
|
|
9505
9476
|
{
|
|
9506
9477
|
path: "src/config/env.ts",
|
|
9507
9478
|
content: `import { Credentials } from '@geekmidas/envkit/credentials';
|
|
@@ -9676,8 +9647,8 @@ export const authService = {
|
|
|
9676
9647
|
files$1.push({
|
|
9677
9648
|
path: "src/router.ts",
|
|
9678
9649
|
content: `import { UnauthorizedError } from '@geekmidas/errors';
|
|
9679
|
-
import { api } from '
|
|
9680
|
-
import { database } from '
|
|
9650
|
+
import { api } from '${constructsImport("api")}';${options.database ? `
|
|
9651
|
+
import { database } from '${constructsImport("database")}';` : ""}
|
|
9681
9652
|
import { authService, type Session } from './services/auth.ts';
|
|
9682
9653
|
import { logger } from './config/logger.ts';
|
|
9683
9654
|
|
|
@@ -9724,8 +9695,8 @@ export const profileEndpoint = sessionRouter
|
|
|
9724
9695
|
}
|
|
9725
9696
|
if (!monorepo) files$1.push({
|
|
9726
9697
|
path: "src/router.ts",
|
|
9727
|
-
content: `import { api } from '
|
|
9728
|
-
import { database } from '
|
|
9698
|
+
content: `import { api } from '${constructsImport("api")}';${options.database ? `
|
|
9699
|
+
import { database } from '${constructsImport("database")}';` : ""}
|
|
9729
9700
|
|
|
9730
9701
|
/**
|
|
9731
9702
|
* The shared endpoint factory.
|
|
@@ -13211,7 +13182,11 @@ async function initCommand(projectName, options = {}) {
|
|
|
13211
13182
|
...isMonorepo$1 ? [] : generateDockerFiles(templateOptions, baseTemplate, dbApps)
|
|
13212
13183
|
] : [];
|
|
13213
13184
|
const dockerFiles = isMonorepo$1 && baseTemplate ? generateDockerFiles(templateOptions, baseTemplate, dbApps) : [];
|
|
13214
|
-
const rootFiles = baseTemplate ? [
|
|
13185
|
+
const rootFiles = baseTemplate ? [
|
|
13186
|
+
...generateMonorepoFiles(templateOptions, baseTemplate),
|
|
13187
|
+
...generateRootConstructs(templateOptions),
|
|
13188
|
+
...generateModelsPackage(templateOptions)
|
|
13189
|
+
] : [];
|
|
13215
13190
|
const webAppFiles = isFullstack ? frontendFramework === "tanstack-start" ? generateTanStackWebFiles(templateOptions) : frontendFramework === "expo" ? generateExpoAppFiles(templateOptions) : generateWebAppFiles(templateOptions) : [];
|
|
13216
13191
|
const authAppFiles = isFullstack ? generateAuthAppFiles(templateOptions) : [];
|
|
13217
13192
|
const uiPackageFiles = isFullstack ? generateUiPackageFiles(templateOptions) : [];
|
|
@@ -13596,7 +13571,7 @@ async function testCommand(options = {}) {
|
|
|
13596
13571
|
console.log(`\n🧪 Running tests with ${stage} environment...\n`);
|
|
13597
13572
|
const autoSetup = options.autoSetup || Boolean(process.env.GKM_AUTO_SETUP);
|
|
13598
13573
|
if (autoSetup) {
|
|
13599
|
-
const { ensureStageSecrets } = await import("./setup-
|
|
13574
|
+
const { ensureStageSecrets } = await import("./setup-DCuudnCl.mjs");
|
|
13600
13575
|
const generated = await ensureStageSecrets(stage, cwd);
|
|
13601
13576
|
if (generated) console.log(` 🔐 Generated fresh ${stage} secrets (auto-setup)`);
|
|
13602
13577
|
}
|
|
@@ -14071,7 +14046,7 @@ program.command("secrets:push").description("Push secrets to remote provider (SS
|
|
|
14071
14046
|
const { workspace } = await loadWorkspaceConfig$1();
|
|
14072
14047
|
const secrets = await readStageSecrets$1(options.stage, workspace.root);
|
|
14073
14048
|
if (secrets) {
|
|
14074
|
-
const { derivedContainers: derivedContainers$1 } = await import("./workspace-
|
|
14049
|
+
const { derivedContainers: derivedContainers$1 } = await import("./workspace-DK4WWJIn.mjs");
|
|
14075
14050
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers$1(workspace, options.stage));
|
|
14076
14051
|
if (result) {
|
|
14077
14052
|
await writeStageSecrets$1(result.secrets, workspace.root);
|
|
@@ -14100,7 +14075,7 @@ program.command("secrets:pull").description("Pull secrets from remote provider (
|
|
|
14100
14075
|
console.error(`No remote secrets found for stage "${options.stage}".`);
|
|
14101
14076
|
process.exit(1);
|
|
14102
14077
|
}
|
|
14103
|
-
const { derivedContainers: derivedContainers$1 } = await import("./workspace-
|
|
14078
|
+
const { derivedContainers: derivedContainers$1 } = await import("./workspace-DK4WWJIn.mjs");
|
|
14104
14079
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers$1(workspace, options.stage));
|
|
14105
14080
|
if (result) {
|
|
14106
14081
|
secrets = result.secrets;
|
|
@@ -14127,7 +14102,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
|
|
|
14127
14102
|
console.error(`No secrets found for stage "${options.stage}". Run "gkm secrets:init --stage ${options.stage}" first.`);
|
|
14128
14103
|
process.exit(1);
|
|
14129
14104
|
}
|
|
14130
|
-
const { derivedContainers: derivedContainers$1 } = await import("./workspace-
|
|
14105
|
+
const { derivedContainers: derivedContainers$1 } = await import("./workspace-DK4WWJIn.mjs");
|
|
14131
14106
|
const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers$1(workspace, options.stage));
|
|
14132
14107
|
if (!result) {
|
|
14133
14108
|
console.log(`\n✓ Secrets for stage "${options.stage}" are up-to-date`);
|