@zenbujs/core 0.0.8 → 0.0.12
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/dist/advice-config-BiYhyeTz.d.mts +41 -0
- package/dist/advice.d.mts +2 -36
- package/dist/advice.mjs +2 -2
- package/dist/{base-window-BxBZ2md_.mjs → base-window-4P-fVvC_.mjs} +37 -26
- package/dist/{build-config-Dzg2frpk.d.mts → build-config-GF0XzR_Y.d.mts} +42 -18
- package/dist/{build-config-pWdmLnrk.mjs → build-config-HMMqpXI1.mjs} +0 -8
- package/dist/{build-electron-Dsbb1EMl.mjs → build-electron-Di_FE62r.mjs} +10 -6
- package/dist/{build-source-d1J3shV8.mjs → build-source-BIaWpaxE.mjs} +2 -2
- package/dist/cli/bin.mjs +7 -7
- package/dist/cli/build.d.mts +1 -1
- package/dist/cli/build.mjs +1 -1
- package/dist/cli/resolve-config.mjs +6 -1
- package/dist/{cli-kL6mPgBE.mjs → cli-5jFDJWM4.mjs} +4 -4
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +2 -2
- package/dist/{db-Bc292RYo.mjs → db-MkOccvBS.mjs} +2 -2
- package/dist/db.d.mts +3 -2
- package/dist/db.mjs +2 -10
- package/dist/{dev-B2emj0HZ.mjs → dev-BSDyzO4j.mjs} +3 -9
- package/dist/env-bootstrap.d.mts +1 -1
- package/dist/events.d.mts +0 -9
- package/dist/{host-version-BIrF8tX7.mjs → host-version-Cog_odmD.mjs} +4 -3
- package/dist/{index-w5QyDjuf.d.mts → index-C0mXKol5.d.mts} +189 -141
- package/dist/{index-DeDxePAa.d.mts → index-FaexRVl_.d.mts} +13 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -2
- package/dist/launcher.mjs +64 -6
- package/dist/link-Bt3LB_NW.mjs +586 -0
- package/dist/{load-config-C4Oe2qZO.mjs → load-config-C2XloBaQ.mjs} +68 -5
- package/dist/node-loader.mjs +1 -1
- package/dist/{publish-source-Dq2c0iOw.mjs → publish-source-v93eB9kA.mjs} +6 -2
- package/dist/react.d.mts +6 -6
- package/dist/react.mjs +4 -4
- package/dist/registry-generated.d.mts +19 -14
- package/dist/registry-saQDMUhT.d.mts +13 -0
- package/dist/registry.d.mts +1 -1
- package/dist/{reloader-B22UiNA2.mjs → reloader-CFzxYa67.mjs} +3 -3
- package/dist/{renderer-host-DD16MXhI.mjs → renderer-host-Cw38dSDe.mjs} +35 -24
- package/dist/{rpc-C4_NQmpT.mjs → rpc-Dg9zwZ33.mjs} +4 -4
- package/dist/rpc.d.mts +1 -1
- package/dist/rpc.mjs +1 -1
- package/dist/runtime-DYUONc3S.mjs +861 -0
- package/dist/{runtime-BQWntcOb.d.mts → runtime-fnPDZFYM.d.mts} +100 -3
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.mjs +2 -578
- package/dist/{schema-CjrMVk36.d.mts → schema-brYpUjYO.d.mts} +13 -25
- package/dist/schema.d.mts +2 -2
- package/dist/schema.mjs +9 -2
- package/dist/{server-CZLMF8Dj.mjs → server-BJ2ZC2z2.mjs} +2 -2
- package/dist/services/default.d.mts +1 -5
- package/dist/services/default.mjs +12 -16
- package/dist/services/index.d.mts +1 -1
- package/dist/services/index.mjs +7 -7
- package/dist/setup-gate.d.mts +1 -1
- package/dist/setup-gate.mjs +25 -11
- package/dist/{transport-F2hv_OEm.mjs → transport-Bqlv9pmJ.mjs} +1 -1
- package/dist/updater-Bs1Jtem6.mjs +480 -0
- package/dist/{vite-plugins-tt6KAtyE.mjs → vite-plugins-Df-cfldF.mjs} +2 -49
- package/dist/vite.d.mts +0 -5
- package/dist/vite.mjs +1 -1
- package/dist/{window-YFKvAM0l.mjs → window-DgB70qeZ.mjs} +113 -22
- package/dist/{write-DgIRjo23.mjs → write-7IfKa_nq.mjs} +1 -1
- package/dist/zenbu-bg-parse-CIyPkJOY.mjs +46 -0
- package/package.json +19 -18
- package/LICENSE +0 -11
- package/dist/advice-config-DXSIo0sg.mjs +0 -154
- package/dist/link-glX89NV5.mjs +0 -673
- package/dist/registry-CMp8FYgS.d.mts +0 -47
- package/dist/updater-DCkz9M1c.mjs +0 -1008
- /package/dist/{config-BK78JDRI.mjs → config-DfciRzDu.mjs} +0 -0
- /package/dist/{env-bootstrap-rTs8KR3-.d.mts → env-bootstrap-UBug-4Kw.d.mts} +0 -0
- /package/dist/{index-C-ALz_SH.d.mts → index-CSMHYi3u.d.mts} +0 -0
- /package/dist/{index-ClXLQ1fw.d.mts → index-DJOHDG5e.d.mts} +0 -0
- /package/dist/{log-6rzaCV0I.mjs → log-BkRqDwwB.mjs} +0 -0
- /package/dist/{mirror-sync-pYU6f3-c.mjs → mirror-sync-snqh9kEp.mjs} +0 -0
- /package/dist/{monorepo-Dct-kkbQ.mjs → monorepo-CBzK3l2i.mjs} +0 -0
- /package/dist/{node-BhfLKYCi.mjs → node-BuHlEsE4.mjs} +0 -0
- /package/dist/{schema-Ca7SxXgS.mjs → schema-C6k0SroY.mjs} +0 -0
- /package/dist/{setup-gate-BQq0QgZH.d.mts → setup-gate-DkysEZQO.d.mts} +0 -0
- /package/dist/{src-Cven45mq.mjs → src-BpZAt9zL.mjs} +0 -0
- /package/dist/{trace-BaVg0rnY.mjs → trace-BVcQSD59.mjs} +0 -0
- /package/dist/{transform-BzrwkEdf.mjs → transform-czrcGnVV.mjs} +0 -0
package/dist/link-glX89NV5.mjs
DELETED
|
@@ -1,673 +0,0 @@
|
|
|
1
|
-
import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
|
|
2
|
-
import { t as loadConfig } from "./load-config-C4Oe2qZO.mjs";
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
//#region src/cli/commands/link.ts
|
|
6
|
-
var link_exports = /* @__PURE__ */ __exportAll({
|
|
7
|
-
linkProject: () => linkProject,
|
|
8
|
-
runLink: () => runLink
|
|
9
|
-
});
|
|
10
|
-
const CONFIG_NAMES = [
|
|
11
|
-
"zenbu.config.ts",
|
|
12
|
-
"zenbu.config.mts",
|
|
13
|
-
"zenbu.config.js",
|
|
14
|
-
"zenbu.config.mjs"
|
|
15
|
-
];
|
|
16
|
-
function findProjectDir(from) {
|
|
17
|
-
let dir = path.resolve(from);
|
|
18
|
-
while (true) {
|
|
19
|
-
for (const name of CONFIG_NAMES) if (fs.existsSync(path.join(dir, name))) return dir;
|
|
20
|
-
const parent = path.dirname(dir);
|
|
21
|
-
if (parent === dir) return null;
|
|
22
|
-
dir = parent;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function findFileUp(from, name) {
|
|
26
|
-
let dir = path.resolve(from);
|
|
27
|
-
while (true) {
|
|
28
|
-
const candidate = path.join(dir, name);
|
|
29
|
-
if (fs.existsSync(candidate)) return candidate;
|
|
30
|
-
const parent = path.dirname(dir);
|
|
31
|
-
if (parent === dir) return null;
|
|
32
|
-
dir = parent;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/** jsonc-lite: strips // and /* * / comments and trailing commas. */
|
|
36
|
-
function readJsonLoose(filePath) {
|
|
37
|
-
const stripped = fs.readFileSync(filePath, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,\s*([\]}])/g, "$1");
|
|
38
|
-
return JSON.parse(stripped);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Extract the `#registry/*` mapping from a tsconfig (typically a
|
|
42
|
-
* gitignored `tsconfig.local.json`) and return the absolute directory it
|
|
43
|
-
* resolves to. Returns null when the alias isn't declared.
|
|
44
|
-
*/
|
|
45
|
-
function readRegistryDirFromTsconfig(tsconfigPath) {
|
|
46
|
-
try {
|
|
47
|
-
const cfg = readJsonLoose(tsconfigPath);
|
|
48
|
-
const entry = cfg?.compilerOptions?.paths?.["#registry/*"];
|
|
49
|
-
if (!Array.isArray(entry) || typeof entry[0] !== "string") return null;
|
|
50
|
-
const trimmed = entry[0].replace(/\/\*$/, "");
|
|
51
|
-
const baseUrl = typeof cfg?.compilerOptions?.baseUrl === "string" ? path.resolve(path.dirname(tsconfigPath), cfg.compilerOptions.baseUrl) : path.dirname(tsconfigPath);
|
|
52
|
-
return path.resolve(baseUrl, trimmed);
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* An app root is the nearest ancestor (or self) that contains a
|
|
59
|
-
* `zenbu.config.ts` (or its .mts/.js/.mjs variants). That single file
|
|
60
|
-
* uniquely identifies a Zenbu project root.
|
|
61
|
-
*/
|
|
62
|
-
function findAppRoot(from) {
|
|
63
|
-
return findProjectDir(from);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Pick the directory `zen link` should write registry types into.
|
|
67
|
-
* Resolution order:
|
|
68
|
-
* 1. `--registry <dir>` flag / `ZENBU_REGISTRY_DIR` env (escape hatch)
|
|
69
|
-
* 2. Nearest `tsconfig.local.json` ancestor's `#registry/*` mapping
|
|
70
|
-
* (canonical — this is the same path TS uses to resolve the alias)
|
|
71
|
-
* 3. The manifest's `devAppPath` field (dev hint, fallback)
|
|
72
|
-
* 4. Walk up to the host app root and use `<app>/types`
|
|
73
|
-
* 5. Fail with a message that explains the available knobs
|
|
74
|
-
*/
|
|
75
|
-
function resolveRegistryDir(opts) {
|
|
76
|
-
if (opts.registryOverride) return path.resolve(opts.registryOverride);
|
|
77
|
-
if (process.env.ZENBU_REGISTRY_DIR) return path.resolve(process.env.ZENBU_REGISTRY_DIR);
|
|
78
|
-
const manifestDir = path.dirname(opts.manifestPath);
|
|
79
|
-
const tsconfigLocal = findFileUp(manifestDir, "tsconfig.local.json");
|
|
80
|
-
if (tsconfigLocal) {
|
|
81
|
-
const fromTs = readRegistryDirFromTsconfig(tsconfigLocal);
|
|
82
|
-
if (fromTs) return fromTs;
|
|
83
|
-
}
|
|
84
|
-
if (opts.manifest.devAppPath) return path.resolve(manifestDir, opts.manifest.devAppPath, "types");
|
|
85
|
-
const appRoot = findAppRoot(manifestDir);
|
|
86
|
-
if (appRoot) return path.join(appRoot, "types");
|
|
87
|
-
throw new Error(`zen link: could not determine target types directory for ${opts.manifestPath}.\n Try one of:\n - run from inside an app dir (with a zenbu.config.ts),\n - add a "devAppPath" field to ${path.basename(opts.manifestPath)} pointing at the host app,\n - create a tsconfig.local.json with a "#registry/*" path mapping,\n - or pass --registry <dir>.`);
|
|
88
|
-
}
|
|
89
|
-
function expandGlob(baseDir, pattern) {
|
|
90
|
-
if (!pattern.includes("*")) {
|
|
91
|
-
const full = path.resolve(baseDir, pattern);
|
|
92
|
-
return fs.existsSync(full) ? [full] : [];
|
|
93
|
-
}
|
|
94
|
-
const dir = path.resolve(baseDir, path.dirname(pattern));
|
|
95
|
-
const filePattern = path.basename(pattern);
|
|
96
|
-
const regex = new RegExp("^" + filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$");
|
|
97
|
-
try {
|
|
98
|
-
return fs.readdirSync(dir).filter((f) => regex.test(f)).map((f) => path.resolve(dir, f));
|
|
99
|
-
} catch {
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function discoverServices(baseDir, serviceGlobs) {
|
|
104
|
-
const entries = [];
|
|
105
|
-
const classKeyRe = /export\s+class\s+(\w+)\s+extends\s+Service\.create\s*\(\s*\{[\s\S]*?\bkey\s*:\s*["']([^"']+)["']/;
|
|
106
|
-
for (const glob of serviceGlobs) for (const filePath of expandGlob(baseDir, glob)) {
|
|
107
|
-
const match = fs.readFileSync(filePath, "utf8").match(classKeyRe);
|
|
108
|
-
if (match) entries.push({
|
|
109
|
-
className: match[1],
|
|
110
|
-
key: match[2],
|
|
111
|
-
filePath
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
return entries;
|
|
115
|
-
}
|
|
116
|
-
function relativeFromRegistry(registryDir, absPath) {
|
|
117
|
-
let rel = path.relative(registryDir, absPath);
|
|
118
|
-
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
119
|
-
return rel.replace(/\.ts$/, "");
|
|
120
|
-
}
|
|
121
|
-
const SERVICE_BASE_LITERAL = [
|
|
122
|
-
` | "evaluate"`,
|
|
123
|
-
` | "shutdown"`,
|
|
124
|
-
` | "constructor"`,
|
|
125
|
-
` | "effect"`,
|
|
126
|
-
` | "__cleanupAllEffects"`,
|
|
127
|
-
` | "__effectCleanups"`,
|
|
128
|
-
` | "ctx"`
|
|
129
|
-
].join("\n");
|
|
130
|
-
function generateServicesFile(registryDir, allServices) {
|
|
131
|
-
const imports = [];
|
|
132
|
-
const routerEntries = [];
|
|
133
|
-
const usedNames = /* @__PURE__ */ new Map();
|
|
134
|
-
function uniqueName(base) {
|
|
135
|
-
const count = usedNames.get(base) ?? 0;
|
|
136
|
-
usedNames.set(base, count + 1);
|
|
137
|
-
return count === 0 ? base : `${base}_${count}`;
|
|
138
|
-
}
|
|
139
|
-
for (const [, services] of allServices) for (const svc of services) {
|
|
140
|
-
const alias = uniqueName(svc.className);
|
|
141
|
-
const importPath = relativeFromRegistry(registryDir, svc.filePath);
|
|
142
|
-
imports.push(`import type { ${svc.className}${alias !== svc.className ? ` as ${alias}` : ""} } from "${importPath}"`);
|
|
143
|
-
const quotedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(svc.key) ? svc.key : `"${svc.key}"`;
|
|
144
|
-
routerEntries.push(` ${quotedKey}: ExtractRpcMethods<${alias}>`);
|
|
145
|
-
}
|
|
146
|
-
return [
|
|
147
|
-
"// Generated by: zen link",
|
|
148
|
-
"",
|
|
149
|
-
`import type { CoreServiceRouter } from "@zenbujs/core/registry-generated"`,
|
|
150
|
-
...imports,
|
|
151
|
-
"",
|
|
152
|
-
`type ServiceBase =\n${SERVICE_BASE_LITERAL}`,
|
|
153
|
-
"",
|
|
154
|
-
"type ExtractRpcMethods<T> = {",
|
|
155
|
-
" [K in Exclude<keyof T, ServiceBase | `_${string}`> as T[K] extends (",
|
|
156
|
-
" ...args: any[]",
|
|
157
|
-
" ) => any",
|
|
158
|
-
" ? K",
|
|
159
|
-
" : never]: T[K]",
|
|
160
|
-
"}",
|
|
161
|
-
"",
|
|
162
|
-
"export type PluginServiceRouter = {",
|
|
163
|
-
...routerEntries.map((e) => e + ";"),
|
|
164
|
-
"}",
|
|
165
|
-
"",
|
|
166
|
-
"export type ServiceRouter = CoreServiceRouter & PluginServiceRouter",
|
|
167
|
-
""
|
|
168
|
-
].join("\n");
|
|
169
|
-
}
|
|
170
|
-
function generatePreloadsFile(registryDir, allPreloads) {
|
|
171
|
-
const imports = [];
|
|
172
|
-
const entries = [];
|
|
173
|
-
const usedAliases = /* @__PURE__ */ new Map();
|
|
174
|
-
function uniqueAlias(base) {
|
|
175
|
-
const count = usedAliases.get(base) ?? 0;
|
|
176
|
-
usedAliases.set(base, count + 1);
|
|
177
|
-
return count === 0 ? base : `${base}${count}`;
|
|
178
|
-
}
|
|
179
|
-
for (const [, { name, preloadPath }] of allPreloads) {
|
|
180
|
-
const alias = uniqueAlias(`${name.replace(/(^|[-_])(\w)/g, (_m, _p, c) => _p ? c.toUpperCase() : c)}Preload`);
|
|
181
|
-
const importPath = relativeFromRegistry(registryDir, preloadPath);
|
|
182
|
-
imports.push(`import type { default as ${alias} } from "${importPath}"`);
|
|
183
|
-
const quotedName = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `"${name}"`;
|
|
184
|
-
entries.push(` ${quotedName}: Awaited<ReturnType<typeof ${alias}>>`);
|
|
185
|
-
}
|
|
186
|
-
return [
|
|
187
|
-
"// Generated by: zen link",
|
|
188
|
-
"",
|
|
189
|
-
`import type { CorePreloads } from "@zenbujs/core/registry-generated"`,
|
|
190
|
-
...imports,
|
|
191
|
-
"",
|
|
192
|
-
"export type PluginPreloads = {",
|
|
193
|
-
...entries.map((e) => e + ";"),
|
|
194
|
-
"}",
|
|
195
|
-
"",
|
|
196
|
-
"export type Preloads = CorePreloads & PluginPreloads",
|
|
197
|
-
""
|
|
198
|
-
].join("\n");
|
|
199
|
-
}
|
|
200
|
-
function generateEventsFile(registryDir, allEvents) {
|
|
201
|
-
const imports = [];
|
|
202
|
-
const aliases = [];
|
|
203
|
-
const usedAliases = /* @__PURE__ */ new Map();
|
|
204
|
-
function uniqueAlias(base) {
|
|
205
|
-
const count = usedAliases.get(base) ?? 0;
|
|
206
|
-
usedAliases.set(base, count + 1);
|
|
207
|
-
return count === 0 ? base : `${base}${count}`;
|
|
208
|
-
}
|
|
209
|
-
for (const [, { name, eventsPath }] of allEvents) {
|
|
210
|
-
const alias = uniqueAlias(`Events_${name.replace(/(^|[-_])(\w)/g, (_m, _p, c) => _p ? c.toUpperCase() : c)}`);
|
|
211
|
-
const importPath = relativeFromRegistry(registryDir, eventsPath);
|
|
212
|
-
imports.push(`import type { Events as ${alias} } from "${importPath}"`);
|
|
213
|
-
aliases.push(alias);
|
|
214
|
-
}
|
|
215
|
-
const body = aliases.length === 0 ? "Record<string, never>" : aliases.join(" & ");
|
|
216
|
-
return [
|
|
217
|
-
"// Generated by: zen link",
|
|
218
|
-
"",
|
|
219
|
-
`import type { CoreEvents } from "@zenbujs/core/registry-generated"`,
|
|
220
|
-
...imports,
|
|
221
|
-
"",
|
|
222
|
-
"/**",
|
|
223
|
-
" * Intersection of every plugin's `Events` type. Plugins extend this",
|
|
224
|
-
" * by declaring `events: \"./path/to/events.ts\"` in their",
|
|
225
|
-
" * zenbu.plugin.json and exporting `export type Events = { ... }` from",
|
|
226
|
-
" * that file. Each plugin chooses its own top-level namespace keys",
|
|
227
|
-
" * (e.g. `pty`, `bottomTerminal`); colliding keys with different payload",
|
|
228
|
-
" * shapes collapse to `never` at use sites — caught at compile time.",
|
|
229
|
-
" */",
|
|
230
|
-
`export type PluginEvents = CoreEvents & ${body}`,
|
|
231
|
-
""
|
|
232
|
-
].join("\n");
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Generate the module-augmentation that wires `DbRoot`, `ServiceRouter`,
|
|
236
|
-
* and `PluginEvents` from the user's registry into `@zenbujs/core/react`'s
|
|
237
|
-
* `ZenbuRegister` interface. With this in place the renderer hooks are
|
|
238
|
-
* fully typed without a single generic at the call site.
|
|
239
|
-
*/
|
|
240
|
-
function generateRegisterFile() {
|
|
241
|
-
return [
|
|
242
|
-
"// Generated by: zen link",
|
|
243
|
-
"",
|
|
244
|
-
`import type {} from "@zenbujs/core/registry"`,
|
|
245
|
-
`import type { DbRoot } from "./db-sections"`,
|
|
246
|
-
`import type { ServiceRouter } from "./services"`,
|
|
247
|
-
`import type { PluginEvents } from "./events"`,
|
|
248
|
-
"",
|
|
249
|
-
`declare module "@zenbujs/core/registry" {`,
|
|
250
|
-
" interface ZenbuRegister {",
|
|
251
|
-
" db: DbRoot",
|
|
252
|
-
" rpc: ServiceRouter",
|
|
253
|
-
" events: PluginEvents",
|
|
254
|
-
" }",
|
|
255
|
-
"}",
|
|
256
|
-
"",
|
|
257
|
-
"export {}",
|
|
258
|
-
""
|
|
259
|
-
].join("\n");
|
|
260
|
-
}
|
|
261
|
-
function generateDbSectionsFile(registryDir, allSchemas) {
|
|
262
|
-
const imports = [];
|
|
263
|
-
const sectionEntries = [];
|
|
264
|
-
const usedAliases = /* @__PURE__ */ new Map();
|
|
265
|
-
function uniqueAlias(base) {
|
|
266
|
-
const count = usedAliases.get(base) ?? 0;
|
|
267
|
-
usedAliases.set(base, count + 1);
|
|
268
|
-
return count === 0 ? base : `${base}${count}`;
|
|
269
|
-
}
|
|
270
|
-
for (const [, { name, schemaPath }] of allSchemas) {
|
|
271
|
-
const alias = uniqueAlias(name.replace(/(^|[-_])(\w)/g, (_m, _p, c) => c.toUpperCase()) + "Root");
|
|
272
|
-
const importPath = relativeFromRegistry(registryDir, schemaPath);
|
|
273
|
-
imports.push(`import type { SchemaRoot as ${alias} } from "${importPath}"`);
|
|
274
|
-
const quotedName = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `"${name}"`;
|
|
275
|
-
sectionEntries.push(` ${quotedName}: ${alias}`);
|
|
276
|
-
}
|
|
277
|
-
return [
|
|
278
|
-
"// Generated by: zen link",
|
|
279
|
-
"",
|
|
280
|
-
`import type { CoreDbSections } from "@zenbujs/core/registry-generated"`,
|
|
281
|
-
...imports,
|
|
282
|
-
"",
|
|
283
|
-
"export type PluginDbSections = {",
|
|
284
|
-
...sectionEntries.map((e) => e + ";"),
|
|
285
|
-
"}",
|
|
286
|
-
"",
|
|
287
|
-
"export type DbSections = CoreDbSections & PluginDbSections",
|
|
288
|
-
"",
|
|
289
|
-
"export type DbRoot = { plugin: DbSections }",
|
|
290
|
-
""
|
|
291
|
-
].join("\n");
|
|
292
|
-
}
|
|
293
|
-
function readExistingRegistry(registryDir) {
|
|
294
|
-
const services = /* @__PURE__ */ new Map();
|
|
295
|
-
const schemas = /* @__PURE__ */ new Map();
|
|
296
|
-
const preloads = /* @__PURE__ */ new Map();
|
|
297
|
-
const events = /* @__PURE__ */ new Map();
|
|
298
|
-
const servicesPath = path.join(registryDir, "services.ts");
|
|
299
|
-
if (fs.existsSync(servicesPath)) {
|
|
300
|
-
const content = fs.readFileSync(servicesPath, "utf8");
|
|
301
|
-
const importRe = /import type \{ (\w+)(?:\s+as\s+(\w+))? \} from "([^"]+)"/g;
|
|
302
|
-
const importMap = /* @__PURE__ */ new Map();
|
|
303
|
-
for (const m of content.matchAll(importRe)) {
|
|
304
|
-
const className = m[1];
|
|
305
|
-
const alias = m[2] ?? m[1];
|
|
306
|
-
const relPath = m[3];
|
|
307
|
-
const absPath = path.resolve(registryDir, relPath) + ".ts";
|
|
308
|
-
importMap.set(alias, {
|
|
309
|
-
className,
|
|
310
|
-
filePath: absPath
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
const dbPath = path.join(registryDir, "db-sections.ts");
|
|
315
|
-
if (fs.existsSync(dbPath)) {
|
|
316
|
-
const content = fs.readFileSync(dbPath, "utf8");
|
|
317
|
-
const importRe = /import type \{ SchemaRoot as (\w+) \} from "([^"]+)"/g;
|
|
318
|
-
const sectionRe = /^\s+(?:"([^"]+)"|(\w+)):\s+(\w+)/gm;
|
|
319
|
-
const importMap = /* @__PURE__ */ new Map();
|
|
320
|
-
for (const m of content.matchAll(importRe)) {
|
|
321
|
-
const alias = m[1];
|
|
322
|
-
const relPath = m[2];
|
|
323
|
-
importMap.set(alias, path.resolve(registryDir, relPath) + ".ts");
|
|
324
|
-
}
|
|
325
|
-
for (const m of content.matchAll(sectionRe)) {
|
|
326
|
-
const name = m[1] ?? m[2];
|
|
327
|
-
const alias = m[3];
|
|
328
|
-
const schemaPath = importMap.get(alias);
|
|
329
|
-
if (schemaPath) schemas.set(name, {
|
|
330
|
-
name,
|
|
331
|
-
schemaPath
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
const preloadsPath = path.join(registryDir, "preloads.ts");
|
|
336
|
-
if (fs.existsSync(preloadsPath)) {
|
|
337
|
-
const content = fs.readFileSync(preloadsPath, "utf8");
|
|
338
|
-
const importRe = /import type \{ default as (\w+) \} from "([^"]+)"/g;
|
|
339
|
-
const entryRe = /^\s+(?:"([^"]+)"|(\w+)):\s+Awaited<ReturnType<typeof (\w+)>>/gm;
|
|
340
|
-
const importMap = /* @__PURE__ */ new Map();
|
|
341
|
-
for (const m of content.matchAll(importRe)) {
|
|
342
|
-
const alias = m[1];
|
|
343
|
-
const relPath = m[2];
|
|
344
|
-
importMap.set(alias, path.resolve(registryDir, relPath) + ".ts");
|
|
345
|
-
}
|
|
346
|
-
for (const m of content.matchAll(entryRe)) {
|
|
347
|
-
const name = m[1] ?? m[2];
|
|
348
|
-
const alias = m[3];
|
|
349
|
-
const preloadPath = importMap.get(alias);
|
|
350
|
-
if (preloadPath) preloads.set(name, {
|
|
351
|
-
name,
|
|
352
|
-
preloadPath
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
return {
|
|
357
|
-
services,
|
|
358
|
-
schemas,
|
|
359
|
-
preloads,
|
|
360
|
-
events
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
function parseLinkArgs(argv) {
|
|
364
|
-
let manifestArg = null;
|
|
365
|
-
let typesConfigArg = null;
|
|
366
|
-
let registryOverride = null;
|
|
367
|
-
let surfaceOutArg = null;
|
|
368
|
-
let augmentOutArg = null;
|
|
369
|
-
for (let i = 0; i < argv.length; i++) {
|
|
370
|
-
const arg = argv[i];
|
|
371
|
-
if (arg === "--registry" && i + 1 < argv.length) registryOverride = argv[++i];
|
|
372
|
-
else if (arg.startsWith("--registry=")) registryOverride = arg.slice(11);
|
|
373
|
-
else if (arg === "--types-config" && i + 1 < argv.length) typesConfigArg = argv[++i];
|
|
374
|
-
else if (arg.startsWith("--types-config=")) typesConfigArg = arg.slice(15);
|
|
375
|
-
else if (arg === "--out" && i + 1 < argv.length) surfaceOutArg = argv[++i];
|
|
376
|
-
else if (arg.startsWith("--out=")) surfaceOutArg = arg.slice(6);
|
|
377
|
-
else if (arg === "--augment-out" && i + 1 < argv.length) augmentOutArg = argv[++i];
|
|
378
|
-
else if (arg.startsWith("--augment-out=")) augmentOutArg = arg.slice(14);
|
|
379
|
-
else if (!arg.startsWith("-") && !manifestArg) manifestArg = arg;
|
|
380
|
-
}
|
|
381
|
-
return {
|
|
382
|
-
manifestArg,
|
|
383
|
-
typesConfigArg,
|
|
384
|
-
registryOverride,
|
|
385
|
-
surfaceOutArg,
|
|
386
|
-
augmentOutArg
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Variant for path-based plugin sources (a `zenbu.plugin.ts` whose default
|
|
391
|
-
* export is a `definePlugin({...})`). Resolved upstream by `loadConfig` so
|
|
392
|
-
* we just consume the resolved record here.
|
|
393
|
-
*/
|
|
394
|
-
function linkResolvedPlugin(plugin, existing, opts) {
|
|
395
|
-
const log = opts.quiet ? () => {} : (msg) => console.log(msg);
|
|
396
|
-
log(`Linking types "${plugin.name}" from ${plugin.dir}`);
|
|
397
|
-
const serviceGlobs = plugin.services.map((abs) => path.relative(plugin.dir, abs).split(path.sep).join("/"));
|
|
398
|
-
const serviceEntries = discoverServices(plugin.dir, serviceGlobs);
|
|
399
|
-
log(` Found ${serviceEntries.length} service(s)`);
|
|
400
|
-
const schemaEntry = plugin.schemaPath ? {
|
|
401
|
-
name: plugin.name,
|
|
402
|
-
schemaPath: plugin.schemaPath
|
|
403
|
-
} : null;
|
|
404
|
-
if (schemaEntry) log(` Schema: ${schemaEntry.schemaPath}`);
|
|
405
|
-
const preloadEntry = plugin.preloadPath ? {
|
|
406
|
-
name: plugin.name,
|
|
407
|
-
preloadPath: plugin.preloadPath
|
|
408
|
-
} : null;
|
|
409
|
-
if (preloadEntry) log(` Preload: ${preloadEntry.preloadPath}`);
|
|
410
|
-
const eventsEntry = plugin.eventsPath ? {
|
|
411
|
-
name: plugin.name,
|
|
412
|
-
eventsPath: plugin.eventsPath
|
|
413
|
-
} : null;
|
|
414
|
-
if (eventsEntry) log(` Events: ${eventsEntry.eventsPath}`);
|
|
415
|
-
existing.services.set(plugin.name, serviceEntries);
|
|
416
|
-
if (schemaEntry) existing.schemas.set(plugin.name, schemaEntry);
|
|
417
|
-
if (preloadEntry) existing.preloads.set(plugin.name, preloadEntry);
|
|
418
|
-
else existing.preloads.delete(plugin.name);
|
|
419
|
-
if (eventsEntry) existing.events.set(plugin.name, eventsEntry);
|
|
420
|
-
else existing.events.delete(plugin.name);
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Generator: `<core>/src/registry-generated.ts` — the publishable
|
|
424
|
-
* type surface that downstream apps' `zen link`-generated files
|
|
425
|
-
* import from `@zenbujs/core/registry-generated`.
|
|
426
|
-
*
|
|
427
|
-
* Imports use public package exports (`@zenbujs/core/services`,
|
|
428
|
-
* `/events`, `/schema`) so the file resolves in any consumer
|
|
429
|
-
* regardless of how `@zenbujs/core` is installed.
|
|
430
|
-
*/
|
|
431
|
-
function generateCoreSurfaceFile(args) {
|
|
432
|
-
const sorted = [...args.services].sort((a, b) => a.className.localeCompare(b.className));
|
|
433
|
-
const importedNames = sorted.map((s) => ` ${s.className},`).join("\n");
|
|
434
|
-
const routerEntries = sorted.map((s) => {
|
|
435
|
-
return ` ${/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s.key) ? s.key : `"${s.key}"`}: ExtractRpcMethods<${s.className}>;`;
|
|
436
|
-
}).join("\n");
|
|
437
|
-
const lines = [
|
|
438
|
-
"// Generated by: pnpm link:types",
|
|
439
|
-
"// DO NOT EDIT. Regenerated automatically (also wired into `prebuild`).",
|
|
440
|
-
""
|
|
441
|
-
];
|
|
442
|
-
if (sorted.length > 0) {
|
|
443
|
-
lines.push("import type {");
|
|
444
|
-
lines.push(importedNames);
|
|
445
|
-
lines.push(`} from "@zenbujs/core/services"`);
|
|
446
|
-
}
|
|
447
|
-
if (args.hasEvents) lines.push(`import type { Events as Events_core } from "@zenbujs/core/events"`);
|
|
448
|
-
if (args.hasSchema) lines.push(`import type { SchemaRoot as SchemaRoot_core } from "@zenbujs/core/schema"`);
|
|
449
|
-
lines.push("");
|
|
450
|
-
lines.push(`type ServiceBase =\n${SERVICE_BASE_LITERAL}`);
|
|
451
|
-
lines.push("");
|
|
452
|
-
lines.push("type ExtractRpcMethods<T> = {");
|
|
453
|
-
lines.push(" [K in Exclude<keyof T, ServiceBase | `_${string}`> as T[K] extends (");
|
|
454
|
-
lines.push(" ...args: any[]");
|
|
455
|
-
lines.push(" ) => any");
|
|
456
|
-
lines.push(" ? K");
|
|
457
|
-
lines.push(" : never]: T[K]");
|
|
458
|
-
lines.push("}");
|
|
459
|
-
lines.push("");
|
|
460
|
-
lines.push("export type CoreServiceRouter = {");
|
|
461
|
-
if (routerEntries.length > 0) lines.push(routerEntries);
|
|
462
|
-
lines.push("}");
|
|
463
|
-
lines.push("");
|
|
464
|
-
lines.push(`export type CoreEvents = ${args.hasEvents ? "Events_core" : "{}"}`);
|
|
465
|
-
lines.push("");
|
|
466
|
-
lines.push("export type CoreDbSections = {");
|
|
467
|
-
if (args.hasSchema) lines.push(" core: SchemaRoot_core;");
|
|
468
|
-
lines.push("}");
|
|
469
|
-
lines.push("");
|
|
470
|
-
lines.push("export type CorePreloads = {}");
|
|
471
|
-
lines.push("");
|
|
472
|
-
return lines.join("\n");
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Generator: `<core>/types/zenbu-register.ts` — local-only
|
|
476
|
-
* augmentation that drives core's OWN typecheck. Pulls
|
|
477
|
-
* `Core*` types from the relative path `../src/registry-generated`
|
|
478
|
-
* (so it works without depending on package self-resolution) and
|
|
479
|
-
* declares the `ZenbuRegister` augmentation. NOT in
|
|
480
|
-
* `package.json#files`; never reaches downstream consumers (where
|
|
481
|
-
* it would conflict with their own augmentation).
|
|
482
|
-
*/
|
|
483
|
-
function generateCoreAugmentFile() {
|
|
484
|
-
return [
|
|
485
|
-
"// Generated by: pnpm link:types",
|
|
486
|
-
"// DO NOT EDIT. Local-only augmentation (NOT shipped via package.json#files).",
|
|
487
|
-
"// Drives core's own typecheck so useRpc()/useEvents()/useDb() resolve",
|
|
488
|
-
"// to the registered surface inside packages/core/src/.",
|
|
489
|
-
"",
|
|
490
|
-
`import type {} from "@zenbujs/core/registry"`,
|
|
491
|
-
`import type {`,
|
|
492
|
-
` CoreServiceRouter,`,
|
|
493
|
-
` CoreEvents,`,
|
|
494
|
-
` CoreDbSections,`,
|
|
495
|
-
`} from "../src/registry-generated"`,
|
|
496
|
-
"",
|
|
497
|
-
`declare module "@zenbujs/core/registry" {`,
|
|
498
|
-
" interface ZenbuRegister {",
|
|
499
|
-
" rpc: CoreServiceRouter",
|
|
500
|
-
" events: CoreEvents",
|
|
501
|
-
" db: { plugin: CoreDbSections }",
|
|
502
|
-
" }",
|
|
503
|
-
"}",
|
|
504
|
-
"",
|
|
505
|
-
"export {}",
|
|
506
|
-
""
|
|
507
|
-
].join("\n");
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Two-file write for the `--types-config` flow: the publishable
|
|
511
|
-
* surface (`registry-generated.ts`) plus the local-only
|
|
512
|
-
* augmentation (`zenbu-register.ts`). Skips writes when content is
|
|
513
|
-
* identical so downstream watchers (Vite, tsc --watch) don't see
|
|
514
|
-
* spurious mtime bumps.
|
|
515
|
-
*/
|
|
516
|
-
function writeCoreSurfaceFiles(args) {
|
|
517
|
-
const surface = generateCoreSurfaceFile({
|
|
518
|
-
services: args.services,
|
|
519
|
-
hasEvents: args.hasEvents,
|
|
520
|
-
hasSchema: args.hasSchema
|
|
521
|
-
});
|
|
522
|
-
const augment = generateCoreAugmentFile();
|
|
523
|
-
for (const [target, body] of [[args.surfaceOut, surface], [args.augmentOut, augment]]) {
|
|
524
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
525
|
-
let prev = null;
|
|
526
|
-
try {
|
|
527
|
-
prev = fs.readFileSync(target, "utf8");
|
|
528
|
-
} catch {}
|
|
529
|
-
if (prev === body) continue;
|
|
530
|
-
fs.writeFileSync(target, body);
|
|
531
|
-
if (!args.quiet) console.log(` Wrote ${target}`);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Per-install bootstrap for a plugin. The plugin ships a portable
|
|
536
|
-
* `tsconfig.json` with no host-specific paths; this writes a sibling
|
|
537
|
-
* `tsconfig.local.json` (gitignored) that wires `#registry/*` to the host
|
|
538
|
-
* app's `types/` so the plugin can `import type {...} from "#registry/foo"`
|
|
539
|
-
* the same way the host does. Idempotent.
|
|
540
|
-
*
|
|
541
|
-
* This is the only mechanism that knows where the host lives — it has to
|
|
542
|
-
* be regenerated whenever the plugin moves between hosts.
|
|
543
|
-
*/
|
|
544
|
-
/**
|
|
545
|
-
* Generate `<plugin>/tsconfig.local.json` — the BASE config that the
|
|
546
|
-
* plugin's committed `tsconfig.json` extends. This file is gitignored and
|
|
547
|
-
* regenerated by every `zen link` so the host-specific bits (the
|
|
548
|
-
* `#registry/*` path mapping and the registry-augmentation include) move
|
|
549
|
-
* with the plugin's host installation.
|
|
550
|
-
*
|
|
551
|
-
* Why this and not `tsconfig.json` itself: the IDE (VSCode/Cursor) walks
|
|
552
|
-
* up looking for `tsconfig.json` and uses only that one. It never picks up
|
|
553
|
-
* a sibling `tsconfig.local.json` on its own. So we keep `tsconfig.json`
|
|
554
|
-
* as the IDE-discovered, plugin-author-edited entry point and have it
|
|
555
|
-
* `"extends": "./tsconfig.local.json"`. The generated file then carries
|
|
556
|
-
* `paths` + `include`, which TS merges into the IDE's resolved program.
|
|
557
|
-
*/
|
|
558
|
-
function writePluginTsconfigLocal(pluginDir, registryDir, opts) {
|
|
559
|
-
const ownTsconfig = path.join(pluginDir, "tsconfig.json");
|
|
560
|
-
if (!fs.existsSync(ownTsconfig)) return;
|
|
561
|
-
for (const name of CONFIG_NAMES) if (fs.existsSync(path.join(pluginDir, name))) return;
|
|
562
|
-
const target = path.join(pluginDir, "tsconfig.local.json");
|
|
563
|
-
let registryRel = path.relative(pluginDir, registryDir);
|
|
564
|
-
if (!registryRel.startsWith(".")) registryRel = "./" + registryRel;
|
|
565
|
-
const body = {
|
|
566
|
-
compilerOptions: { paths: { "#registry/*": [`${registryRel}/*`] } },
|
|
567
|
-
include: ["src", `${registryRel}/zenbu-register.ts`]
|
|
568
|
-
};
|
|
569
|
-
const next = JSON.stringify(body, null, 2) + "\n";
|
|
570
|
-
let prev = null;
|
|
571
|
-
try {
|
|
572
|
-
prev = fs.readFileSync(target, "utf8");
|
|
573
|
-
} catch {}
|
|
574
|
-
if (prev === next) return;
|
|
575
|
-
fs.writeFileSync(target, next);
|
|
576
|
-
if (!opts.quiet) console.log(` Wrote ${target}`);
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Programmatic variant of `zen link` for the host-project flow. Throws on
|
|
580
|
-
* any error instead of `process.exit`. Used by:
|
|
581
|
-
* - `runLink` (CLI entry)
|
|
582
|
-
* - `link-watcher.ts` (file watcher used by `zen dev`)
|
|
583
|
-
*
|
|
584
|
-
* `quiet: true` suppresses the per-step console output the CLI emits — the
|
|
585
|
-
* watcher uses this so the dev terminal stays clean across rapid edits.
|
|
586
|
-
*/
|
|
587
|
-
async function linkProject(projectDir, opts = {}) {
|
|
588
|
-
const log = opts.quiet ? () => {} : (msg) => console.log(msg);
|
|
589
|
-
const { resolved, pluginSourceFiles } = await loadConfig(projectDir);
|
|
590
|
-
const registryDir = resolveRegistryDir({
|
|
591
|
-
manifestPath: resolved.configPath,
|
|
592
|
-
manifest: {},
|
|
593
|
-
registryOverride: opts.registryOverride ?? null
|
|
594
|
-
});
|
|
595
|
-
log(`Registry: ${registryDir}`);
|
|
596
|
-
fs.mkdirSync(registryDir, { recursive: true });
|
|
597
|
-
const existing = readExistingRegistry(registryDir);
|
|
598
|
-
for (const plugin of resolved.plugins) linkResolvedPlugin(plugin, existing, { quiet: !!opts.quiet });
|
|
599
|
-
writeRegistryFiles(registryDir, existing, { quiet: !!opts.quiet });
|
|
600
|
-
for (const plugin of resolved.plugins) writePluginTsconfigLocal(plugin.dir, registryDir, { quiet: !!opts.quiet });
|
|
601
|
-
return {
|
|
602
|
-
registryDir,
|
|
603
|
-
resolvedConfigPath: resolved.configPath,
|
|
604
|
-
pluginSourceFiles,
|
|
605
|
-
resolved
|
|
606
|
-
};
|
|
607
|
-
}
|
|
608
|
-
async function runLink(argv) {
|
|
609
|
-
const { manifestArg, typesConfigArg, registryOverride, surfaceOutArg, augmentOutArg } = parseLinkArgs(argv);
|
|
610
|
-
if (typesConfigArg) {
|
|
611
|
-
const typeConfigPath = path.resolve(typesConfigArg);
|
|
612
|
-
const rootManifest = JSON.parse(fs.readFileSync(typeConfigPath, "utf8"));
|
|
613
|
-
const baseDir = path.dirname(typeConfigPath);
|
|
614
|
-
const surfaceOut = surfaceOutArg ? path.resolve(surfaceOutArg) : path.join(baseDir, "src", "registry-generated.ts");
|
|
615
|
-
const augmentOut = augmentOutArg ? path.resolve(augmentOutArg) : path.join(baseDir, "types", "zenbu-register.ts");
|
|
616
|
-
try {
|
|
617
|
-
console.log(`Linking core types from ${baseDir}`);
|
|
618
|
-
const services = discoverServices(baseDir, rootManifest.services ?? []);
|
|
619
|
-
console.log(` Found ${services.length} service(s)`);
|
|
620
|
-
const hasEvents = !!rootManifest.events;
|
|
621
|
-
const hasSchema = !!rootManifest.schema;
|
|
622
|
-
if (rootManifest.events) console.log(` Events: ${path.resolve(baseDir, rootManifest.events)}`);
|
|
623
|
-
if (rootManifest.schema) console.log(` Schema: ${path.resolve(baseDir, rootManifest.schema)}`);
|
|
624
|
-
writeCoreSurfaceFiles({
|
|
625
|
-
services,
|
|
626
|
-
hasEvents,
|
|
627
|
-
hasSchema,
|
|
628
|
-
surfaceOut,
|
|
629
|
-
augmentOut,
|
|
630
|
-
quiet: false
|
|
631
|
-
});
|
|
632
|
-
console.log("Done.");
|
|
633
|
-
} catch (err) {
|
|
634
|
-
console.error(err instanceof Error ? err.message : err);
|
|
635
|
-
process.exit(1);
|
|
636
|
-
}
|
|
637
|
-
return;
|
|
638
|
-
}
|
|
639
|
-
const projectDir = manifestArg ? path.resolve(manifestArg) : findProjectDir(process.cwd());
|
|
640
|
-
if (!projectDir) {
|
|
641
|
-
console.error("zen link: could not find zenbu.config.ts in current directory or any parent.");
|
|
642
|
-
console.error(" For internal framework types, pass --types-config <path>.");
|
|
643
|
-
process.exit(1);
|
|
644
|
-
}
|
|
645
|
-
try {
|
|
646
|
-
await linkProject(projectDir, { registryOverride });
|
|
647
|
-
console.log("Done.");
|
|
648
|
-
} catch (err) {
|
|
649
|
-
console.error(err instanceof Error ? err.message : err);
|
|
650
|
-
process.exit(1);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
function writeRegistryFiles(registryDir, existing, opts) {
|
|
654
|
-
const writes = [
|
|
655
|
-
["services.ts", generateServicesFile(registryDir, existing.services)],
|
|
656
|
-
["db-sections.ts", generateDbSectionsFile(registryDir, existing.schemas)],
|
|
657
|
-
["preloads.ts", generatePreloadsFile(registryDir, existing.preloads)],
|
|
658
|
-
["events.ts", generateEventsFile(registryDir, existing.events)],
|
|
659
|
-
["zenbu-register.ts", generateRegisterFile()]
|
|
660
|
-
];
|
|
661
|
-
for (const [name, body] of writes) {
|
|
662
|
-
const target = path.join(registryDir, name);
|
|
663
|
-
let prev = null;
|
|
664
|
-
try {
|
|
665
|
-
prev = fs.readFileSync(target, "utf8");
|
|
666
|
-
} catch {}
|
|
667
|
-
if (prev === body) continue;
|
|
668
|
-
fs.writeFileSync(target, body);
|
|
669
|
-
if (!opts.quiet) console.log(` Wrote ${target}`);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
//#endregion
|
|
673
|
-
export { link_exports as n, linkProject as t };
|