everything-dev 1.12.3 → 1.13.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 (124) hide show
  1. package/cli.js +1 -1
  2. package/dist/app.cjs +24 -101
  3. package/dist/app.cjs.map +1 -1
  4. package/dist/app.mjs +25 -102
  5. package/dist/app.mjs.map +1 -1
  6. package/dist/cli/init.cjs +143 -66
  7. package/dist/cli/init.cjs.map +1 -1
  8. package/dist/cli/init.d.cts +1 -1
  9. package/dist/cli/init.d.cts.map +1 -1
  10. package/dist/cli/init.d.mts +1 -1
  11. package/dist/cli/init.d.mts.map +1 -1
  12. package/dist/cli/init.mjs +144 -67
  13. package/dist/cli/init.mjs.map +1 -1
  14. package/dist/cli/prompts.cjs +3 -3
  15. package/dist/cli/prompts.cjs.map +1 -1
  16. package/dist/cli/prompts.mjs +3 -3
  17. package/dist/cli/prompts.mjs.map +1 -1
  18. package/dist/cli/sync.cjs +15 -56
  19. package/dist/cli/sync.cjs.map +1 -1
  20. package/dist/cli/sync.mjs +15 -56
  21. package/dist/cli/sync.mjs.map +1 -1
  22. package/dist/cli/upgrade.cjs +3 -1
  23. package/dist/cli/upgrade.cjs.map +1 -1
  24. package/dist/cli/upgrade.mjs +3 -1
  25. package/dist/cli/upgrade.mjs.map +1 -1
  26. package/dist/config.cjs +223 -81
  27. package/dist/config.cjs.map +1 -1
  28. package/dist/config.d.cts +21 -5
  29. package/dist/config.d.cts.map +1 -1
  30. package/dist/config.d.mts +21 -5
  31. package/dist/config.d.mts.map +1 -1
  32. package/dist/config.mjs +217 -83
  33. package/dist/config.mjs.map +1 -1
  34. package/dist/contract.d.cts +104 -8
  35. package/dist/contract.d.cts.map +1 -1
  36. package/dist/contract.d.mts +104 -8
  37. package/dist/contract.d.mts.map +1 -1
  38. package/dist/host.cjs +34 -1
  39. package/dist/host.cjs.map +1 -1
  40. package/dist/host.d.cts.map +1 -1
  41. package/dist/host.d.mts.map +1 -1
  42. package/dist/host.mjs +34 -1
  43. package/dist/host.mjs.map +1 -1
  44. package/dist/index.cjs +17 -0
  45. package/dist/index.d.cts +5 -3
  46. package/dist/index.d.mts +5 -3
  47. package/dist/index.mjs +5 -3
  48. package/dist/merge.cjs +113 -0
  49. package/dist/merge.cjs.map +1 -0
  50. package/dist/merge.d.cts +7 -0
  51. package/dist/merge.d.cts.map +1 -0
  52. package/dist/merge.d.mts +7 -0
  53. package/dist/merge.d.mts.map +1 -0
  54. package/dist/merge.mjs +107 -0
  55. package/dist/merge.mjs.map +1 -0
  56. package/dist/plugin.cjs +117 -105
  57. package/dist/plugin.cjs.map +1 -1
  58. package/dist/plugin.d.cts +114 -8
  59. package/dist/plugin.d.cts.map +1 -1
  60. package/dist/plugin.d.mts +114 -8
  61. package/dist/plugin.d.mts.map +1 -1
  62. package/dist/plugin.mjs +117 -105
  63. package/dist/plugin.mjs.map +1 -1
  64. package/dist/service-descriptor.cjs +21 -0
  65. package/dist/service-descriptor.cjs.map +1 -1
  66. package/dist/service-descriptor.d.cts +23 -1
  67. package/dist/service-descriptor.d.cts.map +1 -1
  68. package/dist/service-descriptor.d.mts +23 -1
  69. package/dist/service-descriptor.d.mts.map +1 -1
  70. package/dist/service-descriptor.mjs +21 -0
  71. package/dist/service-descriptor.mjs.map +1 -1
  72. package/dist/shared.cjs +24 -2
  73. package/dist/shared.cjs.map +1 -1
  74. package/dist/shared.d.cts +3 -0
  75. package/dist/shared.d.cts.map +1 -1
  76. package/dist/shared.d.mts +3 -0
  77. package/dist/shared.d.mts.map +1 -1
  78. package/dist/shared.mjs +25 -3
  79. package/dist/shared.mjs.map +1 -1
  80. package/dist/sidebar.cjs +124 -0
  81. package/dist/sidebar.cjs.map +1 -0
  82. package/dist/sidebar.d.cts +8 -0
  83. package/dist/sidebar.d.cts.map +1 -0
  84. package/dist/sidebar.d.mts +8 -0
  85. package/dist/sidebar.d.mts.map +1 -0
  86. package/dist/sidebar.mjs +122 -0
  87. package/dist/sidebar.mjs.map +1 -0
  88. package/dist/types.cjs +104 -10
  89. package/dist/types.cjs.map +1 -1
  90. package/dist/types.d.cts +256 -29
  91. package/dist/types.d.cts.map +1 -1
  92. package/dist/types.d.mts +256 -29
  93. package/dist/types.d.mts.map +1 -1
  94. package/dist/types.mjs +100 -11
  95. package/dist/types.mjs.map +1 -1
  96. package/dist/utils/path-match.cjs +18 -0
  97. package/dist/utils/path-match.cjs.map +1 -0
  98. package/dist/utils/path-match.mjs +17 -0
  99. package/dist/utils/path-match.mjs.map +1 -0
  100. package/dist/utils/save-config.cjs +19 -0
  101. package/dist/utils/save-config.cjs.map +1 -0
  102. package/dist/utils/save-config.mjs +18 -0
  103. package/dist/utils/save-config.mjs.map +1 -0
  104. package/package.json +3 -2
  105. package/skills/dev-workflow/SKILL.md +8 -0
  106. package/skills/extends-config/SKILL.md +132 -0
  107. package/skills/init-upgrade/SKILL.md +128 -0
  108. package/skills/publish-sync/SKILL.md +30 -0
  109. package/src/app.ts +23 -118
  110. package/src/cli/init.ts +199 -100
  111. package/src/cli/prompts.ts +2 -2
  112. package/src/cli/sync.ts +27 -96
  113. package/src/cli/upgrade.ts +2 -0
  114. package/src/config.ts +356 -132
  115. package/src/host.ts +45 -0
  116. package/src/index.ts +1 -0
  117. package/src/merge.ts +198 -0
  118. package/src/plugin.ts +340 -318
  119. package/src/service-descriptor.ts +23 -0
  120. package/src/shared.ts +48 -5
  121. package/src/sidebar.ts +162 -0
  122. package/src/types.ts +134 -28
  123. package/src/utils/path-match.ts +16 -0
  124. package/src/utils/save-config.ts +20 -0
package/dist/config.mjs CHANGED
@@ -1,12 +1,14 @@
1
- import { fetchBosConfigFromFastKv } from "./fastkv.mjs";
1
+ import { fetchBosConfigFromFastKv, fetchPluginFromRegistry, parsePluginBosUrl } from "./fastkv.mjs";
2
+ import { BOS_CONFIG_ORDER, isPlainObject, mergeBosConfigWithExtends, rebuildOrderedConfig, resolveExtendsRef } from "./merge.mjs";
2
3
  import { getNetworkIdForAccount } from "./network.mjs";
3
4
  import { BosConfigSchema } from "./types.mjs";
4
- import { existsSync, readFileSync } from "node:fs";
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
6
  import { dirname, isAbsolute, join, resolve } from "node:path";
6
7
 
7
8
  //#region src/config.ts
8
9
  const LOCAL_PREFIX = "local:";
9
10
  const DEFAULT_HOST_PORT = 3e3;
11
+ const RESOLVED_CONFIG_FILENAME = "bos.resolved-config.json";
10
12
  let cachedConfig = null;
11
13
  let projectRoot = null;
12
14
  function clearConfigCache() {
@@ -36,16 +38,17 @@ async function loadConfig(options) {
36
38
  return null;
37
39
  }
38
40
  const baseDir = dirname(configPath);
41
+ const env = options?.env ?? "development";
42
+ const runtimeEnv = env === "staging" ? "production" : env;
39
43
  try {
40
44
  const extendedChain = [];
41
- const parsed = await resolveConfigWithExtends(configPath, baseDir, /* @__PURE__ */ new Set(), extendedChain);
45
+ const parsed = await resolveConfigWithExtends(configPath, baseDir, /* @__PURE__ */ new Set(), extendedChain, env);
42
46
  const config = BosConfigSchema.parse(parsed);
43
47
  cachedConfig = config;
44
48
  projectRoot = baseDir;
45
- const pluginRuntime = await resolveRuntimePlugins(config.plugins ?? {}, baseDir, options?.env ?? "development");
46
49
  return {
47
50
  config,
48
- runtime: buildRuntimeConfig(config, baseDir, options?.env ?? "development", { plugins: pluginRuntime }),
51
+ runtime: buildRuntimeConfig(config, baseDir, runtimeEnv, { plugins: await resolveRuntimePlugins(config.plugins ?? {}, baseDir, runtimeEnv) }),
49
52
  source: {
50
53
  path: configPath,
51
54
  extended: extendedChain.length > 0 ? extendedChain : void 0,
@@ -65,7 +68,60 @@ async function buildRuntimePluginsForConfig(config, baseDir, env) {
65
68
  const plugins = await resolveRuntimePlugins(config.plugins ?? {}, baseDir, env);
66
69
  return Object.keys(plugins).length > 0 ? plugins : void 0;
67
70
  }
68
- function resolveDevelopmentTarget(development, production, baseDir) {
71
+ function getResolvedConfigPath(configDir) {
72
+ return join(configDir, ".bos", RESOLVED_CONFIG_FILENAME);
73
+ }
74
+ function loadResolvedConfig(configDir) {
75
+ const resolvedPath = getResolvedConfigPath(configDir);
76
+ if (!existsSync(resolvedPath)) return null;
77
+ try {
78
+ const raw = JSON.parse(readFileSync(resolvedPath, "utf-8"));
79
+ if (!isPlainObject(raw)) return null;
80
+ const { _resolved, ...configData } = raw;
81
+ return BosConfigSchema.parse(configData);
82
+ } catch {
83
+ return null;
84
+ }
85
+ }
86
+ function writeResolvedConfig(configDir, config, env, extendsChain, source) {
87
+ const resolvedPath = getResolvedConfigPath(configDir);
88
+ const resolvedDir = dirname(resolvedPath);
89
+ if (!existsSync(resolvedDir)) mkdirSync(resolvedDir, { recursive: true });
90
+ const ordered = rebuildOrderedConfig(config);
91
+ const output = {
92
+ _resolved: {
93
+ env,
94
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
95
+ extendsChain: extendsChain ?? [],
96
+ ...source ? { source } : {}
97
+ },
98
+ ...ordered
99
+ };
100
+ const content = `${JSON.stringify(output, null, 2)}\n`;
101
+ try {
102
+ if (readFileSync(resolvedPath, "utf-8") === content) return;
103
+ } catch {}
104
+ writeFileSync(resolvedPath, content);
105
+ }
106
+ function resolveBosConfigPath(configDir) {
107
+ const resolvedPath = getResolvedConfigPath(configDir);
108
+ if (existsSync(resolvedPath)) return resolvedPath;
109
+ return join(configDir, "bos.config.json");
110
+ }
111
+ function readBosConfigForBuild(configDir) {
112
+ const resolvedPath = getResolvedConfigPath(configDir);
113
+ if (existsSync(resolvedPath)) try {
114
+ const raw = JSON.parse(readFileSync(resolvedPath, "utf-8"));
115
+ if (isPlainObject(raw)) {
116
+ const { _resolved, ...configData } = raw;
117
+ return configData;
118
+ }
119
+ } catch {}
120
+ const bosConfigPath = join(configDir, "bos.config.json");
121
+ return JSON.parse(readFileSync(bosConfigPath, "utf-8"));
122
+ }
123
+ function resolveDevelopmentTarget(development, production, baseDir, forceSource) {
124
+ if (forceSource === "remote") return resolveRuntimeTarget(production, baseDir, "remote");
69
125
  const devTarget = resolveRuntimeTarget(development, baseDir);
70
126
  if (devTarget.source === "local" && (!devTarget.localPath || !existsSync(devTarget.localPath))) return resolveRuntimeTarget(production, baseDir, "remote");
71
127
  return devTarget;
@@ -74,12 +130,15 @@ function buildRuntimeConfig(config, baseDir, env, options) {
74
130
  const uiConfig = config.app.ui;
75
131
  const apiConfig = config.app.api;
76
132
  const authConfig = config.app.auth;
77
- const uiRuntime = env === "development" ? resolveDevelopmentTarget(uiConfig.development, uiConfig.production, baseDir) : resolveRuntimeTarget(uiConfig.production, baseDir, "remote");
78
- const apiRuntime = env === "development" ? resolveDevelopmentTarget(apiConfig.development, apiConfig.production, baseDir) : resolveRuntimeTarget(apiConfig.production, baseDir, "remote");
79
- const authRuntime = authConfig ? env === "development" ? resolveDevelopmentTarget(authConfig.development, authConfig.production, baseDir) : resolveRuntimeTarget(authConfig.production, baseDir, "remote") : void 0;
133
+ const uiRuntime = env === "development" ? resolveDevelopmentTarget(uiConfig.development, uiConfig.production, baseDir, options?.uiSource) : resolveRuntimeTarget(uiConfig.production, baseDir, "remote");
134
+ const apiRuntime = env === "development" ? resolveDevelopmentTarget(apiConfig.development, apiConfig.production, baseDir, options?.apiSource) : resolveRuntimeTarget(apiConfig.production, baseDir, "remote");
135
+ const authRuntime = authConfig ? env === "development" ? resolveDevelopmentTarget(authConfig.development, authConfig.production, baseDir, options?.authSource) : resolveRuntimeTarget(authConfig.production, baseDir, "remote") : void 0;
80
136
  const hostConfig = config.app.host;
81
- const hostRuntime = env === "development" ? resolveDevelopmentTarget(hostConfig.development, hostConfig.production, baseDir) : resolveRuntimeTarget(hostConfig.production, baseDir, "remote");
82
- const hostListeningUrl = resolveDevelopmentHostUrl(hostConfig.development);
137
+ const hostRuntime = env === "development" ? resolveDevelopmentTarget(hostConfig.development, hostConfig.production, baseDir, options?.hostSource) : resolveRuntimeTarget(hostConfig.production, baseDir, "remote");
138
+ const hostListeningUrl = env === "development" ? resolveDevelopmentHostUrl(hostConfig.development) : `http://localhost:${hostRuntime.port ?? DEFAULT_HOST_PORT}`;
139
+ const hostIsRemote = hostRuntime.source === "remote";
140
+ const uiIsRemote = uiRuntime.source === "remote";
141
+ const apiIsRemote = apiRuntime.source === "remote";
83
142
  return {
84
143
  env,
85
144
  account: config.account,
@@ -93,9 +152,9 @@ function buildRuntimeConfig(config, baseDir, env, options) {
93
152
  localPath: hostRuntime.localPath,
94
153
  port: hostRuntime.port ?? DEFAULT_HOST_PORT,
95
154
  secrets: hostConfig.secrets,
96
- integrity: env === "production" ? hostConfig.integrity : void 0,
155
+ integrity: hostIsRemote ? hostConfig.integrity : void 0,
97
156
  source: hostRuntime.source,
98
- remoteUrl: hostRuntime.source === "remote" ? hostRuntime.url : void 0
157
+ remoteUrl: hostIsRemote ? hostRuntime.url : void 0
99
158
  },
100
159
  shared: config.shared,
101
160
  ui: {
@@ -104,9 +163,9 @@ function buildRuntimeConfig(config, baseDir, env, options) {
104
163
  entry: uiRuntime.url ? `${uiRuntime.url}/mf-manifest.json` : "/mf-manifest.json",
105
164
  localPath: uiRuntime.localPath,
106
165
  port: uiRuntime.port,
107
- ssrUrl: uiConfig.ssr,
108
- ssrIntegrity: env === "production" ? uiConfig.ssrIntegrity : void 0,
109
- integrity: env === "production" ? uiConfig.integrity : void 0,
166
+ ssrUrl: uiIsRemote ? uiConfig.ssr : void 0,
167
+ ssrIntegrity: uiIsRemote ? uiConfig.ssrIntegrity : void 0,
168
+ integrity: uiIsRemote ? uiConfig.integrity : void 0,
110
169
  source: uiRuntime.source
111
170
  },
112
171
  api: {
@@ -116,23 +175,31 @@ function buildRuntimeConfig(config, baseDir, env, options) {
116
175
  localPath: apiRuntime.localPath,
117
176
  port: apiRuntime.port,
118
177
  source: apiRuntime.source,
119
- proxy: apiConfig.proxy,
178
+ proxy: options?.proxy ?? apiConfig.proxy,
120
179
  variables: apiConfig.variables,
121
180
  secrets: apiConfig.secrets,
122
- integrity: env === "production" ? apiConfig.integrity : void 0
181
+ integrity: apiIsRemote ? apiConfig.integrity : void 0
123
182
  },
124
- auth: authConfig ? {
125
- name: resolvePluginRuntimeName(void 0, authRuntime.localPath, authConfig.name),
126
- url: authRuntime.url,
127
- entry: authRuntime.url ? `${authRuntime.url}/mf-manifest.json` : "/mf-manifest.json",
128
- localPath: authRuntime.localPath,
129
- port: authRuntime.port,
130
- source: authRuntime.source,
131
- proxy: authConfig.proxy,
132
- variables: authConfig.variables,
133
- secrets: authConfig.secrets,
134
- integrity: env === "production" ? authConfig.integrity : void 0
135
- } : void 0,
183
+ auth: (() => {
184
+ if (!authConfig || !authRuntime) return void 0;
185
+ return {
186
+ name: resolvePluginRuntimeName(void 0, authRuntime.localPath, authConfig.name),
187
+ url: authRuntime.url,
188
+ entry: authRuntime.url ? `${authRuntime.url}/mf-manifest.json` : "/mf-manifest.json",
189
+ localPath: authRuntime.localPath,
190
+ port: authRuntime.port,
191
+ source: authRuntime.source,
192
+ proxy: authConfig.proxy,
193
+ variables: authConfig.variables,
194
+ secrets: authConfig.secrets,
195
+ integrity: authRuntime.source === "remote" ? authConfig.integrity : void 0,
196
+ sidebar: authConfig.sidebar?.map((item) => ({
197
+ ...item,
198
+ to: item.to ?? "/auth",
199
+ roleRequired: item.roleRequired ?? "member"
200
+ }))
201
+ };
202
+ })(),
136
203
  plugins: options?.plugins && Object.keys(options.plugins).length > 0 ? options.plugins : void 0
137
204
  };
138
205
  }
@@ -141,42 +208,89 @@ async function loadConfigFile(configPath, baseDir) {
141
208
  const resolvedPath = isAbsolute(configPath) ? configPath : resolve(baseDir, configPath);
142
209
  return JSON.parse(readFileSync(resolvedPath, "utf-8"));
143
210
  }
144
- async function resolveConfigWithExtends(configPath, baseDir, visited, chain) {
211
+ async function resolveConfigWithExtends(configPath, baseDir, visited, chain, env = "development") {
145
212
  if (visited.has(configPath)) throw new Error(`Circular extends detected: ${[...visited, configPath].join(" -> ")}`);
146
213
  const config = await loadConfigFile(configPath, baseDir);
147
- if (configPath.startsWith("bos://")) chain.push(configPath);
214
+ chain.push(configPath);
148
215
  if (!config.extends) return config;
216
+ const extendsRef = resolveExtendsRef(config.extends, env);
217
+ if (!extendsRef) return config;
149
218
  const nextVisited = new Set(visited);
150
219
  nextVisited.add(configPath);
151
- const parentPath = config.extends;
152
- return mergeConfigs(await resolveConfigWithExtends(parentPath, parentPath.startsWith("bos://") ? baseDir : isAbsolute(parentPath) ? dirname(parentPath) : baseDir, nextVisited, chain), config);
220
+ return mergeBosConfigWithExtends(await resolveConfigWithExtends(extendsRef, extendsRef.startsWith("bos://") ? baseDir : isAbsolute(extendsRef) ? dirname(extendsRef) : baseDir, nextVisited, chain, env), config);
153
221
  }
154
- function mergeConfigs(parent, child) {
155
- const result = mergeValues(parent, child);
156
- if (child.plugins !== void 0) result.plugins = child.plugins;
157
- return result;
222
+ function normalizePluginEntry(raw) {
223
+ if (raw === null || raw === false) return raw;
224
+ if (typeof raw === "string") return { extends: raw };
225
+ return raw;
158
226
  }
159
- async function resolveRuntimePlugins(plugins, baseDir, env, prefix = []) {
227
+ async function resolveRuntimePlugins(plugins, baseDir, env) {
160
228
  const out = {};
161
- for (const [pluginId, pluginInput] of Object.entries(plugins)) {
162
- const runtimeKey = [...prefix, pluginId].join("/");
163
- const { config: resolvedConfig, baseDir: pluginBaseDir } = await resolveBosConfigInput(pluginInput, baseDir, /* @__PURE__ */ new Set(), []);
164
- const pluginRuntime = buildRuntimePluginConfig(runtimeKey, resolvedConfig, pluginBaseDir, env, pluginInput);
165
- if (pluginInput.name && typeof pluginInput.name === "string" && !pluginRuntime.name.includes("/")) pluginRuntime.name = pluginInput.name;
166
- const integrity = pluginInput.integrity;
167
- if (env === "production" && integrity) pluginRuntime.integrity = integrity;
168
- if (pluginRuntime.source === "remote" && pluginRuntime.url && !pluginRuntime.localPath && typeof resolvedConfig.app?.api?.name !== "string" && !pluginInput.name) pluginRuntime.name = await resolveRemotePluginRuntimeName(pluginRuntime.url, pluginRuntime.name);
169
- out[runtimeKey] = pluginRuntime;
170
- if (resolvedConfig.plugins && Object.keys(resolvedConfig.plugins).length > 0) {
171
- const nested = await resolveRuntimePlugins(resolvedConfig.plugins, pluginBaseDir, env, [...prefix, pluginId]);
172
- Object.assign(out, nested);
229
+ for (const [pluginId, rawInput] of Object.entries(plugins)) {
230
+ const normalized = normalizePluginEntry(rawInput);
231
+ if (normalized === null || normalized === false) continue;
232
+ let resolvedConfig = {};
233
+ let pluginBaseDir = baseDir;
234
+ if (normalized.extends) try {
235
+ const extendsUrl = resolveExtendsRef(normalized.extends, env);
236
+ if (extendsUrl) resolvedConfig = await fetchBosConfigFromFastKv(extendsUrl);
237
+ } catch {
238
+ resolvedConfig = {};
173
239
  }
240
+ if (normalized.development?.startsWith(LOCAL_PREFIX)) {
241
+ const localPath = resolve(baseDir, normalized.development.slice(6).trim());
242
+ if (existsSync(localPath)) {
243
+ const localConfigPath = join(localPath, "bos.config.json");
244
+ if (existsSync(localConfigPath)) try {
245
+ const localRaw = JSON.parse(readFileSync(localConfigPath, "utf-8"));
246
+ resolvedConfig = mergeBosConfigWithExtends(resolvedConfig, localRaw);
247
+ pluginBaseDir = localPath;
248
+ } catch {}
249
+ }
250
+ }
251
+ if (normalized.app && isPlainObject(normalized.app)) {
252
+ const mergedApp = {
253
+ ...resolvedConfig.app ?? {},
254
+ ...normalized.app
255
+ };
256
+ resolvedConfig = {
257
+ ...resolvedConfig,
258
+ app: mergedApp
259
+ };
260
+ }
261
+ if (normalized.shared && isPlainObject(normalized.shared)) {
262
+ const mergedShared = {
263
+ ...resolvedConfig.shared ?? {},
264
+ ...normalized.shared
265
+ };
266
+ resolvedConfig = {
267
+ ...resolvedConfig,
268
+ shared: mergedShared
269
+ };
270
+ }
271
+ if (normalized.sidebar) resolvedConfig = {
272
+ ...resolvedConfig,
273
+ sidebar: normalized.sidebar
274
+ };
275
+ if (normalized.routes) resolvedConfig = {
276
+ ...resolvedConfig,
277
+ routes: normalized.routes
278
+ };
279
+ const pluginRuntime = await buildRuntimePluginConfig(pluginId, resolvedConfig, pluginBaseDir, env, normalized);
280
+ if (normalized.name && typeof normalized.name === "string" && !pluginRuntime.name.includes("/")) pluginRuntime.name = normalized.name;
281
+ const integrity = normalized.integrity;
282
+ if (env === "production" && integrity) pluginRuntime.integrity = integrity;
283
+ if (pluginRuntime.source === "remote" && pluginRuntime.url && !pluginRuntime.localPath && typeof resolvedConfig.app?.api?.name !== "string" && !normalized.name) pluginRuntime.name = await resolveRemotePluginRuntimeName(pluginRuntime.url, pluginRuntime.name);
284
+ out[pluginId] = pluginRuntime;
174
285
  }
175
286
  return out;
176
287
  }
177
288
  async function resolveRemotePluginRuntimeName(baseUrl, fallback) {
178
289
  try {
179
- const response = await fetch(`${baseUrl.replace(/\/$/, "")}/plugin.manifest.json`);
290
+ const controller = new AbortController();
291
+ const timeout = setTimeout(() => controller.abort(), 5e3);
292
+ const response = await fetch(`${baseUrl.replace(/\/$/, "")}/plugin.manifest.json`, { signal: controller.signal });
293
+ clearTimeout(timeout);
180
294
  if (!response.ok) return fallback;
181
295
  const manifest = await response.json();
182
296
  return typeof manifest.plugin?.name === "string" && manifest.plugin.name.length > 0 ? manifest.plugin.name : fallback;
@@ -184,7 +298,23 @@ async function resolveRemotePluginRuntimeName(baseUrl, fallback) {
184
298
  return fallback;
185
299
  }
186
300
  }
187
- function buildRuntimePluginConfig(pluginId, config, baseDir, env, source) {
301
+ async function resolveBosPluginUrl(bosUrl) {
302
+ const parsed = parsePluginBosUrl(bosUrl);
303
+ if (!parsed) return null;
304
+ try {
305
+ const entry = await fetchPluginFromRegistry(parsed.accountId, parsed.pluginName);
306
+ if (!entry) return null;
307
+ const cdnUrl = entry.metadata.cdnUrl;
308
+ if (!cdnUrl) return null;
309
+ return {
310
+ url: cdnUrl,
311
+ integrity: entry.metadata.integrity ?? void 0
312
+ };
313
+ } catch {
314
+ return null;
315
+ }
316
+ }
317
+ async function buildRuntimePluginConfig(pluginId, config, baseDir, env, source) {
188
318
  const apiConfig = config.app?.api ?? {};
189
319
  const apiDevelopment = typeof apiConfig.development === "string" ? apiConfig.development : void 0;
190
320
  const apiProduction = typeof apiConfig.production === "string" ? apiConfig.production : void 0;
@@ -192,10 +322,28 @@ function buildRuntimePluginConfig(pluginId, config, baseDir, env, source) {
192
322
  const sourceProduction = typeof source.production === "string" ? source.production : void 0;
193
323
  const proxy = typeof apiConfig.proxy === "string" ? apiConfig.proxy : void 0;
194
324
  const development = apiDevelopment ?? sourceDevelopment;
195
- const production = apiProduction ?? sourceProduction;
325
+ let production = apiProduction ?? sourceProduction;
326
+ if (production?.startsWith("bos://")) {
327
+ const resolved = await resolveBosPluginUrl(production);
328
+ if (resolved) {
329
+ production = resolved.url;
330
+ if (resolved.integrity && env === "production") source.integrity = resolved.integrity;
331
+ }
332
+ }
196
333
  const runtimeTarget = env === "development" ? resolveDevelopmentTarget(development, production, baseDir) : resolveRuntimeTarget(production, baseDir, "remote");
334
+ const apiName = resolvePluginRuntimeName(typeof apiConfig.name === "string" ? apiConfig.name : void 0, runtimeTarget.localPath, pluginId);
335
+ const uiConfig = config.app?.ui;
336
+ const uiDevelopment = typeof uiConfig?.development === "string" ? uiConfig.development : void 0;
337
+ const uiProduction = typeof uiConfig?.production === "string" ? uiConfig.production : void 0;
338
+ const uiRuntime = uiConfig && (uiDevelopment || uiProduction) ? env === "development" ? resolveDevelopmentTarget(uiDevelopment, uiProduction, baseDir) : resolveRuntimeTarget(uiProduction, baseDir, "remote") : void 0;
339
+ const sidebar = (config.sidebar ?? source.sidebar)?.map((item) => ({
340
+ ...item,
341
+ to: item.to ?? `/${pluginId}`,
342
+ roleRequired: item.roleRequired ?? "member"
343
+ }));
344
+ const routes = config.routes ?? source.routes;
197
345
  return {
198
- name: resolvePluginRuntimeName(typeof apiConfig.name === "string" ? apiConfig.name : void 0, runtimeTarget.localPath, pluginId),
346
+ name: apiName,
199
347
  url: runtimeTarget.url,
200
348
  entry: runtimeTarget.url ? `${runtimeTarget.url.replace(/\/$/, "")}/mf-manifest.json` : "/mf-manifest.json",
201
349
  source: runtimeTarget.source,
@@ -203,7 +351,18 @@ function buildRuntimePluginConfig(pluginId, config, baseDir, env, source) {
203
351
  port: runtimeTarget.port,
204
352
  proxy: proxy ?? (typeof source.proxy === "string" ? source.proxy : void 0),
205
353
  variables: normalizeStringRecord(apiConfig.variables ?? source.variables),
206
- secrets: normalizeStringArray(apiConfig.secrets ?? source.secrets)
354
+ secrets: normalizeStringArray(apiConfig.secrets ?? source.secrets),
355
+ ui: uiRuntime ? {
356
+ name: typeof uiConfig?.name === "string" ? uiConfig.name : `${apiName}-ui`,
357
+ url: uiRuntime.url,
358
+ entry: uiRuntime.url ? `${uiRuntime.url.replace(/\/$/, "")}/mf-manifest.json` : "/mf-manifest.json",
359
+ source: uiRuntime.source,
360
+ localPath: uiRuntime.localPath,
361
+ port: uiRuntime.port,
362
+ integrity: uiRuntime.source === "remote" && typeof uiConfig?.integrity === "string" ? uiConfig.integrity : void 0
363
+ } : void 0,
364
+ sidebar,
365
+ routes
207
366
  };
208
367
  }
209
368
  function resolvePluginRuntimeName(explicitName, localPath, fallback) {
@@ -216,31 +375,6 @@ function resolvePluginRuntimeName(explicitName, localPath, fallback) {
216
375
  } catch {}
217
376
  return fallback;
218
377
  }
219
- async function resolveBosConfigInput(input, baseDir, visited, chain) {
220
- if (input.extends) {
221
- const parentBaseDir = input.extends.startsWith("bos://") ? baseDir : isAbsolute(input.extends) ? dirname(input.extends) : baseDir;
222
- return {
223
- config: mergeConfigs(await resolveConfigWithExtends(input.extends, parentBaseDir, visited, chain), input),
224
- baseDir: parentBaseDir
225
- };
226
- }
227
- return {
228
- config: input,
229
- baseDir
230
- };
231
- }
232
- function mergeValues(parent, child) {
233
- if (Array.isArray(parent) && Array.isArray(child)) return child;
234
- if (isPlainObject(parent) && isPlainObject(child)) {
235
- const merged = { ...parent };
236
- for (const [key, value] of Object.entries(child)) merged[key] = key in merged ? mergeValues(merged[key], value) : value;
237
- return merged;
238
- }
239
- return child ?? parent;
240
- }
241
- function isPlainObject(value) {
242
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
243
- }
244
378
  function normalizeStringRecord(value) {
245
379
  if (!isPlainObject(value)) return void 0;
246
380
  const out = {};
@@ -258,7 +392,7 @@ function resolveRuntimeTarget(value, baseDir, defaultSource = "remote") {
258
392
  url: ""
259
393
  };
260
394
  if (value.startsWith(LOCAL_PREFIX)) {
261
- const localTarget = value.slice(6).trim();
395
+ const localTarget = value?.slice(6).trim();
262
396
  if (!localTarget) throw new Error(`Invalid local development target: ${value}`);
263
397
  const localPath = resolve(baseDir, localTarget);
264
398
  if (!existsSync(localPath)) return {
@@ -302,5 +436,5 @@ function parsePort(url) {
302
436
  }
303
437
 
304
438
  //#endregion
305
- export { BosConfigSchema, buildRuntimePluginsForConfig, clearConfigCache, findConfigPath, getConfig, getHostDevelopmentPort, getProjectRoot, isLocalDevelopmentTarget, loadBosConfig, loadConfig, parsePort, resolveDevelopmentHostUrl, resolveLocalDevelopmentPath, resolvePluginRuntimeName };
439
+ export { BOS_CONFIG_ORDER, BosConfigSchema, buildRuntimeConfig, buildRuntimePluginsForConfig, clearConfigCache, findConfigPath, getConfig, getHostDevelopmentPort, getProjectRoot, getResolvedConfigPath, isLocalDevelopmentTarget, loadBosConfig, loadConfig, loadResolvedConfig, parsePort, readBosConfigForBuild, rebuildOrderedConfig, resolveBosConfigPath, resolveDevelopmentHostUrl, resolveLocalDevelopmentPath, resolvePluginRuntimeName, writeResolvedConfig };
306
440
  //# sourceMappingURL=config.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { fetchBosConfigFromFastKv } from \"./fastkv\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport type { BosConfig, BosConfigInput, RuntimeConfig, RuntimePluginConfig } from \"./types\";\nimport { BosConfigSchema } from \"./types\";\n\nconst LOCAL_PREFIX = \"local:\";\nconst DEFAULT_HOST_PORT = 3000;\n\ninterface RuntimeTarget {\n source: \"local\" | \"remote\";\n url: string;\n localPath?: string;\n port?: number;\n}\n\nlet cachedConfig: BosConfig | null = null;\nlet projectRoot: string | null = null;\n\nexport function clearConfigCache(): void {\n cachedConfig = null;\n projectRoot = null;\n}\n\nexport function findConfigPath(cwd?: string): string | null {\n let dir = cwd ?? process.cwd();\n while (dir !== \"/\") {\n const configPath = join(dir, \"bos.config.json\");\n if (existsSync(configPath)) {\n return configPath;\n }\n dir = dirname(dir);\n }\n return null;\n}\n\nexport function getConfig(): BosConfig | null {\n return cachedConfig;\n}\n\nexport function getProjectRoot(): string {\n if (!projectRoot) {\n throw new Error(\"Config not loaded. Call loadConfig() first.\");\n }\n return projectRoot;\n}\n\nexport interface ConfigResult {\n config: BosConfig;\n runtime: RuntimeConfig;\n source: {\n path: string;\n extended?: string[];\n remote?: boolean;\n };\n}\n\nexport async function loadConfig(options?: {\n cwd?: string;\n path?: string;\n env?: \"development\" | \"production\";\n}): Promise<ConfigResult | null> {\n const configPath = options?.path ?? findConfigPath(options?.cwd);\n if (!configPath) {\n projectRoot = options?.cwd ?? process.cwd();\n return null;\n }\n\n const baseDir = dirname(configPath);\n\n try {\n const extendedChain: string[] = [];\n const parsed = await resolveConfigWithExtends(configPath, baseDir, new Set(), extendedChain);\n const config = BosConfigSchema.parse(parsed);\n\n cachedConfig = config;\n projectRoot = baseDir;\n\n const pluginRuntime = await resolveRuntimePlugins(\n config.plugins ?? {},\n baseDir,\n options?.env ?? \"development\",\n );\n const runtime = buildRuntimeConfig(config, baseDir, options?.env ?? \"development\", {\n plugins: pluginRuntime,\n });\n\n return {\n config,\n runtime,\n source: {\n path: configPath,\n extended: extendedChain.length > 0 ? extendedChain : undefined,\n remote: extendedChain.some((entry) => entry.startsWith(\"bos://\")),\n },\n };\n } catch (error) {\n throw new Error(`Failed to load config from ${configPath}: ${error}`);\n }\n}\n\nexport async function loadBosConfig(options?: {\n cwd?: string;\n path?: string;\n env?: \"development\" | \"production\";\n}): Promise<RuntimeConfig> {\n const result = await loadConfig(options);\n if (!result) {\n throw new Error(\"No bos.config.json found\");\n }\n\n return result.runtime;\n}\n\nexport async function buildRuntimePluginsForConfig(\n config: BosConfig,\n baseDir: string,\n env: \"development\" | \"production\",\n): Promise<Record<string, RuntimePluginConfig> | undefined> {\n const plugins = await resolveRuntimePlugins(config.plugins ?? {}, baseDir, env);\n return Object.keys(plugins).length > 0 ? plugins : undefined;\n}\n\nfunction resolveDevelopmentTarget(\n development: string | undefined,\n production: string | undefined,\n baseDir: string,\n): RuntimeTarget {\n const devTarget = resolveRuntimeTarget(development, baseDir);\n if (devTarget.source === \"local\" && (!devTarget.localPath || !existsSync(devTarget.localPath))) {\n return resolveRuntimeTarget(production, baseDir, \"remote\");\n }\n return devTarget;\n}\n\nfunction buildRuntimeConfig(\n config: BosConfig,\n baseDir: string,\n env: \"development\" | \"production\",\n options?: { plugins?: Record<string, RuntimePluginConfig> },\n): RuntimeConfig {\n const uiConfig = config.app.ui;\n const apiConfig = config.app.api;\n const authConfig = config.app.auth;\n const uiRuntime =\n env === \"development\"\n ? resolveDevelopmentTarget(uiConfig.development, uiConfig.production, baseDir)\n : resolveRuntimeTarget(uiConfig.production, baseDir, \"remote\");\n const apiRuntime =\n env === \"development\"\n ? resolveDevelopmentTarget(apiConfig.development, apiConfig.production, baseDir)\n : resolveRuntimeTarget(apiConfig.production, baseDir, \"remote\");\n const authRuntime = authConfig\n ? env === \"development\"\n ? resolveDevelopmentTarget(authConfig.development, authConfig.production, baseDir)\n : resolveRuntimeTarget(authConfig.production, baseDir, \"remote\")\n : undefined;\n\n const hostConfig = config.app.host;\n const hostRuntime =\n env === \"development\"\n ? resolveDevelopmentTarget(hostConfig.development, hostConfig.production, baseDir)\n : resolveRuntimeTarget(hostConfig.production, baseDir, \"remote\");\n\n const hostListeningUrl = resolveDevelopmentHostUrl(hostConfig.development);\n\n return {\n env,\n account: config.account,\n domain: config.domain,\n networkId: getNetworkIdForAccount(config.account),\n repository: config.repository,\n host: {\n name: \"host\",\n url: hostListeningUrl,\n entry: `${hostListeningUrl}/mf-manifest.json`,\n localPath: hostRuntime.localPath,\n port: hostRuntime.port ?? DEFAULT_HOST_PORT,\n secrets: hostConfig.secrets,\n integrity: env === \"production\" ? hostConfig.integrity : undefined,\n source: hostRuntime.source,\n remoteUrl: hostRuntime.source === \"remote\" ? hostRuntime.url : undefined,\n },\n shared: config.shared,\n ui: {\n name: uiConfig.name,\n url: uiRuntime.url,\n entry: uiRuntime.url ? `${uiRuntime.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: uiRuntime.localPath,\n port: uiRuntime.port,\n ssrUrl: uiConfig.ssr,\n ssrIntegrity: env === \"production\" ? uiConfig.ssrIntegrity : undefined,\n integrity: env === \"production\" ? uiConfig.integrity : undefined,\n source: uiRuntime.source,\n },\n api: {\n name: apiConfig.name,\n url: apiRuntime.url,\n entry: apiRuntime.url ? `${apiRuntime.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: apiRuntime.localPath,\n port: apiRuntime.port,\n source: apiRuntime.source,\n proxy: apiConfig.proxy,\n variables: apiConfig.variables,\n secrets: apiConfig.secrets,\n integrity: env === \"production\" ? apiConfig.integrity : undefined,\n },\n auth: authConfig\n ? {\n name: resolvePluginRuntimeName(undefined, authRuntime!.localPath, authConfig.name),\n url: authRuntime!.url,\n entry: authRuntime!.url ? `${authRuntime!.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: authRuntime!.localPath,\n port: authRuntime!.port,\n source: authRuntime!.source,\n proxy: authConfig.proxy,\n variables: authConfig.variables,\n secrets: authConfig.secrets,\n integrity: env === \"production\" ? authConfig.integrity : undefined,\n }\n : undefined,\n plugins:\n options?.plugins && Object.keys(options.plugins).length > 0 ? options.plugins : undefined,\n };\n}\n\nasync function loadConfigFile(configPath: string, baseDir: string): Promise<BosConfigInput> {\n if (configPath.startsWith(\"bos://\")) {\n return fetchBosConfigFromFastKv<BosConfigInput>(configPath);\n }\n\n const resolvedPath = isAbsolute(configPath) ? configPath : resolve(baseDir, configPath);\n return JSON.parse(readFileSync(resolvedPath, \"utf-8\")) as BosConfigInput;\n}\n\nasync function resolveConfigWithExtends(\n configPath: string,\n baseDir: string,\n visited: Set<string>,\n chain: string[],\n): Promise<BosConfigInput> {\n if (visited.has(configPath)) {\n throw new Error(`Circular extends detected: ${[...visited, configPath].join(\" -> \")}`);\n }\n\n const config = await loadConfigFile(configPath, baseDir);\n if (configPath.startsWith(\"bos://\")) {\n chain.push(configPath);\n }\n\n if (!config.extends) {\n return config;\n }\n\n const nextVisited = new Set(visited);\n nextVisited.add(configPath);\n const parentPath = config.extends;\n const parentBaseDir = parentPath.startsWith(\"bos://\")\n ? baseDir\n : isAbsolute(parentPath)\n ? dirname(parentPath)\n : baseDir;\n const parent = await resolveConfigWithExtends(parentPath, parentBaseDir, nextVisited, chain);\n\n return mergeConfigs(parent, config);\n}\n\nfunction mergeConfigs(parent: BosConfigInput, child: BosConfigInput): BosConfigInput {\n const result = mergeValues(parent, child) as BosConfigInput;\n if (child.plugins !== undefined) {\n result.plugins = child.plugins;\n }\n return result;\n}\n\nasync function resolveRuntimePlugins(\n plugins: Record<string, BosConfigInput>,\n baseDir: string,\n env: \"development\" | \"production\",\n prefix: string[] = [],\n): Promise<Record<string, RuntimePluginConfig>> {\n const out: Record<string, RuntimePluginConfig> = {};\n\n for (const [pluginId, pluginInput] of Object.entries(plugins)) {\n const runtimeKey = [...prefix, pluginId].join(\"/\");\n const { config: resolvedConfig, baseDir: pluginBaseDir } = await resolveBosConfigInput(\n pluginInput,\n baseDir,\n new Set(),\n [],\n );\n\n const pluginRuntime = buildRuntimePluginConfig(\n runtimeKey,\n resolvedConfig,\n pluginBaseDir,\n env,\n pluginInput,\n );\n if (\n pluginInput.name &&\n typeof pluginInput.name === \"string\" &&\n !pluginRuntime.name.includes(\"/\")\n ) {\n pluginRuntime.name = pluginInput.name;\n }\n\n const integrity = pluginInput.integrity;\n if (env === \"production\" && integrity) {\n pluginRuntime.integrity = integrity;\n }\n\n if (\n pluginRuntime.source === \"remote\" &&\n pluginRuntime.url &&\n !pluginRuntime.localPath &&\n typeof resolvedConfig.app?.api?.name !== \"string\" &&\n !pluginInput.name\n ) {\n pluginRuntime.name = await resolveRemotePluginRuntimeName(\n pluginRuntime.url,\n pluginRuntime.name,\n );\n }\n\n out[runtimeKey] = pluginRuntime;\n\n if (resolvedConfig.plugins && Object.keys(resolvedConfig.plugins).length > 0) {\n const nested = await resolveRuntimePlugins(resolvedConfig.plugins, pluginBaseDir, env, [\n ...prefix,\n pluginId,\n ]);\n Object.assign(out, nested);\n }\n }\n\n return out;\n}\n\nasync function resolveRemotePluginRuntimeName(baseUrl: string, fallback: string): Promise<string> {\n try {\n const response = await fetch(`${baseUrl.replace(/\\/$/, \"\")}/plugin.manifest.json`);\n if (!response.ok) {\n return fallback;\n }\n\n const manifest = (await response.json()) as {\n plugin?: { name?: unknown };\n };\n\n return typeof manifest.plugin?.name === \"string\" && manifest.plugin.name.length > 0\n ? manifest.plugin.name\n : fallback;\n } catch {\n return fallback;\n }\n}\n\nfunction buildRuntimePluginConfig(\n pluginId: string,\n config: BosConfigInput,\n baseDir: string,\n env: \"development\" | \"production\",\n source: BosConfigInput,\n): RuntimePluginConfig {\n const apiConfig = config.app?.api ?? {};\n const apiDevelopment =\n typeof apiConfig.development === \"string\" ? apiConfig.development : undefined;\n const apiProduction = typeof apiConfig.production === \"string\" ? apiConfig.production : undefined;\n const sourceDevelopment = typeof source.development === \"string\" ? source.development : undefined;\n const sourceProduction = typeof source.production === \"string\" ? source.production : undefined;\n const proxy = typeof apiConfig.proxy === \"string\" ? apiConfig.proxy : undefined;\n const development = apiDevelopment ?? sourceDevelopment;\n const production = apiProduction ?? sourceProduction;\n const runtimeTarget =\n env === \"development\"\n ? resolveDevelopmentTarget(development, production, baseDir)\n : resolveRuntimeTarget(production, baseDir, \"remote\");\n const apiName = resolvePluginRuntimeName(\n typeof apiConfig.name === \"string\" ? apiConfig.name : undefined,\n runtimeTarget.localPath,\n pluginId,\n );\n\n return {\n name: apiName,\n url: runtimeTarget.url,\n entry: runtimeTarget.url\n ? `${runtimeTarget.url.replace(/\\/$/, \"\")}/mf-manifest.json`\n : \"/mf-manifest.json\",\n source: runtimeTarget.source,\n localPath: runtimeTarget.localPath,\n port: runtimeTarget.port,\n proxy: proxy ?? (typeof source.proxy === \"string\" ? source.proxy : undefined),\n variables: normalizeStringRecord(apiConfig.variables ?? source.variables),\n secrets: normalizeStringArray(apiConfig.secrets ?? source.secrets),\n };\n}\n\nexport function resolvePluginRuntimeName(\n explicitName: string | undefined,\n localPath: string | undefined,\n fallback: string,\n): string {\n if (explicitName) {\n return explicitName;\n }\n\n if (!localPath) {\n return fallback;\n }\n\n try {\n const packageJsonPath = join(localPath, \"package.json\");\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as { name?: unknown };\n if (typeof packageJson.name === \"string\" && packageJson.name.length > 0) {\n return packageJson.name;\n }\n } catch {}\n\n return fallback;\n}\n\nasync function resolveBosConfigInput(\n input: BosConfigInput,\n baseDir: string,\n visited: Set<string>,\n chain: string[],\n): Promise<{ config: BosConfigInput; baseDir: string }> {\n if (input.extends) {\n const parentBaseDir = input.extends.startsWith(\"bos://\")\n ? baseDir\n : isAbsolute(input.extends)\n ? dirname(input.extends)\n : baseDir;\n const config = await resolveConfigWithExtends(input.extends, parentBaseDir, visited, chain);\n return { config: mergeConfigs(config, input), baseDir: parentBaseDir };\n }\n\n return { config: input, baseDir };\n}\n\nfunction mergeValues(parent: unknown, child: unknown): unknown {\n if (Array.isArray(parent) && Array.isArray(child)) {\n return child;\n }\n\n if (isPlainObject(parent) && isPlainObject(child)) {\n const merged: Record<string, unknown> = { ...parent };\n for (const [key, value] of Object.entries(child)) {\n merged[key] = key in merged ? mergeValues(merged[key], value) : value;\n }\n return merged;\n }\n\n return child ?? parent;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction normalizeStringRecord(value: unknown): Record<string, string> | undefined {\n if (!isPlainObject(value)) return undefined;\n const out: Record<string, string> = {};\n for (const [key, raw] of Object.entries(value)) {\n if (typeof raw === \"string\") {\n out[key] = raw;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction normalizeStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const out = value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n return out.length > 0 ? out : undefined;\n}\n\nfunction resolveRuntimeTarget(\n value: string | undefined,\n baseDir: string,\n defaultSource: \"local\" | \"remote\" = \"remote\",\n): RuntimeTarget {\n if (!value) {\n return { source: defaultSource, url: \"\" };\n }\n\n if (value.startsWith(LOCAL_PREFIX)) {\n const localTarget = value.slice(LOCAL_PREFIX.length).trim();\n if (!localTarget) {\n throw new Error(`Invalid local development target: ${value}`);\n }\n\n const localPath = resolve(baseDir, localTarget);\n if (!existsSync(localPath)) {\n return { source: \"local\", url: \"\" };\n }\n\n return {\n source: \"local\",\n url: \"\",\n localPath,\n };\n }\n\n return {\n source: defaultSource,\n url: value.replace(/\\/$/, \"\"),\n port: parsePort(value),\n };\n}\n\nexport function isLocalDevelopmentTarget(value: string | undefined): boolean {\n return typeof value === \"string\" && value.startsWith(LOCAL_PREFIX);\n}\n\nexport function resolveLocalDevelopmentPath(\n value: string | undefined,\n baseDir: string,\n): string | null {\n if (!isLocalDevelopmentTarget(value)) {\n return null;\n }\n\n const localTarget = value!.slice(LOCAL_PREFIX.length).trim();\n return localTarget ? resolve(baseDir, localTarget) : null;\n}\n\nexport function resolveDevelopmentHostUrl(value: string | undefined): string {\n if (!value || isLocalDevelopmentTarget(value)) {\n return `http://localhost:${DEFAULT_HOST_PORT}`;\n }\n\n return value.replace(/\\/$/, \"\");\n}\n\nexport function getHostDevelopmentPort(value: string | undefined): number {\n return parsePort(resolveDevelopmentHostUrl(value));\n}\n\nexport function parsePort(url: string): number {\n try {\n const parsed = new URL(url);\n return parsed.port ? parseInt(parsed.port, 10) : parsed.protocol === \"https:\" ? 443 : 80;\n } catch {\n return 3000;\n }\n}\n\nexport type { BosConfig, RuntimeConfig } from \"./types\";\nexport { BosConfigSchema } from \"./types\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { fetchBosConfigFromFastKv, fetchPluginFromRegistry, parsePluginBosUrl } from \"./fastkv\";\nimport {\n type BosEnv,\n isPlainObject,\n mergeBosConfigWithExtends,\n type ResolvedConfigMeta,\n rebuildOrderedConfig,\n resolveExtendsRef,\n} from \"./merge\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport type {\n BosConfig,\n BosConfigInput,\n BosPluginRef,\n ExtendsConfig,\n PluginEntryValue,\n RuntimeConfig,\n RuntimePluginConfig,\n SharedDepConfig,\n} from \"./types\";\nimport { BosConfigSchema } from \"./types\";\n\nconst LOCAL_PREFIX = \"local:\";\nconst DEFAULT_HOST_PORT = 3000;\nconst RESOLVED_CONFIG_FILENAME = \"bos.resolved-config.json\";\n\ninterface RuntimeTarget {\n source: \"local\" | \"remote\";\n url: string;\n localPath?: string;\n port?: number;\n}\n\nlet cachedConfig: BosConfig | null = null;\nlet projectRoot: string | null = null;\n\nexport function clearConfigCache(): void {\n cachedConfig = null;\n projectRoot = null;\n}\n\nexport function findConfigPath(cwd?: string): string | null {\n let dir = cwd ?? process.cwd();\n while (dir !== \"/\") {\n const configPath = join(dir, \"bos.config.json\");\n if (existsSync(configPath)) {\n return configPath;\n }\n dir = dirname(dir);\n }\n return null;\n}\n\nexport function getConfig(): BosConfig | null {\n return cachedConfig;\n}\n\nexport function getProjectRoot(): string {\n if (!projectRoot) {\n throw new Error(\"Config not loaded. Call loadConfig() first.\");\n }\n return projectRoot;\n}\n\nexport interface ConfigResult {\n config: BosConfig;\n runtime: RuntimeConfig;\n source: {\n path: string;\n extended?: string[];\n remote?: boolean;\n };\n}\n\nexport async function loadConfig(options?: {\n cwd?: string;\n path?: string;\n env?: BosEnv;\n}): Promise<ConfigResult | null> {\n const configPath = options?.path ?? findConfigPath(options?.cwd);\n if (!configPath) {\n projectRoot = options?.cwd ?? process.cwd();\n return null;\n }\n\n const baseDir = dirname(configPath);\n const env = options?.env ?? \"development\";\n const runtimeEnv: BosEnv = env === \"staging\" ? \"production\" : env;\n\n try {\n const extendedChain: string[] = [];\n const parsed = await resolveConfigWithExtends(\n configPath,\n baseDir,\n new Set(),\n extendedChain,\n env,\n );\n const config = BosConfigSchema.parse(parsed);\n\n cachedConfig = config;\n projectRoot = baseDir;\n\n const pluginRuntime = await resolveRuntimePlugins(config.plugins ?? {}, baseDir, runtimeEnv);\n const runtime = buildRuntimeConfig(config, baseDir, runtimeEnv, {\n plugins: pluginRuntime,\n });\n\n return {\n config,\n runtime,\n source: {\n path: configPath,\n extended: extendedChain.length > 0 ? extendedChain : undefined,\n remote: extendedChain.some((entry) => entry.startsWith(\"bos://\")),\n },\n };\n } catch (error) {\n throw new Error(`Failed to load config from ${configPath}: ${error}`);\n }\n}\n\nexport async function loadBosConfig(options?: {\n cwd?: string;\n path?: string;\n env?: BosEnv;\n}): Promise<RuntimeConfig> {\n const result = await loadConfig(options);\n if (!result) {\n throw new Error(\"No bos.config.json found\");\n }\n\n return result.runtime;\n}\n\nexport async function buildRuntimePluginsForConfig(\n config: BosConfig,\n baseDir: string,\n env: BosEnv,\n): Promise<Record<string, RuntimePluginConfig> | undefined> {\n const plugins = await resolveRuntimePlugins(config.plugins ?? {}, baseDir, env);\n return Object.keys(plugins).length > 0 ? plugins : undefined;\n}\n\nexport function getResolvedConfigPath(configDir: string): string {\n return join(configDir, \".bos\", RESOLVED_CONFIG_FILENAME);\n}\n\nexport function loadResolvedConfig(configDir: string): BosConfig | null {\n const resolvedPath = getResolvedConfigPath(configDir);\n if (!existsSync(resolvedPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(resolvedPath, \"utf-8\"));\n if (!isPlainObject(raw)) return null;\n const { _resolved, ...configData } = raw;\n return BosConfigSchema.parse(configData);\n } catch {\n return null;\n }\n}\n\nexport function writeResolvedConfig(\n configDir: string,\n config: BosConfig,\n env: BosEnv,\n extendsChain?: string[],\n source?: string,\n): void {\n const resolvedPath = getResolvedConfigPath(configDir);\n const resolvedDir = dirname(resolvedPath);\n if (!existsSync(resolvedDir)) {\n mkdirSync(resolvedDir, { recursive: true });\n }\n\n const ordered = rebuildOrderedConfig(config);\n const meta: ResolvedConfigMeta = {\n env,\n resolvedAt: new Date().toISOString(),\n extendsChain: extendsChain ?? [],\n ...(source ? { source } : {}),\n };\n const output = {\n _resolved: meta,\n ...ordered,\n };\n\n const content = `${JSON.stringify(output, null, 2)}\\n`;\n try {\n if (readFileSync(resolvedPath, \"utf-8\") === content) return;\n } catch {\n // file doesn't exist yet\n }\n writeFileSync(resolvedPath, content);\n}\n\nexport function resolveBosConfigPath(configDir: string): string {\n const resolvedPath = getResolvedConfigPath(configDir);\n if (existsSync(resolvedPath)) return resolvedPath;\n return join(configDir, \"bos.config.json\");\n}\n\nexport function readBosConfigForBuild(configDir: string): Record<string, unknown> {\n const resolvedPath = getResolvedConfigPath(configDir);\n if (existsSync(resolvedPath)) {\n try {\n const raw = JSON.parse(readFileSync(resolvedPath, \"utf-8\"));\n if (isPlainObject(raw)) {\n const { _resolved, ...configData } = raw;\n return configData as Record<string, unknown>;\n }\n } catch {}\n }\n const bosConfigPath = join(configDir, \"bos.config.json\");\n return JSON.parse(readFileSync(bosConfigPath, \"utf-8\")) as Record<string, unknown>;\n}\n\nfunction resolveDevelopmentTarget(\n development: string | undefined,\n production: string | undefined,\n baseDir: string,\n forceSource?: \"local\" | \"remote\",\n): RuntimeTarget {\n if (forceSource === \"remote\") {\n return resolveRuntimeTarget(production, baseDir, \"remote\");\n }\n const devTarget = resolveRuntimeTarget(development, baseDir);\n if (devTarget.source === \"local\" && (!devTarget.localPath || !existsSync(devTarget.localPath))) {\n return resolveRuntimeTarget(production, baseDir, \"remote\");\n }\n return devTarget;\n}\n\nexport interface BuildRuntimeConfigOptions {\n plugins?: Record<string, RuntimePluginConfig>;\n hostSource?: \"local\" | \"remote\";\n uiSource?: \"local\" | \"remote\";\n apiSource?: \"local\" | \"remote\";\n authSource?: \"local\" | \"remote\";\n proxy?: string;\n}\n\nexport function buildRuntimeConfig(\n config: BosConfig,\n baseDir: string,\n env: BosEnv,\n options?: BuildRuntimeConfigOptions,\n): RuntimeConfig {\n const uiConfig = config.app.ui;\n const apiConfig = config.app.api;\n const authConfig = config.app.auth;\n const uiRuntime =\n env === \"development\"\n ? resolveDevelopmentTarget(\n uiConfig.development,\n uiConfig.production,\n baseDir,\n options?.uiSource,\n )\n : resolveRuntimeTarget(uiConfig.production, baseDir, \"remote\");\n const apiRuntime =\n env === \"development\"\n ? resolveDevelopmentTarget(\n apiConfig.development,\n apiConfig.production,\n baseDir,\n options?.apiSource,\n )\n : resolveRuntimeTarget(apiConfig.production, baseDir, \"remote\");\n const authRuntime = authConfig\n ? env === \"development\"\n ? resolveDevelopmentTarget(\n authConfig.development,\n authConfig.production,\n baseDir,\n options?.authSource,\n )\n : resolveRuntimeTarget(authConfig.production, baseDir, \"remote\")\n : undefined;\n\n const hostConfig = config.app.host;\n const hostRuntime =\n env === \"development\"\n ? resolveDevelopmentTarget(\n hostConfig.development,\n hostConfig.production,\n baseDir,\n options?.hostSource,\n )\n : resolveRuntimeTarget(hostConfig.production, baseDir, \"remote\");\n\n const hostListeningUrl =\n env === \"development\"\n ? resolveDevelopmentHostUrl(hostConfig.development)\n : `http://localhost:${hostRuntime.port ?? DEFAULT_HOST_PORT}`;\n\n const hostIsRemote = hostRuntime.source === \"remote\";\n const uiIsRemote = uiRuntime.source === \"remote\";\n const apiIsRemote = apiRuntime.source === \"remote\";\n\n return {\n env,\n account: config.account,\n domain: config.domain,\n networkId: getNetworkIdForAccount(config.account),\n repository: config.repository,\n host: {\n name: \"host\",\n url: hostListeningUrl,\n entry: `${hostListeningUrl}/mf-manifest.json`,\n localPath: hostRuntime.localPath,\n port: hostRuntime.port ?? DEFAULT_HOST_PORT,\n secrets: hostConfig.secrets,\n integrity: hostIsRemote ? hostConfig.integrity : undefined,\n source: hostRuntime.source,\n remoteUrl: hostIsRemote ? hostRuntime.url : undefined,\n },\n shared: config.shared,\n ui: {\n name: uiConfig.name,\n url: uiRuntime.url,\n entry: uiRuntime.url ? `${uiRuntime.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: uiRuntime.localPath,\n port: uiRuntime.port,\n ssrUrl: uiIsRemote ? uiConfig.ssr : undefined,\n ssrIntegrity: uiIsRemote ? uiConfig.ssrIntegrity : undefined,\n integrity: uiIsRemote ? uiConfig.integrity : undefined,\n source: uiRuntime.source,\n },\n api: {\n name: apiConfig.name,\n url: apiRuntime.url,\n entry: apiRuntime.url ? `${apiRuntime.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: apiRuntime.localPath,\n port: apiRuntime.port,\n source: apiRuntime.source,\n proxy: options?.proxy ?? apiConfig.proxy,\n variables: apiConfig.variables,\n secrets: apiConfig.secrets,\n integrity: apiIsRemote ? apiConfig.integrity : undefined,\n },\n auth: (() => {\n if (!authConfig || !authRuntime) return undefined;\n return {\n name: resolvePluginRuntimeName(undefined, authRuntime.localPath, authConfig.name),\n url: authRuntime.url,\n entry: authRuntime.url ? `${authRuntime.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: authRuntime.localPath,\n port: authRuntime.port,\n source: authRuntime.source,\n proxy: authConfig.proxy,\n variables: authConfig.variables,\n secrets: authConfig.secrets,\n integrity: authRuntime.source === \"remote\" ? authConfig.integrity : undefined,\n sidebar: authConfig.sidebar?.map((item) => ({\n ...item,\n to: item.to ?? \"/auth\",\n roleRequired: item.roleRequired ?? (\"member\" as const),\n })),\n };\n })(),\n plugins:\n options?.plugins && Object.keys(options.plugins).length > 0 ? options.plugins : undefined,\n };\n}\n\nasync function loadConfigFile(configPath: string, baseDir: string): Promise<BosConfigInput> {\n if (configPath.startsWith(\"bos://\")) {\n return fetchBosConfigFromFastKv<BosConfigInput>(configPath);\n }\n\n const resolvedPath = isAbsolute(configPath) ? configPath : resolve(baseDir, configPath);\n return JSON.parse(readFileSync(resolvedPath, \"utf-8\")) as BosConfigInput;\n}\n\nasync function resolveConfigWithExtends(\n configPath: string,\n baseDir: string,\n visited: Set<string>,\n chain: string[],\n env: BosEnv = \"development\",\n): Promise<BosConfigInput> {\n if (visited.has(configPath)) {\n throw new Error(`Circular extends detected: ${[...visited, configPath].join(\" -> \")}`);\n }\n\n const config = await loadConfigFile(configPath, baseDir);\n chain.push(configPath);\n\n if (!config.extends) {\n return config;\n }\n\n const extendsRef = resolveExtendsRef(config.extends as string | ExtendsConfig, env);\n if (!extendsRef) {\n return config;\n }\n\n const nextVisited = new Set(visited);\n nextVisited.add(configPath);\n const parentBaseDir = extendsRef.startsWith(\"bos://\")\n ? baseDir\n : isAbsolute(extendsRef)\n ? dirname(extendsRef)\n : baseDir;\n const parent = await resolveConfigWithExtends(extendsRef, parentBaseDir, nextVisited, chain, env);\n\n return mergeBosConfigWithExtends(parent, config);\n}\n\ntype PluginOverrideValue = PluginEntryValue | null | false;\n\nfunction normalizePluginEntry(raw: PluginOverrideValue): BosPluginRef | null | false {\n if (raw === null || raw === false) return raw;\n if (typeof raw === \"string\") {\n return { extends: raw };\n }\n return raw;\n}\n\nasync function resolveRuntimePlugins(\n plugins: Record<string, PluginOverrideValue>,\n baseDir: string,\n env: BosEnv,\n): Promise<Record<string, RuntimePluginConfig>> {\n const out: Record<string, RuntimePluginConfig> = {};\n\n for (const [pluginId, rawInput] of Object.entries(plugins)) {\n const normalized = normalizePluginEntry(rawInput);\n if (normalized === null || normalized === false) continue;\n\n let resolvedConfig: BosConfigInput = {};\n let pluginBaseDir = baseDir;\n\n if (normalized.extends) {\n try {\n const extendsUrl = resolveExtendsRef(normalized.extends, env);\n if (extendsUrl) {\n const remoteConfig = await fetchBosConfigFromFastKv<BosConfigInput>(extendsUrl);\n resolvedConfig = remoteConfig;\n }\n } catch {\n resolvedConfig = {};\n }\n }\n\n if (normalized.development?.startsWith(LOCAL_PREFIX)) {\n const localPath = resolve(baseDir, normalized.development.slice(LOCAL_PREFIX.length).trim());\n if (existsSync(localPath)) {\n const localConfigPath = join(localPath, \"bos.config.json\");\n if (existsSync(localConfigPath)) {\n try {\n const localRaw = JSON.parse(readFileSync(localConfigPath, \"utf-8\")) as BosConfigInput;\n resolvedConfig = mergeBosConfigWithExtends(resolvedConfig, localRaw);\n pluginBaseDir = localPath;\n } catch {}\n }\n }\n }\n\n if (normalized.app && isPlainObject(normalized.app)) {\n const mergedApp: Record<string, unknown> = {\n ...((resolvedConfig.app as Record<string, unknown>) ?? {}),\n ...(normalized.app as Record<string, unknown>),\n };\n resolvedConfig = { ...resolvedConfig, app: mergedApp as BosConfigInput[\"app\"] };\n }\n if (normalized.shared && isPlainObject(normalized.shared)) {\n const mergedShared: Record<string, Record<string, SharedDepConfig>> = {\n ...(resolvedConfig.shared ?? {}),\n ...(normalized.shared as Record<string, Record<string, SharedDepConfig>>),\n };\n resolvedConfig = { ...resolvedConfig, shared: mergedShared };\n }\n if (normalized.sidebar) {\n resolvedConfig = { ...resolvedConfig, sidebar: normalized.sidebar };\n }\n if (normalized.routes) {\n resolvedConfig = { ...resolvedConfig, routes: normalized.routes };\n }\n\n const pluginRuntime = await buildRuntimePluginConfig(\n pluginId,\n resolvedConfig,\n pluginBaseDir,\n env,\n normalized,\n );\n if (\n normalized.name &&\n typeof normalized.name === \"string\" &&\n !pluginRuntime.name.includes(\"/\")\n ) {\n pluginRuntime.name = normalized.name;\n }\n\n const integrity = normalized.integrity;\n if (env === \"production\" && integrity) {\n pluginRuntime.integrity = integrity;\n }\n\n if (\n pluginRuntime.source === \"remote\" &&\n pluginRuntime.url &&\n !pluginRuntime.localPath &&\n typeof resolvedConfig.app?.api?.name !== \"string\" &&\n !normalized.name\n ) {\n pluginRuntime.name = await resolveRemotePluginRuntimeName(\n pluginRuntime.url,\n pluginRuntime.name,\n );\n }\n\n out[pluginId] = pluginRuntime;\n }\n\n return out;\n}\n\nasync function resolveRemotePluginRuntimeName(baseUrl: string, fallback: string): Promise<string> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const response = await fetch(`${baseUrl.replace(/\\/$/, \"\")}/plugin.manifest.json`, {\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n if (!response.ok) {\n return fallback;\n }\n\n const manifest = (await response.json()) as {\n plugin?: { name?: unknown };\n };\n\n return typeof manifest.plugin?.name === \"string\" && manifest.plugin.name.length > 0\n ? manifest.plugin.name\n : fallback;\n } catch {\n return fallback;\n }\n}\n\ninterface ResolvedBosPlugin {\n url: string;\n integrity?: string;\n}\n\nasync function resolveBosPluginUrl(bosUrl: string): Promise<ResolvedBosPlugin | null> {\n const parsed = parsePluginBosUrl(bosUrl);\n if (!parsed) return null;\n\n try {\n const entry = await fetchPluginFromRegistry(parsed.accountId, parsed.pluginName);\n if (!entry) return null;\n\n const cdnUrl = entry.metadata.cdnUrl;\n if (!cdnUrl) return null;\n\n return {\n url: cdnUrl,\n integrity: entry.metadata.integrity ?? undefined,\n };\n } catch {\n return null;\n }\n}\n\nasync function buildRuntimePluginConfig(\n pluginId: string,\n config: BosConfigInput,\n baseDir: string,\n env: BosEnv,\n source: BosPluginRef,\n): Promise<RuntimePluginConfig> {\n const apiConfig = config.app?.api ?? {};\n const apiDevelopment =\n typeof apiConfig.development === \"string\" ? apiConfig.development : undefined;\n const apiProduction = typeof apiConfig.production === \"string\" ? apiConfig.production : undefined;\n const sourceDevelopment = typeof source.development === \"string\" ? source.development : undefined;\n const sourceProduction = typeof source.production === \"string\" ? source.production : undefined;\n const proxy = typeof apiConfig.proxy === \"string\" ? apiConfig.proxy : undefined;\n const development = apiDevelopment ?? sourceDevelopment;\n let production = apiProduction ?? sourceProduction;\n\n if (production?.startsWith(\"bos://\")) {\n const resolved = await resolveBosPluginUrl(production);\n if (resolved) {\n production = resolved.url;\n if (resolved.integrity && env === \"production\") {\n source.integrity = resolved.integrity;\n }\n }\n }\n\n const runtimeTarget =\n env === \"development\"\n ? resolveDevelopmentTarget(development, production, baseDir)\n : resolveRuntimeTarget(production, baseDir, \"remote\");\n const apiName = resolvePluginRuntimeName(\n typeof apiConfig.name === \"string\" ? apiConfig.name : undefined,\n runtimeTarget.localPath,\n pluginId,\n );\n\n const uiConfig = config.app?.ui;\n const uiDevelopment =\n typeof uiConfig?.development === \"string\" ? uiConfig.development : undefined;\n const uiProduction = typeof uiConfig?.production === \"string\" ? uiConfig.production : undefined;\n const uiRuntime =\n uiConfig && (uiDevelopment || uiProduction)\n ? env === \"development\"\n ? resolveDevelopmentTarget(uiDevelopment, uiProduction, baseDir)\n : resolveRuntimeTarget(uiProduction, baseDir, \"remote\")\n : undefined;\n\n const sidebar = (config.sidebar ?? source.sidebar)?.map((item) => ({\n ...item,\n to: item.to ?? `/${pluginId}`,\n roleRequired: item.roleRequired ?? (\"member\" as const),\n }));\n\n const routes = config.routes ?? source.routes;\n\n return {\n name: apiName,\n url: runtimeTarget.url,\n entry: runtimeTarget.url\n ? `${runtimeTarget.url.replace(/\\/$/, \"\")}/mf-manifest.json`\n : \"/mf-manifest.json\",\n source: runtimeTarget.source,\n localPath: runtimeTarget.localPath,\n port: runtimeTarget.port,\n proxy: proxy ?? (typeof source.proxy === \"string\" ? source.proxy : undefined),\n variables: normalizeStringRecord(apiConfig.variables ?? source.variables),\n secrets: normalizeStringArray(apiConfig.secrets ?? source.secrets),\n ui: uiRuntime\n ? {\n name: typeof uiConfig?.name === \"string\" ? uiConfig.name : `${apiName}-ui`,\n url: uiRuntime.url,\n entry: uiRuntime.url\n ? `${uiRuntime.url.replace(/\\/$/, \"\")}/mf-manifest.json`\n : \"/mf-manifest.json\",\n source: uiRuntime.source,\n localPath: uiRuntime.localPath,\n port: uiRuntime.port,\n integrity:\n uiRuntime.source === \"remote\" && typeof uiConfig?.integrity === \"string\"\n ? uiConfig.integrity\n : undefined,\n }\n : undefined,\n sidebar,\n routes,\n };\n}\n\nexport function resolvePluginRuntimeName(\n explicitName: string | undefined,\n localPath: string | undefined,\n fallback: string,\n): string {\n if (explicitName) {\n return explicitName;\n }\n\n if (!localPath) {\n return fallback;\n }\n\n try {\n const packageJsonPath = join(localPath, \"package.json\");\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as { name?: unknown };\n if (typeof packageJson.name === \"string\" && packageJson.name.length > 0) {\n return packageJson.name;\n }\n } catch {}\n\n return fallback;\n}\n\nfunction normalizeStringRecord(value: unknown): Record<string, string> | undefined {\n if (!isPlainObject(value)) return undefined;\n const out: Record<string, string> = {};\n for (const [key, raw] of Object.entries(value)) {\n if (typeof raw === \"string\") {\n out[key] = raw;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction normalizeStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const out = value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n return out.length > 0 ? out : undefined;\n}\n\nfunction resolveRuntimeTarget(\n value: string | undefined,\n baseDir: string,\n defaultSource: \"local\" | \"remote\" = \"remote\",\n): RuntimeTarget {\n if (!value) {\n return { source: defaultSource, url: \"\" };\n }\n\n if (value.startsWith(LOCAL_PREFIX)) {\n const localTarget = value?.slice(LOCAL_PREFIX.length).trim();\n if (!localTarget) {\n throw new Error(`Invalid local development target: ${value}`);\n }\n\n const localPath = resolve(baseDir, localTarget);\n if (!existsSync(localPath)) {\n return { source: \"local\", url: \"\" };\n }\n\n return {\n source: \"local\",\n url: \"\",\n localPath,\n };\n }\n\n return {\n source: defaultSource,\n url: value.replace(/\\/$/, \"\"),\n port: parsePort(value),\n };\n}\n\nexport function isLocalDevelopmentTarget(\n value: string | undefined,\n): value is `${typeof LOCAL_PREFIX}${string}` {\n return typeof value === \"string\" && value.startsWith(LOCAL_PREFIX);\n}\n\nexport function resolveLocalDevelopmentPath(\n value: string | undefined,\n baseDir: string,\n): string | null {\n if (!isLocalDevelopmentTarget(value)) {\n return null;\n }\n\n const localTarget = value.slice(LOCAL_PREFIX.length).trim();\n return localTarget ? resolve(baseDir, localTarget) : null;\n}\n\nexport function resolveDevelopmentHostUrl(value: string | undefined): string {\n if (!value || isLocalDevelopmentTarget(value)) {\n return `http://localhost:${DEFAULT_HOST_PORT}`;\n }\n\n return value.replace(/\\/$/, \"\");\n}\n\nexport function getHostDevelopmentPort(value: string | undefined): number {\n return parsePort(resolveDevelopmentHostUrl(value));\n}\n\nexport function parsePort(url: string): number {\n try {\n const parsed = new URL(url);\n return parsed.port ? parseInt(parsed.port, 10) : parsed.protocol === \"https:\" ? 443 : 80;\n } catch {\n return 3000;\n }\n}\n\nexport { BOS_CONFIG_ORDER, rebuildOrderedConfig } from \"./merge\";\nexport type { BosConfig, RuntimeConfig } from \"./types\";\nexport { BosConfigSchema } from \"./types\";\n"],"mappings":";;;;;;;;AAwBA,MAAM,eAAe;AACrB,MAAM,oBAAoB;AAC1B,MAAM,2BAA2B;AASjC,IAAI,eAAiC;AACrC,IAAI,cAA6B;AAEjC,SAAgB,mBAAyB;AACvC,gBAAe;AACf,eAAc;;AAGhB,SAAgB,eAAe,KAA6B;CAC1D,IAAI,MAAM,OAAO,QAAQ,KAAK;AAC9B,QAAO,QAAQ,KAAK;EAClB,MAAM,aAAa,KAAK,KAAK,kBAAkB;AAC/C,MAAI,WAAW,WAAW,CACxB,QAAO;AAET,QAAM,QAAQ,IAAI;;AAEpB,QAAO;;AAGT,SAAgB,YAA8B;AAC5C,QAAO;;AAGT,SAAgB,iBAAyB;AACvC,KAAI,CAAC,YACH,OAAM,IAAI,MAAM,8CAA8C;AAEhE,QAAO;;AAaT,eAAsB,WAAW,SAIA;CAC/B,MAAM,aAAa,SAAS,QAAQ,eAAe,SAAS,IAAI;AAChE,KAAI,CAAC,YAAY;AACf,gBAAc,SAAS,OAAO,QAAQ,KAAK;AAC3C,SAAO;;CAGT,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,MAAM,SAAS,OAAO;CAC5B,MAAM,aAAqB,QAAQ,YAAY,eAAe;AAE9D,KAAI;EACF,MAAM,gBAA0B,EAAE;EAClC,MAAM,SAAS,MAAM,yBACnB,YACA,yBACA,IAAI,KAAK,EACT,eACA,IACD;EACD,MAAM,SAAS,gBAAgB,MAAM,OAAO;AAE5C,iBAAe;AACf,gBAAc;AAOd,SAAO;GACL;GACA,SANc,mBAAmB,QAAQ,SAAS,YAAY,EAC9D,SAFoB,MAAM,sBAAsB,OAAO,WAAW,EAAE,EAAE,SAAS,WAAW,EAG3F,CAAC;GAKA,QAAQ;IACN,MAAM;IACN,UAAU,cAAc,SAAS,IAAI,gBAAgB;IACrD,QAAQ,cAAc,MAAM,UAAU,MAAM,WAAW,SAAS,CAAC;IAClE;GACF;UACM,OAAO;AACd,QAAM,IAAI,MAAM,8BAA8B,WAAW,IAAI,QAAQ;;;AAIzE,eAAsB,cAAc,SAIT;CACzB,MAAM,SAAS,MAAM,WAAW,QAAQ;AACxC,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,2BAA2B;AAG7C,QAAO,OAAO;;AAGhB,eAAsB,6BACpB,QACA,SACA,KAC0D;CAC1D,MAAM,UAAU,MAAM,sBAAsB,OAAO,WAAW,EAAE,EAAE,SAAS,IAAI;AAC/E,QAAO,OAAO,KAAK,QAAQ,CAAC,SAAS,IAAI,UAAU;;AAGrD,SAAgB,sBAAsB,WAA2B;AAC/D,QAAO,KAAK,WAAW,QAAQ,yBAAyB;;AAG1D,SAAgB,mBAAmB,WAAqC;CACtE,MAAM,eAAe,sBAAsB,UAAU;AACrD,KAAI,CAAC,WAAW,aAAa,CAAE,QAAO;AACtC,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,cAAc,QAAQ,CAAC;AAC3D,MAAI,CAAC,cAAc,IAAI,CAAE,QAAO;EAChC,MAAM,EAAE,WAAW,GAAG,eAAe;AACrC,SAAO,gBAAgB,MAAM,WAAW;SAClC;AACN,SAAO;;;AAIX,SAAgB,oBACd,WACA,QACA,KACA,cACA,QACM;CACN,MAAM,eAAe,sBAAsB,UAAU;CACrD,MAAM,cAAc,QAAQ,aAAa;AACzC,KAAI,CAAC,WAAW,YAAY,CAC1B,WAAU,aAAa,EAAE,WAAW,MAAM,CAAC;CAG7C,MAAM,UAAU,qBAAqB,OAAO;CAO5C,MAAM,SAAS;EACb,WAP+B;GAC/B;GACA,6BAAY,IAAI,MAAM,EAAC,aAAa;GACpC,cAAc,gBAAgB,EAAE;GAChC,GAAI,SAAS,EAAE,QAAQ,GAAG,EAAE;GAC7B;EAGC,GAAG;EACJ;CAED,MAAM,UAAU,GAAG,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;AACnD,KAAI;AACF,MAAI,aAAa,cAAc,QAAQ,KAAK,QAAS;SAC/C;AAGR,eAAc,cAAc,QAAQ;;AAGtC,SAAgB,qBAAqB,WAA2B;CAC9D,MAAM,eAAe,sBAAsB,UAAU;AACrD,KAAI,WAAW,aAAa,CAAE,QAAO;AACrC,QAAO,KAAK,WAAW,kBAAkB;;AAG3C,SAAgB,sBAAsB,WAA4C;CAChF,MAAM,eAAe,sBAAsB,UAAU;AACrD,KAAI,WAAW,aAAa,CAC1B,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,cAAc,QAAQ,CAAC;AAC3D,MAAI,cAAc,IAAI,EAAE;GACtB,MAAM,EAAE,WAAW,GAAG,eAAe;AACrC,UAAO;;SAEH;CAEV,MAAM,gBAAgB,KAAK,WAAW,kBAAkB;AACxD,QAAO,KAAK,MAAM,aAAa,eAAe,QAAQ,CAAC;;AAGzD,SAAS,yBACP,aACA,YACA,SACA,aACe;AACf,KAAI,gBAAgB,SAClB,QAAO,qBAAqB,YAAY,SAAS,SAAS;CAE5D,MAAM,YAAY,qBAAqB,aAAa,QAAQ;AAC5D,KAAI,UAAU,WAAW,YAAY,CAAC,UAAU,aAAa,CAAC,WAAW,UAAU,UAAU,EAC3F,QAAO,qBAAqB,YAAY,SAAS,SAAS;AAE5D,QAAO;;AAYT,SAAgB,mBACd,QACA,SACA,KACA,SACe;CACf,MAAM,WAAW,OAAO,IAAI;CAC5B,MAAM,YAAY,OAAO,IAAI;CAC7B,MAAM,aAAa,OAAO,IAAI;CAC9B,MAAM,YACJ,QAAQ,gBACJ,yBACE,SAAS,aACT,SAAS,YACT,SACA,SAAS,SACV,GACD,qBAAqB,SAAS,YAAY,SAAS,SAAS;CAClE,MAAM,aACJ,QAAQ,gBACJ,yBACE,UAAU,aACV,UAAU,YACV,SACA,SAAS,UACV,GACD,qBAAqB,UAAU,YAAY,SAAS,SAAS;CACnE,MAAM,cAAc,aAChB,QAAQ,gBACN,yBACE,WAAW,aACX,WAAW,YACX,SACA,SAAS,WACV,GACD,qBAAqB,WAAW,YAAY,SAAS,SAAS,GAChE;CAEJ,MAAM,aAAa,OAAO,IAAI;CAC9B,MAAM,cACJ,QAAQ,gBACJ,yBACE,WAAW,aACX,WAAW,YACX,SACA,SAAS,WACV,GACD,qBAAqB,WAAW,YAAY,SAAS,SAAS;CAEpE,MAAM,mBACJ,QAAQ,gBACJ,0BAA0B,WAAW,YAAY,GACjD,oBAAoB,YAAY,QAAQ;CAE9C,MAAM,eAAe,YAAY,WAAW;CAC5C,MAAM,aAAa,UAAU,WAAW;CACxC,MAAM,cAAc,WAAW,WAAW;AAE1C,QAAO;EACL;EACA,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,WAAW,uBAAuB,OAAO,QAAQ;EACjD,YAAY,OAAO;EACnB,MAAM;GACJ,MAAM;GACN,KAAK;GACL,OAAO,GAAG,iBAAiB;GAC3B,WAAW,YAAY;GACvB,MAAM,YAAY,QAAQ;GAC1B,SAAS,WAAW;GACpB,WAAW,eAAe,WAAW,YAAY;GACjD,QAAQ,YAAY;GACpB,WAAW,eAAe,YAAY,MAAM;GAC7C;EACD,QAAQ,OAAO;EACf,IAAI;GACF,MAAM,SAAS;GACf,KAAK,UAAU;GACf,OAAO,UAAU,MAAM,GAAG,UAAU,IAAI,qBAAqB;GAC7D,WAAW,UAAU;GACrB,MAAM,UAAU;GAChB,QAAQ,aAAa,SAAS,MAAM;GACpC,cAAc,aAAa,SAAS,eAAe;GACnD,WAAW,aAAa,SAAS,YAAY;GAC7C,QAAQ,UAAU;GACnB;EACD,KAAK;GACH,MAAM,UAAU;GAChB,KAAK,WAAW;GAChB,OAAO,WAAW,MAAM,GAAG,WAAW,IAAI,qBAAqB;GAC/D,WAAW,WAAW;GACtB,MAAM,WAAW;GACjB,QAAQ,WAAW;GACnB,OAAO,SAAS,SAAS,UAAU;GACnC,WAAW,UAAU;GACrB,SAAS,UAAU;GACnB,WAAW,cAAc,UAAU,YAAY;GAChD;EACD,aAAa;AACX,OAAI,CAAC,cAAc,CAAC,YAAa,QAAO;AACxC,UAAO;IACL,MAAM,yBAAyB,QAAW,YAAY,WAAW,WAAW,KAAK;IACjF,KAAK,YAAY;IACjB,OAAO,YAAY,MAAM,GAAG,YAAY,IAAI,qBAAqB;IACjE,WAAW,YAAY;IACvB,MAAM,YAAY;IAClB,QAAQ,YAAY;IACpB,OAAO,WAAW;IAClB,WAAW,WAAW;IACtB,SAAS,WAAW;IACpB,WAAW,YAAY,WAAW,WAAW,WAAW,YAAY;IACpE,SAAS,WAAW,SAAS,KAAK,UAAU;KAC1C,GAAG;KACH,IAAI,KAAK,MAAM;KACf,cAAc,KAAK,gBAAiB;KACrC,EAAE;IACJ;MACC;EACJ,SACE,SAAS,WAAW,OAAO,KAAK,QAAQ,QAAQ,CAAC,SAAS,IAAI,QAAQ,UAAU;EACnF;;AAGH,eAAe,eAAe,YAAoB,SAA0C;AAC1F,KAAI,WAAW,WAAW,SAAS,CACjC,QAAO,yBAAyC,WAAW;CAG7D,MAAM,eAAe,WAAW,WAAW,GAAG,aAAa,QAAQ,SAAS,WAAW;AACvF,QAAO,KAAK,MAAM,aAAa,cAAc,QAAQ,CAAC;;AAGxD,eAAe,yBACb,YACA,SACA,SACA,OACA,MAAc,eACW;AACzB,KAAI,QAAQ,IAAI,WAAW,CACzB,OAAM,IAAI,MAAM,8BAA8B,CAAC,GAAG,SAAS,WAAW,CAAC,KAAK,OAAO,GAAG;CAGxF,MAAM,SAAS,MAAM,eAAe,YAAY,QAAQ;AACxD,OAAM,KAAK,WAAW;AAEtB,KAAI,CAAC,OAAO,QACV,QAAO;CAGT,MAAM,aAAa,kBAAkB,OAAO,SAAmC,IAAI;AACnF,KAAI,CAAC,WACH,QAAO;CAGT,MAAM,cAAc,IAAI,IAAI,QAAQ;AACpC,aAAY,IAAI,WAAW;AAQ3B,QAAO,0BAFQ,MAAM,yBAAyB,YALxB,WAAW,WAAW,SAAS,GACjD,UACA,WAAW,WAAW,GACpB,QAAQ,WAAW,GACnB,SACmE,aAAa,OAAO,IAAI,EAExD,OAAO;;AAKlD,SAAS,qBAAqB,KAAuD;AACnF,KAAI,QAAQ,QAAQ,QAAQ,MAAO,QAAO;AAC1C,KAAI,OAAO,QAAQ,SACjB,QAAO,EAAE,SAAS,KAAK;AAEzB,QAAO;;AAGT,eAAe,sBACb,SACA,SACA,KAC8C;CAC9C,MAAM,MAA2C,EAAE;AAEnD,MAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,QAAQ,EAAE;EAC1D,MAAM,aAAa,qBAAqB,SAAS;AACjD,MAAI,eAAe,QAAQ,eAAe,MAAO;EAEjD,IAAI,iBAAiC,EAAE;EACvC,IAAI,gBAAgB;AAEpB,MAAI,WAAW,QACb,KAAI;GACF,MAAM,aAAa,kBAAkB,WAAW,SAAS,IAAI;AAC7D,OAAI,WAEF,kBADqB,MAAM,yBAAyC,WAAW;UAG3E;AACN,oBAAiB,EAAE;;AAIvB,MAAI,WAAW,aAAa,WAAW,aAAa,EAAE;GACpD,MAAM,YAAY,QAAQ,SAAS,WAAW,YAAY,MAAM,EAAoB,CAAC,MAAM,CAAC;AAC5F,OAAI,WAAW,UAAU,EAAE;IACzB,MAAM,kBAAkB,KAAK,WAAW,kBAAkB;AAC1D,QAAI,WAAW,gBAAgB,CAC7B,KAAI;KACF,MAAM,WAAW,KAAK,MAAM,aAAa,iBAAiB,QAAQ,CAAC;AACnE,sBAAiB,0BAA0B,gBAAgB,SAAS;AACpE,qBAAgB;YACV;;;AAKd,MAAI,WAAW,OAAO,cAAc,WAAW,IAAI,EAAE;GACnD,MAAM,YAAqC;IACzC,GAAK,eAAe,OAAmC,EAAE;IACzD,GAAI,WAAW;IAChB;AACD,oBAAiB;IAAE,GAAG;IAAgB,KAAK;IAAoC;;AAEjF,MAAI,WAAW,UAAU,cAAc,WAAW,OAAO,EAAE;GACzD,MAAM,eAAgE;IACpE,GAAI,eAAe,UAAU,EAAE;IAC/B,GAAI,WAAW;IAChB;AACD,oBAAiB;IAAE,GAAG;IAAgB,QAAQ;IAAc;;AAE9D,MAAI,WAAW,QACb,kBAAiB;GAAE,GAAG;GAAgB,SAAS,WAAW;GAAS;AAErE,MAAI,WAAW,OACb,kBAAiB;GAAE,GAAG;GAAgB,QAAQ,WAAW;GAAQ;EAGnE,MAAM,gBAAgB,MAAM,yBAC1B,UACA,gBACA,eACA,KACA,WACD;AACD,MACE,WAAW,QACX,OAAO,WAAW,SAAS,YAC3B,CAAC,cAAc,KAAK,SAAS,IAAI,CAEjC,eAAc,OAAO,WAAW;EAGlC,MAAM,YAAY,WAAW;AAC7B,MAAI,QAAQ,gBAAgB,UAC1B,eAAc,YAAY;AAG5B,MACE,cAAc,WAAW,YACzB,cAAc,OACd,CAAC,cAAc,aACf,OAAO,eAAe,KAAK,KAAK,SAAS,YACzC,CAAC,WAAW,KAEZ,eAAc,OAAO,MAAM,+BACzB,cAAc,KACd,cAAc,KACf;AAGH,MAAI,YAAY;;AAGlB,QAAO;;AAGT,eAAe,+BAA+B,SAAiB,UAAmC;AAChG,KAAI;EACF,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,UAAU,iBAAiB,WAAW,OAAO,EAAE,IAAK;EAC1D,MAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,GAAG,CAAC,wBAAwB,EACjF,QAAQ,WAAW,QACpB,CAAC;AACF,eAAa,QAAQ;AAErB,MAAI,CAAC,SAAS,GACZ,QAAO;EAGT,MAAM,WAAY,MAAM,SAAS,MAAM;AAIvC,SAAO,OAAO,SAAS,QAAQ,SAAS,YAAY,SAAS,OAAO,KAAK,SAAS,IAC9E,SAAS,OAAO,OAChB;SACE;AACN,SAAO;;;AASX,eAAe,oBAAoB,QAAmD;CACpF,MAAM,SAAS,kBAAkB,OAAO;AACxC,KAAI,CAAC,OAAQ,QAAO;AAEpB,KAAI;EACF,MAAM,QAAQ,MAAM,wBAAwB,OAAO,WAAW,OAAO,WAAW;AAChF,MAAI,CAAC,MAAO,QAAO;EAEnB,MAAM,SAAS,MAAM,SAAS;AAC9B,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO;GACL,KAAK;GACL,WAAW,MAAM,SAAS,aAAa;GACxC;SACK;AACN,SAAO;;;AAIX,eAAe,yBACb,UACA,QACA,SACA,KACA,QAC8B;CAC9B,MAAM,YAAY,OAAO,KAAK,OAAO,EAAE;CACvC,MAAM,iBACJ,OAAO,UAAU,gBAAgB,WAAW,UAAU,cAAc;CACtE,MAAM,gBAAgB,OAAO,UAAU,eAAe,WAAW,UAAU,aAAa;CACxF,MAAM,oBAAoB,OAAO,OAAO,gBAAgB,WAAW,OAAO,cAAc;CACxF,MAAM,mBAAmB,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;CACrF,MAAM,QAAQ,OAAO,UAAU,UAAU,WAAW,UAAU,QAAQ;CACtE,MAAM,cAAc,kBAAkB;CACtC,IAAI,aAAa,iBAAiB;AAElC,KAAI,YAAY,WAAW,SAAS,EAAE;EACpC,MAAM,WAAW,MAAM,oBAAoB,WAAW;AACtD,MAAI,UAAU;AACZ,gBAAa,SAAS;AACtB,OAAI,SAAS,aAAa,QAAQ,aAChC,QAAO,YAAY,SAAS;;;CAKlC,MAAM,gBACJ,QAAQ,gBACJ,yBAAyB,aAAa,YAAY,QAAQ,GAC1D,qBAAqB,YAAY,SAAS,SAAS;CACzD,MAAM,UAAU,yBACd,OAAO,UAAU,SAAS,WAAW,UAAU,OAAO,QACtD,cAAc,WACd,SACD;CAED,MAAM,WAAW,OAAO,KAAK;CAC7B,MAAM,gBACJ,OAAO,UAAU,gBAAgB,WAAW,SAAS,cAAc;CACrE,MAAM,eAAe,OAAO,UAAU,eAAe,WAAW,SAAS,aAAa;CACtF,MAAM,YACJ,aAAa,iBAAiB,gBAC1B,QAAQ,gBACN,yBAAyB,eAAe,cAAc,QAAQ,GAC9D,qBAAqB,cAAc,SAAS,SAAS,GACvD;CAEN,MAAM,WAAW,OAAO,WAAW,OAAO,UAAU,KAAK,UAAU;EACjE,GAAG;EACH,IAAI,KAAK,MAAM,IAAI;EACnB,cAAc,KAAK,gBAAiB;EACrC,EAAE;CAEH,MAAM,SAAS,OAAO,UAAU,OAAO;AAEvC,QAAO;EACL,MAAM;EACN,KAAK,cAAc;EACnB,OAAO,cAAc,MACjB,GAAG,cAAc,IAAI,QAAQ,OAAO,GAAG,CAAC,qBACxC;EACJ,QAAQ,cAAc;EACtB,WAAW,cAAc;EACzB,MAAM,cAAc;EACpB,OAAO,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;EACnE,WAAW,sBAAsB,UAAU,aAAa,OAAO,UAAU;EACzE,SAAS,qBAAqB,UAAU,WAAW,OAAO,QAAQ;EAClE,IAAI,YACA;GACE,MAAM,OAAO,UAAU,SAAS,WAAW,SAAS,OAAO,GAAG,QAAQ;GACtE,KAAK,UAAU;GACf,OAAO,UAAU,MACb,GAAG,UAAU,IAAI,QAAQ,OAAO,GAAG,CAAC,qBACpC;GACJ,QAAQ,UAAU;GAClB,WAAW,UAAU;GACrB,MAAM,UAAU;GAChB,WACE,UAAU,WAAW,YAAY,OAAO,UAAU,cAAc,WAC5D,SAAS,YACT;GACP,GACD;EACJ;EACA;EACD;;AAGH,SAAgB,yBACd,cACA,WACA,UACQ;AACR,KAAI,aACF,QAAO;AAGT,KAAI,CAAC,UACH,QAAO;AAGT,KAAI;EACF,MAAM,kBAAkB,KAAK,WAAW,eAAe;EACvD,MAAM,cAAc,KAAK,MAAM,aAAa,iBAAiB,QAAQ,CAAC;AACtE,MAAI,OAAO,YAAY,SAAS,YAAY,YAAY,KAAK,SAAS,EACpE,QAAO,YAAY;SAEf;AAER,QAAO;;AAGT,SAAS,sBAAsB,OAAoD;AACjF,KAAI,CAAC,cAAc,MAAM,CAAE,QAAO;CAClC,MAAM,MAA8B,EAAE;AACtC,MAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,MAAM,CAC5C,KAAI,OAAO,QAAQ,SACjB,KAAI,OAAO;AAGf,QAAO,OAAO,KAAK,IAAI,CAAC,SAAS,IAAI,MAAM;;AAG7C,SAAS,qBAAqB,OAAsC;AAClE,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO;CAClC,MAAM,MAAM,MAAM,QAAQ,SAAyB,OAAO,SAAS,YAAY,KAAK,SAAS,EAAE;AAC/F,QAAO,IAAI,SAAS,IAAI,MAAM;;AAGhC,SAAS,qBACP,OACA,SACA,gBAAoC,UACrB;AACf,KAAI,CAAC,MACH,QAAO;EAAE,QAAQ;EAAe,KAAK;EAAI;AAG3C,KAAI,MAAM,WAAW,aAAa,EAAE;EAClC,MAAM,cAAc,OAAO,MAAM,EAAoB,CAAC,MAAM;AAC5D,MAAI,CAAC,YACH,OAAM,IAAI,MAAM,qCAAqC,QAAQ;EAG/D,MAAM,YAAY,QAAQ,SAAS,YAAY;AAC/C,MAAI,CAAC,WAAW,UAAU,CACxB,QAAO;GAAE,QAAQ;GAAS,KAAK;GAAI;AAGrC,SAAO;GACL,QAAQ;GACR,KAAK;GACL;GACD;;AAGH,QAAO;EACL,QAAQ;EACR,KAAK,MAAM,QAAQ,OAAO,GAAG;EAC7B,MAAM,UAAU,MAAM;EACvB;;AAGH,SAAgB,yBACd,OAC4C;AAC5C,QAAO,OAAO,UAAU,YAAY,MAAM,WAAW,aAAa;;AAGpE,SAAgB,4BACd,OACA,SACe;AACf,KAAI,CAAC,yBAAyB,MAAM,CAClC,QAAO;CAGT,MAAM,cAAc,MAAM,MAAM,EAAoB,CAAC,MAAM;AAC3D,QAAO,cAAc,QAAQ,SAAS,YAAY,GAAG;;AAGvD,SAAgB,0BAA0B,OAAmC;AAC3E,KAAI,CAAC,SAAS,yBAAyB,MAAM,CAC3C,QAAO,oBAAoB;AAG7B,QAAO,MAAM,QAAQ,OAAO,GAAG;;AAGjC,SAAgB,uBAAuB,OAAmC;AACxE,QAAO,UAAU,0BAA0B,MAAM,CAAC;;AAGpD,SAAgB,UAAU,KAAqB;AAC7C,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,SAAO,OAAO,OAAO,SAAS,OAAO,MAAM,GAAG,GAAG,OAAO,aAAa,WAAW,MAAM;SAChF;AACN,SAAO"}