@geekmidas/cli 10.0.0-alpha.62 → 10.0.0-alpha.63
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 +2 -0
- package/dist/{HostingerProvider-B92qH4dC.mjs → HostingerProvider-DBBwpDjn.mjs} +2 -2
- package/dist/{HostingerProvider-B92qH4dC.mjs.map → HostingerProvider-DBBwpDjn.mjs.map} +1 -1
- package/dist/{HostingerProvider-DyD1Hin8.cjs → HostingerProvider-mJ7YruxH.cjs} +2 -2
- package/dist/{HostingerProvider-DyD1Hin8.cjs.map → HostingerProvider-mJ7YruxH.cjs.map} +1 -1
- package/dist/{LegacyStateStore-UHJEBLdn.cjs → LegacyStateStore-CP7SZwTP.cjs} +2 -2
- package/dist/{LegacyStateStore-UHJEBLdn.cjs.map → LegacyStateStore-CP7SZwTP.cjs.map} +1 -1
- package/dist/{LegacyStateStore-A8d2GdT7.mjs → LegacyStateStore-Q3GmKOdw.mjs} +2 -2
- package/dist/{LegacyStateStore-A8d2GdT7.mjs.map → LegacyStateStore-Q3GmKOdw.mjs.map} +1 -1
- package/dist/{LocalStateStore-B51rnfgn.mjs → LocalStateStore-BGIXcrvX.mjs} +2 -2
- package/dist/{LocalStateStore-B51rnfgn.mjs.map → LocalStateStore-BGIXcrvX.mjs.map} +1 -1
- package/dist/{LocalStateStore-COW3Ldwa.cjs → LocalStateStore-sS8mvLeq.cjs} +2 -2
- package/dist/{LocalStateStore-COW3Ldwa.cjs.map → LocalStateStore-sS8mvLeq.cjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-BSrgw7B0.cjs → OpenApiTsGenerator-CjHWFRDd.cjs} +2 -2
- package/dist/{OpenApiTsGenerator-BSrgw7B0.cjs.map → OpenApiTsGenerator-CjHWFRDd.cjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-q5B0z8Xg.mjs → OpenApiTsGenerator-CnAwhGxi.mjs} +2 -2
- package/dist/{OpenApiTsGenerator-q5B0z8Xg.mjs.map → OpenApiTsGenerator-CnAwhGxi.mjs.map} +1 -1
- package/dist/{S3StateStore-WUJGdRNL.cjs → S3StateStore-6jqITH2F.cjs} +2 -2
- package/dist/{S3StateStore-WUJGdRNL.cjs.map → S3StateStore-6jqITH2F.cjs.map} +1 -1
- package/dist/{S3StateStore-CJewPhgz.mjs → S3StateStore-D7l_lWJ3.mjs} +2 -2
- package/dist/{S3StateStore-CJewPhgz.mjs.map → S3StateStore-D7l_lWJ3.mjs.map} +1 -1
- package/dist/{SSMStateStore-Zejt42V8.cjs → SSMStateStore-B__F7IJa.cjs} +2 -2
- package/dist/{SSMStateStore-Zejt42V8.cjs.map → SSMStateStore-B__F7IJa.cjs.map} +1 -1
- package/dist/{SSMStateStore-iK5UKp9d.mjs → SSMStateStore-CAQDVpoc.mjs} +2 -2
- package/dist/{SSMStateStore-iK5UKp9d.mjs.map → SSMStateStore-CAQDVpoc.mjs.map} +1 -1
- package/dist/{bundler-CfH9frOS.cjs → bundler-DLfOn0ls.cjs} +3 -3
- package/dist/{bundler-CfH9frOS.cjs.map → bundler-DLfOn0ls.cjs.map} +1 -1
- package/dist/{bundler-DN5r4x5b.mjs → bundler-DyWI41Iy.mjs} +2 -2
- package/dist/{bundler-DN5r4x5b.mjs.map → bundler-DyWI41Iy.mjs.map} +1 -1
- package/dist/{cli-DOAUp80L.cjs → cli-D-ZM-X2s.cjs} +4 -4
- package/dist/{cli-DOAUp80L.cjs.map → cli-D-ZM-X2s.cjs.map} +1 -1
- package/dist/{cli-DYwxmfsW.mjs → cli-PkVF28LM.mjs} +4 -4
- package/dist/{cli-DYwxmfsW.mjs.map → cli-PkVF28LM.mjs.map} +1 -1
- package/dist/{config-BYh9S0cZ.cjs → config-BEJYKd4s.cjs} +132 -18
- package/dist/config-BEJYKd4s.cjs.map +1 -0
- package/dist/config-C2BUosLm.d.mts +256 -0
- package/dist/config-C2BUosLm.d.mts.map +1 -0
- package/dist/config-CemHVcIr.d.cts +256 -0
- package/dist/config-CemHVcIr.d.cts.map +1 -0
- package/dist/{config-Bf4-bROQ.mjs → config-LKKCVCnC.mjs} +109 -19
- package/dist/config-LKKCVCnC.mjs.map +1 -0
- package/dist/config.cjs +6 -2
- package/dist/config.d.cts +3 -210
- package/dist/config.d.mts +3 -210
- package/dist/config.mjs +3 -3
- package/dist/deploy/public.cjs +151 -5
- package/dist/deploy/public.cjs.map +1 -0
- package/dist/deploy/public.d.cts +186 -1
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +186 -1
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +134 -6
- package/dist/deploy/public.mjs.map +1 -0
- package/dist/deploy/sniffer-envparser-worker.cjs +54 -0
- package/dist/deploy/sniffer-envparser-worker.cjs.map +1 -0
- package/dist/deploy/sniffer-envparser-worker.d.cts +1 -0
- package/dist/deploy/sniffer-envparser-worker.d.mts +1 -0
- package/dist/deploy/sniffer-envparser-worker.mjs +55 -0
- package/dist/deploy/sniffer-envparser-worker.mjs.map +1 -0
- package/dist/{deploy-DSaCYvcO.cjs → deploy-ABBI0lf1.cjs} +7 -7
- package/dist/{deploy-DSaCYvcO.cjs.map → deploy-ABBI0lf1.cjs.map} +1 -1
- package/dist/{deploy-D8Qr-Xto.cjs → deploy-BiMrP9i7.cjs} +11 -9
- package/dist/deploy-BiMrP9i7.cjs.map +1 -0
- package/dist/{deploy-B7jvUORo.mjs → deploy-CG8bfFij.mjs} +7 -7
- package/dist/{deploy-B7jvUORo.mjs.map → deploy-CG8bfFij.mjs.map} +1 -1
- package/dist/{deploy-Cg9fae7a.mjs → deploy-CGW-QY9D.mjs} +11 -9
- package/dist/deploy-CGW-QY9D.mjs.map +1 -0
- package/dist/discover-B6yPpvRV.d.mts +99 -0
- package/dist/discover-B6yPpvRV.d.mts.map +1 -0
- package/dist/discover-B_IkPukx.d.cts +99 -0
- package/dist/discover-B_IkPukx.d.cts.map +1 -0
- package/dist/discover-BaT6bpnA.mjs +614 -0
- package/dist/discover-BaT6bpnA.mjs.map +1 -0
- package/dist/discover-C_6COHEv.cjs +729 -0
- package/dist/discover-C_6COHEv.cjs.map +1 -0
- package/dist/{dokploy-CD9PY-3D.mjs → dokploy-CwdmlyQL.mjs} +2 -2
- package/dist/{dokploy-CD9PY-3D.mjs.map → dokploy-CwdmlyQL.mjs.map} +1 -1
- package/dist/{dokploy-Ey2foJLv.cjs → dokploy-QJxMhxdf.cjs} +2 -2
- package/dist/{dokploy-Ey2foJLv.cjs.map → dokploy-QJxMhxdf.cjs.map} +1 -1
- package/dist/{encryption-CVwvGbsL.mjs → encryption-CbQG_ayW.mjs} +4 -4
- package/dist/{encryption-CVwvGbsL.mjs.map → encryption-CbQG_ayW.mjs.map} +1 -1
- package/dist/{encryption-ChBk3hTj.cjs → encryption-DXw3jj0c.cjs} +4 -4
- package/dist/{encryption-ChBk3hTj.cjs.map → encryption-DXw3jj0c.cjs.map} +1 -1
- package/dist/fakes-C9RiT6XG.mjs.map +1 -1
- package/dist/fakes-zW-jNAbQ.cjs.map +1 -1
- package/dist/{github-OUgPDlqg.cjs → github-BH_mETav.cjs} +3 -3
- package/dist/{github-OUgPDlqg.cjs.map → github-BH_mETav.cjs.map} +1 -1
- package/dist/{github-BCB3_LBX.mjs → github-ciwbIwVa.mjs} +3 -3
- package/dist/{github-BCB3_LBX.mjs.map → github-ciwbIwVa.mjs.map} +1 -1
- package/dist/index.cjs +55 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +52 -45
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-dnaFMvOm.cjs → migrate-6oa9y_f2.cjs} +5 -5
- package/dist/{migrate-dnaFMvOm.cjs.map → migrate-6oa9y_f2.cjs.map} +1 -1
- package/dist/{migrate-BoHMqdCu.mjs → migrate-ImBKTBcW.mjs} +5 -5
- package/dist/{migrate-BoHMqdCu.mjs.map → migrate-ImBKTBcW.mjs.map} +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.mjs +3 -3
- package/dist/{ready-XlNx-Gbo.cjs → ready-BiG0rt4h.cjs} +3 -3
- package/dist/{ready-XlNx-Gbo.cjs.map → ready-BiG0rt4h.cjs.map} +1 -1
- package/dist/{ready-DQIy21W5.mjs → ready-Bpdnn2ON.mjs} +3 -3
- package/dist/{ready-DQIy21W5.mjs.map → ready-Bpdnn2ON.mjs.map} +1 -1
- package/dist/reconcile/public.cjs +1 -1
- package/dist/reconcile/public.d.cts +3 -76
- package/dist/reconcile/public.d.cts.map +1 -1
- package/dist/reconcile/public.d.mts +3 -76
- package/dist/reconcile/public.d.mts.map +1 -1
- package/dist/reconcile/public.mjs +1 -1
- package/dist/{resolve-CFCIkm7m.mjs → resolve-B1T0hUaR.mjs} +2 -2
- package/dist/{resolve-CFCIkm7m.mjs.map → resolve-B1T0hUaR.mjs.map} +1 -1
- package/dist/{resolve-wbv66HjD.cjs → resolve-xytBTtG4.cjs} +2 -2
- package/dist/{resolve-wbv66HjD.cjs.map → resolve-xytBTtG4.cjs.map} +1 -1
- package/dist/sandbox/config-worker.cjs +43 -0
- package/dist/sandbox/config-worker.cjs.map +1 -0
- package/dist/sandbox/config-worker.d.cts +1 -0
- package/dist/sandbox/config-worker.d.mts +1 -0
- package/dist/sandbox/config-worker.mjs +44 -0
- package/dist/sandbox/config-worker.mjs.map +1 -0
- package/dist/sandbox/discover-worker.cjs +44 -0
- package/dist/sandbox/discover-worker.cjs.map +1 -0
- package/dist/sandbox/discover-worker.d.cts +1 -0
- package/dist/sandbox/discover-worker.d.mts +1 -0
- package/dist/sandbox/discover-worker.mjs +45 -0
- package/dist/sandbox/discover-worker.mjs.map +1 -0
- package/dist/sandbox-M8UnLhXE.d.cts +126 -0
- package/dist/sandbox-M8UnLhXE.d.cts.map +1 -0
- package/dist/sandbox-M8UnLhXE.d.mts +126 -0
- package/dist/sandbox-M8UnLhXE.d.mts.map +1 -0
- package/dist/{workspace-BFe57es7.mjs → schemas-Ckm_aBnF.cjs} +71 -982
- package/dist/schemas-Ckm_aBnF.cjs.map +1 -0
- package/dist/{workspace-B6zQO6RY.cjs → schemas-D2LCF689.mjs} +2 -1168
- package/dist/schemas-D2LCF689.mjs.map +1 -0
- package/dist/{sniffer-BsfPa-GA.cjs → sniffer-D_SYc_pO.cjs} +369 -207
- package/dist/sniffer-D_SYc_pO.cjs.map +1 -0
- package/dist/{sniffer-DHE2Nafd.mjs → sniffer-aO_-s5vq.mjs} +336 -204
- package/dist/sniffer-aO_-s5vq.mjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.mjs +1 -1
- package/dist/{terminal-6oL0vANs.cjs → terminal-D0f1u0LG.cjs} +6 -6
- package/dist/{terminal-6oL0vANs.cjs.map → terminal-D0f1u0LG.cjs.map} +1 -1
- package/dist/{terminal-ByZNjuig.mjs → terminal-gMxAo9Dj.mjs} +6 -6
- package/dist/{terminal-ByZNjuig.mjs.map → terminal-gMxAo9Dj.mjs.map} +1 -1
- package/dist/vitest.cjs +2 -2
- package/dist/vitest.mjs +2 -2
- package/dist/workerRuntime-BXfhbe13.cjs +108 -0
- package/dist/workerRuntime-BXfhbe13.cjs.map +1 -0
- package/dist/workerRuntime-CsOyBRx2.mjs +79 -0
- package/dist/workerRuntime-CsOyBRx2.mjs.map +1 -0
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.mjs +1 -1
- package/dist/workspace-Dh7rr7l4.mjs +1024 -0
- package/dist/workspace-Dh7rr7l4.mjs.map +1 -0
- package/dist/workspace-Kl4NG9IH.cjs +1196 -0
- package/dist/workspace-Kl4NG9IH.cjs.map +1 -0
- package/package.json +13 -13
- package/dist/config-BYh9S0cZ.cjs.map +0 -1
- package/dist/config-Bf4-bROQ.mjs.map +0 -1
- package/dist/config.d.cts.map +0 -1
- package/dist/config.d.mts.map +0 -1
- package/dist/deploy-Cg9fae7a.mjs.map +0 -1
- package/dist/deploy-D8Qr-Xto.cjs.map +0 -1
- package/dist/discover-Bc-4eA_p.cjs +0 -299
- package/dist/discover-Bc-4eA_p.cjs.map +0 -1
- package/dist/discover-FrYvzkeC.mjs +0 -262
- package/dist/discover-FrYvzkeC.mjs.map +0 -1
- package/dist/sniffer-BsfPa-GA.cjs.map +0 -1
- package/dist/sniffer-DHE2Nafd.mjs.map +0 -1
- package/dist/workspace-B6zQO6RY.cjs.map +0 -1
- package/dist/workspace-BFe57es7.mjs.map +0 -1
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
-
let node_path = require("node:path");
|
|
3
|
-
let node_async_hooks = require("node:async_hooks");
|
|
4
|
-
let node_util = require("node:util");
|
|
5
|
-
let _geekmidas_manifest = require("@geekmidas/manifest");
|
|
6
|
-
let fast_glob = require("fast-glob");
|
|
7
|
-
fast_glob = require_rolldown_runtime.__toESM(fast_glob, 1);
|
|
8
|
-
let lodash_kebabcase = require("lodash.kebabcase");
|
|
9
|
-
lodash_kebabcase = require_rolldown_runtime.__toESM(lodash_kebabcase, 1);
|
|
10
|
-
//#region src/output.ts
|
|
11
|
-
/**
|
|
12
|
-
* Where the CLI's progress lines go.
|
|
13
|
-
*
|
|
14
|
-
* Commands write their progress through `output` rather than `console`. Run
|
|
15
|
-
* from the terminal that is the same thing. Run inside `deploy()`, each line
|
|
16
|
-
* goes to the run that wrote it instead — as an event its caller can iterate,
|
|
17
|
-
* and to the logger it was handed — so a deploy embedded in another program
|
|
18
|
-
* does not print over that program's own output.
|
|
19
|
-
*
|
|
20
|
-
* Carried by `AsyncLocalStorage` rather than passed down, because the lines
|
|
21
|
-
* come from everywhere a deploy reaches — the Dockerfile generator, the env
|
|
22
|
-
* sniffer, construct discovery — and two deploys running in one process must
|
|
23
|
-
* not hear each other.
|
|
24
|
-
*/
|
|
25
|
-
const current = new node_async_hooks.AsyncLocalStorage();
|
|
26
|
-
/** Runs `fn` with every line written through `output` sent to `sink`. */
|
|
27
|
-
function withOutput(sink, fn) {
|
|
28
|
-
return current.run(sink, fn);
|
|
29
|
-
}
|
|
30
|
-
function write(level, fallback) {
|
|
31
|
-
return (...args) => {
|
|
32
|
-
const sink = current.getStore();
|
|
33
|
-
if (sink) sink(level, (0, node_util.format)(...args));
|
|
34
|
-
else fallback(...args);
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* `console`, for the methods the CLI logs through — routed to the current
|
|
39
|
-
* run's sink when there is one.
|
|
40
|
-
*/
|
|
41
|
-
const output = {
|
|
42
|
-
log: write("info", (...args) => console.log(...args)),
|
|
43
|
-
info: write("info", (...args) => console.info(...args)),
|
|
44
|
-
warn: write("warn", (...args) => console.warn(...args)),
|
|
45
|
-
error: write("error", (...args) => console.error(...args))
|
|
46
|
-
};
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/generators/Generator.ts
|
|
49
|
-
/**
|
|
50
|
-
* Zod v4 maintains a process-wide registry of schemas registered via
|
|
51
|
-
* `.meta({ id })`. When we cache-bust user module imports (by appending a
|
|
52
|
-
* `?t=timestamp` query), those modules re-execute and try to register the
|
|
53
|
-
* same ids again, which throws `ID X already exists in the registry`.
|
|
54
|
-
*
|
|
55
|
-
* Clearing the registry in the CLI process is safe: the user's running
|
|
56
|
-
* server lives in a subprocess and has its own isolated registry.
|
|
57
|
-
*
|
|
58
|
-
* Exported for tests.
|
|
59
|
-
*/
|
|
60
|
-
function clearZodGlobalRegistry() {
|
|
61
|
-
const registry = globalThis.__zod_globalRegistry;
|
|
62
|
-
if (registry && typeof registry.clear === "function") registry.clear();
|
|
63
|
-
}
|
|
64
|
-
var ConstructGenerator = class {
|
|
65
|
-
static async build(context, outputDir, generator, patterns, options) {
|
|
66
|
-
const constructs = await generator.load(patterns);
|
|
67
|
-
return generator.build(context, constructs, outputDir, options);
|
|
68
|
-
}
|
|
69
|
-
async load(patterns, cwd = process.cwd(), bustCache = false) {
|
|
70
|
-
const logger = console;
|
|
71
|
-
const globPatterns = Array.isArray(patterns) ? patterns : patterns ? [patterns] : [];
|
|
72
|
-
const files = fast_glob.default.stream(globPatterns, {
|
|
73
|
-
cwd,
|
|
74
|
-
absolute: true
|
|
75
|
-
});
|
|
76
|
-
if (bustCache) clearZodGlobalRegistry();
|
|
77
|
-
const constructs = [];
|
|
78
|
-
for await (const f of files) try {
|
|
79
|
-
const file = f.toString();
|
|
80
|
-
const module = await (bustCache ? import(`${file}?t=${Date.now()}`) : import(file));
|
|
81
|
-
for (const [key, construct] of Object.entries(module)) if (this.isConstruct(construct)) constructs.push({
|
|
82
|
-
key,
|
|
83
|
-
name: (0, lodash_kebabcase.default)(key),
|
|
84
|
-
construct,
|
|
85
|
-
path: {
|
|
86
|
-
absolute: file,
|
|
87
|
-
relative: (0, node_path.relative)(process.cwd(), file)
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
} catch (error) {
|
|
91
|
-
const err = error;
|
|
92
|
-
logger.error(`Failed to load ${f}: ${err.message}`);
|
|
93
|
-
if (err.stack) logger.error(err.stack);
|
|
94
|
-
throw error;
|
|
95
|
-
}
|
|
96
|
-
return constructs;
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
//#endregion
|
|
100
|
-
//#region src/reconcile/discover.ts
|
|
101
|
-
/**
|
|
102
|
-
* Discovery — one glob, one structural test.
|
|
103
|
-
*
|
|
104
|
-
* A glob per kind is the same specialness the construct model removes, and
|
|
105
|
-
* resources have no kind to be listed under: a declared `ObjectStorage` would
|
|
106
|
-
* never be found by `routes:` or `crons:`. So there is one `constructs` glob,
|
|
107
|
-
* every export of every matching module is inspected, and the per-kind
|
|
108
|
-
* `isConstruct` checks collapse into a single question — does it have an id and
|
|
109
|
-
* can it declare?
|
|
110
|
-
*
|
|
111
|
-
* Structural rather than `instanceof` on purpose. A construct from a different
|
|
112
|
-
* copy of `@geekmidas/constructs` — a linked workspace, two versions in a
|
|
113
|
-
* lockfile — is still a construct, and `instanceof` is exactly the check that
|
|
114
|
-
* says otherwise.
|
|
115
|
-
*/
|
|
116
|
-
var discover_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
117
|
-
DuplicateConstruct: () => DuplicateConstruct,
|
|
118
|
-
discover: () => discover,
|
|
119
|
-
isDeclarable: () => isDeclarable
|
|
120
|
-
});
|
|
121
|
-
/** `console`, or the deploy run discovering the manifest. */
|
|
122
|
-
const logger = output;
|
|
123
|
-
/**
|
|
124
|
-
* Whether a module export is a construct.
|
|
125
|
-
*
|
|
126
|
-
* Deliberately loose about what else it carries — a construct that also has a
|
|
127
|
-
* `service` is still a construct, and requiring one would exclude the kinds that
|
|
128
|
-
* own no address.
|
|
129
|
-
*/
|
|
130
|
-
function isDeclarable(value) {
|
|
131
|
-
if (typeof value !== "object" || value === null) return false;
|
|
132
|
-
const candidate = value;
|
|
133
|
-
return typeof candidate.id === "string" && candidate.id.length > 0 && typeof candidate.declare === "function";
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Build the construct manifest for a project.
|
|
137
|
-
*
|
|
138
|
-
* Runs the manifest's own validation before returning, so an app is wrong here
|
|
139
|
-
* — where the error names a file — rather than at deploy.
|
|
140
|
-
*
|
|
141
|
-
* @throws {DuplicateConstruct} when two exports claim one id.
|
|
142
|
-
*/
|
|
143
|
-
async function discover(options) {
|
|
144
|
-
const { patterns, cwd = process.cwd(), bustCache = false, sources: out } = options;
|
|
145
|
-
if (bustCache) clearZodGlobalRegistry();
|
|
146
|
-
const manifest = {};
|
|
147
|
-
/** Which file declared each id, for the error when two of them do. */
|
|
148
|
-
const sources = {};
|
|
149
|
-
/**
|
|
150
|
-
* Constructs already seen, by identity.
|
|
151
|
-
*
|
|
152
|
-
* A re-export is the *same object* reached through a second file — ESM
|
|
153
|
-
* bindings are live, so `export * from './database.js'` hands back the
|
|
154
|
-
* binding rather than a copy. Without this, a barrel file made every
|
|
155
|
-
* construct in it appear declared twice, and `constructs/index.ts` is the
|
|
156
|
-
* first thing anyone writes in a shared folder.
|
|
157
|
-
*
|
|
158
|
-
* Identity rather than file is also the more honest rule: what may not
|
|
159
|
-
* happen twice is two *different* constructs claiming one id, and that is
|
|
160
|
-
* still an error below.
|
|
161
|
-
*/
|
|
162
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
163
|
-
const globs = Array.isArray(patterns) ? [...patterns] : [patterns];
|
|
164
|
-
const files = fast_glob.default.stream(globs, {
|
|
165
|
-
cwd,
|
|
166
|
-
absolute: true
|
|
167
|
-
});
|
|
168
|
-
/** Matched files, for the diagnostic below. */
|
|
169
|
-
let matched = 0;
|
|
170
|
-
for await (const found of files) {
|
|
171
|
-
matched++;
|
|
172
|
-
const file = found.toString();
|
|
173
|
-
const module = await (bustCache ? import(`${file}?t=${Date.now()}`) : import(file));
|
|
174
|
-
for (const [exportName, exported] of Object.entries(module)) {
|
|
175
|
-
if (!isDeclarable(exported)) {
|
|
176
|
-
if (options.runnables) recordRunnable(options.runnables, exported);
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
if (seen.has(exported)) continue;
|
|
180
|
-
seen.add(exported);
|
|
181
|
-
if (options.runnables && typeof exported.owner === "string") recordRunnable(options.runnables, exported);
|
|
182
|
-
for (const declaration of exported.declare()) {
|
|
183
|
-
const id = (0, _geekmidas_manifest.canonicalId)(declaration.id);
|
|
184
|
-
const source = (0, node_path.relative)(cwd, file);
|
|
185
|
-
const claimed = sources[id];
|
|
186
|
-
if (claimed !== void 0 && claimed !== source) throw new DuplicateConstruct(id, [claimed, source]);
|
|
187
|
-
manifest[id] = {
|
|
188
|
-
...declaration,
|
|
189
|
-
id
|
|
190
|
-
};
|
|
191
|
-
sources[id] = source;
|
|
192
|
-
if (out) out[id] = {
|
|
193
|
-
file,
|
|
194
|
-
exportName,
|
|
195
|
-
construct: exported
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
(0, _geekmidas_manifest.assertDerivations)(manifest);
|
|
201
|
-
warnIfNothingFound(globs, matched, Object.keys(manifest).length);
|
|
202
|
-
return manifest;
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Record a runnable's edges under the construct that owns it — the surface an
|
|
206
|
-
* endpoint was built from, or the worker a cron or subscriber was. Anything
|
|
207
|
-
* with no owner, or that is not a runnable at all, is left alone.
|
|
208
|
-
*/
|
|
209
|
-
function recordRunnable(runnables, exported) {
|
|
210
|
-
if (typeof exported !== "object" || exported === null) return;
|
|
211
|
-
const runnable = exported;
|
|
212
|
-
const owner = typeof runnable.surface?.id === "string" ? runnable.surface.id : typeof runnable.owner === "string" ? runnable.owner : void 0;
|
|
213
|
-
if (!owner || !Array.isArray(runnable.constructs)) return;
|
|
214
|
-
const key = (0, _geekmidas_manifest.canonicalId)(owner);
|
|
215
|
-
const edges = runnables[key] ?? [];
|
|
216
|
-
runnables[key] = edges;
|
|
217
|
-
for (const id of runnable.constructs) {
|
|
218
|
-
if (typeof id !== "string") continue;
|
|
219
|
-
const target = (0, _geekmidas_manifest.canonicalId)(id);
|
|
220
|
-
if (!edges.includes(target)) edges.push(target);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Say so when a glob was configured and found nothing.
|
|
225
|
-
*
|
|
226
|
-
* The glob is not a filter over declarations already known — it is *how they
|
|
227
|
-
* are found*, by importing what it matches. So a file it misses is a
|
|
228
|
-
* declaration that does not exist, and every symptom of that appears somewhere
|
|
229
|
-
* other than the cause: no container starts, no env key is written, and the
|
|
230
|
-
* application fails on first use against a resource it can see in its own
|
|
231
|
-
* source.
|
|
232
|
-
*
|
|
233
|
-
* Nothing reported it before, because an unmatched file is indistinguishable
|
|
234
|
-
* from a file nobody wrote. These two cases are the ones that are *not*
|
|
235
|
-
* ambiguous — a glob was configured, so something was expected.
|
|
236
|
-
*
|
|
237
|
-
* Silent when no glob is configured at all: that is a project which has not
|
|
238
|
-
* adopted constructs, and has nothing to be missing.
|
|
239
|
-
*/
|
|
240
|
-
function warnIfNothingFound(globs, matched, declared) {
|
|
241
|
-
if (globs.length === 0) return;
|
|
242
|
-
if (matched === 0) {
|
|
243
|
-
logger.warn(`\n⚠️ The constructs glob matched no files, so nothing was declared.\n Patterns: ${globs.join(", ")}\n Nothing will be provisioned — no containers, no env keys, no resources.\n A common cause is depth: '*.ts' matches one level, '**/*.ts' matches any.`);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (declared === 0) logger.warn(`\n⚠️ The constructs glob matched ${matched} file(s) but none declared anything.\n Patterns: ${globs.join(", ")}\n Discovery keeps exports with an 'id' that can 'declare()'. A construct that is\n built but never exported is invisible to it.`);
|
|
247
|
-
}
|
|
248
|
-
/** Two constructs claiming one id. */
|
|
249
|
-
var DuplicateConstruct = class extends Error {
|
|
250
|
-
/** The id claimed twice. */
|
|
251
|
-
id;
|
|
252
|
-
/** The files that claimed it. */
|
|
253
|
-
sources;
|
|
254
|
-
constructor(id, sources) {
|
|
255
|
-
super("Two constructs declare the same id");
|
|
256
|
-
this.name = "DuplicateConstruct";
|
|
257
|
-
this.id = id;
|
|
258
|
-
this.sources = sources;
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
//#endregion
|
|
262
|
-
Object.defineProperty(exports, "ConstructGenerator", {
|
|
263
|
-
enumerable: true,
|
|
264
|
-
get: function() {
|
|
265
|
-
return ConstructGenerator;
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
Object.defineProperty(exports, "discover", {
|
|
269
|
-
enumerable: true,
|
|
270
|
-
get: function() {
|
|
271
|
-
return discover;
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
Object.defineProperty(exports, "discover_exports", {
|
|
275
|
-
enumerable: true,
|
|
276
|
-
get: function() {
|
|
277
|
-
return discover_exports;
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
Object.defineProperty(exports, "isDeclarable", {
|
|
281
|
-
enumerable: true,
|
|
282
|
-
get: function() {
|
|
283
|
-
return isDeclarable;
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
Object.defineProperty(exports, "output", {
|
|
287
|
-
enumerable: true,
|
|
288
|
-
get: function() {
|
|
289
|
-
return output;
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
Object.defineProperty(exports, "withOutput", {
|
|
293
|
-
enumerable: true,
|
|
294
|
-
get: function() {
|
|
295
|
-
return withOutput;
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
//# sourceMappingURL=discover-Bc-4eA_p.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discover-Bc-4eA_p.cjs","names":["AsyncLocalStorage","format","fg","kebabCase","relative","fg","canonicalId","relative"],"sources":["../src/output.ts","../src/generators/Generator.ts","../src/reconcile/discover.ts"],"sourcesContent":["/**\n * Where the CLI's progress lines go.\n *\n * Commands write their progress through `output` rather than `console`. Run\n * from the terminal that is the same thing. Run inside `deploy()`, each line\n * goes to the run that wrote it instead — as an event its caller can iterate,\n * and to the logger it was handed — so a deploy embedded in another program\n * does not print over that program's own output.\n *\n * Carried by `AsyncLocalStorage` rather than passed down, because the lines\n * come from everywhere a deploy reaches — the Dockerfile generator, the env\n * sniffer, construct discovery — and two deploys running in one process must\n * not hear each other.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { format } from 'node:util';\n\n/** How loud a line is. */\nexport type OutputLevel = 'info' | 'warn' | 'error';\n\n/** Receives each line written while it is the current sink. */\nexport type OutputSink = (level: OutputLevel, message: string) => void;\n\nconst current = new AsyncLocalStorage<OutputSink>();\n\n/** Runs `fn` with every line written through `output` sent to `sink`. */\nexport function withOutput<T>(sink: OutputSink, fn: () => T): T {\n\treturn current.run(sink, fn);\n}\n\nfunction write(\n\tlevel: OutputLevel,\n\tfallback: (...args: unknown[]) => void,\n): (...args: unknown[]) => void {\n\treturn (...args) => {\n\t\tconst sink = current.getStore();\n\t\tif (sink) sink(level, format(...args));\n\t\telse fallback(...args);\n\t};\n}\n\n/**\n * `console`, for the methods the CLI logs through — routed to the current\n * run's sink when there is one.\n */\nexport const output = {\n\tlog: write('info', (...args) => console.log(...args)),\n\tinfo: write('info', (...args) => console.info(...args)),\n\twarn: write('warn', (...args) => console.warn(...args)),\n\terror: write('error', (...args) => console.error(...args)),\n};\n","import { relative } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\nimport fg from 'fast-glob';\nimport kebabCase from 'lodash.kebabcase';\nimport type { BuildContext } from '../build/types';\nimport type { MainProvider, Routes } from '../types';\n\n/**\n * Zod v4 maintains a process-wide registry of schemas registered via\n * `.meta({ id })`. When we cache-bust user module imports (by appending a\n * `?t=timestamp` query), those modules re-execute and try to register the\n * same ids again, which throws `ID X already exists in the registry`.\n *\n * Clearing the registry in the CLI process is safe: the user's running\n * server lives in a subprocess and has its own isolated registry.\n *\n * Exported for tests.\n */\nexport function clearZodGlobalRegistry(): void {\n\tconst registry = (\n\t\tglobalThis as { __zod_globalRegistry?: { clear?: () => void } }\n\t).__zod_globalRegistry;\n\tif (registry && typeof registry.clear === 'function') {\n\t\tregistry.clear();\n\t}\n}\n\nexport interface GeneratorOptions {\n\t/** Where the build deploys: one Lambda per construct, or one process. */\n\ttarget?: MainProvider;\n\t/**\n\t * What a handler path in the manifest is relative to — the workspace root,\n\t * which is where `sst.config.ts` runs and resolves it from.\n\t */\n\troot?: string;\n\t[key: string]: any;\n}\n\nexport abstract class ConstructGenerator<T extends Construct, R = void> {\n\tabstract isConstruct(value: any): value is T;\n\n\tstatic async build<T extends Construct, R = void>(\n\t\tcontext: BuildContext,\n\t\toutputDir: string,\n\t\tgenerator: ConstructGenerator<T, R>,\n\t\tpatterns?: Routes,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R> {\n\t\tconst constructs = await generator.load(patterns);\n\t\treturn generator.build(context, constructs, outputDir, options);\n\t}\n\n\tabstract build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<T>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R>;\n\n\tasync load(\n\t\tpatterns?: Routes,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t): Promise<GeneratedConstruct<T>[]> {\n\t\tconst logger = console;\n\n\t\tconst globPatterns = Array.isArray(patterns)\n\t\t\t? patterns\n\t\t\t: patterns\n\t\t\t\t? [patterns]\n\t\t\t\t: [];\n\n\t\t// Find all files\n\t\tconst files = fg.stream(globPatterns, {\n\t\t\tcwd,\n\t\t\tabsolute: true,\n\t\t});\n\n\t\t// Cache-busted re-imports re-execute user modules, which would try to\n\t\t// re-register Zod schemas with the same `.meta({ id })`. Clear the\n\t\t// global registry once per load to prevent duplicate-id errors.\n\t\tif (bustCache) {\n\t\t\tclearZodGlobalRegistry();\n\t\t}\n\n\t\t// Load constructs\n\t\tconst constructs: GeneratedConstruct<T>[] = [];\n\n\t\tfor await (const f of files) {\n\t\t\ttry {\n\t\t\t\tconst file = f.toString();\n\t\t\t\t// Append cache-busting query param to force re-import of changed modules\n\t\t\t\tconst importPath = bustCache ? `${file}?t=${Date.now()}` : file;\n\t\t\t\tconst module = await import(importPath);\n\n\t\t\t\t// Check all exports for constructs\n\t\t\t\tfor (const [key, construct] of Object.entries(module)) {\n\t\t\t\t\tif (this.isConstruct(construct)) {\n\t\t\t\t\t\tconstructs.push({\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tname: kebabCase(key),\n\t\t\t\t\t\t\tconstruct,\n\t\t\t\t\t\t\tpath: {\n\t\t\t\t\t\t\t\tabsolute: file,\n\t\t\t\t\t\t\t\trelative: relative(process.cwd(), file),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tlogger.error(`Failed to load ${f}: ${err.message}`);\n\t\t\t\tif (err.stack) {\n\t\t\t\t\tlogger.error(err.stack);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn constructs;\n\t}\n}\n\nexport interface GeneratedConstruct<T extends Construct> {\n\tkey: string;\n\tname: string;\n\tconstruct: T;\n\tpath: {\n\t\tabsolute: string;\n\t\trelative: string;\n\t};\n}\n","/**\n * Discovery — one glob, one structural test.\n *\n * A glob per kind is the same specialness the construct model removes, and\n * resources have no kind to be listed under: a declared `ObjectStorage` would\n * never be found by `routes:` or `crons:`. So there is one `constructs` glob,\n * every export of every matching module is inspected, and the per-kind\n * `isConstruct` checks collapse into a single question — does it have an id and\n * can it declare?\n *\n * Structural rather than `instanceof` on purpose. A construct from a different\n * copy of `@geekmidas/constructs` — a linked workspace, two versions in a\n * lockfile — is still a construct, and `instanceof` is exactly the check that\n * says otherwise.\n */\n\nimport { relative } from 'node:path';\nimport {\n\tassertDerivations,\n\ttype ConstructManifest,\n\tcanonicalId,\n\ttype Declaration,\n} from '@geekmidas/manifest';\nimport fg from 'fast-glob';\nimport { clearZodGlobalRegistry } from '../generators/Generator';\nimport { output } from '../output';\n\n/** `console`, or the deploy run discovering the manifest. */\nconst logger = output;\n\n/** The construct face discovery needs: an id, and the ability to declare. */\ninterface Declarable {\n\tid: string;\n\tdeclare(): Declaration[];\n}\n\n/**\n * Whether a module export is a construct.\n *\n * Deliberately loose about what else it carries — a construct that also has a\n * `service` is still a construct, and requiring one would exclude the kinds that\n * own no address.\n */\nexport function isDeclarable(value: unknown): value is Declarable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Declarable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.declare === 'function'\n\t);\n}\n\nexport interface DiscoverOptions {\n\t/** The glob(s) to search. One pattern, not one per kind. */\n\tpatterns: string | readonly string[];\n\tcwd?: string;\n\t/**\n\t * Re-import changed modules, for the dev watcher.\n\t *\n\t * A single glob makes discovery more central, not less: a new construct file\n\t * has to be picked up on `add`, not only on `change`.\n\t */\n\tbustCache?: boolean;\n\t/**\n\t * Filled in with where each construct was found, when provided.\n\t *\n\t * Discovery is the only thing that knows: it globbed the files and imported\n\t * them. Everything downstream that needs to *write* an import — the build,\n\t * generating a server entry that reads a surface's logger — would otherwise\n\t * have to be told the path in config, which is the string this removes.\n\t *\n\t * An out-parameter rather than a second return value so that every existing\n\t * caller, which wants the manifest and nothing else, is unchanged.\n\t */\n\tsources?: Record<string, ConstructSource>;\n\t/**\n\t * Filled in, when provided, with the ids each owner's runnables declared an\n\t * edge to — keyed by the surface an endpoint was built from, or the worker\n\t * a cron or subscriber was.\n\t *\n\t * A runnable is not a declaration: a surface's endpoints are found by the\n\t * glob, not listed by the surface, so its node says `endpoints: []` until a\n\t * build folds the routes in. Anything deciding what an app's process reaches\n\t * — which keys its container is given — needs those edges before any build,\n\t * and discovery is already importing the files they are in.\n\t */\n\trunnables?: Record<string, string[]>;\n}\n\n/** Where a construct was declared, and under what name. */\nexport interface ConstructSource {\n\t/** Absolute path to the module that exported it. */\n\tfile: string;\n\t/** The name it was exported as — what an import statement has to say. */\n\texportName: string;\n\t/**\n\t * The exported construct itself.\n\t *\n\t * What a declaration cannot say — whether it serves itself — the object can\n\t * be asked, and discovery already imported it.\n\t */\n\tconstruct: unknown;\n}\n\n/**\n * Build the construct manifest for a project.\n *\n * Runs the manifest's own validation before returning, so an app is wrong here\n * — where the error names a file — rather than at deploy.\n *\n * @throws {DuplicateConstruct} when two exports claim one id.\n */\nexport async function discover(\n\toptions: DiscoverOptions,\n): Promise<ConstructManifest> {\n\tconst {\n\t\tpatterns,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t\tsources: out,\n\t} = options;\n\n\t// Re-importing user modules re-executes them, and Zod v4 throws on a\n\t// re-registered `.meta({ id })`. Same reason the generators clear it.\n\tif (bustCache) clearZodGlobalRegistry();\n\n\tconst manifest: Record<string, Declaration> = {};\n\t/** Which file declared each id, for the error when two of them do. */\n\tconst sources: Record<string, string> = {};\n\t/**\n\t * Constructs already seen, by identity.\n\t *\n\t * A re-export is the *same object* reached through a second file — ESM\n\t * bindings are live, so `export * from './database.js'` hands back the\n\t * binding rather than a copy. Without this, a barrel file made every\n\t * construct in it appear declared twice, and `constructs/index.ts` is the\n\t * first thing anyone writes in a shared folder.\n\t *\n\t * Identity rather than file is also the more honest rule: what may not\n\t * happen twice is two *different* constructs claiming one id, and that is\n\t * still an error below.\n\t */\n\tconst seen = new WeakSet<object>();\n\n\tconst globs = Array.isArray(patterns) ? [...patterns] : [patterns as string];\n\tconst files = fg.stream(globs, { cwd, absolute: true });\n\n\t/** Matched files, for the diagnostic below. */\n\tlet matched = 0;\n\n\tfor await (const found of files) {\n\t\tmatched++;\n\t\tconst file = found.toString();\n\t\tconst module = await import(bustCache ? `${file}?t=${Date.now()}` : file);\n\n\t\tfor (const [exportName, exported] of Object.entries(module)) {\n\t\t\tif (!isDeclarable(exported)) {\n\t\t\t\tif (options.runnables) recordRunnable(options.runnables, exported);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// The same construct, reached again through a re-export. Skipped\n\t\t\t// rather than re-declared: it has already claimed its id, from the\n\t\t\t// file that defined it.\n\t\t\tif (seen.has(exported as object)) continue;\n\t\t\tseen.add(exported as object);\n\n\t\t\t// A construct that is also something a process runs — a queue and its\n\t\t\t// consumer, built from a worker — reaches what it depends on through\n\t\t\t// that process, exactly as an endpoint or a cron does.\n\t\t\tif (\n\t\t\t\toptions.runnables &&\n\t\t\t\ttypeof (exported as { owner?: unknown }).owner === 'string'\n\t\t\t) {\n\t\t\t\trecordRunnable(options.runnables, exported);\n\t\t\t}\n\n\t\t\tfor (const declaration of exported.declare()) {\n\t\t\t\t// Canonicalise here too: a construct built by hand rather than through\n\t\t\t\t// a constructor is still subject to the same identity rule.\n\t\t\t\tconst id = canonicalId(declaration.id);\n\t\t\t\tconst source = relative(cwd, file);\n\n\t\t\t\tconst claimed = sources[id];\n\t\t\t\tif (claimed !== undefined && claimed !== source) {\n\t\t\t\t\tthrow new DuplicateConstruct(id, [claimed, source]);\n\t\t\t\t}\n\n\t\t\t\tmanifest[id] = { ...declaration, id };\n\t\t\t\tsources[id] = source;\n\t\t\t\tif (out) out[id] = { file, exportName, construct: exported };\n\t\t\t}\n\t\t}\n\t}\n\n\t// Reference integrity before anyone reads it — a schema tenant naming a\n\t// database that was deleted is a manifest error, not a reconcile failure.\n\tassertDerivations(manifest);\n\n\twarnIfNothingFound(globs, matched, Object.keys(manifest).length);\n\n\treturn manifest;\n}\n\n/**\n * Record a runnable's edges under the construct that owns it — the surface an\n * endpoint was built from, or the worker a cron or subscriber was. Anything\n * with no owner, or that is not a runnable at all, is left alone.\n */\nfunction recordRunnable(\n\trunnables: Record<string, string[]>,\n\texported: unknown,\n): void {\n\tif (typeof exported !== 'object' || exported === null) return;\n\n\tconst runnable = exported as {\n\t\tsurface?: { id?: unknown };\n\t\towner?: unknown;\n\t\tconstructs?: unknown;\n\t};\n\tconst owner =\n\t\ttypeof runnable.surface?.id === 'string'\n\t\t\t? runnable.surface.id\n\t\t\t: typeof runnable.owner === 'string'\n\t\t\t\t? runnable.owner\n\t\t\t\t: undefined;\n\tif (!owner || !Array.isArray(runnable.constructs)) return;\n\n\tconst key = canonicalId(owner);\n\tconst edges = runnables[key] ?? [];\n\trunnables[key] = edges;\n\tfor (const id of runnable.constructs) {\n\t\tif (typeof id !== 'string') continue;\n\t\tconst target = canonicalId(id);\n\t\tif (!edges.includes(target)) edges.push(target);\n\t}\n}\n\n/**\n * Say so when a glob was configured and found nothing.\n *\n * The glob is not a filter over declarations already known — it is *how they\n * are found*, by importing what it matches. So a file it misses is a\n * declaration that does not exist, and every symptom of that appears somewhere\n * other than the cause: no container starts, no env key is written, and the\n * application fails on first use against a resource it can see in its own\n * source.\n *\n * Nothing reported it before, because an unmatched file is indistinguishable\n * from a file nobody wrote. These two cases are the ones that are *not*\n * ambiguous — a glob was configured, so something was expected.\n *\n * Silent when no glob is configured at all: that is a project which has not\n * adopted constructs, and has nothing to be missing.\n */\nfunction warnIfNothingFound(\n\tglobs: readonly string[],\n\tmatched: number,\n\tdeclared: number,\n): void {\n\tif (globs.length === 0) return;\n\n\tif (matched === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched no files, so nothing was declared.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Nothing will be provisioned — no containers, no env keys, no ` +\n\t\t\t\t`resources.\\n` +\n\t\t\t\t` A common cause is depth: '*.ts' matches one level, '**/*.ts' ` +\n\t\t\t\t`matches any.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (declared === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched ${matched} file(s) but none declared ` +\n\t\t\t\t`anything.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Discovery keeps exports with an 'id' that can 'declare()'. A ` +\n\t\t\t\t`construct that is\\n` +\n\t\t\t\t` built but never exported is invisible to it.`,\n\t\t);\n\t}\n}\n\n/** Two constructs claiming one id. */\nexport class DuplicateConstruct extends Error {\n\t/** The id claimed twice. */\n\treadonly id: string;\n\t/** The files that claimed it. */\n\treadonly sources: readonly string[];\n\n\tconstructor(id: string, sources: readonly string[]) {\n\t\tsuper('Two constructs declare the same id');\n\t\tthis.name = 'DuplicateConstruct';\n\t\tthis.id = id;\n\t\tthis.sources = sources;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mjs";
|
|
2
|
-
import { relative } from "node:path";
|
|
3
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
-
import { format } from "node:util";
|
|
5
|
-
import { assertDerivations, canonicalId } from "@geekmidas/manifest";
|
|
6
|
-
import fg from "fast-glob";
|
|
7
|
-
import kebabCase$1 from "lodash.kebabcase";
|
|
8
|
-
//#region src/output.ts
|
|
9
|
-
/**
|
|
10
|
-
* Where the CLI's progress lines go.
|
|
11
|
-
*
|
|
12
|
-
* Commands write their progress through `output` rather than `console`. Run
|
|
13
|
-
* from the terminal that is the same thing. Run inside `deploy()`, each line
|
|
14
|
-
* goes to the run that wrote it instead — as an event its caller can iterate,
|
|
15
|
-
* and to the logger it was handed — so a deploy embedded in another program
|
|
16
|
-
* does not print over that program's own output.
|
|
17
|
-
*
|
|
18
|
-
* Carried by `AsyncLocalStorage` rather than passed down, because the lines
|
|
19
|
-
* come from everywhere a deploy reaches — the Dockerfile generator, the env
|
|
20
|
-
* sniffer, construct discovery — and two deploys running in one process must
|
|
21
|
-
* not hear each other.
|
|
22
|
-
*/
|
|
23
|
-
const current = new AsyncLocalStorage();
|
|
24
|
-
/** Runs `fn` with every line written through `output` sent to `sink`. */
|
|
25
|
-
function withOutput(sink, fn) {
|
|
26
|
-
return current.run(sink, fn);
|
|
27
|
-
}
|
|
28
|
-
function write(level, fallback) {
|
|
29
|
-
return (...args) => {
|
|
30
|
-
const sink = current.getStore();
|
|
31
|
-
if (sink) sink(level, format(...args));
|
|
32
|
-
else fallback(...args);
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* `console`, for the methods the CLI logs through — routed to the current
|
|
37
|
-
* run's sink when there is one.
|
|
38
|
-
*/
|
|
39
|
-
const output = {
|
|
40
|
-
log: write("info", (...args) => console.log(...args)),
|
|
41
|
-
info: write("info", (...args) => console.info(...args)),
|
|
42
|
-
warn: write("warn", (...args) => console.warn(...args)),
|
|
43
|
-
error: write("error", (...args) => console.error(...args))
|
|
44
|
-
};
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/generators/Generator.ts
|
|
47
|
-
/**
|
|
48
|
-
* Zod v4 maintains a process-wide registry of schemas registered via
|
|
49
|
-
* `.meta({ id })`. When we cache-bust user module imports (by appending a
|
|
50
|
-
* `?t=timestamp` query), those modules re-execute and try to register the
|
|
51
|
-
* same ids again, which throws `ID X already exists in the registry`.
|
|
52
|
-
*
|
|
53
|
-
* Clearing the registry in the CLI process is safe: the user's running
|
|
54
|
-
* server lives in a subprocess and has its own isolated registry.
|
|
55
|
-
*
|
|
56
|
-
* Exported for tests.
|
|
57
|
-
*/
|
|
58
|
-
function clearZodGlobalRegistry() {
|
|
59
|
-
const registry = globalThis.__zod_globalRegistry;
|
|
60
|
-
if (registry && typeof registry.clear === "function") registry.clear();
|
|
61
|
-
}
|
|
62
|
-
var ConstructGenerator = class {
|
|
63
|
-
static async build(context, outputDir, generator, patterns, options) {
|
|
64
|
-
const constructs = await generator.load(patterns);
|
|
65
|
-
return generator.build(context, constructs, outputDir, options);
|
|
66
|
-
}
|
|
67
|
-
async load(patterns, cwd = process.cwd(), bustCache = false) {
|
|
68
|
-
const logger = console;
|
|
69
|
-
const globPatterns = Array.isArray(patterns) ? patterns : patterns ? [patterns] : [];
|
|
70
|
-
const files = fg.stream(globPatterns, {
|
|
71
|
-
cwd,
|
|
72
|
-
absolute: true
|
|
73
|
-
});
|
|
74
|
-
if (bustCache) clearZodGlobalRegistry();
|
|
75
|
-
const constructs = [];
|
|
76
|
-
for await (const f of files) try {
|
|
77
|
-
const file = f.toString();
|
|
78
|
-
const module = await (bustCache ? import(`${file}?t=${Date.now()}`) : import(file));
|
|
79
|
-
for (const [key, construct] of Object.entries(module)) if (this.isConstruct(construct)) constructs.push({
|
|
80
|
-
key,
|
|
81
|
-
name: kebabCase$1(key),
|
|
82
|
-
construct,
|
|
83
|
-
path: {
|
|
84
|
-
absolute: file,
|
|
85
|
-
relative: relative(process.cwd(), file)
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
} catch (error) {
|
|
89
|
-
const err = error;
|
|
90
|
-
logger.error(`Failed to load ${f}: ${err.message}`);
|
|
91
|
-
if (err.stack) logger.error(err.stack);
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
return constructs;
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
//#endregion
|
|
98
|
-
//#region src/reconcile/discover.ts
|
|
99
|
-
/**
|
|
100
|
-
* Discovery — one glob, one structural test.
|
|
101
|
-
*
|
|
102
|
-
* A glob per kind is the same specialness the construct model removes, and
|
|
103
|
-
* resources have no kind to be listed under: a declared `ObjectStorage` would
|
|
104
|
-
* never be found by `routes:` or `crons:`. So there is one `constructs` glob,
|
|
105
|
-
* every export of every matching module is inspected, and the per-kind
|
|
106
|
-
* `isConstruct` checks collapse into a single question — does it have an id and
|
|
107
|
-
* can it declare?
|
|
108
|
-
*
|
|
109
|
-
* Structural rather than `instanceof` on purpose. A construct from a different
|
|
110
|
-
* copy of `@geekmidas/constructs` — a linked workspace, two versions in a
|
|
111
|
-
* lockfile — is still a construct, and `instanceof` is exactly the check that
|
|
112
|
-
* says otherwise.
|
|
113
|
-
*/
|
|
114
|
-
var discover_exports = /* @__PURE__ */ __exportAll({
|
|
115
|
-
DuplicateConstruct: () => DuplicateConstruct,
|
|
116
|
-
discover: () => discover,
|
|
117
|
-
isDeclarable: () => isDeclarable
|
|
118
|
-
});
|
|
119
|
-
/** `console`, or the deploy run discovering the manifest. */
|
|
120
|
-
const logger = output;
|
|
121
|
-
/**
|
|
122
|
-
* Whether a module export is a construct.
|
|
123
|
-
*
|
|
124
|
-
* Deliberately loose about what else it carries — a construct that also has a
|
|
125
|
-
* `service` is still a construct, and requiring one would exclude the kinds that
|
|
126
|
-
* own no address.
|
|
127
|
-
*/
|
|
128
|
-
function isDeclarable(value) {
|
|
129
|
-
if (typeof value !== "object" || value === null) return false;
|
|
130
|
-
const candidate = value;
|
|
131
|
-
return typeof candidate.id === "string" && candidate.id.length > 0 && typeof candidate.declare === "function";
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Build the construct manifest for a project.
|
|
135
|
-
*
|
|
136
|
-
* Runs the manifest's own validation before returning, so an app is wrong here
|
|
137
|
-
* — where the error names a file — rather than at deploy.
|
|
138
|
-
*
|
|
139
|
-
* @throws {DuplicateConstruct} when two exports claim one id.
|
|
140
|
-
*/
|
|
141
|
-
async function discover(options) {
|
|
142
|
-
const { patterns, cwd = process.cwd(), bustCache = false, sources: out } = options;
|
|
143
|
-
if (bustCache) clearZodGlobalRegistry();
|
|
144
|
-
const manifest = {};
|
|
145
|
-
/** Which file declared each id, for the error when two of them do. */
|
|
146
|
-
const sources = {};
|
|
147
|
-
/**
|
|
148
|
-
* Constructs already seen, by identity.
|
|
149
|
-
*
|
|
150
|
-
* A re-export is the *same object* reached through a second file — ESM
|
|
151
|
-
* bindings are live, so `export * from './database.js'` hands back the
|
|
152
|
-
* binding rather than a copy. Without this, a barrel file made every
|
|
153
|
-
* construct in it appear declared twice, and `constructs/index.ts` is the
|
|
154
|
-
* first thing anyone writes in a shared folder.
|
|
155
|
-
*
|
|
156
|
-
* Identity rather than file is also the more honest rule: what may not
|
|
157
|
-
* happen twice is two *different* constructs claiming one id, and that is
|
|
158
|
-
* still an error below.
|
|
159
|
-
*/
|
|
160
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
161
|
-
const globs = Array.isArray(patterns) ? [...patterns] : [patterns];
|
|
162
|
-
const files = fg.stream(globs, {
|
|
163
|
-
cwd,
|
|
164
|
-
absolute: true
|
|
165
|
-
});
|
|
166
|
-
/** Matched files, for the diagnostic below. */
|
|
167
|
-
let matched = 0;
|
|
168
|
-
for await (const found of files) {
|
|
169
|
-
matched++;
|
|
170
|
-
const file = found.toString();
|
|
171
|
-
const module = await (bustCache ? import(`${file}?t=${Date.now()}`) : import(file));
|
|
172
|
-
for (const [exportName, exported] of Object.entries(module)) {
|
|
173
|
-
if (!isDeclarable(exported)) {
|
|
174
|
-
if (options.runnables) recordRunnable(options.runnables, exported);
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
if (seen.has(exported)) continue;
|
|
178
|
-
seen.add(exported);
|
|
179
|
-
if (options.runnables && typeof exported.owner === "string") recordRunnable(options.runnables, exported);
|
|
180
|
-
for (const declaration of exported.declare()) {
|
|
181
|
-
const id = canonicalId(declaration.id);
|
|
182
|
-
const source = relative(cwd, file);
|
|
183
|
-
const claimed = sources[id];
|
|
184
|
-
if (claimed !== void 0 && claimed !== source) throw new DuplicateConstruct(id, [claimed, source]);
|
|
185
|
-
manifest[id] = {
|
|
186
|
-
...declaration,
|
|
187
|
-
id
|
|
188
|
-
};
|
|
189
|
-
sources[id] = source;
|
|
190
|
-
if (out) out[id] = {
|
|
191
|
-
file,
|
|
192
|
-
exportName,
|
|
193
|
-
construct: exported
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
assertDerivations(manifest);
|
|
199
|
-
warnIfNothingFound(globs, matched, Object.keys(manifest).length);
|
|
200
|
-
return manifest;
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Record a runnable's edges under the construct that owns it — the surface an
|
|
204
|
-
* endpoint was built from, or the worker a cron or subscriber was. Anything
|
|
205
|
-
* with no owner, or that is not a runnable at all, is left alone.
|
|
206
|
-
*/
|
|
207
|
-
function recordRunnable(runnables, exported) {
|
|
208
|
-
if (typeof exported !== "object" || exported === null) return;
|
|
209
|
-
const runnable = exported;
|
|
210
|
-
const owner = typeof runnable.surface?.id === "string" ? runnable.surface.id : typeof runnable.owner === "string" ? runnable.owner : void 0;
|
|
211
|
-
if (!owner || !Array.isArray(runnable.constructs)) return;
|
|
212
|
-
const key = canonicalId(owner);
|
|
213
|
-
const edges = runnables[key] ?? [];
|
|
214
|
-
runnables[key] = edges;
|
|
215
|
-
for (const id of runnable.constructs) {
|
|
216
|
-
if (typeof id !== "string") continue;
|
|
217
|
-
const target = canonicalId(id);
|
|
218
|
-
if (!edges.includes(target)) edges.push(target);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Say so when a glob was configured and found nothing.
|
|
223
|
-
*
|
|
224
|
-
* The glob is not a filter over declarations already known — it is *how they
|
|
225
|
-
* are found*, by importing what it matches. So a file it misses is a
|
|
226
|
-
* declaration that does not exist, and every symptom of that appears somewhere
|
|
227
|
-
* other than the cause: no container starts, no env key is written, and the
|
|
228
|
-
* application fails on first use against a resource it can see in its own
|
|
229
|
-
* source.
|
|
230
|
-
*
|
|
231
|
-
* Nothing reported it before, because an unmatched file is indistinguishable
|
|
232
|
-
* from a file nobody wrote. These two cases are the ones that are *not*
|
|
233
|
-
* ambiguous — a glob was configured, so something was expected.
|
|
234
|
-
*
|
|
235
|
-
* Silent when no glob is configured at all: that is a project which has not
|
|
236
|
-
* adopted constructs, and has nothing to be missing.
|
|
237
|
-
*/
|
|
238
|
-
function warnIfNothingFound(globs, matched, declared) {
|
|
239
|
-
if (globs.length === 0) return;
|
|
240
|
-
if (matched === 0) {
|
|
241
|
-
logger.warn(`\n⚠️ The constructs glob matched no files, so nothing was declared.\n Patterns: ${globs.join(", ")}\n Nothing will be provisioned — no containers, no env keys, no resources.\n A common cause is depth: '*.ts' matches one level, '**/*.ts' matches any.`);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (declared === 0) logger.warn(`\n⚠️ The constructs glob matched ${matched} file(s) but none declared anything.\n Patterns: ${globs.join(", ")}\n Discovery keeps exports with an 'id' that can 'declare()'. A construct that is\n built but never exported is invisible to it.`);
|
|
245
|
-
}
|
|
246
|
-
/** Two constructs claiming one id. */
|
|
247
|
-
var DuplicateConstruct = class extends Error {
|
|
248
|
-
/** The id claimed twice. */
|
|
249
|
-
id;
|
|
250
|
-
/** The files that claimed it. */
|
|
251
|
-
sources;
|
|
252
|
-
constructor(id, sources) {
|
|
253
|
-
super("Two constructs declare the same id");
|
|
254
|
-
this.name = "DuplicateConstruct";
|
|
255
|
-
this.id = id;
|
|
256
|
-
this.sources = sources;
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
//#endregion
|
|
260
|
-
export { output as a, ConstructGenerator as i, discover_exports as n, withOutput as o, isDeclarable as r, discover as t };
|
|
261
|
-
|
|
262
|
-
//# sourceMappingURL=discover-FrYvzkeC.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discover-FrYvzkeC.mjs","names":["kebabCase"],"sources":["../src/output.ts","../src/generators/Generator.ts","../src/reconcile/discover.ts"],"sourcesContent":["/**\n * Where the CLI's progress lines go.\n *\n * Commands write their progress through `output` rather than `console`. Run\n * from the terminal that is the same thing. Run inside `deploy()`, each line\n * goes to the run that wrote it instead — as an event its caller can iterate,\n * and to the logger it was handed — so a deploy embedded in another program\n * does not print over that program's own output.\n *\n * Carried by `AsyncLocalStorage` rather than passed down, because the lines\n * come from everywhere a deploy reaches — the Dockerfile generator, the env\n * sniffer, construct discovery — and two deploys running in one process must\n * not hear each other.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { format } from 'node:util';\n\n/** How loud a line is. */\nexport type OutputLevel = 'info' | 'warn' | 'error';\n\n/** Receives each line written while it is the current sink. */\nexport type OutputSink = (level: OutputLevel, message: string) => void;\n\nconst current = new AsyncLocalStorage<OutputSink>();\n\n/** Runs `fn` with every line written through `output` sent to `sink`. */\nexport function withOutput<T>(sink: OutputSink, fn: () => T): T {\n\treturn current.run(sink, fn);\n}\n\nfunction write(\n\tlevel: OutputLevel,\n\tfallback: (...args: unknown[]) => void,\n): (...args: unknown[]) => void {\n\treturn (...args) => {\n\t\tconst sink = current.getStore();\n\t\tif (sink) sink(level, format(...args));\n\t\telse fallback(...args);\n\t};\n}\n\n/**\n * `console`, for the methods the CLI logs through — routed to the current\n * run's sink when there is one.\n */\nexport const output = {\n\tlog: write('info', (...args) => console.log(...args)),\n\tinfo: write('info', (...args) => console.info(...args)),\n\twarn: write('warn', (...args) => console.warn(...args)),\n\terror: write('error', (...args) => console.error(...args)),\n};\n","import { relative } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\nimport fg from 'fast-glob';\nimport kebabCase from 'lodash.kebabcase';\nimport type { BuildContext } from '../build/types';\nimport type { MainProvider, Routes } from '../types';\n\n/**\n * Zod v4 maintains a process-wide registry of schemas registered via\n * `.meta({ id })`. When we cache-bust user module imports (by appending a\n * `?t=timestamp` query), those modules re-execute and try to register the\n * same ids again, which throws `ID X already exists in the registry`.\n *\n * Clearing the registry in the CLI process is safe: the user's running\n * server lives in a subprocess and has its own isolated registry.\n *\n * Exported for tests.\n */\nexport function clearZodGlobalRegistry(): void {\n\tconst registry = (\n\t\tglobalThis as { __zod_globalRegistry?: { clear?: () => void } }\n\t).__zod_globalRegistry;\n\tif (registry && typeof registry.clear === 'function') {\n\t\tregistry.clear();\n\t}\n}\n\nexport interface GeneratorOptions {\n\t/** Where the build deploys: one Lambda per construct, or one process. */\n\ttarget?: MainProvider;\n\t/**\n\t * What a handler path in the manifest is relative to — the workspace root,\n\t * which is where `sst.config.ts` runs and resolves it from.\n\t */\n\troot?: string;\n\t[key: string]: any;\n}\n\nexport abstract class ConstructGenerator<T extends Construct, R = void> {\n\tabstract isConstruct(value: any): value is T;\n\n\tstatic async build<T extends Construct, R = void>(\n\t\tcontext: BuildContext,\n\t\toutputDir: string,\n\t\tgenerator: ConstructGenerator<T, R>,\n\t\tpatterns?: Routes,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R> {\n\t\tconst constructs = await generator.load(patterns);\n\t\treturn generator.build(context, constructs, outputDir, options);\n\t}\n\n\tabstract build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<T>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<R>;\n\n\tasync load(\n\t\tpatterns?: Routes,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t): Promise<GeneratedConstruct<T>[]> {\n\t\tconst logger = console;\n\n\t\tconst globPatterns = Array.isArray(patterns)\n\t\t\t? patterns\n\t\t\t: patterns\n\t\t\t\t? [patterns]\n\t\t\t\t: [];\n\n\t\t// Find all files\n\t\tconst files = fg.stream(globPatterns, {\n\t\t\tcwd,\n\t\t\tabsolute: true,\n\t\t});\n\n\t\t// Cache-busted re-imports re-execute user modules, which would try to\n\t\t// re-register Zod schemas with the same `.meta({ id })`. Clear the\n\t\t// global registry once per load to prevent duplicate-id errors.\n\t\tif (bustCache) {\n\t\t\tclearZodGlobalRegistry();\n\t\t}\n\n\t\t// Load constructs\n\t\tconst constructs: GeneratedConstruct<T>[] = [];\n\n\t\tfor await (const f of files) {\n\t\t\ttry {\n\t\t\t\tconst file = f.toString();\n\t\t\t\t// Append cache-busting query param to force re-import of changed modules\n\t\t\t\tconst importPath = bustCache ? `${file}?t=${Date.now()}` : file;\n\t\t\t\tconst module = await import(importPath);\n\n\t\t\t\t// Check all exports for constructs\n\t\t\t\tfor (const [key, construct] of Object.entries(module)) {\n\t\t\t\t\tif (this.isConstruct(construct)) {\n\t\t\t\t\t\tconstructs.push({\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\tname: kebabCase(key),\n\t\t\t\t\t\t\tconstruct,\n\t\t\t\t\t\t\tpath: {\n\t\t\t\t\t\t\t\tabsolute: file,\n\t\t\t\t\t\t\t\trelative: relative(process.cwd(), file),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tlogger.error(`Failed to load ${f}: ${err.message}`);\n\t\t\t\tif (err.stack) {\n\t\t\t\t\tlogger.error(err.stack);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn constructs;\n\t}\n}\n\nexport interface GeneratedConstruct<T extends Construct> {\n\tkey: string;\n\tname: string;\n\tconstruct: T;\n\tpath: {\n\t\tabsolute: string;\n\t\trelative: string;\n\t};\n}\n","/**\n * Discovery — one glob, one structural test.\n *\n * A glob per kind is the same specialness the construct model removes, and\n * resources have no kind to be listed under: a declared `ObjectStorage` would\n * never be found by `routes:` or `crons:`. So there is one `constructs` glob,\n * every export of every matching module is inspected, and the per-kind\n * `isConstruct` checks collapse into a single question — does it have an id and\n * can it declare?\n *\n * Structural rather than `instanceof` on purpose. A construct from a different\n * copy of `@geekmidas/constructs` — a linked workspace, two versions in a\n * lockfile — is still a construct, and `instanceof` is exactly the check that\n * says otherwise.\n */\n\nimport { relative } from 'node:path';\nimport {\n\tassertDerivations,\n\ttype ConstructManifest,\n\tcanonicalId,\n\ttype Declaration,\n} from '@geekmidas/manifest';\nimport fg from 'fast-glob';\nimport { clearZodGlobalRegistry } from '../generators/Generator';\nimport { output } from '../output';\n\n/** `console`, or the deploy run discovering the manifest. */\nconst logger = output;\n\n/** The construct face discovery needs: an id, and the ability to declare. */\ninterface Declarable {\n\tid: string;\n\tdeclare(): Declaration[];\n}\n\n/**\n * Whether a module export is a construct.\n *\n * Deliberately loose about what else it carries — a construct that also has a\n * `service` is still a construct, and requiring one would exclude the kinds that\n * own no address.\n */\nexport function isDeclarable(value: unknown): value is Declarable {\n\tif (typeof value !== 'object' || value === null) return false;\n\n\tconst candidate = value as Partial<Declarable>;\n\n\treturn (\n\t\ttypeof candidate.id === 'string' &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.declare === 'function'\n\t);\n}\n\nexport interface DiscoverOptions {\n\t/** The glob(s) to search. One pattern, not one per kind. */\n\tpatterns: string | readonly string[];\n\tcwd?: string;\n\t/**\n\t * Re-import changed modules, for the dev watcher.\n\t *\n\t * A single glob makes discovery more central, not less: a new construct file\n\t * has to be picked up on `add`, not only on `change`.\n\t */\n\tbustCache?: boolean;\n\t/**\n\t * Filled in with where each construct was found, when provided.\n\t *\n\t * Discovery is the only thing that knows: it globbed the files and imported\n\t * them. Everything downstream that needs to *write* an import — the build,\n\t * generating a server entry that reads a surface's logger — would otherwise\n\t * have to be told the path in config, which is the string this removes.\n\t *\n\t * An out-parameter rather than a second return value so that every existing\n\t * caller, which wants the manifest and nothing else, is unchanged.\n\t */\n\tsources?: Record<string, ConstructSource>;\n\t/**\n\t * Filled in, when provided, with the ids each owner's runnables declared an\n\t * edge to — keyed by the surface an endpoint was built from, or the worker\n\t * a cron or subscriber was.\n\t *\n\t * A runnable is not a declaration: a surface's endpoints are found by the\n\t * glob, not listed by the surface, so its node says `endpoints: []` until a\n\t * build folds the routes in. Anything deciding what an app's process reaches\n\t * — which keys its container is given — needs those edges before any build,\n\t * and discovery is already importing the files they are in.\n\t */\n\trunnables?: Record<string, string[]>;\n}\n\n/** Where a construct was declared, and under what name. */\nexport interface ConstructSource {\n\t/** Absolute path to the module that exported it. */\n\tfile: string;\n\t/** The name it was exported as — what an import statement has to say. */\n\texportName: string;\n\t/**\n\t * The exported construct itself.\n\t *\n\t * What a declaration cannot say — whether it serves itself — the object can\n\t * be asked, and discovery already imported it.\n\t */\n\tconstruct: unknown;\n}\n\n/**\n * Build the construct manifest for a project.\n *\n * Runs the manifest's own validation before returning, so an app is wrong here\n * — where the error names a file — rather than at deploy.\n *\n * @throws {DuplicateConstruct} when two exports claim one id.\n */\nexport async function discover(\n\toptions: DiscoverOptions,\n): Promise<ConstructManifest> {\n\tconst {\n\t\tpatterns,\n\t\tcwd = process.cwd(),\n\t\tbustCache = false,\n\t\tsources: out,\n\t} = options;\n\n\t// Re-importing user modules re-executes them, and Zod v4 throws on a\n\t// re-registered `.meta({ id })`. Same reason the generators clear it.\n\tif (bustCache) clearZodGlobalRegistry();\n\n\tconst manifest: Record<string, Declaration> = {};\n\t/** Which file declared each id, for the error when two of them do. */\n\tconst sources: Record<string, string> = {};\n\t/**\n\t * Constructs already seen, by identity.\n\t *\n\t * A re-export is the *same object* reached through a second file — ESM\n\t * bindings are live, so `export * from './database.js'` hands back the\n\t * binding rather than a copy. Without this, a barrel file made every\n\t * construct in it appear declared twice, and `constructs/index.ts` is the\n\t * first thing anyone writes in a shared folder.\n\t *\n\t * Identity rather than file is also the more honest rule: what may not\n\t * happen twice is two *different* constructs claiming one id, and that is\n\t * still an error below.\n\t */\n\tconst seen = new WeakSet<object>();\n\n\tconst globs = Array.isArray(patterns) ? [...patterns] : [patterns as string];\n\tconst files = fg.stream(globs, { cwd, absolute: true });\n\n\t/** Matched files, for the diagnostic below. */\n\tlet matched = 0;\n\n\tfor await (const found of files) {\n\t\tmatched++;\n\t\tconst file = found.toString();\n\t\tconst module = await import(bustCache ? `${file}?t=${Date.now()}` : file);\n\n\t\tfor (const [exportName, exported] of Object.entries(module)) {\n\t\t\tif (!isDeclarable(exported)) {\n\t\t\t\tif (options.runnables) recordRunnable(options.runnables, exported);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// The same construct, reached again through a re-export. Skipped\n\t\t\t// rather than re-declared: it has already claimed its id, from the\n\t\t\t// file that defined it.\n\t\t\tif (seen.has(exported as object)) continue;\n\t\t\tseen.add(exported as object);\n\n\t\t\t// A construct that is also something a process runs — a queue and its\n\t\t\t// consumer, built from a worker — reaches what it depends on through\n\t\t\t// that process, exactly as an endpoint or a cron does.\n\t\t\tif (\n\t\t\t\toptions.runnables &&\n\t\t\t\ttypeof (exported as { owner?: unknown }).owner === 'string'\n\t\t\t) {\n\t\t\t\trecordRunnable(options.runnables, exported);\n\t\t\t}\n\n\t\t\tfor (const declaration of exported.declare()) {\n\t\t\t\t// Canonicalise here too: a construct built by hand rather than through\n\t\t\t\t// a constructor is still subject to the same identity rule.\n\t\t\t\tconst id = canonicalId(declaration.id);\n\t\t\t\tconst source = relative(cwd, file);\n\n\t\t\t\tconst claimed = sources[id];\n\t\t\t\tif (claimed !== undefined && claimed !== source) {\n\t\t\t\t\tthrow new DuplicateConstruct(id, [claimed, source]);\n\t\t\t\t}\n\n\t\t\t\tmanifest[id] = { ...declaration, id };\n\t\t\t\tsources[id] = source;\n\t\t\t\tif (out) out[id] = { file, exportName, construct: exported };\n\t\t\t}\n\t\t}\n\t}\n\n\t// Reference integrity before anyone reads it — a schema tenant naming a\n\t// database that was deleted is a manifest error, not a reconcile failure.\n\tassertDerivations(manifest);\n\n\twarnIfNothingFound(globs, matched, Object.keys(manifest).length);\n\n\treturn manifest;\n}\n\n/**\n * Record a runnable's edges under the construct that owns it — the surface an\n * endpoint was built from, or the worker a cron or subscriber was. Anything\n * with no owner, or that is not a runnable at all, is left alone.\n */\nfunction recordRunnable(\n\trunnables: Record<string, string[]>,\n\texported: unknown,\n): void {\n\tif (typeof exported !== 'object' || exported === null) return;\n\n\tconst runnable = exported as {\n\t\tsurface?: { id?: unknown };\n\t\towner?: unknown;\n\t\tconstructs?: unknown;\n\t};\n\tconst owner =\n\t\ttypeof runnable.surface?.id === 'string'\n\t\t\t? runnable.surface.id\n\t\t\t: typeof runnable.owner === 'string'\n\t\t\t\t? runnable.owner\n\t\t\t\t: undefined;\n\tif (!owner || !Array.isArray(runnable.constructs)) return;\n\n\tconst key = canonicalId(owner);\n\tconst edges = runnables[key] ?? [];\n\trunnables[key] = edges;\n\tfor (const id of runnable.constructs) {\n\t\tif (typeof id !== 'string') continue;\n\t\tconst target = canonicalId(id);\n\t\tif (!edges.includes(target)) edges.push(target);\n\t}\n}\n\n/**\n * Say so when a glob was configured and found nothing.\n *\n * The glob is not a filter over declarations already known — it is *how they\n * are found*, by importing what it matches. So a file it misses is a\n * declaration that does not exist, and every symptom of that appears somewhere\n * other than the cause: no container starts, no env key is written, and the\n * application fails on first use against a resource it can see in its own\n * source.\n *\n * Nothing reported it before, because an unmatched file is indistinguishable\n * from a file nobody wrote. These two cases are the ones that are *not*\n * ambiguous — a glob was configured, so something was expected.\n *\n * Silent when no glob is configured at all: that is a project which has not\n * adopted constructs, and has nothing to be missing.\n */\nfunction warnIfNothingFound(\n\tglobs: readonly string[],\n\tmatched: number,\n\tdeclared: number,\n): void {\n\tif (globs.length === 0) return;\n\n\tif (matched === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched no files, so nothing was declared.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Nothing will be provisioned — no containers, no env keys, no ` +\n\t\t\t\t`resources.\\n` +\n\t\t\t\t` A common cause is depth: '*.ts' matches one level, '**/*.ts' ` +\n\t\t\t\t`matches any.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (declared === 0) {\n\t\tlogger.warn(\n\t\t\t`\\n⚠️ The constructs glob matched ${matched} file(s) but none declared ` +\n\t\t\t\t`anything.\\n` +\n\t\t\t\t` Patterns: ${globs.join(', ')}\\n` +\n\t\t\t\t` Discovery keeps exports with an 'id' that can 'declare()'. A ` +\n\t\t\t\t`construct that is\\n` +\n\t\t\t\t` built but never exported is invisible to it.`,\n\t\t);\n\t}\n}\n\n/** Two constructs claiming one id. */\nexport class DuplicateConstruct extends Error {\n\t/** The id claimed twice. */\n\treadonly id: string;\n\t/** The files that claimed it. */\n\treadonly sources: readonly string[];\n\n\tconstructor(id: string, sources: readonly string[]) {\n\t\tsuper('Two constructs declare the same id');\n\t\tthis.name = 'DuplicateConstruct';\n\t\tthis.id = id;\n\t\tthis.sources = sources;\n\t}\n}\n"],"mappings":"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"}
|