everything-dev 1.33.7 → 1.35.1

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.
Files changed (66) hide show
  1. package/dist/api-contract.cjs +48 -68
  2. package/dist/api-contract.cjs.map +1 -1
  3. package/dist/api-contract.mjs +48 -68
  4. package/dist/api-contract.mjs.map +1 -1
  5. package/dist/cli/init.cjs +64 -41
  6. package/dist/cli/init.cjs.map +1 -1
  7. package/dist/cli/init.d.cts.map +1 -1
  8. package/dist/cli/init.d.mts.map +1 -1
  9. package/dist/cli/init.mjs +65 -42
  10. package/dist/cli/init.mjs.map +1 -1
  11. package/dist/cli/sync.cjs +5 -0
  12. package/dist/cli/sync.cjs.map +1 -1
  13. package/dist/cli/sync.mjs +5 -0
  14. package/dist/cli/sync.mjs.map +1 -1
  15. package/dist/cli/upgrade.cjs +6 -3
  16. package/dist/cli/upgrade.cjs.map +1 -1
  17. package/dist/cli/upgrade.mjs +6 -3
  18. package/dist/cli/upgrade.mjs.map +1 -1
  19. package/dist/config.cjs +12 -4
  20. package/dist/config.cjs.map +1 -1
  21. package/dist/config.d.cts.map +1 -1
  22. package/dist/config.d.mts.map +1 -1
  23. package/dist/config.mjs +12 -4
  24. package/dist/config.mjs.map +1 -1
  25. package/dist/contract.d.cts +60 -44
  26. package/dist/contract.d.cts.map +1 -1
  27. package/dist/contract.d.mts +60 -44
  28. package/dist/contract.d.mts.map +1 -1
  29. package/dist/index.cjs +1 -0
  30. package/dist/index.d.cts +2 -2
  31. package/dist/index.d.mts +2 -2
  32. package/dist/index.mjs +2 -2
  33. package/dist/merge.cjs +1 -2
  34. package/dist/merge.cjs.map +1 -1
  35. package/dist/merge.d.cts +1 -1
  36. package/dist/merge.d.cts.map +1 -1
  37. package/dist/merge.d.mts +1 -1
  38. package/dist/merge.d.mts.map +1 -1
  39. package/dist/merge.mjs +1 -2
  40. package/dist/merge.mjs.map +1 -1
  41. package/dist/plugin.cjs +7 -3
  42. package/dist/plugin.cjs.map +1 -1
  43. package/dist/plugin.d.cts +71 -49
  44. package/dist/plugin.d.mts +71 -49
  45. package/dist/plugin.mjs +7 -3
  46. package/dist/plugin.mjs.map +1 -1
  47. package/dist/shared-deps.cjs +201 -0
  48. package/dist/shared-deps.cjs.map +1 -0
  49. package/dist/shared-deps.mjs +200 -0
  50. package/dist/shared-deps.mjs.map +1 -0
  51. package/dist/types.cjs +14 -12
  52. package/dist/types.cjs.map +1 -1
  53. package/dist/types.d.cts +88 -40
  54. package/dist/types.d.cts.map +1 -1
  55. package/dist/types.d.mts +88 -40
  56. package/dist/types.d.mts.map +1 -1
  57. package/dist/types.mjs +14 -13
  58. package/dist/types.mjs.map +1 -1
  59. package/package.json +4 -4
  60. package/skills/extends-config/SKILL.md +7 -8
  61. package/skills/init-upgrade/SKILL.md +5 -2
  62. package/skills/publish-sync/SKILL.md +1 -1
  63. package/dist/shared.cjs +0 -155
  64. package/dist/shared.cjs.map +0 -1
  65. package/dist/shared.mjs +0 -154
  66. package/dist/shared.mjs.map +0 -1
@@ -0,0 +1,201 @@
1
+ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
+ const require_merge = require('./merge.cjs');
3
+ const require_types = require('./types.cjs');
4
+ let node_fs = require("node:fs");
5
+ let node_path = require("node:path");
6
+ let node_crypto = require("node:crypto");
7
+
8
+ //#region src/shared-deps.ts
9
+ function sha256(input) {
10
+ return (0, node_crypto.createHash)("sha256").update(input).digest("hex");
11
+ }
12
+ function extractSemverExact(input) {
13
+ if (typeof input !== "string") return null;
14
+ const match = input.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
15
+ return match ? match[0] : null;
16
+ }
17
+ function caretRange(version) {
18
+ return `^${version}`;
19
+ }
20
+ function stableDepsObject(deps) {
21
+ const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));
22
+ const out = {};
23
+ for (const key of keys) out[key] = deps[key];
24
+ return out;
25
+ }
26
+ function normalizeSharedDepConfig(config) {
27
+ return {
28
+ version: config.version,
29
+ requiredVersion: config.requiredVersion ?? false,
30
+ singleton: config.singleton ?? false,
31
+ eager: config.eager ?? false,
32
+ strictVersion: config.strictVersion ?? false,
33
+ shareScope: config.shareScope ?? "default"
34
+ };
35
+ }
36
+ function getObject(value) {
37
+ return require_merge.isPlainObject(value) ? value : void 0;
38
+ }
39
+ function getSharedDepsMap(value, source) {
40
+ if (value === void 0) return void 0;
41
+ if (!require_types.SharedDepMapSchema.safeParse(value).success) throw new Error(`Invalid shared dependency map at ${source}`);
42
+ return value;
43
+ }
44
+ function writeFileIfChanged(filePath, nextContent) {
45
+ try {
46
+ if ((0, node_fs.readFileSync)(filePath, "utf-8") === nextContent) return false;
47
+ } catch {}
48
+ (0, node_fs.writeFileSync)(filePath, nextContent);
49
+ return true;
50
+ }
51
+ function fingerprintResolved(deps) {
52
+ return sha256(JSON.stringify(stableDepsObject(deps)));
53
+ }
54
+ function isSameSharedDepConfig(a, b) {
55
+ const left = normalizeSharedDepConfig(a);
56
+ const right = normalizeSharedDepConfig(b);
57
+ return left.version === right.version && left.requiredVersion === right.requiredVersion && left.singleton === right.singleton && left.eager === right.eager && left.strictVersion === right.strictVersion && left.shareScope === right.shareScope;
58
+ }
59
+ function collectSharedDepRefs(bosConfig) {
60
+ const refs = /* @__PURE__ */ new Map();
61
+ const app = getObject(bosConfig.app);
62
+ const appUi = getObject(app?.ui);
63
+ const appApi = getObject(app?.api);
64
+ const appAuth = getObject(app?.auth);
65
+ const plugins = getObject(bosConfig.plugins);
66
+ if (appUi && "shared" in appUi) throw new Error("app.ui.shared is no longer supported. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.");
67
+ const append = (source, shared) => {
68
+ if (!shared) return;
69
+ for (const [name, config] of Object.entries(shared)) {
70
+ const existing = refs.get(name);
71
+ if (!existing) {
72
+ refs.set(name, [{
73
+ source,
74
+ config
75
+ }]);
76
+ continue;
77
+ }
78
+ if (!isSameSharedDepConfig(existing[0].config, config)) {
79
+ const previous = existing.map((ref) => ref.source).join(", ");
80
+ throw new Error(`Conflicting shared dependency "${name}" between ${previous} and ${source}`);
81
+ }
82
+ existing.push({
83
+ source,
84
+ config
85
+ });
86
+ }
87
+ };
88
+ append("app.api", getSharedDepsMap(appApi?.shared, "app.api.shared"));
89
+ append("app.auth", getSharedDepsMap(appAuth?.shared, "app.auth.shared"));
90
+ for (const [pluginId, plugin] of Object.entries(plugins ?? {})) {
91
+ const pluginRecord = getObject(plugin);
92
+ if (!pluginRecord) continue;
93
+ const pluginUi = getObject(getObject(pluginRecord.app)?.ui);
94
+ if (pluginUi && "shared" in pluginUi) throw new Error(`app.ui.shared is no longer supported in plugins.${pluginId}. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.`);
95
+ append(`plugins.${pluginId}`, getSharedDepsMap(pluginRecord.shared, `plugins.${pluginId}.shared`));
96
+ }
97
+ return Object.fromEntries(refs);
98
+ }
99
+ async function syncResolvedSharedDeps(opts) {
100
+ const bosConfigPath = (0, node_path.join)(opts.configDir, "bos.config.json");
101
+ const resolvedConfigPath = (0, node_path.join)(opts.configDir, ".bos", "bos.resolved-config.json");
102
+ const packageJsonPath = (0, node_path.join)(opts.configDir, "package.json");
103
+ const generatedPath = (0, node_path.join)(opts.configDir, ".bos", "generated", "shared-deps.json");
104
+ const bosConfig = opts.bosConfig ?? JSON.parse((0, node_fs.readFileSync)(bosConfigPath, "utf-8"));
105
+ if (!require_merge.isPlainObject(bosConfig)) throw new Error("bos.config.json must be an object");
106
+ const pkgJson = (0, node_fs.existsSync)(packageJsonPath) ? JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf-8")) : {};
107
+ const originalBos = JSON.stringify(bosConfig);
108
+ const originalPkg = JSON.stringify(pkgJson);
109
+ const mode = opts.hostMode === "local" ? "catalog->bos" : "bos->catalog";
110
+ const refsByName = collectSharedDepRefs(bosConfig);
111
+ const catalog = pkgJson.workspaces?.catalog ?? {};
112
+ const resolvedDeps = {};
113
+ for (const [name, refs] of Object.entries(refsByName)) {
114
+ const first = refs[0];
115
+ if (!first) continue;
116
+ const exactFromConfig = extractSemverExact(first.config.version) ?? extractSemverExact(first.config.requiredVersion);
117
+ const exactFromCatalog = extractSemverExact(catalog[name]);
118
+ const version = mode === "catalog->bos" ? exactFromCatalog ?? exactFromConfig : exactFromConfig ?? exactFromCatalog;
119
+ if (!version) {
120
+ const sources = refs.map((ref) => ref.source).join(", ");
121
+ throw new Error(`Could not resolve exact version for shared dependency "${name}" from ${sources}`);
122
+ }
123
+ if (mode === "catalog->bos" && exactFromCatalog === null && exactFromConfig) catalog[name] = exactFromConfig;
124
+ if (mode === "bos->catalog" && catalog[name] !== version) catalog[name] = version;
125
+ for (const ref of refs) {
126
+ ref.config.version = version;
127
+ ref.config.requiredVersion = caretRange(version);
128
+ ref.config.shareScope = ref.config.shareScope ?? "default";
129
+ }
130
+ resolvedDeps[name] = {
131
+ name,
132
+ version,
133
+ requiredVersion: caretRange(version),
134
+ shareScope: first.config.shareScope ?? "default",
135
+ singleton: first.config.singleton ?? false,
136
+ eager: first.config.eager ?? false,
137
+ strictVersion: first.config.strictVersion ?? false,
138
+ sources: refs.map((ref) => ref.source).sort((a, b) => a.localeCompare(b))
139
+ };
140
+ }
141
+ if (!pkgJson.workspaces) pkgJson.workspaces = {
142
+ packages: [],
143
+ catalog: {}
144
+ };
145
+ pkgJson.workspaces.catalog = catalog;
146
+ const nextBos = JSON.stringify(bosConfig);
147
+ const nextPkg = JSON.stringify(pkgJson);
148
+ const bosConfigChanged = nextBos !== originalBos;
149
+ const catalogChanged = nextPkg !== originalPkg;
150
+ if (bosConfigChanged) {
151
+ const resolvedDir = (0, node_path.dirname)(resolvedConfigPath);
152
+ if (!(0, node_fs.existsSync)(resolvedDir)) (0, node_fs.mkdirSync)(resolvedDir, { recursive: true });
153
+ const ordered = require_merge.rebuildOrderedConfig(bosConfig);
154
+ const resolvedOutput = {
155
+ _resolved: {
156
+ env: opts.env ?? "development",
157
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
158
+ extendsChain: opts.extendsChain ?? [],
159
+ source: "shared-sync"
160
+ },
161
+ ...ordered
162
+ };
163
+ writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\n`);
164
+ }
165
+ if (catalogChanged) writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\n`);
166
+ const stableResolvedDeps = stableDepsObject(resolvedDeps);
167
+ const resolved = {
168
+ deps: stableResolvedDeps,
169
+ fingerprintSha256: fingerprintResolved(stableResolvedDeps)
170
+ };
171
+ const nextGenerated = {
172
+ schemaVersion: 1,
173
+ kind: "everything-dev/shared-deps",
174
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
175
+ deps: stableResolvedDeps,
176
+ fingerprintSha256: resolved.fingerprintSha256,
177
+ inputs: {
178
+ mode,
179
+ hostMode: opts.hostMode
180
+ }
181
+ };
182
+ let prevFingerprint = null;
183
+ try {
184
+ prevFingerprint = JSON.parse((0, node_fs.readFileSync)(generatedPath, "utf-8"))?.fingerprintSha256 ?? null;
185
+ } catch {}
186
+ (0, node_fs.mkdirSync)((0, node_path.dirname)(generatedPath), { recursive: true });
187
+ writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\n`);
188
+ const generatedChanged = prevFingerprint !== nextGenerated.fingerprintSha256;
189
+ return {
190
+ mode,
191
+ hostMode: opts.hostMode,
192
+ bosConfigChanged,
193
+ catalogChanged,
194
+ generatedChanged,
195
+ resolved
196
+ };
197
+ }
198
+
199
+ //#endregion
200
+ exports.syncResolvedSharedDeps = syncResolvedSharedDeps;
201
+ //# sourceMappingURL=shared-deps.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-deps.cjs","names":["isPlainObject","SharedDepMapSchema","rebuildOrderedConfig"],"sources":["../src/shared-deps.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { type BosEnv, isPlainObject, type ResolvedConfigMeta, rebuildOrderedConfig } from \"./merge\";\nimport { type SharedDepConfig, SharedDepMapSchema } from \"./types\";\n\ninterface PackageJson {\n workspaces?: {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n}\n\ninterface SharedDepRef {\n source: string;\n config: SharedDepConfig;\n}\n\ntype SharedDepsConfig = Record<string, unknown>;\n\ninterface NormalizedSharedDepConfig {\n version: string;\n requiredVersion: string | false;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n shareScope: string;\n}\n\nexport interface ResolvedSharedDep {\n name: string;\n version: string;\n requiredVersion: string;\n shareScope: string;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n sources: string[];\n}\n\nexport interface ResolvedSharedDeps {\n deps: Record<string, ResolvedSharedDep>;\n fingerprintSha256: string;\n}\n\nexport interface SharedDepsSyncResult {\n mode: \"catalog->bos\" | \"bos->catalog\";\n hostMode: \"local\" | \"remote\";\n bosConfigChanged: boolean;\n catalogChanged: boolean;\n generatedChanged: boolean;\n resolved: ResolvedSharedDeps;\n}\n\nfunction sha256(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction extractSemverExact(input: unknown): string | null {\n if (typeof input !== \"string\") return null;\n const match = input.match(/\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?/);\n return match ? match[0] : null;\n}\n\nfunction caretRange(version: string): string {\n return `^${version}`;\n}\n\nfunction stableDepsObject(\n deps: Record<string, ResolvedSharedDep>,\n): Record<string, ResolvedSharedDep> {\n const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));\n const out: Record<string, ResolvedSharedDep> = {};\n for (const key of keys) {\n out[key] = deps[key]!;\n }\n return out;\n}\n\nfunction normalizeSharedDepConfig(config: SharedDepConfig): NormalizedSharedDepConfig {\n return {\n version: config.version,\n requiredVersion: config.requiredVersion ?? false,\n singleton: config.singleton ?? false,\n eager: config.eager ?? false,\n strictVersion: config.strictVersion ?? false,\n shareScope: config.shareScope ?? \"default\",\n };\n}\n\nfunction getObject(value: unknown): Record<string, unknown> | undefined {\n return isPlainObject(value) ? value : undefined;\n}\n\nfunction getSharedDepsMap(\n value: unknown,\n source: string,\n): Record<string, SharedDepConfig> | undefined {\n if (value === undefined) return undefined;\n const parsed = SharedDepMapSchema.safeParse(value);\n if (!parsed.success) {\n throw new Error(`Invalid shared dependency map at ${source}`);\n }\n return value as Record<string, SharedDepConfig>;\n}\n\nfunction writeFileIfChanged(filePath: string, nextContent: string): boolean {\n try {\n const current = readFileSync(filePath, \"utf-8\");\n if (current === nextContent) return false;\n } catch {\n // file does not exist yet\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nfunction fingerprintResolved(deps: Record<string, ResolvedSharedDep>): string {\n return sha256(JSON.stringify(stableDepsObject(deps)));\n}\n\nfunction isSameSharedDepConfig(a: SharedDepConfig, b: SharedDepConfig): boolean {\n const left = normalizeSharedDepConfig(a);\n const right = normalizeSharedDepConfig(b);\n\n return (\n left.version === right.version &&\n left.requiredVersion === right.requiredVersion &&\n left.singleton === right.singleton &&\n left.eager === right.eager &&\n left.strictVersion === right.strictVersion &&\n left.shareScope === right.shareScope\n );\n}\n\nfunction collectSharedDepRefs(bosConfig: SharedDepsConfig): Record<string, SharedDepRef[]> {\n const refs = new Map<string, SharedDepRef[]>();\n\n const app = getObject(bosConfig.app);\n const appUi = getObject(app?.ui);\n const appApi = getObject(app?.api);\n const appAuth = getObject(app?.auth);\n const plugins = getObject(bosConfig.plugins);\n\n if (appUi && \"shared\" in appUi) {\n throw new Error(\n \"app.ui.shared is no longer supported. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.\",\n );\n }\n\n const append = (source: string, shared: Record<string, SharedDepConfig> | undefined) => {\n if (!shared) return;\n\n for (const [name, config] of Object.entries(shared)) {\n const existing = refs.get(name);\n if (!existing) {\n refs.set(name, [{ source, config }]);\n continue;\n }\n\n if (!isSameSharedDepConfig(existing[0]!.config, config)) {\n const previous = existing.map((ref) => ref.source).join(\", \");\n throw new Error(\n `Conflicting shared dependency \"${name}\" between ${previous} and ${source}`,\n );\n }\n\n existing.push({ source, config });\n }\n };\n\n append(\"app.api\", getSharedDepsMap(appApi?.shared, \"app.api.shared\"));\n append(\"app.auth\", getSharedDepsMap(appAuth?.shared, \"app.auth.shared\"));\n\n for (const [pluginId, plugin] of Object.entries(plugins ?? {})) {\n const pluginRecord = getObject(plugin);\n if (!pluginRecord) continue;\n\n const pluginApp = getObject(pluginRecord.app);\n const pluginUi = getObject(pluginApp?.ui);\n if (pluginUi && \"shared\" in pluginUi) {\n throw new Error(\n `app.ui.shared is no longer supported in plugins.${pluginId}. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.`,\n );\n }\n append(\n `plugins.${pluginId}`,\n getSharedDepsMap(pluginRecord.shared, `plugins.${pluginId}.shared`),\n );\n }\n\n return Object.fromEntries(refs);\n}\n\nexport async function syncResolvedSharedDeps(opts: {\n configDir: string;\n hostMode: \"local\" | \"remote\";\n bosConfig?: SharedDepsConfig;\n env?: BosEnv;\n extendsChain?: string[];\n}): Promise<SharedDepsSyncResult> {\n const bosConfigPath = join(opts.configDir, \"bos.config.json\");\n const resolvedConfigPath = join(opts.configDir, \".bos\", \"bos.resolved-config.json\");\n const packageJsonPath = join(opts.configDir, \"package.json\");\n const generatedPath = join(opts.configDir, \".bos\", \"generated\", \"shared-deps.json\");\n\n const bosConfig: unknown = opts.bosConfig ?? JSON.parse(readFileSync(bosConfigPath, \"utf-8\"));\n if (!isPlainObject(bosConfig)) {\n throw new Error(\"bos.config.json must be an object\");\n }\n\n const pkgJson = existsSync(packageJsonPath)\n ? (JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as PackageJson)\n : {};\n\n const originalBos = JSON.stringify(bosConfig);\n const originalPkg = JSON.stringify(pkgJson);\n\n const mode = opts.hostMode === \"local\" ? \"catalog->bos\" : \"bos->catalog\";\n const refsByName = collectSharedDepRefs(bosConfig);\n const catalog = pkgJson.workspaces?.catalog ?? {};\n\n const resolvedDeps: Record<string, ResolvedSharedDep> = {};\n\n for (const [name, refs] of Object.entries(refsByName)) {\n const first = refs[0];\n if (!first) continue;\n\n const exactFromConfig =\n extractSemverExact(first.config.version) ?? extractSemverExact(first.config.requiredVersion);\n const exactFromCatalog = extractSemverExact(catalog[name]);\n const version =\n mode === \"catalog->bos\"\n ? (exactFromCatalog ?? exactFromConfig)\n : (exactFromConfig ?? exactFromCatalog);\n\n if (!version) {\n const sources = refs.map((ref) => ref.source).join(\", \");\n throw new Error(\n `Could not resolve exact version for shared dependency \"${name}\" from ${sources}`,\n );\n }\n\n if (mode === \"catalog->bos\" && exactFromCatalog === null && exactFromConfig) {\n catalog[name] = exactFromConfig;\n }\n\n if (mode === \"bos->catalog\" && catalog[name] !== version) {\n catalog[name] = version;\n }\n\n for (const ref of refs) {\n ref.config.version = version;\n ref.config.requiredVersion = caretRange(version);\n ref.config.shareScope = ref.config.shareScope ?? \"default\";\n }\n\n resolvedDeps[name] = {\n name,\n version,\n requiredVersion: caretRange(version),\n shareScope: first.config.shareScope ?? \"default\",\n singleton: first.config.singleton ?? false,\n eager: first.config.eager ?? false,\n strictVersion: first.config.strictVersion ?? false,\n sources: refs.map((ref) => ref.source).sort((a, b) => a.localeCompare(b)),\n };\n }\n\n if (!pkgJson.workspaces) {\n pkgJson.workspaces = { packages: [], catalog: {} };\n }\n pkgJson.workspaces.catalog = catalog;\n\n const nextBos = JSON.stringify(bosConfig);\n const nextPkg = JSON.stringify(pkgJson);\n const bosConfigChanged = nextBos !== originalBos;\n const catalogChanged = nextPkg !== originalPkg;\n\n if (bosConfigChanged) {\n const resolvedDir = dirname(resolvedConfigPath);\n if (!existsSync(resolvedDir)) {\n mkdirSync(resolvedDir, { recursive: true });\n }\n\n const ordered = rebuildOrderedConfig(bosConfig);\n const meta: ResolvedConfigMeta = {\n env: opts.env ?? \"development\",\n resolvedAt: new Date().toISOString(),\n extendsChain: opts.extendsChain ?? [],\n source: \"shared-sync\",\n };\n const resolvedOutput = {\n _resolved: meta,\n ...ordered,\n };\n\n writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\\n`);\n }\n\n if (catalogChanged) {\n writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\\n`);\n }\n\n const stableResolvedDeps = stableDepsObject(resolvedDeps);\n const resolved: ResolvedSharedDeps = {\n deps: stableResolvedDeps,\n fingerprintSha256: fingerprintResolved(stableResolvedDeps),\n };\n\n const nextGenerated = {\n schemaVersion: 1,\n kind: \"everything-dev/shared-deps\",\n generatedAt: new Date().toISOString(),\n deps: stableResolvedDeps,\n fingerprintSha256: resolved.fingerprintSha256,\n inputs: {\n mode,\n hostMode: opts.hostMode,\n },\n };\n\n let prevFingerprint: string | null = null;\n try {\n const prev = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n prevFingerprint = prev?.fingerprintSha256 ?? null;\n } catch {\n // ignore\n }\n\n mkdirSync(dirname(generatedPath), { recursive: true });\n writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\\n`);\n\n const generatedChanged = prevFingerprint !== nextGenerated.fingerprintSha256;\n\n return {\n mode,\n hostMode: opts.hostMode,\n bosConfigChanged,\n catalogChanged,\n generatedChanged,\n resolved,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,200 @@
1
+ import { isPlainObject, rebuildOrderedConfig } from "./merge.mjs";
2
+ import { SharedDepMapSchema } from "./types.mjs";
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { createHash } from "node:crypto";
6
+
7
+ //#region src/shared-deps.ts
8
+ function sha256(input) {
9
+ return createHash("sha256").update(input).digest("hex");
10
+ }
11
+ function extractSemverExact(input) {
12
+ if (typeof input !== "string") return null;
13
+ const match = input.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
14
+ return match ? match[0] : null;
15
+ }
16
+ function caretRange(version) {
17
+ return `^${version}`;
18
+ }
19
+ function stableDepsObject(deps) {
20
+ const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));
21
+ const out = {};
22
+ for (const key of keys) out[key] = deps[key];
23
+ return out;
24
+ }
25
+ function normalizeSharedDepConfig(config) {
26
+ return {
27
+ version: config.version,
28
+ requiredVersion: config.requiredVersion ?? false,
29
+ singleton: config.singleton ?? false,
30
+ eager: config.eager ?? false,
31
+ strictVersion: config.strictVersion ?? false,
32
+ shareScope: config.shareScope ?? "default"
33
+ };
34
+ }
35
+ function getObject(value) {
36
+ return isPlainObject(value) ? value : void 0;
37
+ }
38
+ function getSharedDepsMap(value, source) {
39
+ if (value === void 0) return void 0;
40
+ if (!SharedDepMapSchema.safeParse(value).success) throw new Error(`Invalid shared dependency map at ${source}`);
41
+ return value;
42
+ }
43
+ function writeFileIfChanged(filePath, nextContent) {
44
+ try {
45
+ if (readFileSync(filePath, "utf-8") === nextContent) return false;
46
+ } catch {}
47
+ writeFileSync(filePath, nextContent);
48
+ return true;
49
+ }
50
+ function fingerprintResolved(deps) {
51
+ return sha256(JSON.stringify(stableDepsObject(deps)));
52
+ }
53
+ function isSameSharedDepConfig(a, b) {
54
+ const left = normalizeSharedDepConfig(a);
55
+ const right = normalizeSharedDepConfig(b);
56
+ return left.version === right.version && left.requiredVersion === right.requiredVersion && left.singleton === right.singleton && left.eager === right.eager && left.strictVersion === right.strictVersion && left.shareScope === right.shareScope;
57
+ }
58
+ function collectSharedDepRefs(bosConfig) {
59
+ const refs = /* @__PURE__ */ new Map();
60
+ const app = getObject(bosConfig.app);
61
+ const appUi = getObject(app?.ui);
62
+ const appApi = getObject(app?.api);
63
+ const appAuth = getObject(app?.auth);
64
+ const plugins = getObject(bosConfig.plugins);
65
+ if (appUi && "shared" in appUi) throw new Error("app.ui.shared is no longer supported. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.");
66
+ const append = (source, shared) => {
67
+ if (!shared) return;
68
+ for (const [name, config] of Object.entries(shared)) {
69
+ const existing = refs.get(name);
70
+ if (!existing) {
71
+ refs.set(name, [{
72
+ source,
73
+ config
74
+ }]);
75
+ continue;
76
+ }
77
+ if (!isSameSharedDepConfig(existing[0].config, config)) {
78
+ const previous = existing.map((ref) => ref.source).join(", ");
79
+ throw new Error(`Conflicting shared dependency "${name}" between ${previous} and ${source}`);
80
+ }
81
+ existing.push({
82
+ source,
83
+ config
84
+ });
85
+ }
86
+ };
87
+ append("app.api", getSharedDepsMap(appApi?.shared, "app.api.shared"));
88
+ append("app.auth", getSharedDepsMap(appAuth?.shared, "app.auth.shared"));
89
+ for (const [pluginId, plugin] of Object.entries(plugins ?? {})) {
90
+ const pluginRecord = getObject(plugin);
91
+ if (!pluginRecord) continue;
92
+ const pluginUi = getObject(getObject(pluginRecord.app)?.ui);
93
+ if (pluginUi && "shared" in pluginUi) throw new Error(`app.ui.shared is no longer supported in plugins.${pluginId}. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.`);
94
+ append(`plugins.${pluginId}`, getSharedDepsMap(pluginRecord.shared, `plugins.${pluginId}.shared`));
95
+ }
96
+ return Object.fromEntries(refs);
97
+ }
98
+ async function syncResolvedSharedDeps(opts) {
99
+ const bosConfigPath = join(opts.configDir, "bos.config.json");
100
+ const resolvedConfigPath = join(opts.configDir, ".bos", "bos.resolved-config.json");
101
+ const packageJsonPath = join(opts.configDir, "package.json");
102
+ const generatedPath = join(opts.configDir, ".bos", "generated", "shared-deps.json");
103
+ const bosConfig = opts.bosConfig ?? JSON.parse(readFileSync(bosConfigPath, "utf-8"));
104
+ if (!isPlainObject(bosConfig)) throw new Error("bos.config.json must be an object");
105
+ const pkgJson = existsSync(packageJsonPath) ? JSON.parse(readFileSync(packageJsonPath, "utf-8")) : {};
106
+ const originalBos = JSON.stringify(bosConfig);
107
+ const originalPkg = JSON.stringify(pkgJson);
108
+ const mode = opts.hostMode === "local" ? "catalog->bos" : "bos->catalog";
109
+ const refsByName = collectSharedDepRefs(bosConfig);
110
+ const catalog = pkgJson.workspaces?.catalog ?? {};
111
+ const resolvedDeps = {};
112
+ for (const [name, refs] of Object.entries(refsByName)) {
113
+ const first = refs[0];
114
+ if (!first) continue;
115
+ const exactFromConfig = extractSemverExact(first.config.version) ?? extractSemverExact(first.config.requiredVersion);
116
+ const exactFromCatalog = extractSemverExact(catalog[name]);
117
+ const version = mode === "catalog->bos" ? exactFromCatalog ?? exactFromConfig : exactFromConfig ?? exactFromCatalog;
118
+ if (!version) {
119
+ const sources = refs.map((ref) => ref.source).join(", ");
120
+ throw new Error(`Could not resolve exact version for shared dependency "${name}" from ${sources}`);
121
+ }
122
+ if (mode === "catalog->bos" && exactFromCatalog === null && exactFromConfig) catalog[name] = exactFromConfig;
123
+ if (mode === "bos->catalog" && catalog[name] !== version) catalog[name] = version;
124
+ for (const ref of refs) {
125
+ ref.config.version = version;
126
+ ref.config.requiredVersion = caretRange(version);
127
+ ref.config.shareScope = ref.config.shareScope ?? "default";
128
+ }
129
+ resolvedDeps[name] = {
130
+ name,
131
+ version,
132
+ requiredVersion: caretRange(version),
133
+ shareScope: first.config.shareScope ?? "default",
134
+ singleton: first.config.singleton ?? false,
135
+ eager: first.config.eager ?? false,
136
+ strictVersion: first.config.strictVersion ?? false,
137
+ sources: refs.map((ref) => ref.source).sort((a, b) => a.localeCompare(b))
138
+ };
139
+ }
140
+ if (!pkgJson.workspaces) pkgJson.workspaces = {
141
+ packages: [],
142
+ catalog: {}
143
+ };
144
+ pkgJson.workspaces.catalog = catalog;
145
+ const nextBos = JSON.stringify(bosConfig);
146
+ const nextPkg = JSON.stringify(pkgJson);
147
+ const bosConfigChanged = nextBos !== originalBos;
148
+ const catalogChanged = nextPkg !== originalPkg;
149
+ if (bosConfigChanged) {
150
+ const resolvedDir = dirname(resolvedConfigPath);
151
+ if (!existsSync(resolvedDir)) mkdirSync(resolvedDir, { recursive: true });
152
+ const ordered = rebuildOrderedConfig(bosConfig);
153
+ const resolvedOutput = {
154
+ _resolved: {
155
+ env: opts.env ?? "development",
156
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
157
+ extendsChain: opts.extendsChain ?? [],
158
+ source: "shared-sync"
159
+ },
160
+ ...ordered
161
+ };
162
+ writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\n`);
163
+ }
164
+ if (catalogChanged) writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\n`);
165
+ const stableResolvedDeps = stableDepsObject(resolvedDeps);
166
+ const resolved = {
167
+ deps: stableResolvedDeps,
168
+ fingerprintSha256: fingerprintResolved(stableResolvedDeps)
169
+ };
170
+ const nextGenerated = {
171
+ schemaVersion: 1,
172
+ kind: "everything-dev/shared-deps",
173
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
174
+ deps: stableResolvedDeps,
175
+ fingerprintSha256: resolved.fingerprintSha256,
176
+ inputs: {
177
+ mode,
178
+ hostMode: opts.hostMode
179
+ }
180
+ };
181
+ let prevFingerprint = null;
182
+ try {
183
+ prevFingerprint = JSON.parse(readFileSync(generatedPath, "utf-8"))?.fingerprintSha256 ?? null;
184
+ } catch {}
185
+ mkdirSync(dirname(generatedPath), { recursive: true });
186
+ writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\n`);
187
+ const generatedChanged = prevFingerprint !== nextGenerated.fingerprintSha256;
188
+ return {
189
+ mode,
190
+ hostMode: opts.hostMode,
191
+ bosConfigChanged,
192
+ catalogChanged,
193
+ generatedChanged,
194
+ resolved
195
+ };
196
+ }
197
+
198
+ //#endregion
199
+ export { syncResolvedSharedDeps };
200
+ //# sourceMappingURL=shared-deps.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-deps.mjs","names":[],"sources":["../src/shared-deps.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { type BosEnv, isPlainObject, type ResolvedConfigMeta, rebuildOrderedConfig } from \"./merge\";\nimport { type SharedDepConfig, SharedDepMapSchema } from \"./types\";\n\ninterface PackageJson {\n workspaces?: {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n}\n\ninterface SharedDepRef {\n source: string;\n config: SharedDepConfig;\n}\n\ntype SharedDepsConfig = Record<string, unknown>;\n\ninterface NormalizedSharedDepConfig {\n version: string;\n requiredVersion: string | false;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n shareScope: string;\n}\n\nexport interface ResolvedSharedDep {\n name: string;\n version: string;\n requiredVersion: string;\n shareScope: string;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n sources: string[];\n}\n\nexport interface ResolvedSharedDeps {\n deps: Record<string, ResolvedSharedDep>;\n fingerprintSha256: string;\n}\n\nexport interface SharedDepsSyncResult {\n mode: \"catalog->bos\" | \"bos->catalog\";\n hostMode: \"local\" | \"remote\";\n bosConfigChanged: boolean;\n catalogChanged: boolean;\n generatedChanged: boolean;\n resolved: ResolvedSharedDeps;\n}\n\nfunction sha256(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction extractSemverExact(input: unknown): string | null {\n if (typeof input !== \"string\") return null;\n const match = input.match(/\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?/);\n return match ? match[0] : null;\n}\n\nfunction caretRange(version: string): string {\n return `^${version}`;\n}\n\nfunction stableDepsObject(\n deps: Record<string, ResolvedSharedDep>,\n): Record<string, ResolvedSharedDep> {\n const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));\n const out: Record<string, ResolvedSharedDep> = {};\n for (const key of keys) {\n out[key] = deps[key]!;\n }\n return out;\n}\n\nfunction normalizeSharedDepConfig(config: SharedDepConfig): NormalizedSharedDepConfig {\n return {\n version: config.version,\n requiredVersion: config.requiredVersion ?? false,\n singleton: config.singleton ?? false,\n eager: config.eager ?? false,\n strictVersion: config.strictVersion ?? false,\n shareScope: config.shareScope ?? \"default\",\n };\n}\n\nfunction getObject(value: unknown): Record<string, unknown> | undefined {\n return isPlainObject(value) ? value : undefined;\n}\n\nfunction getSharedDepsMap(\n value: unknown,\n source: string,\n): Record<string, SharedDepConfig> | undefined {\n if (value === undefined) return undefined;\n const parsed = SharedDepMapSchema.safeParse(value);\n if (!parsed.success) {\n throw new Error(`Invalid shared dependency map at ${source}`);\n }\n return value as Record<string, SharedDepConfig>;\n}\n\nfunction writeFileIfChanged(filePath: string, nextContent: string): boolean {\n try {\n const current = readFileSync(filePath, \"utf-8\");\n if (current === nextContent) return false;\n } catch {\n // file does not exist yet\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nfunction fingerprintResolved(deps: Record<string, ResolvedSharedDep>): string {\n return sha256(JSON.stringify(stableDepsObject(deps)));\n}\n\nfunction isSameSharedDepConfig(a: SharedDepConfig, b: SharedDepConfig): boolean {\n const left = normalizeSharedDepConfig(a);\n const right = normalizeSharedDepConfig(b);\n\n return (\n left.version === right.version &&\n left.requiredVersion === right.requiredVersion &&\n left.singleton === right.singleton &&\n left.eager === right.eager &&\n left.strictVersion === right.strictVersion &&\n left.shareScope === right.shareScope\n );\n}\n\nfunction collectSharedDepRefs(bosConfig: SharedDepsConfig): Record<string, SharedDepRef[]> {\n const refs = new Map<string, SharedDepRef[]>();\n\n const app = getObject(bosConfig.app);\n const appUi = getObject(app?.ui);\n const appApi = getObject(app?.api);\n const appAuth = getObject(app?.auth);\n const plugins = getObject(bosConfig.plugins);\n\n if (appUi && \"shared\" in appUi) {\n throw new Error(\n \"app.ui.shared is no longer supported. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.\",\n );\n }\n\n const append = (source: string, shared: Record<string, SharedDepConfig> | undefined) => {\n if (!shared) return;\n\n for (const [name, config] of Object.entries(shared)) {\n const existing = refs.get(name);\n if (!existing) {\n refs.set(name, [{ source, config }]);\n continue;\n }\n\n if (!isSameSharedDepConfig(existing[0]!.config, config)) {\n const previous = existing.map((ref) => ref.source).join(\", \");\n throw new Error(\n `Conflicting shared dependency \"${name}\" between ${previous} and ${source}`,\n );\n }\n\n existing.push({ source, config });\n }\n };\n\n append(\"app.api\", getSharedDepsMap(appApi?.shared, \"app.api.shared\"));\n append(\"app.auth\", getSharedDepsMap(appAuth?.shared, \"app.auth.shared\"));\n\n for (const [pluginId, plugin] of Object.entries(plugins ?? {})) {\n const pluginRecord = getObject(plugin);\n if (!pluginRecord) continue;\n\n const pluginApp = getObject(pluginRecord.app);\n const pluginUi = getObject(pluginApp?.ui);\n if (pluginUi && \"shared\" in pluginUi) {\n throw new Error(\n `app.ui.shared is no longer supported in plugins.${pluginId}. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.`,\n );\n }\n append(\n `plugins.${pluginId}`,\n getSharedDepsMap(pluginRecord.shared, `plugins.${pluginId}.shared`),\n );\n }\n\n return Object.fromEntries(refs);\n}\n\nexport async function syncResolvedSharedDeps(opts: {\n configDir: string;\n hostMode: \"local\" | \"remote\";\n bosConfig?: SharedDepsConfig;\n env?: BosEnv;\n extendsChain?: string[];\n}): Promise<SharedDepsSyncResult> {\n const bosConfigPath = join(opts.configDir, \"bos.config.json\");\n const resolvedConfigPath = join(opts.configDir, \".bos\", \"bos.resolved-config.json\");\n const packageJsonPath = join(opts.configDir, \"package.json\");\n const generatedPath = join(opts.configDir, \".bos\", \"generated\", \"shared-deps.json\");\n\n const bosConfig: unknown = opts.bosConfig ?? JSON.parse(readFileSync(bosConfigPath, \"utf-8\"));\n if (!isPlainObject(bosConfig)) {\n throw new Error(\"bos.config.json must be an object\");\n }\n\n const pkgJson = existsSync(packageJsonPath)\n ? (JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as PackageJson)\n : {};\n\n const originalBos = JSON.stringify(bosConfig);\n const originalPkg = JSON.stringify(pkgJson);\n\n const mode = opts.hostMode === \"local\" ? \"catalog->bos\" : \"bos->catalog\";\n const refsByName = collectSharedDepRefs(bosConfig);\n const catalog = pkgJson.workspaces?.catalog ?? {};\n\n const resolvedDeps: Record<string, ResolvedSharedDep> = {};\n\n for (const [name, refs] of Object.entries(refsByName)) {\n const first = refs[0];\n if (!first) continue;\n\n const exactFromConfig =\n extractSemverExact(first.config.version) ?? extractSemverExact(first.config.requiredVersion);\n const exactFromCatalog = extractSemverExact(catalog[name]);\n const version =\n mode === \"catalog->bos\"\n ? (exactFromCatalog ?? exactFromConfig)\n : (exactFromConfig ?? exactFromCatalog);\n\n if (!version) {\n const sources = refs.map((ref) => ref.source).join(\", \");\n throw new Error(\n `Could not resolve exact version for shared dependency \"${name}\" from ${sources}`,\n );\n }\n\n if (mode === \"catalog->bos\" && exactFromCatalog === null && exactFromConfig) {\n catalog[name] = exactFromConfig;\n }\n\n if (mode === \"bos->catalog\" && catalog[name] !== version) {\n catalog[name] = version;\n }\n\n for (const ref of refs) {\n ref.config.version = version;\n ref.config.requiredVersion = caretRange(version);\n ref.config.shareScope = ref.config.shareScope ?? \"default\";\n }\n\n resolvedDeps[name] = {\n name,\n version,\n requiredVersion: caretRange(version),\n shareScope: first.config.shareScope ?? \"default\",\n singleton: first.config.singleton ?? false,\n eager: first.config.eager ?? false,\n strictVersion: first.config.strictVersion ?? false,\n sources: refs.map((ref) => ref.source).sort((a, b) => a.localeCompare(b)),\n };\n }\n\n if (!pkgJson.workspaces) {\n pkgJson.workspaces = { packages: [], catalog: {} };\n }\n pkgJson.workspaces.catalog = catalog;\n\n const nextBos = JSON.stringify(bosConfig);\n const nextPkg = JSON.stringify(pkgJson);\n const bosConfigChanged = nextBos !== originalBos;\n const catalogChanged = nextPkg !== originalPkg;\n\n if (bosConfigChanged) {\n const resolvedDir = dirname(resolvedConfigPath);\n if (!existsSync(resolvedDir)) {\n mkdirSync(resolvedDir, { recursive: true });\n }\n\n const ordered = rebuildOrderedConfig(bosConfig);\n const meta: ResolvedConfigMeta = {\n env: opts.env ?? \"development\",\n resolvedAt: new Date().toISOString(),\n extendsChain: opts.extendsChain ?? [],\n source: \"shared-sync\",\n };\n const resolvedOutput = {\n _resolved: meta,\n ...ordered,\n };\n\n writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\\n`);\n }\n\n if (catalogChanged) {\n writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\\n`);\n }\n\n const stableResolvedDeps = stableDepsObject(resolvedDeps);\n const resolved: ResolvedSharedDeps = {\n deps: stableResolvedDeps,\n fingerprintSha256: fingerprintResolved(stableResolvedDeps),\n };\n\n const nextGenerated = {\n schemaVersion: 1,\n kind: \"everything-dev/shared-deps\",\n generatedAt: new Date().toISOString(),\n deps: stableResolvedDeps,\n fingerprintSha256: resolved.fingerprintSha256,\n inputs: {\n mode,\n hostMode: opts.hostMode,\n },\n };\n\n let prevFingerprint: string | null = null;\n try {\n const prev = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n prevFingerprint = prev?.fingerprintSha256 ?? null;\n } catch {\n // ignore\n }\n\n mkdirSync(dirname(generatedPath), { recursive: true });\n writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\\n`);\n\n const generatedChanged = prevFingerprint !== nextGenerated.fingerprintSha256;\n\n return {\n mode,\n hostMode: opts.hostMode,\n bosConfigChanged,\n catalogChanged,\n generatedChanged,\n resolved,\n };\n}\n"],"mappings":"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"}
package/dist/types.cjs CHANGED
@@ -28,6 +28,7 @@ const SharedConfigSchema = zod.object({
28
28
  shareScope: zod.string().optional()
29
29
  });
30
30
  const SharedDepConfigSchema = SharedConfigSchema;
31
+ const SharedDepMapSchema = zod.record(zod.string(), SharedConfigSchema);
31
32
  const FederationEntrySchema = zod.object({
32
33
  name: zod.string(),
33
34
  url: zod.string(),
@@ -56,7 +57,8 @@ const ComposableAppEntrySchema = zod.object({
56
57
  variables: JsonObjectSchema.optional(),
57
58
  secrets: zod.array(zod.string()).optional(),
58
59
  sidebar: zod.array(SidebarItemSchema).optional(),
59
- routes: zod.array(zod.string()).optional()
60
+ routes: zod.array(zod.string()).optional(),
61
+ shared: SharedDepMapSchema.optional()
60
62
  });
61
63
  const ApiPluginConfigSchema = ComposableAppEntrySchema;
62
64
  const PluginUiConfigSchema = zod.object({
@@ -68,7 +70,6 @@ const PluginUiConfigSchema = zod.object({
68
70
  const BosPluginRefSchema = ComposableAppEntrySchema.extend({
69
71
  version: zod.string().optional(),
70
72
  app: zod.record(zod.string(), zod.unknown()).optional(),
71
- shared: zod.record(zod.string(), zod.record(zod.string(), SharedConfigSchema)).optional(),
72
73
  plugins: zod.record(zod.string(), zod.unknown()).optional()
73
74
  });
74
75
  const PluginRuntimeUiSchema = zod.object({
@@ -91,6 +92,7 @@ const RuntimePluginConfigSchema = zod.object({
91
92
  variables: JsonObjectSchema.optional(),
92
93
  secrets: zod.array(zod.string()).optional(),
93
94
  integrity: zod.string().optional(),
95
+ shared: SharedDepMapSchema.optional(),
94
96
  ui: PluginRuntimeUiSchema.optional(),
95
97
  sidebar: zod.array(SidebarItemSchema).optional(),
96
98
  routes: zod.array(zod.string()).optional()
@@ -102,7 +104,7 @@ const UiConfigSchema = zod.object({
102
104
  integrity: zod.string().optional(),
103
105
  ssr: zod.string().optional(),
104
106
  ssrIntegrity: zod.string().optional()
105
- });
107
+ }).strict();
106
108
  const HostConfigSchema = zod.object({
107
109
  development: zod.string(),
108
110
  production: zod.string(),
@@ -147,7 +149,6 @@ const BosConfigInputSchema = zod.lazy(() => zod.object({
147
149
  routes: zod.array(zod.string()).optional(),
148
150
  sidebar: zod.array(SidebarItemSchema).optional(),
149
151
  app: zod.record(zod.string(), BosConfigInputAppEntrySchema).optional(),
150
- shared: zod.record(zod.string(), zod.record(zod.string(), SharedConfigSchema)).optional(),
151
152
  plugins: zod.record(zod.string(), zod.union([zod.string(), BosConfigInputSchema])).optional(),
152
153
  ci: CiConfigSchema.optional()
153
154
  }));
@@ -163,7 +164,6 @@ const BosConfigSchema = zod.object({
163
164
  staging: BosStagingSchema.optional(),
164
165
  repository: zod.string().optional(),
165
166
  ci: CiConfigSchema.optional(),
166
- shared: zod.record(zod.string(), zod.record(zod.string(), SharedConfigSchema)).optional(),
167
167
  plugins: zod.record(zod.string(), zod.union([zod.string(), BosPluginRefSchema])).optional(),
168
168
  app: zod.object({
169
169
  host: HostConfigSchema,
@@ -190,10 +190,6 @@ const RuntimeConfigSchema = zod.object({
190
190
  secrets: zod.array(zod.string()).optional(),
191
191
  remoteUrl: zod.string().optional()
192
192
  }),
193
- shared: zod.object({
194
- ui: zod.record(zod.string(), SharedConfigSchema).optional(),
195
- plugins: zod.record(zod.string(), SharedConfigSchema).optional()
196
- }).optional(),
197
193
  ui: FederationEntrySchema.extend({
198
194
  localPath: zod.string().optional(),
199
195
  port: zod.number().optional(),
@@ -205,7 +201,8 @@ const RuntimeConfigSchema = zod.object({
205
201
  port: zod.number().optional(),
206
202
  proxy: zod.string().optional(),
207
203
  variables: JsonObjectSchema.optional(),
208
- secrets: zod.array(zod.string()).optional()
204
+ secrets: zod.array(zod.string()).optional(),
205
+ shared: SharedDepMapSchema.optional()
209
206
  }),
210
207
  auth: FederationEntrySchema.extend({
211
208
  localPath: zod.string().optional(),
@@ -213,7 +210,8 @@ const RuntimeConfigSchema = zod.object({
213
210
  proxy: zod.string().optional(),
214
211
  variables: JsonObjectSchema.optional(),
215
212
  secrets: zod.array(zod.string()).optional(),
216
- sidebar: zod.array(SidebarItemSchema).optional()
213
+ sidebar: zod.array(SidebarItemSchema).optional(),
214
+ shared: SharedDepMapSchema.optional()
217
215
  }).optional(),
218
216
  plugins: zod.record(zod.string(), RuntimePluginConfigSchema).optional()
219
217
  });
@@ -242,13 +240,15 @@ const ClientRuntimeConfigSchema = zod.object({
242
240
  name: zod.string(),
243
241
  url: zod.string(),
244
242
  entry: zod.string(),
245
- integrity: zod.string().optional()
243
+ integrity: zod.string().optional(),
244
+ variables: JsonObjectSchema.optional()
246
245
  }).optional(),
247
246
  auth: zod.object({
248
247
  name: zod.string(),
249
248
  url: zod.string(),
250
249
  entry: zod.string(),
251
250
  integrity: zod.string().optional(),
251
+ variables: JsonObjectSchema.optional(),
252
252
  sidebar: zod.array(SidebarItemSchema).optional()
253
253
  }).optional(),
254
254
  plugins: zod.record(zod.string(), zod.object({
@@ -256,6 +256,7 @@ const ClientRuntimeConfigSchema = zod.object({
256
256
  url: zod.string(),
257
257
  entry: zod.string(),
258
258
  integrity: zod.string().optional(),
259
+ variables: JsonObjectSchema.optional(),
259
260
  ui: zod.object({
260
261
  name: zod.string(),
261
262
  url: zod.string(),
@@ -289,6 +290,7 @@ exports.RuntimeLineageSchema = RuntimeLineageSchema;
289
290
  exports.RuntimePluginConfigSchema = RuntimePluginConfigSchema;
290
291
  exports.SharedConfigSchema = SharedConfigSchema;
291
292
  exports.SharedDepConfigSchema = SharedDepConfigSchema;
293
+ exports.SharedDepMapSchema = SharedDepMapSchema;
292
294
  exports.SidebarItemSchema = SidebarItemSchema;
293
295
  exports.SidebarRoleSchema = SidebarRoleSchema;
294
296
  exports.SourceModeSchema = SourceModeSchema;