@pattern-stack/codegen 0.6.4 → 0.6.5
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/CHANGELOG.md +10 -0
- package/README.md +2 -0
- package/dist/runtime/subsystems/auth/auth-oauth-state.schema.d.ts +81 -0
- package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js +12 -0
- package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js.map +1 -0
- package/dist/runtime/subsystems/auth/auth.module.d.ts +39 -24
- package/dist/runtime/subsystems/auth/auth.module.js +246 -13
- package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
- package/dist/runtime/subsystems/auth/auth.tokens.d.ts +15 -2
- package/dist/runtime/subsystems/auth/auth.tokens.js +9 -1
- package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
- package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.d.ts +23 -0
- package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js +68 -0
- package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js.map +1 -0
- package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.d.ts +21 -0
- package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js +51 -0
- package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/auth/controllers/auth.controller.d.ts +31 -0
- package/dist/runtime/subsystems/auth/controllers/auth.controller.js +137 -0
- package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -0
- package/dist/runtime/subsystems/auth/index.d.ts +13 -4
- package/dist/runtime/subsystems/auth/index.js +253 -14
- package/dist/runtime/subsystems/auth/index.js.map +1 -1
- package/dist/runtime/subsystems/auth/protocols/integration-store.d.ts +36 -1
- package/dist/runtime/subsystems/auth/protocols/oauth-state-store.d.ts +33 -7
- package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js +12 -0
- package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js.map +1 -1
- package/dist/runtime/subsystems/auth/protocols/provider-strategy.d.ts +47 -0
- package/dist/runtime/subsystems/auth/protocols/provider-strategy.js +1 -0
- package/dist/runtime/subsystems/auth/protocols/provider-strategy.js.map +1 -0
- package/dist/runtime/subsystems/auth/protocols/user-context.d.ts +24 -0
- package/dist/runtime/subsystems/auth/protocols/user-context.js +1 -0
- package/dist/runtime/subsystems/auth/protocols/user-context.js.map +1 -0
- package/dist/runtime/subsystems/index.d.ts +9 -4
- package/dist/runtime/subsystems/index.js +247 -14
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/src/cli/index.js +574 -142
- package/dist/src/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/runtime/subsystems/auth/auth-oauth-state.schema.ts +30 -0
- package/runtime/subsystems/auth/auth.module.ts +89 -32
- package/runtime/subsystems/auth/auth.tokens.ts +14 -1
- package/runtime/subsystems/auth/backends/state-store.drizzle-backend.ts +83 -0
- package/runtime/subsystems/auth/backends/state-store.memory-backend.ts +76 -0
- package/runtime/subsystems/auth/controllers/auth.controller.ts +155 -0
- package/runtime/subsystems/auth/index.ts +43 -4
- package/runtime/subsystems/auth/protocols/integration-store.ts +37 -0
- package/runtime/subsystems/auth/protocols/oauth-state-store.ts +38 -6
- package/runtime/subsystems/auth/protocols/provider-strategy.ts +41 -0
- package/runtime/subsystems/auth/protocols/user-context.ts +22 -0
- package/runtime/subsystems/index.ts +17 -2
- package/templates/subsystem/auth/app-module-hook.ejs.t +21 -0
- package/templates/subsystem/auth/auth-oauth-state.schema.ejs.t +35 -0
- package/templates/subsystem/auth/env-config.ejs.t +20 -0
- package/templates/subsystem/auth/prompt.js +46 -0
- package/templates/subsystem/auth-config/codegen-config-auth-block.ejs.t +20 -0
- package/templates/subsystem/auth-config/prompt.js +20 -0
- package/templates/subsystem/auth-integrations/app-module-hook.ejs.t +16 -0
- package/templates/subsystem/auth-integrations/prompt.js +23 -0
- package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.d.ts +0 -24
- package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.js +0 -24
- package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.js.map +0 -1
- package/runtime/subsystems/auth/backends/oauth-state-store/in-memory.ts +0 -42
package/dist/src/cli/index.js
CHANGED
|
@@ -2839,8 +2839,8 @@ function loadEntityFromYaml(filePath) {
|
|
|
2839
2839
|
}
|
|
2840
2840
|
function formatZodErrors(error) {
|
|
2841
2841
|
return error.errors.map((err) => {
|
|
2842
|
-
const
|
|
2843
|
-
const location =
|
|
2842
|
+
const path29 = err.path.join(".");
|
|
2843
|
+
const location = path29 ? `at '${path29}'` : "at root";
|
|
2844
2844
|
return `${err.message} ${location}`;
|
|
2845
2845
|
});
|
|
2846
2846
|
}
|
|
@@ -3392,19 +3392,19 @@ function findCircularDependencies(graph) {
|
|
|
3392
3392
|
const cycles = [];
|
|
3393
3393
|
const visited = /* @__PURE__ */ new Set();
|
|
3394
3394
|
const recursionStack = /* @__PURE__ */ new Set();
|
|
3395
|
-
function dfs(node,
|
|
3395
|
+
function dfs(node, path29) {
|
|
3396
3396
|
visited.add(node);
|
|
3397
3397
|
recursionStack.add(node);
|
|
3398
3398
|
const outgoingEdges = graph.edges.filter((e) => e.from === node);
|
|
3399
3399
|
for (const edge of outgoingEdges) {
|
|
3400
3400
|
if (!visited.has(edge.to)) {
|
|
3401
|
-
dfs(edge.to, [...
|
|
3401
|
+
dfs(edge.to, [...path29, edge.to]);
|
|
3402
3402
|
} else if (recursionStack.has(edge.to)) {
|
|
3403
|
-
const cycleStart =
|
|
3403
|
+
const cycleStart = path29.indexOf(edge.to);
|
|
3404
3404
|
if (cycleStart !== -1) {
|
|
3405
|
-
cycles.push([...
|
|
3405
|
+
cycles.push([...path29.slice(cycleStart), edge.to]);
|
|
3406
3406
|
} else {
|
|
3407
|
-
cycles.push([...
|
|
3407
|
+
cycles.push([...path29, edge.to]);
|
|
3408
3408
|
}
|
|
3409
3409
|
}
|
|
3410
3410
|
}
|
|
@@ -4001,8 +4001,8 @@ function suggestTransitiveRelationships(graph, options) {
|
|
|
4001
4001
|
for (const [entityName, entity] of graph.entities) {
|
|
4002
4002
|
if (shouldExcludeEntity(entityName, opts)) continue;
|
|
4003
4003
|
const paths = findTransitivePaths(graph, entityName, opts);
|
|
4004
|
-
for (const
|
|
4005
|
-
suggestions.push(createSuggestion(
|
|
4004
|
+
for (const path29 of paths) {
|
|
4005
|
+
suggestions.push(createSuggestion(path29));
|
|
4006
4006
|
}
|
|
4007
4007
|
}
|
|
4008
4008
|
return suggestions;
|
|
@@ -4033,7 +4033,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
|
|
|
4033
4033
|
while (queue.length > 0) {
|
|
4034
4034
|
const current = queue.shift();
|
|
4035
4035
|
if (!current) continue;
|
|
4036
|
-
const { entity, depth, path:
|
|
4036
|
+
const { entity, depth, path: path29, visited } = current;
|
|
4037
4037
|
if (depth >= opts.maxDepth) continue;
|
|
4038
4038
|
const currentEntity = graph.entities.get(entity);
|
|
4039
4039
|
if (!currentEntity) continue;
|
|
@@ -4044,7 +4044,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
|
|
|
4044
4044
|
if (shouldExcludeEntity(target, opts)) continue;
|
|
4045
4045
|
if (visited.has(target)) continue;
|
|
4046
4046
|
const newPath = [
|
|
4047
|
-
...
|
|
4047
|
+
...path29,
|
|
4048
4048
|
{
|
|
4049
4049
|
via: entity,
|
|
4050
4050
|
relationship: relName,
|
|
@@ -4112,15 +4112,15 @@ function generateYamlSnippet(name, target, throughPath) {
|
|
|
4112
4112
|
target: ${target}
|
|
4113
4113
|
through: "${throughPath}"`;
|
|
4114
4114
|
}
|
|
4115
|
-
function createSuggestion(
|
|
4116
|
-
const pathDescription = [
|
|
4115
|
+
function createSuggestion(path29) {
|
|
4116
|
+
const pathDescription = [path29.source, ...path29.hops.map((h) => h.via), path29.target].join(" -> ");
|
|
4117
4117
|
return {
|
|
4118
4118
|
severity: "info",
|
|
4119
4119
|
type: "transitive_suggestion",
|
|
4120
|
-
entity:
|
|
4120
|
+
entity: path29.source,
|
|
4121
4121
|
message: `Potential transitive relationship: ${pathDescription}`,
|
|
4122
|
-
suggestion: `Add "${
|
|
4123
|
-
path:
|
|
4122
|
+
suggestion: `Add "${path29.suggestedName}" relationship via "${path29.throughPath}"`,
|
|
4123
|
+
path: path29
|
|
4124
4124
|
};
|
|
4125
4125
|
}
|
|
4126
4126
|
|
|
@@ -7902,7 +7902,7 @@ var entity_default = entityNoun;
|
|
|
7902
7902
|
|
|
7903
7903
|
// src/cli/commands/subsystem.ts
|
|
7904
7904
|
import fs10 from "fs";
|
|
7905
|
-
import
|
|
7905
|
+
import path21 from "path";
|
|
7906
7906
|
import { Command as Command3, Option as Option3 } from "clipanion";
|
|
7907
7907
|
|
|
7908
7908
|
// src/cli/shared/config-block-detect.ts
|
|
@@ -8146,9 +8146,90 @@ function localsToHygenArgs5(locals) {
|
|
|
8146
8146
|
];
|
|
8147
8147
|
}
|
|
8148
8148
|
|
|
8149
|
+
// src/cli/shared/auth-scaffold-locals.ts
|
|
8150
|
+
import crypto2 from "crypto";
|
|
8151
|
+
import path17 from "path";
|
|
8152
|
+
var FALLBACK_BACKEND_SRC3 = "src";
|
|
8153
|
+
var DEFAULT_REDIRECT_URI_BASE = "http://localhost:3000";
|
|
8154
|
+
function resolveAuthScaffoldLocals(input) {
|
|
8155
|
+
const { cwd, config } = input;
|
|
8156
|
+
const backendSrc = typeof config?.paths?.backend_src === "string" && config.paths.backend_src.length > 0 ? config.paths.backend_src : FALLBACK_BACKEND_SRC3;
|
|
8157
|
+
const subsystemsRoot = resolveSubsystemsRootFromConfig(cwd, config);
|
|
8158
|
+
const authBlock = config?.auth ?? {};
|
|
8159
|
+
const redirectRaw = authBlock.redirect_uri_base;
|
|
8160
|
+
const redirectUriBase = typeof redirectRaw === "string" && redirectRaw.length > 0 ? redirectRaw : DEFAULT_REDIRECT_URI_BASE;
|
|
8161
|
+
const tokenEncryptionKey = crypto2.randomBytes(32).toString("base64");
|
|
8162
|
+
return {
|
|
8163
|
+
appName: path17.basename(cwd),
|
|
8164
|
+
configPath: path17.resolve(cwd, "codegen.config.yaml"),
|
|
8165
|
+
schemaPath: path17.resolve(
|
|
8166
|
+
subsystemsRoot,
|
|
8167
|
+
"auth",
|
|
8168
|
+
"auth-oauth-state.schema.ts"
|
|
8169
|
+
),
|
|
8170
|
+
appModulePath: path17.resolve(cwd, backendSrc, "app.module.ts"),
|
|
8171
|
+
envConfigPath: path17.resolve(cwd, ".env.config"),
|
|
8172
|
+
redirectUriBase,
|
|
8173
|
+
tokenEncryptionKey
|
|
8174
|
+
};
|
|
8175
|
+
}
|
|
8176
|
+
function localsToHygenArgs6(locals) {
|
|
8177
|
+
return [
|
|
8178
|
+
"--appName",
|
|
8179
|
+
locals.appName,
|
|
8180
|
+
"--configPath",
|
|
8181
|
+
locals.configPath,
|
|
8182
|
+
"--schemaPath",
|
|
8183
|
+
locals.schemaPath,
|
|
8184
|
+
"--appModulePath",
|
|
8185
|
+
locals.appModulePath,
|
|
8186
|
+
"--envConfigPath",
|
|
8187
|
+
locals.envConfigPath,
|
|
8188
|
+
"--redirectUriBase",
|
|
8189
|
+
locals.redirectUriBase,
|
|
8190
|
+
"--tokenEncryptionKey",
|
|
8191
|
+
locals.tokenEncryptionKey
|
|
8192
|
+
];
|
|
8193
|
+
}
|
|
8194
|
+
|
|
8195
|
+
// src/cli/shared/auth-integrations-scaffold-locals.ts
|
|
8196
|
+
import path18 from "path";
|
|
8197
|
+
var FALLBACK_BACKEND_SRC4 = "src";
|
|
8198
|
+
var SHARED_DIR_NAME = "shared";
|
|
8199
|
+
var DEFAULT_DEFINITIONS_DIR = "definitions/entities";
|
|
8200
|
+
function resolveAuthIntegrationsScaffoldLocals(input) {
|
|
8201
|
+
const { cwd, config } = input;
|
|
8202
|
+
const backendSrc = typeof config?.paths?.backend_src === "string" && config.paths.backend_src.length > 0 ? config.paths.backend_src : FALLBACK_BACKEND_SRC4;
|
|
8203
|
+
const sharedConfigured = config?.paths?.shared;
|
|
8204
|
+
const sharedRoot = typeof sharedConfigured === "string" && sharedConfigured.length > 0 ? path18.resolve(cwd, sharedConfigured) : path18.resolve(cwd, backendSrc, SHARED_DIR_NAME);
|
|
8205
|
+
const definitionsConfigured = config?.paths?.definitions;
|
|
8206
|
+
const definitionsPath = typeof definitionsConfigured === "string" && definitionsConfigured.length > 0 ? path18.resolve(cwd, definitionsConfigured, "integration.yaml") : path18.resolve(cwd, DEFAULT_DEFINITIONS_DIR, "integration.yaml");
|
|
8207
|
+
const appModulePath = path18.resolve(cwd, backendSrc, "app.module.ts");
|
|
8208
|
+
let authModuleRegistered = false;
|
|
8209
|
+
const appModuleSource = input.readFile(appModulePath);
|
|
8210
|
+
if (appModuleSource && appModuleSource.includes("AuthModule.forRoot")) {
|
|
8211
|
+
authModuleRegistered = true;
|
|
8212
|
+
}
|
|
8213
|
+
return {
|
|
8214
|
+
appName: path18.basename(cwd),
|
|
8215
|
+
appModulePath,
|
|
8216
|
+
sharedRoot,
|
|
8217
|
+
definitionsPath,
|
|
8218
|
+
authModuleRegistered
|
|
8219
|
+
};
|
|
8220
|
+
}
|
|
8221
|
+
function localsToHygenArgs7(locals) {
|
|
8222
|
+
return [
|
|
8223
|
+
"--appName",
|
|
8224
|
+
locals.appName,
|
|
8225
|
+
"--appModulePath",
|
|
8226
|
+
locals.appModulePath
|
|
8227
|
+
];
|
|
8228
|
+
}
|
|
8229
|
+
|
|
8149
8230
|
// src/cli/shared/runtime-copier.ts
|
|
8150
8231
|
import fs8 from "fs";
|
|
8151
|
-
import
|
|
8232
|
+
import path19 from "path";
|
|
8152
8233
|
function readIfExists(p) {
|
|
8153
8234
|
try {
|
|
8154
8235
|
return fs8.readFileSync(p, "utf-8");
|
|
@@ -8159,7 +8240,7 @@ function readIfExists(p) {
|
|
|
8159
8240
|
function writeFile(target, content) {
|
|
8160
8241
|
const existing = readIfExists(target);
|
|
8161
8242
|
if (existing === content) return "unchanged";
|
|
8162
|
-
fs8.mkdirSync(
|
|
8243
|
+
fs8.mkdirSync(path19.dirname(target), { recursive: true });
|
|
8163
8244
|
fs8.writeFileSync(target, content);
|
|
8164
8245
|
return existing === null ? "written" : "updated";
|
|
8165
8246
|
}
|
|
@@ -8173,8 +8254,8 @@ function extractRelativeImports(source) {
|
|
|
8173
8254
|
return out;
|
|
8174
8255
|
}
|
|
8175
8256
|
function resolveSourceImport(sourceFile, specifier) {
|
|
8176
|
-
const base =
|
|
8177
|
-
const candidates = [base + ".ts", base + ".tsx",
|
|
8257
|
+
const base = path19.resolve(path19.dirname(sourceFile), specifier);
|
|
8258
|
+
const candidates = [base + ".ts", base + ".tsx", path19.join(base, "index.ts")];
|
|
8178
8259
|
for (const c of candidates) {
|
|
8179
8260
|
if (fs8.existsSync(c)) return c;
|
|
8180
8261
|
}
|
|
@@ -8185,8 +8266,8 @@ async function copyRuntime(opts) {
|
|
|
8185
8266
|
if (!fs8.existsSync(sourceDir) || !fs8.statSync(sourceDir).isDirectory()) {
|
|
8186
8267
|
throw new Error(`runtime source directory not found: ${sourceDir}`);
|
|
8187
8268
|
}
|
|
8188
|
-
const runtimeRoot4 = opts.runtimeRoot ?
|
|
8189
|
-
const depsTargetRoot = opts.depsTargetRoot ??
|
|
8269
|
+
const runtimeRoot4 = opts.runtimeRoot ? path19.resolve(opts.runtimeRoot) : path19.resolve(sourceDir, "..", "..");
|
|
8270
|
+
const depsTargetRoot = opts.depsTargetRoot ?? path19.resolve(targetDir, "..");
|
|
8190
8271
|
const result = {
|
|
8191
8272
|
written: [],
|
|
8192
8273
|
updated: [],
|
|
@@ -8197,7 +8278,7 @@ async function copyRuntime(opts) {
|
|
|
8197
8278
|
const queue = [];
|
|
8198
8279
|
function walk(dir) {
|
|
8199
8280
|
for (const entry of fs8.readdirSync(dir)) {
|
|
8200
|
-
const src =
|
|
8281
|
+
const src = path19.join(dir, entry);
|
|
8201
8282
|
const stat = fs8.statSync(src);
|
|
8202
8283
|
if (stat.isDirectory()) {
|
|
8203
8284
|
if (entry === "generated") continue;
|
|
@@ -8206,9 +8287,9 @@ async function copyRuntime(opts) {
|
|
|
8206
8287
|
}
|
|
8207
8288
|
if (!stat.isFile()) continue;
|
|
8208
8289
|
if (!entry.endsWith(".ts") && !entry.endsWith(".tsx")) continue;
|
|
8209
|
-
const rel =
|
|
8290
|
+
const rel = path19.relative(sourceDir, src);
|
|
8210
8291
|
if (filter && !filter(rel) && !filter(entry)) continue;
|
|
8211
|
-
queue.push({ src, dest:
|
|
8292
|
+
queue.push({ src, dest: path19.join(targetDir, rel), isDep: false });
|
|
8212
8293
|
}
|
|
8213
8294
|
}
|
|
8214
8295
|
walk(sourceDir);
|
|
@@ -8230,11 +8311,11 @@ async function copyRuntime(opts) {
|
|
|
8230
8311
|
for (const spec of extractRelativeImports(content)) {
|
|
8231
8312
|
const resolvedSrc = resolveSourceImport(next.src, spec);
|
|
8232
8313
|
if (!resolvedSrc) continue;
|
|
8233
|
-
const relToRuntime =
|
|
8234
|
-
if (relToRuntime.startsWith("..") ||
|
|
8235
|
-
const relToSource =
|
|
8236
|
-
if (!relToSource.startsWith("..") && !
|
|
8237
|
-
const depDest =
|
|
8314
|
+
const relToRuntime = path19.relative(runtimeRoot4, resolvedSrc);
|
|
8315
|
+
if (relToRuntime.startsWith("..") || path19.isAbsolute(relToRuntime)) continue;
|
|
8316
|
+
const relToSource = path19.relative(sourceDir, resolvedSrc);
|
|
8317
|
+
if (!relToSource.startsWith("..") && !path19.isAbsolute(relToSource)) continue;
|
|
8318
|
+
const depDest = path19.join(depsTargetRoot, relToRuntime);
|
|
8238
8319
|
queue.push({ src: resolvedSrc, dest: depDest, isDep: true });
|
|
8239
8320
|
}
|
|
8240
8321
|
}
|
|
@@ -8244,7 +8325,7 @@ async function copyRuntime(opts) {
|
|
|
8244
8325
|
|
|
8245
8326
|
// src/cli/shared/subsystem-detect.ts
|
|
8246
8327
|
import fs9 from "fs";
|
|
8247
|
-
import
|
|
8328
|
+
import path20 from "path";
|
|
8248
8329
|
var SUBSYSTEMS = [
|
|
8249
8330
|
{
|
|
8250
8331
|
name: "events",
|
|
@@ -8301,21 +8382,49 @@ var SUBSYSTEMS = [
|
|
|
8301
8382
|
description: "Observability combiner \u2014 composes sibling read ports via @Optional() DI (ADR-025)",
|
|
8302
8383
|
backends: ["combiner"],
|
|
8303
8384
|
defaultBackend: "combiner"
|
|
8385
|
+
},
|
|
8386
|
+
{
|
|
8387
|
+
// #287. Auth subsystem (PR #289) — AuthModule + ports + OAuth state
|
|
8388
|
+
// store + AuthController. Backends: drizzle (prod, persists OAuth
|
|
8389
|
+
// state in `auth_oauth_state`) or memory (dev/tests). Detection in
|
|
8390
|
+
// `detectInstalledSubsystems` is a special case: auth's protocols
|
|
8391
|
+
// live under `protocols/`, not at the subsystem root, so we look
|
|
8392
|
+
// for `auth.module.ts` instead of `*.protocol.ts`.
|
|
8393
|
+
name: "auth",
|
|
8394
|
+
description: "OAuth integration auth (AuthModule + ports + state store)",
|
|
8395
|
+
backends: ["drizzle", "memory"],
|
|
8396
|
+
defaultBackend: "drizzle"
|
|
8397
|
+
},
|
|
8398
|
+
{
|
|
8399
|
+
// #287. Auth-integrations starter (PR #290) — vendored from
|
|
8400
|
+
// `examples/auth-integrations/`, NOT from `runtime/subsystems/`.
|
|
8401
|
+
// Bundles a canonical `integration` entity yaml + the three
|
|
8402
|
+
// integration-store-port adapters + the `IntegrationsService`
|
|
8403
|
+
// facade. Single-backend (drizzle); the runtime adapters call
|
|
8404
|
+
// directly into the codegen-emitted `IntegrationService` from the
|
|
8405
|
+
// entity layer. Detection: presence of
|
|
8406
|
+
// `<sharedRoot>/integrations/integrations-auth.module.ts`.
|
|
8407
|
+
name: "auth-integrations",
|
|
8408
|
+
description: "Vendored integrations entity + adapters (consumes auth subsystem)",
|
|
8409
|
+
backends: ["drizzle"],
|
|
8410
|
+
defaultBackend: "drizzle"
|
|
8304
8411
|
}
|
|
8305
8412
|
];
|
|
8306
8413
|
var KNOWN_NAMES = SUBSYSTEMS.map((s) => s.name);
|
|
8307
8414
|
function candidateRoots(cwd, configured) {
|
|
8308
8415
|
const roots = [
|
|
8309
|
-
...configured ? [
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8416
|
+
...configured ? [path20.resolve(cwd, configured)] : [],
|
|
8417
|
+
path20.resolve(cwd, "src/shared/subsystems"),
|
|
8418
|
+
path20.resolve(cwd, "src/subsystems"),
|
|
8419
|
+
path20.resolve(cwd, "shared/subsystems")
|
|
8313
8420
|
];
|
|
8314
8421
|
return Array.from(new Set(roots));
|
|
8315
8422
|
}
|
|
8316
8423
|
function inferBackend(dir, name) {
|
|
8317
8424
|
if (name === "observability") return "combiner";
|
|
8318
|
-
|
|
8425
|
+
if (name === "auth") return "drizzle";
|
|
8426
|
+
if (name === "auth-integrations") return "drizzle";
|
|
8427
|
+
const hasDrizzle = fs9.existsSync(path20.join(dir, `${name.replace(/s$/, "")}-bus.drizzle-backend.ts`)) || fs9.readdirSync(dir).some((f) => f.endsWith(".drizzle-backend.ts"));
|
|
8319
8428
|
const hasMemory = fs9.readdirSync(dir).some((f) => f.endsWith(".memory-backend.ts"));
|
|
8320
8429
|
const hasLocal = fs9.readdirSync(dir).some((f) => f.includes("local"));
|
|
8321
8430
|
if (hasDrizzle && hasMemory) return "drizzle";
|
|
@@ -8334,10 +8443,14 @@ async function detectInstalledSubsystems(ctx) {
|
|
|
8334
8443
|
for (const name of KNOWN_NAMES) {
|
|
8335
8444
|
if (seen.has(name)) continue;
|
|
8336
8445
|
if (name === "openapi-config") continue;
|
|
8337
|
-
|
|
8446
|
+
if (name === "auth-integrations") continue;
|
|
8447
|
+
const dir = path20.join(root, name);
|
|
8338
8448
|
if (!fs9.existsSync(dir) || !fs9.statSync(dir).isDirectory()) continue;
|
|
8339
8449
|
const files = fs9.readdirSync(dir);
|
|
8340
|
-
|
|
8450
|
+
let hasProtocol = files.some((f) => f.endsWith(".protocol.ts"));
|
|
8451
|
+
if (name === "auth") {
|
|
8452
|
+
hasProtocol = files.includes("auth.module.ts");
|
|
8453
|
+
}
|
|
8341
8454
|
if (!hasProtocol) continue;
|
|
8342
8455
|
seen.add(name);
|
|
8343
8456
|
found.push({
|
|
@@ -8348,7 +8461,7 @@ async function detectInstalledSubsystems(ctx) {
|
|
|
8348
8461
|
}
|
|
8349
8462
|
}
|
|
8350
8463
|
if (!seen.has("openapi-config")) {
|
|
8351
|
-
const configPath =
|
|
8464
|
+
const configPath = path20.resolve(
|
|
8352
8465
|
ctx.cwd,
|
|
8353
8466
|
ctx.config ? "codegen.config.yaml" : "codegen.config.yaml"
|
|
8354
8467
|
);
|
|
@@ -8366,18 +8479,35 @@ async function detectInstalledSubsystems(ctx) {
|
|
|
8366
8479
|
}
|
|
8367
8480
|
}
|
|
8368
8481
|
}
|
|
8482
|
+
if (!seen.has("auth-integrations")) {
|
|
8483
|
+
const backendSrc = ctx.config?.paths?.backend_src ?? "src";
|
|
8484
|
+
const sharedConfigured = ctx.config?.paths?.shared;
|
|
8485
|
+
const sharedRoot = typeof sharedConfigured === "string" && sharedConfigured.length > 0 ? path20.resolve(ctx.cwd, sharedConfigured) : path20.resolve(ctx.cwd, backendSrc, "shared");
|
|
8486
|
+
const moduleFile = path20.join(
|
|
8487
|
+
sharedRoot,
|
|
8488
|
+
"integrations",
|
|
8489
|
+
"integrations-auth.module.ts"
|
|
8490
|
+
);
|
|
8491
|
+
if (fs9.existsSync(moduleFile)) {
|
|
8492
|
+
found.push({
|
|
8493
|
+
name: "auth-integrations",
|
|
8494
|
+
path: path20.dirname(moduleFile),
|
|
8495
|
+
backend: "drizzle"
|
|
8496
|
+
});
|
|
8497
|
+
}
|
|
8498
|
+
}
|
|
8369
8499
|
return found;
|
|
8370
8500
|
}
|
|
8371
8501
|
|
|
8372
8502
|
// src/cli/commands/subsystem.ts
|
|
8373
8503
|
function runtimeRoot() {
|
|
8374
|
-
const pkgRoot =
|
|
8375
|
-
const topLevel =
|
|
8504
|
+
const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
|
|
8505
|
+
const topLevel = path21.join(pkgRoot, "runtime");
|
|
8376
8506
|
if (fs10.existsSync(topLevel)) return topLevel;
|
|
8377
|
-
return
|
|
8507
|
+
return path21.join(pkgRoot, "dist", "runtime");
|
|
8378
8508
|
}
|
|
8379
8509
|
function subsystemSource(name) {
|
|
8380
|
-
return
|
|
8510
|
+
return path21.join(runtimeRoot(), "subsystems", name);
|
|
8381
8511
|
}
|
|
8382
8512
|
function describeSubsystem(name) {
|
|
8383
8513
|
return SUBSYSTEMS.find((s) => s.name === name) ?? null;
|
|
@@ -8404,7 +8534,7 @@ async function summary2(ctx) {
|
|
|
8404
8534
|
}
|
|
8405
8535
|
body.push(theme.muted("Installed:"));
|
|
8406
8536
|
for (const i of installed) {
|
|
8407
|
-
const rel =
|
|
8537
|
+
const rel = path21.relative(ctx.cwd, i.path) || i.path;
|
|
8408
8538
|
body.push(
|
|
8409
8539
|
` ${theme.success(icons.check)} ${i.name.padEnd(10)} ${theme.muted(
|
|
8410
8540
|
`${i.backend} backend`
|
|
@@ -8461,6 +8591,9 @@ function backendFileFilter(backend, subsystemName) {
|
|
|
8461
8591
|
if (subsystemName === "sync" && file === "sync-audit.schema.ts") {
|
|
8462
8592
|
return false;
|
|
8463
8593
|
}
|
|
8594
|
+
if (subsystemName === "auth" && file === "auth-oauth-state.schema.ts") {
|
|
8595
|
+
return false;
|
|
8596
|
+
}
|
|
8464
8597
|
if (backend === "memory") {
|
|
8465
8598
|
if (file.endsWith(".drizzle-backend.ts")) return false;
|
|
8466
8599
|
if (file.endsWith(".schema.ts")) return false;
|
|
@@ -8519,6 +8652,9 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8519
8652
|
if (desc3.name === "openapi-config") {
|
|
8520
8653
|
return this.executeOpenApiConfig(ctx);
|
|
8521
8654
|
}
|
|
8655
|
+
if (desc3.name === "auth-integrations") {
|
|
8656
|
+
return this.executeAuthIntegrations(ctx);
|
|
8657
|
+
}
|
|
8522
8658
|
const installed = await detectInstalledSubsystems(ctx);
|
|
8523
8659
|
const already = installed.find((i) => i.name === desc3.name);
|
|
8524
8660
|
if (already && !this.force) {
|
|
@@ -8536,14 +8672,14 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8536
8672
|
return 0;
|
|
8537
8673
|
}
|
|
8538
8674
|
const targetRoot = resolveSubsystemsRoot(ctx, this.target);
|
|
8539
|
-
const subsystemTarget =
|
|
8675
|
+
const subsystemTarget = path21.join(targetRoot, desc3.name);
|
|
8540
8676
|
const source = subsystemSource(desc3.name);
|
|
8541
8677
|
if (!fs10.existsSync(source)) {
|
|
8542
8678
|
printError(`Runtime subsystem source missing: ${source}`);
|
|
8543
8679
|
return 1;
|
|
8544
8680
|
}
|
|
8545
8681
|
if (!this.force) {
|
|
8546
|
-
const gitCheck = checkGitSafety([
|
|
8682
|
+
const gitCheck = checkGitSafety([path21.relative(ctx.cwd, subsystemTarget) || subsystemTarget], ctx.cwd);
|
|
8547
8683
|
if (gitCheck.inRepo && !gitCheck.clean) {
|
|
8548
8684
|
printWarning(
|
|
8549
8685
|
`Uncommitted changes under ${subsystemTarget}. Pass --force to overwrite.`
|
|
@@ -8552,7 +8688,7 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8552
8688
|
}
|
|
8553
8689
|
}
|
|
8554
8690
|
if (!isJsonMode()) {
|
|
8555
|
-
printInfo(`target = ${
|
|
8691
|
+
printInfo(`target = ${path21.relative(ctx.cwd, subsystemTarget) || subsystemTarget}`);
|
|
8556
8692
|
printInfo(`backend = ${backend}`);
|
|
8557
8693
|
}
|
|
8558
8694
|
const result = await copyRuntime({
|
|
@@ -8561,7 +8697,7 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8561
8697
|
filter: backendFileFilter(backend, desc3.name),
|
|
8562
8698
|
resolveDeps: true,
|
|
8563
8699
|
runtimeRoot: runtimeRoot(),
|
|
8564
|
-
depsTargetRoot:
|
|
8700
|
+
depsTargetRoot: path21.resolve(targetRoot, ".."),
|
|
8565
8701
|
dryRun: this.dryRun
|
|
8566
8702
|
});
|
|
8567
8703
|
const jobsScaffold = desc3.name === "jobs" ? runJobsScaffold(ctx.cwd, ctx.config, {
|
|
@@ -8589,6 +8725,11 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8589
8725
|
json: isJsonMode(),
|
|
8590
8726
|
forceConfig: this.forceConfig
|
|
8591
8727
|
}) : null;
|
|
8728
|
+
const authScaffold = desc3.name === "auth" ? runAuthScaffold(ctx.cwd, ctx.config, {
|
|
8729
|
+
dryRun: this.dryRun,
|
|
8730
|
+
json: isJsonMode(),
|
|
8731
|
+
forceConfig: this.forceConfig
|
|
8732
|
+
}) : null;
|
|
8592
8733
|
if (jobsScaffold?.configBlockOutcome === "parse-error") {
|
|
8593
8734
|
printError(
|
|
8594
8735
|
"codegen.config.yaml is not valid YAML: refusing to inject jobs config block. Fix the YAML and re-run."
|
|
@@ -8619,6 +8760,12 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8619
8760
|
);
|
|
8620
8761
|
return 1;
|
|
8621
8762
|
}
|
|
8763
|
+
if (authScaffold?.configBlockOutcome === "parse-error") {
|
|
8764
|
+
printError(
|
|
8765
|
+
"codegen.config.yaml is not valid YAML: refusing to inject auth config block. Fix the YAML and re-run."
|
|
8766
|
+
);
|
|
8767
|
+
return 1;
|
|
8768
|
+
}
|
|
8622
8769
|
if (isJsonMode()) {
|
|
8623
8770
|
printJson({
|
|
8624
8771
|
command: "subsystem install",
|
|
@@ -8637,21 +8784,22 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8637
8784
|
...eventsScaffold ? { scaffold: eventsScaffold } : {},
|
|
8638
8785
|
...syncScaffold ? { scaffold: syncScaffold } : {},
|
|
8639
8786
|
...bridgeScaffold ? { scaffold: bridgeScaffold } : {},
|
|
8640
|
-
...observabilityScaffold ? { scaffold: observabilityScaffold } : {}
|
|
8787
|
+
...observabilityScaffold ? { scaffold: observabilityScaffold } : {},
|
|
8788
|
+
...authScaffold ? { scaffold: authScaffold } : {}
|
|
8641
8789
|
});
|
|
8642
8790
|
return 0;
|
|
8643
8791
|
}
|
|
8644
8792
|
if (this.dryRun) {
|
|
8645
8793
|
printInfo(`Dry run \u2014 ${result.planned.length} files would be written`);
|
|
8646
8794
|
for (const p of result.planned) {
|
|
8647
|
-
console.log(` ${theme.muted(icons.arrow)} ${
|
|
8795
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
|
|
8648
8796
|
}
|
|
8649
8797
|
if (jobsScaffold?.planned?.length) {
|
|
8650
8798
|
printInfo(
|
|
8651
8799
|
`Jobs scaffold \u2014 ${jobsScaffold.planned.length} template targets`
|
|
8652
8800
|
);
|
|
8653
8801
|
for (const p of jobsScaffold.planned) {
|
|
8654
|
-
console.log(` ${theme.muted(icons.arrow)} ${
|
|
8802
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
|
|
8655
8803
|
}
|
|
8656
8804
|
}
|
|
8657
8805
|
if (eventsScaffold?.planned?.length) {
|
|
@@ -8659,7 +8807,7 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8659
8807
|
`Events scaffold \u2014 ${eventsScaffold.planned.length} template targets`
|
|
8660
8808
|
);
|
|
8661
8809
|
for (const p of eventsScaffold.planned) {
|
|
8662
|
-
console.log(` ${theme.muted(icons.arrow)} ${
|
|
8810
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
|
|
8663
8811
|
}
|
|
8664
8812
|
}
|
|
8665
8813
|
if (syncScaffold?.planned?.length) {
|
|
@@ -8667,7 +8815,7 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8667
8815
|
`Sync scaffold \u2014 ${syncScaffold.planned.length} template targets`
|
|
8668
8816
|
);
|
|
8669
8817
|
for (const p of syncScaffold.planned) {
|
|
8670
|
-
console.log(` ${theme.muted(icons.arrow)} ${
|
|
8818
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
|
|
8671
8819
|
}
|
|
8672
8820
|
}
|
|
8673
8821
|
if (bridgeScaffold?.planned?.length) {
|
|
@@ -8675,7 +8823,7 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8675
8823
|
`Bridge scaffold \u2014 ${bridgeScaffold.planned.length} template targets`
|
|
8676
8824
|
);
|
|
8677
8825
|
for (const p of bridgeScaffold.planned) {
|
|
8678
|
-
console.log(` ${theme.muted(icons.arrow)} ${
|
|
8826
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
|
|
8679
8827
|
}
|
|
8680
8828
|
}
|
|
8681
8829
|
if (observabilityScaffold?.planned?.length) {
|
|
@@ -8683,7 +8831,15 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8683
8831
|
`Observability scaffold \u2014 ${observabilityScaffold.planned.length} template targets`
|
|
8684
8832
|
);
|
|
8685
8833
|
for (const p of observabilityScaffold.planned) {
|
|
8686
|
-
console.log(` ${theme.muted(icons.arrow)} ${
|
|
8834
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
if (authScaffold?.planned?.length) {
|
|
8838
|
+
printInfo(
|
|
8839
|
+
`Auth scaffold \u2014 ${authScaffold.planned.length} template targets`
|
|
8840
|
+
);
|
|
8841
|
+
for (const p of authScaffold.planned) {
|
|
8842
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
|
|
8687
8843
|
}
|
|
8688
8844
|
}
|
|
8689
8845
|
return 0;
|
|
@@ -8750,11 +8906,29 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8750
8906
|
);
|
|
8751
8907
|
}
|
|
8752
8908
|
}
|
|
8909
|
+
if (authScaffold) {
|
|
8910
|
+
if (authScaffold.ok) {
|
|
8911
|
+
printSuccess(
|
|
8912
|
+
`auth scaffold applied (schema, config block, app.module.ts hint, .env.config key)`
|
|
8913
|
+
);
|
|
8914
|
+
} else {
|
|
8915
|
+
printWarning(
|
|
8916
|
+
`auth scaffold (Hygen) failed \u2014 runtime files were written; re-run after fixing: ${authScaffold.error ?? "unknown error"}`
|
|
8917
|
+
);
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8753
8920
|
printSuccess(`${desc3.name} subsystem installed with ${backend} backend.`);
|
|
8754
8921
|
if (desc3.name === "observability") {
|
|
8755
8922
|
printInfo(
|
|
8756
8923
|
"Register `ObservabilityModule.forRoot()` AFTER Events/Jobs/Bridge/Sync in app.module.ts"
|
|
8757
8924
|
);
|
|
8925
|
+
} else if (desc3.name === "auth") {
|
|
8926
|
+
printInfo("auth subsystem installed.");
|
|
8927
|
+
printInfo("Next steps:");
|
|
8928
|
+
printInfo(" 1. Provide an IUserContext adapter (your app's session/JWT scheme \u2014 req is typed `unknown`, narrow to your framework's Request inside the adapter).");
|
|
8929
|
+
printInfo(" 2. Install the auth-integrations starter: cdp subsystem install auth-integrations");
|
|
8930
|
+
printInfo(" 3. Bind per-provider strategies into STRATEGY_REGISTRY (HubSpot, SFDC, Google, ...).");
|
|
8931
|
+
printInfo(" 4. Configure provider client_id/client_secret in secrets/secrets.yaml.");
|
|
8758
8932
|
} else {
|
|
8759
8933
|
printInfo(
|
|
8760
8934
|
`Register ${capitalize(desc3.name)}Module.forRoot({ backend: '${backend}' }) in your app.module.ts`
|
|
@@ -8778,7 +8952,7 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8778
8952
|
* semantics as jobs/events/sync/bridge.
|
|
8779
8953
|
*/
|
|
8780
8954
|
async executeOpenApiConfig(ctx) {
|
|
8781
|
-
const configPath =
|
|
8955
|
+
const configPath = path21.join(ctx.cwd, "codegen.config.yaml");
|
|
8782
8956
|
const outcome = planConfigBlockAction(configPath, "openapi", this.forceConfig);
|
|
8783
8957
|
if (outcome === "parse-error") {
|
|
8784
8958
|
printError(
|
|
@@ -8797,7 +8971,7 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8797
8971
|
});
|
|
8798
8972
|
} else {
|
|
8799
8973
|
printInfo(`Dry run \u2014 openapi config block would be ${outcome}`);
|
|
8800
|
-
console.log(` ${theme.muted(icons.arrow)} ${
|
|
8974
|
+
console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, configPath) || configPath}`);
|
|
8801
8975
|
}
|
|
8802
8976
|
return 0;
|
|
8803
8977
|
}
|
|
@@ -8833,6 +9007,87 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8833
9007
|
);
|
|
8834
9008
|
return 0;
|
|
8835
9009
|
}
|
|
9010
|
+
/**
|
|
9011
|
+
* #287: install flow for the `auth-integrations` starter.
|
|
9012
|
+
*
|
|
9013
|
+
* Source is `examples/auth-integrations/`, NOT `runtime/subsystems/`,
|
|
9014
|
+
* so this method short-circuits the `copyRuntime` flow. It vendors the
|
|
9015
|
+
* adapters tree + the canonical `integration.yaml`, then invokes the
|
|
9016
|
+
* `subsystem auth-integrations` Hygen action to append the
|
|
9017
|
+
* `IntegrationsAuthModule` TODO to `app.module.ts`.
|
|
9018
|
+
*
|
|
9019
|
+
* Idempotent: pre-existing files are skipped unless `--force` is set.
|
|
9020
|
+
*/
|
|
9021
|
+
async executeAuthIntegrations(ctx) {
|
|
9022
|
+
const installed = await detectInstalledSubsystems(ctx);
|
|
9023
|
+
const already = installed.find((i) => i.name === "auth-integrations");
|
|
9024
|
+
if (already && !this.force) {
|
|
9025
|
+
if (isJsonMode()) {
|
|
9026
|
+
printJson({
|
|
9027
|
+
command: "subsystem install",
|
|
9028
|
+
subsystem: "auth-integrations",
|
|
9029
|
+
status: "already-installed",
|
|
9030
|
+
path: already.path,
|
|
9031
|
+
backend: already.backend
|
|
9032
|
+
});
|
|
9033
|
+
} else {
|
|
9034
|
+
printInfo(
|
|
9035
|
+
`auth-integrations is already installed at ${already.path} (pass --force to reinstall)`
|
|
9036
|
+
);
|
|
9037
|
+
}
|
|
9038
|
+
return 0;
|
|
9039
|
+
}
|
|
9040
|
+
const scaffold = runAuthIntegrationsScaffold(ctx.cwd, ctx.config, {
|
|
9041
|
+
dryRun: this.dryRun,
|
|
9042
|
+
json: isJsonMode(),
|
|
9043
|
+
force: this.force
|
|
9044
|
+
});
|
|
9045
|
+
if (!scaffold.ok) {
|
|
9046
|
+
printError(
|
|
9047
|
+
`auth-integrations install failed: ${scaffold.error ?? "unknown error"}`
|
|
9048
|
+
);
|
|
9049
|
+
return 1;
|
|
9050
|
+
}
|
|
9051
|
+
if (isJsonMode()) {
|
|
9052
|
+
printJson({
|
|
9053
|
+
command: "subsystem install",
|
|
9054
|
+
subsystem: "auth-integrations",
|
|
9055
|
+
dryRun: this.dryRun,
|
|
9056
|
+
planned: scaffold.planned,
|
|
9057
|
+
written: scaffold.written ?? [],
|
|
9058
|
+
skipped: scaffold.skipped ?? [],
|
|
9059
|
+
authModuleRegistered: scaffold.authModuleRegistered ?? false
|
|
9060
|
+
});
|
|
9061
|
+
return 0;
|
|
9062
|
+
}
|
|
9063
|
+
if (this.dryRun) {
|
|
9064
|
+
printInfo(
|
|
9065
|
+
`Dry run \u2014 auth-integrations would vendor adapters + integration.yaml + append TODO`
|
|
9066
|
+
);
|
|
9067
|
+
for (const p of scaffold.planned) {
|
|
9068
|
+
console.log(
|
|
9069
|
+
` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`
|
|
9070
|
+
);
|
|
9071
|
+
}
|
|
9072
|
+
return 0;
|
|
9073
|
+
}
|
|
9074
|
+
const writtenCount = scaffold.written?.length ?? 0;
|
|
9075
|
+
const skippedCount = scaffold.skipped?.length ?? 0;
|
|
9076
|
+
printSuccess(
|
|
9077
|
+
`auth-integrations starter vendored (${writtenCount} files written, ${skippedCount} skipped).`
|
|
9078
|
+
);
|
|
9079
|
+
if (scaffold.authModuleRegistered === false) {
|
|
9080
|
+
printWarning(
|
|
9081
|
+
"AuthModule.forRoot(...) not detected in app.module.ts. Run `cdp subsystem install auth` first \u2014 IntegrationsAuthModule requires ENCRYPTION_KEY from it."
|
|
9082
|
+
);
|
|
9083
|
+
}
|
|
9084
|
+
printInfo("auth-integrations starter vendored.");
|
|
9085
|
+
printInfo("Next steps:");
|
|
9086
|
+
printInfo(" 1. Run `cdp entity new integration` to scaffold the codegen layer (apps/api/src/modules/integrations/integration.service) the adapters import.");
|
|
9087
|
+
printInfo(" 2. Ensure AuthModule.forRoot(...) is registered in AppModule (run `cdp subsystem install auth` if not).");
|
|
9088
|
+
printInfo(" 3. Wire IntegrationsAuthModule into AppModule (see TODO appended to app.module.ts).");
|
|
9089
|
+
return 0;
|
|
9090
|
+
}
|
|
8836
9091
|
};
|
|
8837
9092
|
function planConfigBlockAction(configPath, subsystem, forceConfig) {
|
|
8838
9093
|
if (!fs10.existsSync(configPath)) {
|
|
@@ -9171,6 +9426,183 @@ function runObservabilityScaffold(cwd, config, opts) {
|
|
|
9171
9426
|
}
|
|
9172
9427
|
return { ok: true, planned, configBlockOutcome };
|
|
9173
9428
|
}
|
|
9429
|
+
function runAuthScaffold(cwd, config, opts) {
|
|
9430
|
+
const locals = resolveAuthScaffoldLocals({
|
|
9431
|
+
cwd,
|
|
9432
|
+
config
|
|
9433
|
+
});
|
|
9434
|
+
const planned = [
|
|
9435
|
+
locals.schemaPath,
|
|
9436
|
+
locals.configPath,
|
|
9437
|
+
locals.appModulePath,
|
|
9438
|
+
locals.envConfigPath
|
|
9439
|
+
];
|
|
9440
|
+
const configBlockOutcome = planConfigBlockAction(
|
|
9441
|
+
locals.configPath,
|
|
9442
|
+
"auth",
|
|
9443
|
+
opts.forceConfig
|
|
9444
|
+
);
|
|
9445
|
+
if (configBlockOutcome === "parse-error") {
|
|
9446
|
+
return { ok: false, planned, configBlockOutcome };
|
|
9447
|
+
}
|
|
9448
|
+
if (opts.dryRun) {
|
|
9449
|
+
return { ok: true, planned, configBlockOutcome };
|
|
9450
|
+
}
|
|
9451
|
+
if (!fs10.existsSync(locals.envConfigPath)) {
|
|
9452
|
+
fs10.mkdirSync(path21.dirname(locals.envConfigPath), { recursive: true });
|
|
9453
|
+
fs10.writeFileSync(locals.envConfigPath, "", "utf-8");
|
|
9454
|
+
}
|
|
9455
|
+
const result = invokeHygen({
|
|
9456
|
+
generator: "subsystem",
|
|
9457
|
+
action: "auth",
|
|
9458
|
+
cwd,
|
|
9459
|
+
args: localsToHygenArgs6(locals),
|
|
9460
|
+
inherit: !opts.json
|
|
9461
|
+
});
|
|
9462
|
+
if (!result.ok) {
|
|
9463
|
+
return {
|
|
9464
|
+
ok: false,
|
|
9465
|
+
planned,
|
|
9466
|
+
error: result.stderr?.trim() || "hygen exited non-zero",
|
|
9467
|
+
configBlockOutcome
|
|
9468
|
+
};
|
|
9469
|
+
}
|
|
9470
|
+
const configResult = runConfigBlockAction({
|
|
9471
|
+
cwd,
|
|
9472
|
+
actionFolder: "auth-config",
|
|
9473
|
+
configPath: locals.configPath,
|
|
9474
|
+
subsystem: "auth",
|
|
9475
|
+
outcome: configBlockOutcome,
|
|
9476
|
+
json: opts.json
|
|
9477
|
+
});
|
|
9478
|
+
if (!configResult.ok) {
|
|
9479
|
+
return {
|
|
9480
|
+
ok: false,
|
|
9481
|
+
planned,
|
|
9482
|
+
error: configResult.error,
|
|
9483
|
+
configBlockOutcome
|
|
9484
|
+
};
|
|
9485
|
+
}
|
|
9486
|
+
return { ok: true, planned, configBlockOutcome };
|
|
9487
|
+
}
|
|
9488
|
+
function authIntegrationsExamplesRoot() {
|
|
9489
|
+
const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
|
|
9490
|
+
const topLevel = path21.join(pkgRoot, "examples", "auth-integrations");
|
|
9491
|
+
if (fs10.existsSync(topLevel)) return topLevel;
|
|
9492
|
+
return path21.join(pkgRoot, "dist", "examples", "auth-integrations");
|
|
9493
|
+
}
|
|
9494
|
+
function copyTreeIdempotent(srcDir, destDir, force) {
|
|
9495
|
+
const written = [];
|
|
9496
|
+
const skipped = [];
|
|
9497
|
+
const walk = (src, dest) => {
|
|
9498
|
+
const entries = fs10.readdirSync(src, { withFileTypes: true });
|
|
9499
|
+
for (const entry of entries) {
|
|
9500
|
+
const srcPath = path21.join(src, entry.name);
|
|
9501
|
+
const destPath = path21.join(dest, entry.name);
|
|
9502
|
+
if (entry.isDirectory()) {
|
|
9503
|
+
fs10.mkdirSync(destPath, { recursive: true });
|
|
9504
|
+
walk(srcPath, destPath);
|
|
9505
|
+
continue;
|
|
9506
|
+
}
|
|
9507
|
+
if (!entry.isFile()) continue;
|
|
9508
|
+
if (fs10.existsSync(destPath) && !force) {
|
|
9509
|
+
skipped.push(destPath);
|
|
9510
|
+
continue;
|
|
9511
|
+
}
|
|
9512
|
+
fs10.mkdirSync(path21.dirname(destPath), { recursive: true });
|
|
9513
|
+
fs10.copyFileSync(srcPath, destPath);
|
|
9514
|
+
written.push(destPath);
|
|
9515
|
+
}
|
|
9516
|
+
};
|
|
9517
|
+
if (!fs10.existsSync(srcDir)) return { written, skipped };
|
|
9518
|
+
fs10.mkdirSync(destDir, { recursive: true });
|
|
9519
|
+
walk(srcDir, destDir);
|
|
9520
|
+
return { written, skipped };
|
|
9521
|
+
}
|
|
9522
|
+
function runAuthIntegrationsScaffold(cwd, config, opts) {
|
|
9523
|
+
const locals = resolveAuthIntegrationsScaffoldLocals({
|
|
9524
|
+
cwd,
|
|
9525
|
+
config,
|
|
9526
|
+
fileExists: (p) => fs10.existsSync(p),
|
|
9527
|
+
readFile: (p) => fs10.existsSync(p) ? fs10.readFileSync(p, "utf-8") : null
|
|
9528
|
+
});
|
|
9529
|
+
const examplesRoot = authIntegrationsExamplesRoot();
|
|
9530
|
+
if (!fs10.existsSync(examplesRoot)) {
|
|
9531
|
+
return {
|
|
9532
|
+
ok: false,
|
|
9533
|
+
planned: [],
|
|
9534
|
+
error: `auth-integrations starter source missing: ${examplesRoot}`
|
|
9535
|
+
};
|
|
9536
|
+
}
|
|
9537
|
+
const adaptersSrc = path21.join(examplesRoot, "runtime", "integrations");
|
|
9538
|
+
const adaptersDest = path21.join(locals.sharedRoot, "integrations");
|
|
9539
|
+
const integrationYamlSrc = path21.join(
|
|
9540
|
+
examplesRoot,
|
|
9541
|
+
"definitions",
|
|
9542
|
+
"entities",
|
|
9543
|
+
"integration.yaml"
|
|
9544
|
+
);
|
|
9545
|
+
const integrationYamlDest = locals.definitionsPath;
|
|
9546
|
+
const planned = [
|
|
9547
|
+
adaptersDest,
|
|
9548
|
+
integrationYamlDest,
|
|
9549
|
+
locals.appModulePath
|
|
9550
|
+
];
|
|
9551
|
+
if (opts.dryRun) {
|
|
9552
|
+
return {
|
|
9553
|
+
ok: true,
|
|
9554
|
+
planned,
|
|
9555
|
+
authModuleRegistered: locals.authModuleRegistered
|
|
9556
|
+
};
|
|
9557
|
+
}
|
|
9558
|
+
const adapterCopy = copyTreeIdempotent(
|
|
9559
|
+
adaptersSrc,
|
|
9560
|
+
adaptersDest,
|
|
9561
|
+
opts.force
|
|
9562
|
+
);
|
|
9563
|
+
let yamlWritten = false;
|
|
9564
|
+
let yamlSkipped = false;
|
|
9565
|
+
try {
|
|
9566
|
+
if (fs10.existsSync(integrationYamlDest) && !opts.force) {
|
|
9567
|
+
yamlSkipped = true;
|
|
9568
|
+
} else if (fs10.existsSync(integrationYamlSrc)) {
|
|
9569
|
+
fs10.mkdirSync(path21.dirname(integrationYamlDest), { recursive: true });
|
|
9570
|
+
fs10.copyFileSync(integrationYamlSrc, integrationYamlDest);
|
|
9571
|
+
yamlWritten = true;
|
|
9572
|
+
}
|
|
9573
|
+
} catch (err) {
|
|
9574
|
+
return {
|
|
9575
|
+
ok: false,
|
|
9576
|
+
planned,
|
|
9577
|
+
error: `failed to vendor integration.yaml: ${err instanceof Error ? err.message : String(err)}`,
|
|
9578
|
+
authModuleRegistered: locals.authModuleRegistered
|
|
9579
|
+
};
|
|
9580
|
+
}
|
|
9581
|
+
const result = invokeHygen({
|
|
9582
|
+
generator: "subsystem",
|
|
9583
|
+
action: "auth-integrations",
|
|
9584
|
+
cwd,
|
|
9585
|
+
args: localsToHygenArgs7(locals),
|
|
9586
|
+
inherit: !opts.json
|
|
9587
|
+
});
|
|
9588
|
+
if (!result.ok) {
|
|
9589
|
+
return {
|
|
9590
|
+
ok: false,
|
|
9591
|
+
planned,
|
|
9592
|
+
error: result.stderr?.trim() || "hygen exited non-zero",
|
|
9593
|
+
written: adapterCopy.written.concat(yamlWritten ? [integrationYamlDest] : []),
|
|
9594
|
+
skipped: adapterCopy.skipped.concat(yamlSkipped ? [integrationYamlDest] : []),
|
|
9595
|
+
authModuleRegistered: locals.authModuleRegistered
|
|
9596
|
+
};
|
|
9597
|
+
}
|
|
9598
|
+
return {
|
|
9599
|
+
ok: true,
|
|
9600
|
+
planned,
|
|
9601
|
+
written: adapterCopy.written.concat(yamlWritten ? [integrationYamlDest] : []),
|
|
9602
|
+
skipped: adapterCopy.skipped.concat(yamlSkipped ? [integrationYamlDest] : []),
|
|
9603
|
+
authModuleRegistered: locals.authModuleRegistered
|
|
9604
|
+
};
|
|
9605
|
+
}
|
|
9174
9606
|
function capitalize(s) {
|
|
9175
9607
|
return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
|
|
9176
9608
|
}
|
|
@@ -9200,7 +9632,7 @@ var SubsystemListCommand = class extends Command3 {
|
|
|
9200
9632
|
name: s.name,
|
|
9201
9633
|
status: inst ? "installed" : "available",
|
|
9202
9634
|
backend: inst ? inst.backend : null,
|
|
9203
|
-
path: inst ?
|
|
9635
|
+
path: inst ? path21.relative(ctx.cwd, inst.path) || inst.path : null
|
|
9204
9636
|
};
|
|
9205
9637
|
});
|
|
9206
9638
|
if (isJsonMode()) {
|
|
@@ -9261,27 +9693,27 @@ var subsystem_default = subsystemNoun;
|
|
|
9261
9693
|
|
|
9262
9694
|
// src/cli/commands/project.ts
|
|
9263
9695
|
import fs13 from "fs";
|
|
9264
|
-
import
|
|
9696
|
+
import path24 from "path";
|
|
9265
9697
|
import readline from "readline";
|
|
9266
9698
|
import { Command as Command5, Option as Option5 } from "clipanion";
|
|
9267
9699
|
import { stringify as stringifyYaml2 } from "yaml";
|
|
9268
9700
|
|
|
9269
9701
|
// src/cli/shared/init-scaffold.ts
|
|
9270
9702
|
import fs11 from "fs";
|
|
9271
|
-
import
|
|
9703
|
+
import path22 from "path";
|
|
9272
9704
|
import { stringify as stringifyYaml } from "yaml";
|
|
9273
9705
|
function runtimeRoot2() {
|
|
9274
|
-
const pkgRoot =
|
|
9275
|
-
const topLevel =
|
|
9706
|
+
const pkgRoot = path22.resolve(import.meta.dirname, "..", "..", "..");
|
|
9707
|
+
const topLevel = path22.join(pkgRoot, "runtime");
|
|
9276
9708
|
if (fs11.existsSync(topLevel)) return topLevel;
|
|
9277
|
-
return
|
|
9709
|
+
return path22.join(pkgRoot, "dist", "runtime");
|
|
9278
9710
|
}
|
|
9279
9711
|
function resolveRuntimePath(cwd) {
|
|
9280
|
-
const shimDir =
|
|
9281
|
-
return
|
|
9712
|
+
const shimDir = path22.join(cwd, "src", "shared", "base-classes");
|
|
9713
|
+
return path22.relative(shimDir, runtimeRoot2());
|
|
9282
9714
|
}
|
|
9283
9715
|
function loadRuntimeFile(relPath2) {
|
|
9284
|
-
return fs11.readFileSync(
|
|
9716
|
+
return fs11.readFileSync(path22.join(runtimeRoot2(), relPath2), "utf-8");
|
|
9285
9717
|
}
|
|
9286
9718
|
var VENDORED_RUNTIME_FILES = [
|
|
9287
9719
|
// base-classes — consumer-facing inheritance targets
|
|
@@ -9678,7 +10110,7 @@ function mergeTsconfig(raw) {
|
|
|
9678
10110
|
};
|
|
9679
10111
|
}
|
|
9680
10112
|
function relOf(cwd, abs) {
|
|
9681
|
-
return
|
|
10113
|
+
return path22.relative(cwd, abs) || abs;
|
|
9682
10114
|
}
|
|
9683
10115
|
function fileEntry(cwd, absPath, content, opts) {
|
|
9684
10116
|
const exists = fs11.existsSync(absPath);
|
|
@@ -9728,7 +10160,7 @@ async function buildInitPlan(ctx, options) {
|
|
|
9728
10160
|
const runtimePath = options.runtimePath ?? resolveRuntimePath(cwd);
|
|
9729
10161
|
const entries = [];
|
|
9730
10162
|
{
|
|
9731
|
-
const configPath =
|
|
10163
|
+
const configPath = path22.join(cwd, "codegen.config.yaml");
|
|
9732
10164
|
const config = {
|
|
9733
10165
|
paths: {
|
|
9734
10166
|
backend_src: "src",
|
|
@@ -9758,7 +10190,7 @@ async function buildInitPlan(ctx, options) {
|
|
|
9758
10190
|
entries.push(fileEntry(cwd, configPath, content, { force }));
|
|
9759
10191
|
}
|
|
9760
10192
|
{
|
|
9761
|
-
const tsconfigPath =
|
|
10193
|
+
const tsconfigPath = path22.join(cwd, "tsconfig.json");
|
|
9762
10194
|
if (fs11.existsSync(tsconfigPath)) {
|
|
9763
10195
|
const raw = fs11.readFileSync(tsconfigPath, "utf-8");
|
|
9764
10196
|
const merged = mergeTsconfig(raw);
|
|
@@ -9805,20 +10237,20 @@ async function buildInitPlan(ctx, options) {
|
|
|
9805
10237
|
entries.push(
|
|
9806
10238
|
fileEntry(
|
|
9807
10239
|
cwd,
|
|
9808
|
-
|
|
10240
|
+
path22.join(cwd, "src", "shared", "database", "database.module.ts"),
|
|
9809
10241
|
databaseModuleContent(),
|
|
9810
10242
|
{ force }
|
|
9811
10243
|
)
|
|
9812
10244
|
);
|
|
9813
10245
|
for (const v of VENDORED_RUNTIME_FILES) {
|
|
9814
10246
|
entries.push(
|
|
9815
|
-
fileEntry(cwd,
|
|
10247
|
+
fileEntry(cwd, path22.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
|
|
9816
10248
|
);
|
|
9817
10249
|
}
|
|
9818
10250
|
entries.push(
|
|
9819
10251
|
fileEntry(
|
|
9820
10252
|
cwd,
|
|
9821
|
-
|
|
10253
|
+
path22.join(cwd, "src", "generated", "modules.ts"),
|
|
9822
10254
|
emptyModulesBarrel(),
|
|
9823
10255
|
{ force }
|
|
9824
10256
|
)
|
|
@@ -9826,13 +10258,13 @@ async function buildInitPlan(ctx, options) {
|
|
|
9826
10258
|
entries.push(
|
|
9827
10259
|
fileEntry(
|
|
9828
10260
|
cwd,
|
|
9829
|
-
|
|
10261
|
+
path22.join(cwd, "src", "generated", "schema.ts"),
|
|
9830
10262
|
emptySchemaBarrel(),
|
|
9831
10263
|
{ force }
|
|
9832
10264
|
)
|
|
9833
10265
|
);
|
|
9834
10266
|
{
|
|
9835
|
-
const appModulePath =
|
|
10267
|
+
const appModulePath = path22.join(cwd, "src", "app.module.ts");
|
|
9836
10268
|
if (!fs11.existsSync(appModulePath)) {
|
|
9837
10269
|
entries.push({
|
|
9838
10270
|
path: appModulePath,
|
|
@@ -9850,7 +10282,7 @@ async function buildInitPlan(ctx, options) {
|
|
|
9850
10282
|
}
|
|
9851
10283
|
}
|
|
9852
10284
|
{
|
|
9853
|
-
const mainPath =
|
|
10285
|
+
const mainPath = path22.join(cwd, "src", "main.ts");
|
|
9854
10286
|
if (!fs11.existsSync(mainPath)) {
|
|
9855
10287
|
entries.push({
|
|
9856
10288
|
path: mainPath,
|
|
@@ -9868,7 +10300,7 @@ async function buildInitPlan(ctx, options) {
|
|
|
9868
10300
|
}
|
|
9869
10301
|
}
|
|
9870
10302
|
{
|
|
9871
|
-
const schemaPath =
|
|
10303
|
+
const schemaPath = path22.join(cwd, "src", "schema.ts");
|
|
9872
10304
|
if (!fs11.existsSync(schemaPath)) {
|
|
9873
10305
|
entries.push({
|
|
9874
10306
|
path: schemaPath,
|
|
@@ -9885,10 +10317,10 @@ async function buildInitPlan(ctx, options) {
|
|
|
9885
10317
|
});
|
|
9886
10318
|
}
|
|
9887
10319
|
}
|
|
9888
|
-
entries.push(dirEntry(cwd,
|
|
10320
|
+
entries.push(dirEntry(cwd, path22.join(cwd, "entities")));
|
|
9889
10321
|
{
|
|
9890
|
-
const entitiesDir =
|
|
9891
|
-
const examplePath =
|
|
10322
|
+
const entitiesDir = path22.join(cwd, "entities");
|
|
10323
|
+
const examplePath = path22.join(entitiesDir, "example.yaml");
|
|
9892
10324
|
const hasOtherYamls = fs11.existsSync(entitiesDir) && fs11.readdirSync(entitiesDir).some(
|
|
9893
10325
|
(f) => (f.endsWith(".yaml") || f.endsWith(".yml")) && f !== "example.yaml"
|
|
9894
10326
|
);
|
|
@@ -9946,7 +10378,7 @@ function writePlan(plan) {
|
|
|
9946
10378
|
skipped.push(e);
|
|
9947
10379
|
continue;
|
|
9948
10380
|
}
|
|
9949
|
-
fs11.mkdirSync(
|
|
10381
|
+
fs11.mkdirSync(path22.dirname(e.path), { recursive: true });
|
|
9950
10382
|
fs11.writeFileSync(e.path, e.content, "utf-8");
|
|
9951
10383
|
if (e.action === "create") created.push(e);
|
|
9952
10384
|
else if (e.action === "merge") merged.push(e);
|
|
@@ -9957,7 +10389,7 @@ function writePlan(plan) {
|
|
|
9957
10389
|
|
|
9958
10390
|
// src/cli/commands/project-upgrade-openapi.ts
|
|
9959
10391
|
import fs12 from "fs";
|
|
9960
|
-
import
|
|
10392
|
+
import path23 from "path";
|
|
9961
10393
|
import { Command as Command4, Option as Option4 } from "clipanion";
|
|
9962
10394
|
import { Project, IndentationText, QuoteKind, NewLineKind } from "ts-morph";
|
|
9963
10395
|
|
|
@@ -10196,31 +10628,31 @@ var MAIN_SWAGGER_IMPORTS = [
|
|
|
10196
10628
|
"import { OPENAPI_REGISTRY, OpenApiRegistry } from './shared/openapi';"
|
|
10197
10629
|
];
|
|
10198
10630
|
function runtimeRoot3() {
|
|
10199
|
-
const pkgRoot =
|
|
10200
|
-
const topLevel =
|
|
10631
|
+
const pkgRoot = path23.resolve(import.meta.dirname, "..", "..", "..");
|
|
10632
|
+
const topLevel = path23.join(pkgRoot, "runtime");
|
|
10201
10633
|
if (fs12.existsSync(topLevel)) return topLevel;
|
|
10202
|
-
return
|
|
10634
|
+
return path23.join(pkgRoot, "dist", "runtime");
|
|
10203
10635
|
}
|
|
10204
10636
|
function loadRuntimeFile2(rel) {
|
|
10205
|
-
return fs12.readFileSync(
|
|
10637
|
+
return fs12.readFileSync(path23.join(runtimeRoot3(), rel), "utf-8");
|
|
10206
10638
|
}
|
|
10207
10639
|
function resolveProjectRoot(startDir) {
|
|
10208
|
-
let dir =
|
|
10640
|
+
let dir = path23.resolve(startDir);
|
|
10209
10641
|
for (let i = 0; i < 16; i++) {
|
|
10210
|
-
if (fs12.existsSync(
|
|
10642
|
+
if (fs12.existsSync(path23.join(dir, "codegen.config.yaml")) || fs12.existsSync(path23.join(dir, "package.json"))) {
|
|
10211
10643
|
return dir;
|
|
10212
10644
|
}
|
|
10213
|
-
const parent =
|
|
10645
|
+
const parent = path23.dirname(dir);
|
|
10214
10646
|
if (parent === dir) break;
|
|
10215
10647
|
dir = parent;
|
|
10216
10648
|
}
|
|
10217
|
-
return
|
|
10649
|
+
return path23.resolve(startDir);
|
|
10218
10650
|
}
|
|
10219
10651
|
async function runUpgradeOpenapi(opts) {
|
|
10220
10652
|
const { projectRoot, dryRun, force } = opts;
|
|
10221
10653
|
const changes = [];
|
|
10222
10654
|
for (const v of OPENAPI_VENDORED_FILES) {
|
|
10223
|
-
const target =
|
|
10655
|
+
const target = path23.join(projectRoot, v.target);
|
|
10224
10656
|
const exists = fs12.existsSync(target);
|
|
10225
10657
|
const newContent = loadRuntimeFile2(v.runtime);
|
|
10226
10658
|
if (exists && !force) {
|
|
@@ -10236,7 +10668,7 @@ async function runUpgradeOpenapi(opts) {
|
|
|
10236
10668
|
}
|
|
10237
10669
|
} else {
|
|
10238
10670
|
if (!dryRun) {
|
|
10239
|
-
fs12.mkdirSync(
|
|
10671
|
+
fs12.mkdirSync(path23.dirname(target), { recursive: true });
|
|
10240
10672
|
fs12.writeFileSync(target, newContent);
|
|
10241
10673
|
}
|
|
10242
10674
|
changes.push({
|
|
@@ -10245,7 +10677,7 @@ async function runUpgradeOpenapi(opts) {
|
|
|
10245
10677
|
});
|
|
10246
10678
|
}
|
|
10247
10679
|
}
|
|
10248
|
-
const appModulePath =
|
|
10680
|
+
const appModulePath = path23.join(projectRoot, "src", "app.module.ts");
|
|
10249
10681
|
if (!fs12.existsSync(appModulePath)) {
|
|
10250
10682
|
return {
|
|
10251
10683
|
projectRoot,
|
|
@@ -10329,7 +10761,7 @@ async function runUpgradeOpenapi(opts) {
|
|
|
10329
10761
|
} else {
|
|
10330
10762
|
changes.push({ path: "src/app.module.ts", action: "unchanged" });
|
|
10331
10763
|
}
|
|
10332
|
-
const mainPath =
|
|
10764
|
+
const mainPath = path23.join(projectRoot, "src", "main.ts");
|
|
10333
10765
|
if (fs12.existsSync(mainPath)) {
|
|
10334
10766
|
const mainSource = project.addSourceFileAtPath(mainPath);
|
|
10335
10767
|
const mainBefore = mainSource.getFullText();
|
|
@@ -10410,7 +10842,7 @@ var ProjectUpgradeOpenapiCommand = class extends Command4 {
|
|
|
10410
10842
|
json = Option4.Boolean("--json", false);
|
|
10411
10843
|
async execute() {
|
|
10412
10844
|
if (this.json) setJsonMode(true);
|
|
10413
|
-
const startDir = this.pathOpt ?
|
|
10845
|
+
const startDir = this.pathOpt ? path23.resolve(this.pathOpt) : process.cwd();
|
|
10414
10846
|
if (!fs12.existsSync(startDir)) {
|
|
10415
10847
|
printError(`Directory not found: ${startDir}`);
|
|
10416
10848
|
return 1;
|
|
@@ -10695,8 +11127,8 @@ var ProjectScanCommand = class extends Command5 {
|
|
|
10695
11127
|
cwd = Option5.String("--cwd", { required: false });
|
|
10696
11128
|
async execute() {
|
|
10697
11129
|
if (this.json) setJsonMode(true);
|
|
10698
|
-
const baseCwd = this.cwd ?
|
|
10699
|
-
const target = this.directory ?
|
|
11130
|
+
const baseCwd = this.cwd ? path24.resolve(this.cwd) : process.cwd();
|
|
11131
|
+
const target = this.directory ? path24.resolve(baseCwd, this.directory) : baseCwd;
|
|
10700
11132
|
if (!fs13.existsSync(target)) {
|
|
10701
11133
|
printError(`Directory not found: ${target}`);
|
|
10702
11134
|
return 1;
|
|
@@ -10747,7 +11179,7 @@ var ProjectScanCommand = class extends Command5 {
|
|
|
10747
11179
|
`architecture: ${profile.architecture.evidence.join(", ") || "\u2014"}`
|
|
10748
11180
|
]);
|
|
10749
11181
|
}
|
|
10750
|
-
const outPath =
|
|
11182
|
+
const outPath = path24.join(target, "codegen.config.yaml");
|
|
10751
11183
|
const existsNow = fs13.existsSync(outPath);
|
|
10752
11184
|
if (this.dryRun) {
|
|
10753
11185
|
console.log("");
|
|
@@ -10868,8 +11300,8 @@ var ProjectInspectCommand = class extends Command5 {
|
|
|
10868
11300
|
return 2;
|
|
10869
11301
|
}
|
|
10870
11302
|
resolveEntitiesDir(ctx) {
|
|
10871
|
-
if (this.dir) return
|
|
10872
|
-
return ctx.entitiesDir ??
|
|
11303
|
+
if (this.dir) return path24.resolve(ctx.cwd, this.dir);
|
|
11304
|
+
return ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
|
|
10873
11305
|
}
|
|
10874
11306
|
async runAnalysis(ctx, kind) {
|
|
10875
11307
|
const entitiesDir = this.resolveEntitiesDir(ctx);
|
|
@@ -11072,15 +11504,15 @@ var ProjectGraphCommand = class extends Command5 {
|
|
|
11072
11504
|
json: this.json,
|
|
11073
11505
|
skipDetection: true
|
|
11074
11506
|
});
|
|
11075
|
-
const entitiesDir = this.dir ?
|
|
11507
|
+
const entitiesDir = this.dir ? path24.resolve(ctx.cwd, this.dir) : ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
|
|
11076
11508
|
if (!fs13.existsSync(entitiesDir)) {
|
|
11077
11509
|
printError(`Entity directory not found: ${entitiesDir}`);
|
|
11078
11510
|
return 1;
|
|
11079
11511
|
}
|
|
11080
11512
|
const relCandidates = [
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11513
|
+
path24.resolve(path24.dirname(entitiesDir), "relationships"),
|
|
11514
|
+
path24.resolve(entitiesDir, "relationships"),
|
|
11515
|
+
path24.resolve(ctx.cwd, "relationships")
|
|
11084
11516
|
];
|
|
11085
11517
|
const relationshipsDir = relCandidates.find((d) => fs13.existsSync(d));
|
|
11086
11518
|
const result = await analyzeDomain(entitiesDir, relationshipsDir);
|
|
@@ -11096,20 +11528,20 @@ var ProjectGraphCommand = class extends Command5 {
|
|
|
11096
11528
|
return 0;
|
|
11097
11529
|
}
|
|
11098
11530
|
if (this.output) {
|
|
11099
|
-
const outPath =
|
|
11531
|
+
const outPath = path24.resolve(ctx.cwd, this.output);
|
|
11100
11532
|
fs13.writeFileSync(outPath, JSON.stringify(serialized, null, 2));
|
|
11101
11533
|
printSuccess(`Graph written to ${outPath}`);
|
|
11102
11534
|
printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
|
|
11103
11535
|
return 0;
|
|
11104
11536
|
}
|
|
11105
11537
|
const os = await import("os");
|
|
11106
|
-
const tmpDir = fs13.mkdtempSync(
|
|
11107
|
-
const graphPath =
|
|
11538
|
+
const tmpDir = fs13.mkdtempSync(path24.join(os.default.tmpdir(), "codegen-graph-"));
|
|
11539
|
+
const graphPath = path24.join(tmpDir, "graph.json");
|
|
11108
11540
|
fs13.writeFileSync(graphPath, JSON.stringify(serialized, null, 2));
|
|
11109
|
-
const viewerDir =
|
|
11110
|
-
const viewerDist =
|
|
11541
|
+
const viewerDir = path24.resolve(import.meta.dirname, "..", "..", "..", "tools", "schema-graph-viewer");
|
|
11542
|
+
const viewerDist = path24.join(viewerDir, "dist", "index.html");
|
|
11111
11543
|
if (fs13.existsSync(viewerDist)) {
|
|
11112
|
-
fs13.copyFileSync(graphPath,
|
|
11544
|
+
fs13.copyFileSync(graphPath, path24.join(viewerDir, "dist", "graph.json"));
|
|
11113
11545
|
printSuccess("Graph exported");
|
|
11114
11546
|
printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
|
|
11115
11547
|
printInfo(`Graph JSON: ${graphPath}`);
|
|
@@ -11140,7 +11572,7 @@ var project_default = projectNoun;
|
|
|
11140
11572
|
|
|
11141
11573
|
// src/cli/commands/dev.ts
|
|
11142
11574
|
import fs14 from "fs";
|
|
11143
|
-
import
|
|
11575
|
+
import path25 from "path";
|
|
11144
11576
|
import { execSync as execSync3, spawn, spawnSync } from "child_process";
|
|
11145
11577
|
import { Command as Command6, Option as Option6 } from "clipanion";
|
|
11146
11578
|
var DEFAULT_APP_PORT = 3e3;
|
|
@@ -11173,14 +11605,14 @@ function getRedisPort(_ctx) {
|
|
|
11173
11605
|
return Number(process.env.DEV_REDIS_PORT ?? DEFAULT_REDIS_PORT);
|
|
11174
11606
|
}
|
|
11175
11607
|
function composeFilePath(cwd) {
|
|
11176
|
-
const devPath =
|
|
11608
|
+
const devPath = path25.join(cwd, COMPOSE_FILE);
|
|
11177
11609
|
if (fs14.existsSync(devPath)) return devPath;
|
|
11178
|
-
const rootPath =
|
|
11610
|
+
const rootPath = path25.join(cwd, "docker-compose.yml");
|
|
11179
11611
|
if (fs14.existsSync(rootPath)) return rootPath;
|
|
11180
11612
|
return devPath;
|
|
11181
11613
|
}
|
|
11182
11614
|
function pidFilePath(cwd) {
|
|
11183
|
-
return
|
|
11615
|
+
return path25.join(cwd, PID_FILE);
|
|
11184
11616
|
}
|
|
11185
11617
|
function readAppPid(cwd) {
|
|
11186
11618
|
const p = pidFilePath(cwd);
|
|
@@ -11249,7 +11681,7 @@ function formatServiceLine(svc) {
|
|
|
11249
11681
|
return `${icon} ${svc.name.padEnd(12)} ${theme.muted(`${svc.host}:${svc.port}`)} ${status}${pidStr}`;
|
|
11250
11682
|
}
|
|
11251
11683
|
function ensureComposeFile(cwd, pgPort, redisPort) {
|
|
11252
|
-
const composePath =
|
|
11684
|
+
const composePath = path25.join(cwd, COMPOSE_FILE);
|
|
11253
11685
|
if (fs14.existsSync(composePath)) return composePath;
|
|
11254
11686
|
const content = `# Auto-generated by codegen dev
|
|
11255
11687
|
# Ports offset from defaults to avoid conflicts with other local services.
|
|
@@ -11334,7 +11766,7 @@ var DevUpCommand = class extends Command6 {
|
|
|
11334
11766
|
if (!pgReady) printWarning("postgres did not become healthy in time");
|
|
11335
11767
|
if (!redisReady) printWarning("redis did not become healthy in time");
|
|
11336
11768
|
const drizzleConfig = ["drizzle.config.ts", "drizzle.config.js"].find(
|
|
11337
|
-
(f) => fs14.existsSync(
|
|
11769
|
+
(f) => fs14.existsSync(path25.join(ctx.cwd, f))
|
|
11338
11770
|
);
|
|
11339
11771
|
if (drizzleConfig) {
|
|
11340
11772
|
if (!isJsonMode()) printInfo("pushing database schema...");
|
|
@@ -11354,7 +11786,7 @@ var DevUpCommand = class extends Command6 {
|
|
|
11354
11786
|
if (!isJsonMode()) printInfo("starting NestJS app...");
|
|
11355
11787
|
const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
|
|
11356
11788
|
const redisUrl = `redis://localhost:${redisPort}`;
|
|
11357
|
-
const logFile =
|
|
11789
|
+
const logFile = path25.join(ctx.cwd, ".dev-app.log");
|
|
11358
11790
|
const logFd = fs14.openSync(logFile, "a");
|
|
11359
11791
|
const child = spawn("bun", ["src/main.ts"], {
|
|
11360
11792
|
cwd: ctx.cwd,
|
|
@@ -11512,7 +11944,7 @@ var DevLogsCommand = class extends Command6 {
|
|
|
11512
11944
|
}
|
|
11513
11945
|
return 0;
|
|
11514
11946
|
}
|
|
11515
|
-
const logFile =
|
|
11947
|
+
const logFile = path25.join(ctx.cwd, ".dev-app.log");
|
|
11516
11948
|
if (!fs14.existsSync(logFile)) {
|
|
11517
11949
|
printInfo("no app logs found \u2014 is the app running?");
|
|
11518
11950
|
return 0;
|
|
@@ -11556,7 +11988,7 @@ var DevRestartCommand = class extends Command6 {
|
|
|
11556
11988
|
spawnSync("sleep", ["1"]);
|
|
11557
11989
|
const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
|
|
11558
11990
|
const redisUrl = `redis://localhost:${redisPort}`;
|
|
11559
|
-
const logFile =
|
|
11991
|
+
const logFile = path25.join(ctx.cwd, ".dev-app.log");
|
|
11560
11992
|
const logFd = fs14.openSync(logFile, "a");
|
|
11561
11993
|
const child = spawn("bun", ["src/main.ts"], {
|
|
11562
11994
|
cwd: ctx.cwd,
|
|
@@ -11686,14 +12118,14 @@ var dev_default = devNoun;
|
|
|
11686
12118
|
|
|
11687
12119
|
// src/cli/commands/relationship.ts
|
|
11688
12120
|
import fs15 from "fs";
|
|
11689
|
-
import
|
|
12121
|
+
import path26 from "path";
|
|
11690
12122
|
import { Command as Command7, Option as Option7 } from "clipanion";
|
|
11691
12123
|
function listRelationshipYamls2(dir) {
|
|
11692
12124
|
if (!fs15.existsSync(dir)) return [];
|
|
11693
12125
|
return fs15.readdirSync(dir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml")).filter((f) => {
|
|
11694
|
-
const fullPath =
|
|
12126
|
+
const fullPath = path26.join(dir, f);
|
|
11695
12127
|
return detectYamlType(fullPath) === "relationship";
|
|
11696
|
-
}).map((f) =>
|
|
12128
|
+
}).map((f) => path26.join(dir, f));
|
|
11697
12129
|
}
|
|
11698
12130
|
function summarizeRelationshipFile(filePath) {
|
|
11699
12131
|
const result = loadRelationshipFromYaml(filePath);
|
|
@@ -11714,7 +12146,7 @@ function padRight2(s, n) {
|
|
|
11714
12146
|
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
11715
12147
|
}
|
|
11716
12148
|
async function summary5(ctx) {
|
|
11717
|
-
const relDir =
|
|
12149
|
+
const relDir = path26.resolve(ctx.cwd, "relationships");
|
|
11718
12150
|
const files = listRelationshipYamls2(relDir);
|
|
11719
12151
|
if (files.length === 0) {
|
|
11720
12152
|
return {
|
|
@@ -11784,14 +12216,14 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
11784
12216
|
}
|
|
11785
12217
|
let targets = [];
|
|
11786
12218
|
if (this.all) {
|
|
11787
|
-
const dir =
|
|
12219
|
+
const dir = path26.resolve(ctx.cwd, "relationships");
|
|
11788
12220
|
targets = listRelationshipYamls2(dir);
|
|
11789
12221
|
if (targets.length === 0) {
|
|
11790
12222
|
printError(`No relationship YAML files found in ${dir}`);
|
|
11791
12223
|
return 1;
|
|
11792
12224
|
}
|
|
11793
12225
|
} else if (this.yaml) {
|
|
11794
|
-
targets = [
|
|
12226
|
+
targets = [path26.resolve(ctx.cwd, this.yaml)];
|
|
11795
12227
|
} else {
|
|
11796
12228
|
printError("Missing YAML path. Pass a file or --all.");
|
|
11797
12229
|
return 2;
|
|
@@ -11808,7 +12240,7 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
11808
12240
|
}
|
|
11809
12241
|
if (invalid.length > 0) {
|
|
11810
12242
|
for (const i of invalid) {
|
|
11811
|
-
printError(`${
|
|
12243
|
+
printError(`${path26.basename(i.file)} \u2014 ${i.message}`);
|
|
11812
12244
|
}
|
|
11813
12245
|
if (!isJsonMode()) return 1;
|
|
11814
12246
|
}
|
|
@@ -11839,7 +12271,7 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
11839
12271
|
}
|
|
11840
12272
|
const succeeded = [];
|
|
11841
12273
|
const failed = [
|
|
11842
|
-
...invalid.map((i) => ({ name:
|
|
12274
|
+
...invalid.map((i) => ({ name: path26.basename(i.file), file: i.file, message: i.message }))
|
|
11843
12275
|
];
|
|
11844
12276
|
for (const v of validated) {
|
|
11845
12277
|
if (!isJsonMode()) {
|
|
@@ -11858,8 +12290,8 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
11858
12290
|
if (!isJsonMode()) printError(`${v.name} \u2014 ${res.stderr ?? "failed"}`);
|
|
11859
12291
|
}
|
|
11860
12292
|
}
|
|
11861
|
-
const entitiesDir = ctx.entitiesDir ??
|
|
11862
|
-
const relationshipsDir =
|
|
12293
|
+
const entitiesDir = ctx.entitiesDir ?? path26.resolve(ctx.cwd, "entities");
|
|
12294
|
+
const relationshipsDir = path26.resolve(ctx.cwd, "relationships");
|
|
11863
12295
|
const generatedDir = resolveGeneratedDir(ctx);
|
|
11864
12296
|
const architecture = resolveArchitecture(ctx);
|
|
11865
12297
|
let barrelResult = null;
|
|
@@ -11904,7 +12336,7 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
11904
12336
|
}
|
|
11905
12337
|
if (barrelResult) {
|
|
11906
12338
|
printInfo(
|
|
11907
|
-
`barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${
|
|
12339
|
+
`barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path26.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path26.relative(ctx.cwd, barrelResult.schemaBarrel)}`
|
|
11908
12340
|
);
|
|
11909
12341
|
}
|
|
11910
12342
|
}
|
|
@@ -11927,7 +12359,7 @@ var RelationshipListCommand = class extends Command7 {
|
|
|
11927
12359
|
json: this.json,
|
|
11928
12360
|
skipDetection: true
|
|
11929
12361
|
});
|
|
11930
|
-
const relDir =
|
|
12362
|
+
const relDir = path26.resolve(ctx.cwd, "relationships");
|
|
11931
12363
|
const files = listRelationshipYamls2(relDir);
|
|
11932
12364
|
if (files.length === 0) {
|
|
11933
12365
|
printInfo("No relationship definitions found.");
|
|
@@ -11968,7 +12400,7 @@ var relationship_default = relationshipNoun;
|
|
|
11968
12400
|
|
|
11969
12401
|
// src/cli/commands/events.ts
|
|
11970
12402
|
import fs16 from "fs";
|
|
11971
|
-
import
|
|
12403
|
+
import path27 from "path";
|
|
11972
12404
|
import ts2 from "typescript";
|
|
11973
12405
|
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
11974
12406
|
function scanSourceFileForConsumers(sourceFile, filePath, eventType) {
|
|
@@ -12104,7 +12536,7 @@ function suggestEventTypes(target, known, limit = 3) {
|
|
|
12104
12536
|
return known.map((t) => ({ t, d: levenshtein(target, t) })).sort((a, b) => a.d - b.d).slice(0, limit).map((x) => x.t);
|
|
12105
12537
|
}
|
|
12106
12538
|
function renderConsumerReport(result, cwd) {
|
|
12107
|
-
const rel = (p) =>
|
|
12539
|
+
const rel = (p) => path27.relative(cwd, p) || p;
|
|
12108
12540
|
const lines = [];
|
|
12109
12541
|
const total = result.tier3.length + result.tier2.length + result.tier1.length;
|
|
12110
12542
|
lines.push(`Event: ${result.eventType}`);
|
|
@@ -12140,7 +12572,7 @@ function renderConsumerReport(result, cwd) {
|
|
|
12140
12572
|
return lines;
|
|
12141
12573
|
}
|
|
12142
12574
|
function runConsumersScan(opts) {
|
|
12143
|
-
const scanRoot = opts.scanRoot ??
|
|
12575
|
+
const scanRoot = opts.scanRoot ?? path27.join(opts.cwd, "src");
|
|
12144
12576
|
const handlersDir = opts.handlersDir ?? scanRoot;
|
|
12145
12577
|
const allTriggers = scanHandlerFiles(handlersDir);
|
|
12146
12578
|
const tier3 = allTriggers.filter((t) => t.event === opts.eventType).map((t) => ({
|
|
@@ -12150,7 +12582,7 @@ function runConsumersScan(opts) {
|
|
|
12150
12582
|
sourceLine: t.sourceLine
|
|
12151
12583
|
}));
|
|
12152
12584
|
const tier21 = fs16.existsSync(scanRoot) ? scanDirectoryForConsumers(scanRoot, opts.eventType) : { tier2: [], tier1: [], hasEventFlowImport: false };
|
|
12153
|
-
const eventsGeneratedDir = opts.eventsGeneratedDir ??
|
|
12585
|
+
const eventsGeneratedDir = opts.eventsGeneratedDir ?? path27.join(
|
|
12154
12586
|
resolveSubsystemsRootFromContext(opts.cwd, opts.config),
|
|
12155
12587
|
"events",
|
|
12156
12588
|
"generated"
|
|
@@ -12171,11 +12603,11 @@ function runConsumersScan(opts) {
|
|
|
12171
12603
|
function resolveSubsystemsRootFromContext(cwd, config) {
|
|
12172
12604
|
const configured = config?.paths?.subsystems;
|
|
12173
12605
|
if (typeof configured === "string" && configured.length > 0) {
|
|
12174
|
-
return
|
|
12606
|
+
return path27.resolve(cwd, configured);
|
|
12175
12607
|
}
|
|
12176
12608
|
const backendSrc = config?.paths?.backend_src;
|
|
12177
12609
|
const base = typeof backendSrc === "string" && backendSrc.length > 0 ? backendSrc : "src";
|
|
12178
|
-
return
|
|
12610
|
+
return path27.resolve(cwd, base, "shared", "subsystems");
|
|
12179
12611
|
}
|
|
12180
12612
|
var EventsConsumersCommand = class extends Command8 {
|
|
12181
12613
|
static paths = [["events", "consumers"]];
|
|
@@ -12264,7 +12696,7 @@ var eventsNoun = {
|
|
|
12264
12696
|
var events_default = eventsNoun;
|
|
12265
12697
|
|
|
12266
12698
|
// src/cli/commands/orchestration.ts
|
|
12267
|
-
import
|
|
12699
|
+
import path28 from "path";
|
|
12268
12700
|
import { Command as Command9, Option as Option9 } from "clipanion";
|
|
12269
12701
|
var DEFAULT_PATTERN_GLOBS = ["src/patterns/*.pattern.ts"];
|
|
12270
12702
|
function resolvePatternGlobs(ctx) {
|
|
@@ -12278,10 +12710,10 @@ function resolveOrchestrationOutputRoot(ctx) {
|
|
|
12278
12710
|
const paths = ctx.config?.paths;
|
|
12279
12711
|
const explicit = paths?.orchestration_src;
|
|
12280
12712
|
if (typeof explicit === "string" && explicit.length > 0) {
|
|
12281
|
-
return
|
|
12713
|
+
return path28.resolve(ctx.cwd, explicit);
|
|
12282
12714
|
}
|
|
12283
12715
|
const backendSrc = typeof paths?.backend_src === "string" && paths.backend_src.length > 0 ? paths.backend_src : "app/backend/src";
|
|
12284
|
-
return
|
|
12716
|
+
return path28.resolve(ctx.cwd, backendSrc, "orchestration");
|
|
12285
12717
|
}
|
|
12286
12718
|
async function reloadRegistry(ctx) {
|
|
12287
12719
|
_resetRegistryForTests({ includeLibrary: false });
|
|
@@ -12370,12 +12802,12 @@ var OrchestrationGenCommand = class extends Command9 {
|
|
|
12370
12802
|
);
|
|
12371
12803
|
for (const f of result.files) {
|
|
12372
12804
|
console.log(
|
|
12373
|
-
` ${theme.muted(icons.arrow)} ${
|
|
12805
|
+
` ${theme.muted(icons.arrow)} ${path28.relative(ctx.cwd, f.outputPath)}`
|
|
12374
12806
|
);
|
|
12375
12807
|
}
|
|
12376
12808
|
} else {
|
|
12377
12809
|
printSuccess(
|
|
12378
|
-
`Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${
|
|
12810
|
+
`Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${path28.relative(ctx.cwd, outputRoot)}`
|
|
12379
12811
|
);
|
|
12380
12812
|
}
|
|
12381
12813
|
return 0;
|