everything-dev 1.16.3 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/init.cjs +50 -51
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts.map +1 -1
- package/dist/cli/init.d.mts.map +1 -1
- package/dist/cli/init.mjs +50 -51
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli/sync.cjs +3 -5
- package/dist/cli/sync.cjs.map +1 -1
- package/dist/cli/sync.mjs +3 -5
- package/dist/cli/sync.mjs.map +1 -1
- package/dist/cli/upgrade.cjs +149 -2
- package/dist/cli/upgrade.cjs.map +1 -1
- package/dist/cli/upgrade.mjs +149 -2
- package/dist/cli/upgrade.mjs.map +1 -1
- package/dist/config.cjs +125 -74
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +9 -2
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +9 -2
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +126 -76
- package/dist/config.mjs.map +1 -1
- package/dist/contract.d.cts +34 -10
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +34 -10
- package/dist/contract.d.mts.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -3
- package/dist/merge.cjs +1 -0
- package/dist/merge.mjs +1 -1
- package/dist/plugin.cjs +11 -13
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +34 -10
- package/dist/plugin.d.mts +34 -10
- package/dist/plugin.mjs +11 -13
- package/dist/plugin.mjs.map +1 -1
- package/dist/sidebar.cjs +6 -14
- package/dist/sidebar.cjs.map +1 -1
- package/dist/sidebar.d.cts +3 -3
- package/dist/sidebar.d.cts.map +1 -1
- package/dist/sidebar.d.mts +3 -3
- package/dist/sidebar.d.mts.map +1 -1
- package/dist/sidebar.mjs +6 -14
- package/dist/sidebar.mjs.map +1 -1
- package/dist/types.cjs +10 -16
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +54 -10
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +54 -10
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +10 -17
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cli/init.ts +95 -63
- package/src/cli/sync.ts +5 -8
- package/src/cli/upgrade.ts +209 -2
- package/src/config.ts +250 -107
- package/src/plugin.ts +22 -16
- package/src/sidebar.ts +9 -31
- package/src/types.ts +10 -15
package/src/config.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
|
3
3
|
import { fetchBosConfigFromFastKv } from "./fastkv";
|
|
4
4
|
import {
|
|
5
5
|
type BosEnv,
|
|
6
|
+
bosConfigMerger,
|
|
6
7
|
isPlainObject,
|
|
7
8
|
mergeBosConfigWithExtends,
|
|
8
9
|
type ResolvedConfigMeta,
|
|
@@ -18,7 +19,6 @@ import type {
|
|
|
18
19
|
PluginEntryValue,
|
|
19
20
|
RuntimeConfig,
|
|
20
21
|
RuntimePluginConfig,
|
|
21
|
-
SharedDepConfig,
|
|
22
22
|
} from "./types";
|
|
23
23
|
import { BosConfigSchema } from "./types";
|
|
24
24
|
|
|
@@ -74,6 +74,18 @@ export interface ConfigResult {
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
export interface ResolvedComposableReference {
|
|
78
|
+
entry: BosPluginRef;
|
|
79
|
+
providerBaseDir: string;
|
|
80
|
+
targetPath: string;
|
|
81
|
+
associatedUi?: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface ParsedExtendsTarget {
|
|
85
|
+
configPath: string;
|
|
86
|
+
targetPath?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
77
89
|
export async function loadConfig(options?: {
|
|
78
90
|
cwd?: string;
|
|
79
91
|
path?: string;
|
|
@@ -98,7 +110,11 @@ export async function loadConfig(options?: {
|
|
|
98
110
|
extendedChain,
|
|
99
111
|
env,
|
|
100
112
|
);
|
|
101
|
-
const config =
|
|
113
|
+
const config = await resolveRootComposableEntries(
|
|
114
|
+
BosConfigSchema.parse(parsed),
|
|
115
|
+
baseDir,
|
|
116
|
+
runtimeEnv,
|
|
117
|
+
);
|
|
102
118
|
|
|
103
119
|
cachedConfig = config;
|
|
104
120
|
projectRoot = baseDir;
|
|
@@ -144,6 +160,31 @@ export async function buildRuntimePluginsForConfig(
|
|
|
144
160
|
return Object.keys(plugins).length > 0 ? plugins : undefined;
|
|
145
161
|
}
|
|
146
162
|
|
|
163
|
+
async function resolveRootComposableEntries(
|
|
164
|
+
config: BosConfig,
|
|
165
|
+
baseDir: string,
|
|
166
|
+
env: BosEnv,
|
|
167
|
+
): Promise<BosConfig> {
|
|
168
|
+
const resolvedApi = await resolveComposableReference(
|
|
169
|
+
config.app.api as BosPluginRef,
|
|
170
|
+
baseDir,
|
|
171
|
+
env,
|
|
172
|
+
"app.api",
|
|
173
|
+
);
|
|
174
|
+
const resolvedAuth = config.app.auth
|
|
175
|
+
? await resolveComposableReference(config.app.auth as BosPluginRef, baseDir, env, "app.auth")
|
|
176
|
+
: undefined;
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
...config,
|
|
180
|
+
app: {
|
|
181
|
+
...config.app,
|
|
182
|
+
api: resolvedApi.entry,
|
|
183
|
+
auth: resolvedAuth?.entry,
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
147
188
|
export function getResolvedConfigPath(configDir: string): string {
|
|
148
189
|
return join(configDir, ".bos", RESOLVED_CONFIG_FILENAME);
|
|
149
190
|
}
|
|
@@ -216,6 +257,173 @@ export function readBosConfigForBuild(configDir: string): Record<string, unknown
|
|
|
216
257
|
return JSON.parse(readFileSync(bosConfigPath, "utf-8")) as Record<string, unknown>;
|
|
217
258
|
}
|
|
218
259
|
|
|
260
|
+
function parseExtendsTarget(ref: string): ParsedExtendsTarget {
|
|
261
|
+
const hashIndex = ref.indexOf("#");
|
|
262
|
+
if (hashIndex === -1) {
|
|
263
|
+
return { configPath: ref };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const configPath = ref.slice(0, hashIndex);
|
|
267
|
+
const targetPath = ref.slice(hashIndex + 1);
|
|
268
|
+
return {
|
|
269
|
+
configPath,
|
|
270
|
+
targetPath: targetPath.length > 0 ? targetPath : undefined,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function getConfigBaseDir(configPath: string, baseDir: string): string {
|
|
275
|
+
if (configPath.startsWith("bos://")) return baseDir;
|
|
276
|
+
return dirname(isAbsolute(configPath) ? configPath : resolve(baseDir, configPath));
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function asComposableEntry(value: unknown): BosPluginRef {
|
|
280
|
+
if (typeof value === "string") {
|
|
281
|
+
return { extends: value };
|
|
282
|
+
}
|
|
283
|
+
if (!isPlainObject(value)) {
|
|
284
|
+
throw new Error(`Expected config entry object, received ${typeof value}`);
|
|
285
|
+
}
|
|
286
|
+
return value as BosPluginRef;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function getTargetedEntry(config: BosConfigInput, targetPath: string): BosPluginRef {
|
|
290
|
+
if (targetPath === "app.api") {
|
|
291
|
+
return asComposableEntry(config.app?.api);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (targetPath === "app.auth") {
|
|
295
|
+
return asComposableEntry(config.app?.auth);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (targetPath.startsWith("plugins.")) {
|
|
299
|
+
const pluginId = targetPath.slice("plugins.".length);
|
|
300
|
+
if (pluginId.length === 0) {
|
|
301
|
+
throw new Error(`Invalid plugin target path: ${targetPath}`);
|
|
302
|
+
}
|
|
303
|
+
return asComposableEntry(config.plugins?.[pluginId]);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
throw new Error(`Unsupported extends target path: ${targetPath}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function getAssociatedUi(
|
|
310
|
+
config: BosConfigInput,
|
|
311
|
+
_targetPath: string,
|
|
312
|
+
): Record<string, unknown> | undefined {
|
|
313
|
+
return isPlainObject(config.app?.ui) ? (config.app.ui as Record<string, unknown>) : undefined;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function mergeComposableEntries(
|
|
317
|
+
parent: Partial<BosPluginRef>,
|
|
318
|
+
child: Partial<BosPluginRef>,
|
|
319
|
+
): BosPluginRef {
|
|
320
|
+
return bosConfigMerger({ ...child }, parent) as BosPluginRef;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function stripUnsafeLocalDevelopment<T extends Record<string, unknown> | undefined>(
|
|
324
|
+
entry: T,
|
|
325
|
+
allowLocalPaths: boolean,
|
|
326
|
+
): T {
|
|
327
|
+
if (!entry || allowLocalPaths) {
|
|
328
|
+
return entry;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (typeof entry.development === "string" && entry.development.startsWith(LOCAL_PREFIX)) {
|
|
332
|
+
const { development: _ignored, ...rest } = entry;
|
|
333
|
+
return rest as T;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return entry;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export async function resolveComposableReference(
|
|
340
|
+
source: BosPluginRef,
|
|
341
|
+
baseDir: string,
|
|
342
|
+
env: BosEnv,
|
|
343
|
+
defaultTargetPath: string,
|
|
344
|
+
): Promise<ResolvedComposableReference> {
|
|
345
|
+
let resolvedEntry: BosPluginRef = {};
|
|
346
|
+
let providerBaseDir = baseDir;
|
|
347
|
+
let targetPath = defaultTargetPath;
|
|
348
|
+
let associatedUi: Record<string, unknown> | undefined;
|
|
349
|
+
let allowLocalPaths = false;
|
|
350
|
+
let extendsError: unknown;
|
|
351
|
+
|
|
352
|
+
const extendsRef = source.extends ? resolveExtendsRef(source.extends, env) : undefined;
|
|
353
|
+
if (extendsRef) {
|
|
354
|
+
const parsed = parseExtendsTarget(extendsRef);
|
|
355
|
+
targetPath = parsed.targetPath ?? defaultTargetPath;
|
|
356
|
+
const extendsBaseDir = getConfigBaseDir(parsed.configPath, baseDir);
|
|
357
|
+
try {
|
|
358
|
+
const extendedConfig = await resolveConfigWithExtends(
|
|
359
|
+
parsed.configPath,
|
|
360
|
+
extendsBaseDir,
|
|
361
|
+
new Set(),
|
|
362
|
+
[],
|
|
363
|
+
env,
|
|
364
|
+
);
|
|
365
|
+
resolvedEntry = mergeComposableEntries(
|
|
366
|
+
resolvedEntry,
|
|
367
|
+
getTargetedEntry(extendedConfig, targetPath),
|
|
368
|
+
);
|
|
369
|
+
providerBaseDir = extendsBaseDir;
|
|
370
|
+
associatedUi = getAssociatedUi(extendedConfig, targetPath);
|
|
371
|
+
} catch (error) {
|
|
372
|
+
extendsError = error;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const localDevelopment =
|
|
377
|
+
typeof source.development === "string" && source.development.startsWith(LOCAL_PREFIX)
|
|
378
|
+
? source.development
|
|
379
|
+
: undefined;
|
|
380
|
+
|
|
381
|
+
if (localDevelopment) {
|
|
382
|
+
const localPath = resolve(baseDir, localDevelopment.slice(LOCAL_PREFIX.length).trim());
|
|
383
|
+
const localConfigPath = join(localPath, "bos.config.json");
|
|
384
|
+
if (existsSync(localConfigPath)) {
|
|
385
|
+
const localConfig = await resolveConfigWithExtends(
|
|
386
|
+
localConfigPath,
|
|
387
|
+
localPath,
|
|
388
|
+
new Set(),
|
|
389
|
+
[],
|
|
390
|
+
env,
|
|
391
|
+
);
|
|
392
|
+
resolvedEntry = mergeComposableEntries(
|
|
393
|
+
resolvedEntry,
|
|
394
|
+
getTargetedEntry(localConfig, targetPath),
|
|
395
|
+
);
|
|
396
|
+
providerBaseDir = localPath;
|
|
397
|
+
associatedUi = getAssociatedUi(localConfig, targetPath);
|
|
398
|
+
allowLocalPaths = true;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const sourceOverrides = { ...source };
|
|
403
|
+
if (allowLocalPaths && localDevelopment) {
|
|
404
|
+
delete sourceOverrides.development;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
resolvedEntry = mergeComposableEntries(resolvedEntry, sourceOverrides);
|
|
408
|
+
|
|
409
|
+
if (
|
|
410
|
+
extendsError &&
|
|
411
|
+
!allowLocalPaths &&
|
|
412
|
+
typeof resolvedEntry.development !== "string" &&
|
|
413
|
+
typeof resolvedEntry.production !== "string" &&
|
|
414
|
+
typeof resolvedEntry.name !== "string"
|
|
415
|
+
) {
|
|
416
|
+
throw extendsError;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
entry: stripUnsafeLocalDevelopment(resolvedEntry, allowLocalPaths || Boolean(localDevelopment)),
|
|
421
|
+
providerBaseDir,
|
|
422
|
+
targetPath,
|
|
423
|
+
associatedUi: stripUnsafeLocalDevelopment(associatedUi, allowLocalPaths),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
219
427
|
function resolveDevelopmentTarget(
|
|
220
428
|
development: string | undefined,
|
|
221
429
|
production: string | undefined,
|
|
@@ -225,6 +433,9 @@ function resolveDevelopmentTarget(
|
|
|
225
433
|
if (forceSource === "remote") {
|
|
226
434
|
return resolveRuntimeTarget(production, baseDir, "remote");
|
|
227
435
|
}
|
|
436
|
+
if (!development) {
|
|
437
|
+
return resolveRuntimeTarget(production, baseDir, "remote");
|
|
438
|
+
}
|
|
228
439
|
const devTarget = resolveRuntimeTarget(development, baseDir);
|
|
229
440
|
if (devTarget.source === "local" && (!devTarget.localPath || !existsSync(devTarget.localPath))) {
|
|
230
441
|
return resolveRuntimeTarget(production, baseDir, "remote");
|
|
@@ -298,6 +509,7 @@ export function buildRuntimeConfig(
|
|
|
298
509
|
const hostIsRemote = hostRuntime.source === "remote";
|
|
299
510
|
const uiIsRemote = uiRuntime.source === "remote";
|
|
300
511
|
const apiIsRemote = apiRuntime.source === "remote";
|
|
512
|
+
const resolvedApiName = resolvePluginRuntimeName(apiConfig.name, apiRuntime.localPath, "api");
|
|
301
513
|
|
|
302
514
|
return {
|
|
303
515
|
env,
|
|
@@ -331,7 +543,7 @@ export function buildRuntimeConfig(
|
|
|
331
543
|
source: uiRuntime.source,
|
|
332
544
|
},
|
|
333
545
|
api: {
|
|
334
|
-
name:
|
|
546
|
+
name: resolvedApiName,
|
|
335
547
|
url: apiRuntime.url,
|
|
336
548
|
entry: apiRuntime.url ? `${apiRuntime.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
337
549
|
localPath: apiRuntime.localPath,
|
|
@@ -345,7 +557,7 @@ export function buildRuntimeConfig(
|
|
|
345
557
|
auth: (() => {
|
|
346
558
|
if (!authConfig || !authRuntime) return undefined;
|
|
347
559
|
return {
|
|
348
|
-
name: resolvePluginRuntimeName(
|
|
560
|
+
name: resolvePluginRuntimeName(authConfig.name, authRuntime.localPath, "auth"),
|
|
349
561
|
url: authRuntime.url,
|
|
350
562
|
entry: authRuntime.url ? `${authRuntime.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
351
563
|
localPath: authRuntime.localPath,
|
|
@@ -399,14 +611,18 @@ async function resolveConfigWithExtends(
|
|
|
399
611
|
return config;
|
|
400
612
|
}
|
|
401
613
|
|
|
614
|
+
const parsedParentRef = parseExtendsTarget(extendsRef);
|
|
615
|
+
|
|
402
616
|
const nextVisited = new Set(visited);
|
|
403
617
|
nextVisited.add(configPath);
|
|
404
|
-
const parentBaseDir =
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
618
|
+
const parentBaseDir = getConfigBaseDir(parsedParentRef.configPath, baseDir);
|
|
619
|
+
const parent = await resolveConfigWithExtends(
|
|
620
|
+
parsedParentRef.configPath,
|
|
621
|
+
parentBaseDir,
|
|
622
|
+
nextVisited,
|
|
623
|
+
chain,
|
|
624
|
+
env,
|
|
625
|
+
);
|
|
410
626
|
|
|
411
627
|
return mergeBosConfigWithExtends(parent, config);
|
|
412
628
|
}
|
|
@@ -432,82 +648,20 @@ async function resolveRuntimePlugins(
|
|
|
432
648
|
const normalized = normalizePluginEntry(rawInput);
|
|
433
649
|
if (normalized === null || normalized === false) continue;
|
|
434
650
|
|
|
435
|
-
|
|
436
|
-
let pluginBaseDir = baseDir;
|
|
437
|
-
|
|
438
|
-
if (normalized.extends) {
|
|
439
|
-
try {
|
|
440
|
-
const extendsUrl = resolveExtendsRef(normalized.extends, env);
|
|
441
|
-
if (extendsUrl) {
|
|
442
|
-
const remoteConfig = await fetchBosConfigFromFastKv<BosConfigInput>(extendsUrl);
|
|
443
|
-
resolvedConfig = remoteConfig;
|
|
444
|
-
}
|
|
445
|
-
} catch {
|
|
446
|
-
resolvedConfig = {};
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
if (normalized.development?.startsWith(LOCAL_PREFIX)) {
|
|
451
|
-
const localPath = resolve(baseDir, normalized.development.slice(LOCAL_PREFIX.length).trim());
|
|
452
|
-
if (existsSync(localPath)) {
|
|
453
|
-
const localConfigPath = join(localPath, "bos.config.json");
|
|
454
|
-
if (existsSync(localConfigPath)) {
|
|
455
|
-
try {
|
|
456
|
-
const localRaw = JSON.parse(readFileSync(localConfigPath, "utf-8")) as BosConfigInput;
|
|
457
|
-
resolvedConfig = mergeBosConfigWithExtends(resolvedConfig, localRaw);
|
|
458
|
-
pluginBaseDir = localPath;
|
|
459
|
-
} catch {}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (normalized.app && isPlainObject(normalized.app)) {
|
|
465
|
-
const mergedApp: Record<string, unknown> = {
|
|
466
|
-
...((resolvedConfig.app as Record<string, unknown>) ?? {}),
|
|
467
|
-
...(normalized.app as Record<string, unknown>),
|
|
468
|
-
};
|
|
469
|
-
resolvedConfig = { ...resolvedConfig, app: mergedApp as BosConfigInput["app"] };
|
|
470
|
-
}
|
|
471
|
-
if (normalized.shared && isPlainObject(normalized.shared)) {
|
|
472
|
-
const mergedShared: Record<string, Record<string, SharedDepConfig>> = {
|
|
473
|
-
...(resolvedConfig.shared ?? {}),
|
|
474
|
-
...(normalized.shared as Record<string, Record<string, SharedDepConfig>>),
|
|
475
|
-
};
|
|
476
|
-
resolvedConfig = { ...resolvedConfig, shared: mergedShared };
|
|
477
|
-
}
|
|
478
|
-
if (normalized.sidebar) {
|
|
479
|
-
resolvedConfig = { ...resolvedConfig, sidebar: normalized.sidebar };
|
|
480
|
-
}
|
|
481
|
-
if (normalized.routes) {
|
|
482
|
-
resolvedConfig = { ...resolvedConfig, routes: normalized.routes };
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const pluginRuntime = await buildRuntimePluginConfig(
|
|
486
|
-
pluginId,
|
|
487
|
-
resolvedConfig,
|
|
488
|
-
pluginBaseDir,
|
|
489
|
-
env,
|
|
651
|
+
const resolvedReference = await resolveComposableReference(
|
|
490
652
|
normalized,
|
|
653
|
+
baseDir,
|
|
654
|
+
env,
|
|
655
|
+
`plugins.${pluginId}`,
|
|
491
656
|
);
|
|
492
|
-
if (
|
|
493
|
-
normalized.name &&
|
|
494
|
-
typeof normalized.name === "string" &&
|
|
495
|
-
!pluginRuntime.name.includes("/")
|
|
496
|
-
) {
|
|
497
|
-
pluginRuntime.name = normalized.name;
|
|
498
|
-
}
|
|
499
657
|
|
|
500
|
-
const
|
|
501
|
-
if (env === "production" && integrity) {
|
|
502
|
-
pluginRuntime.integrity = integrity;
|
|
503
|
-
}
|
|
658
|
+
const pluginRuntime = buildRuntimePluginConfig(pluginId, env, resolvedReference);
|
|
504
659
|
|
|
505
660
|
if (
|
|
506
661
|
pluginRuntime.source === "remote" &&
|
|
507
662
|
pluginRuntime.url &&
|
|
508
663
|
!pluginRuntime.localPath &&
|
|
509
|
-
typeof
|
|
510
|
-
!normalized.name
|
|
664
|
+
typeof resolvedReference.entry.name !== "string"
|
|
511
665
|
) {
|
|
512
666
|
pluginRuntime.name = await resolveRemotePluginRuntimeName(
|
|
513
667
|
pluginRuntime.url,
|
|
@@ -546,22 +700,14 @@ async function resolveRemotePluginRuntimeName(baseUrl: string, fallback: string)
|
|
|
546
700
|
}
|
|
547
701
|
}
|
|
548
702
|
|
|
549
|
-
|
|
703
|
+
function buildRuntimePluginConfig(
|
|
550
704
|
pluginId: string,
|
|
551
|
-
config: BosConfigInput,
|
|
552
|
-
baseDir: string,
|
|
553
705
|
env: BosEnv,
|
|
554
|
-
|
|
555
|
-
):
|
|
556
|
-
const
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
const apiProduction = typeof apiConfig.production === "string" ? apiConfig.production : undefined;
|
|
560
|
-
const sourceDevelopment = typeof source.development === "string" ? source.development : undefined;
|
|
561
|
-
const sourceProduction = typeof source.production === "string" ? source.production : undefined;
|
|
562
|
-
const proxy = typeof apiConfig.proxy === "string" ? apiConfig.proxy : undefined;
|
|
563
|
-
const development = apiDevelopment ?? sourceDevelopment;
|
|
564
|
-
const production = apiProduction ?? sourceProduction;
|
|
706
|
+
resolved: ResolvedComposableReference,
|
|
707
|
+
): RuntimePluginConfig {
|
|
708
|
+
const source = resolved.entry;
|
|
709
|
+
const development = typeof source.development === "string" ? source.development : undefined;
|
|
710
|
+
const production = typeof source.production === "string" ? source.production : undefined;
|
|
565
711
|
|
|
566
712
|
if (production?.startsWith("bos://")) {
|
|
567
713
|
throw new Error(
|
|
@@ -571,32 +717,28 @@ async function buildRuntimePluginConfig(
|
|
|
571
717
|
|
|
572
718
|
const runtimeTarget =
|
|
573
719
|
env === "development"
|
|
574
|
-
? resolveDevelopmentTarget(development, production,
|
|
575
|
-
: resolveRuntimeTarget(production,
|
|
576
|
-
const apiName = resolvePluginRuntimeName(
|
|
577
|
-
typeof apiConfig.name === "string" ? apiConfig.name : undefined,
|
|
578
|
-
runtimeTarget.localPath,
|
|
579
|
-
pluginId,
|
|
580
|
-
);
|
|
720
|
+
? resolveDevelopmentTarget(development, production, resolved.providerBaseDir)
|
|
721
|
+
: resolveRuntimeTarget(production, resolved.providerBaseDir, "remote");
|
|
722
|
+
const apiName = resolvePluginRuntimeName(source.name, runtimeTarget.localPath, pluginId);
|
|
581
723
|
|
|
582
|
-
const uiConfig =
|
|
724
|
+
const uiConfig = resolved.associatedUi;
|
|
583
725
|
const uiDevelopment =
|
|
584
726
|
typeof uiConfig?.development === "string" ? uiConfig.development : undefined;
|
|
585
727
|
const uiProduction = typeof uiConfig?.production === "string" ? uiConfig.production : undefined;
|
|
586
728
|
const uiRuntime =
|
|
587
729
|
uiConfig && (uiDevelopment || uiProduction)
|
|
588
730
|
? env === "development"
|
|
589
|
-
? resolveDevelopmentTarget(uiDevelopment, uiProduction,
|
|
590
|
-
: resolveRuntimeTarget(uiProduction,
|
|
731
|
+
? resolveDevelopmentTarget(uiDevelopment, uiProduction, resolved.providerBaseDir)
|
|
732
|
+
: resolveRuntimeTarget(uiProduction, resolved.providerBaseDir, "remote")
|
|
591
733
|
: undefined;
|
|
592
734
|
|
|
593
|
-
const sidebar =
|
|
735
|
+
const sidebar = source.sidebar?.map((item) => ({
|
|
594
736
|
...item,
|
|
595
737
|
to: item.to ?? `/${pluginId}`,
|
|
596
738
|
roleRequired: item.roleRequired ?? ("member" as const),
|
|
597
739
|
}));
|
|
598
740
|
|
|
599
|
-
const routes =
|
|
741
|
+
const routes = source.routes;
|
|
600
742
|
|
|
601
743
|
return {
|
|
602
744
|
name: apiName,
|
|
@@ -607,9 +749,10 @@ async function buildRuntimePluginConfig(
|
|
|
607
749
|
source: runtimeTarget.source,
|
|
608
750
|
localPath: runtimeTarget.localPath,
|
|
609
751
|
port: runtimeTarget.port,
|
|
610
|
-
proxy:
|
|
611
|
-
variables: normalizeStringRecord(
|
|
612
|
-
secrets: normalizeStringArray(
|
|
752
|
+
proxy: typeof source.proxy === "string" ? source.proxy : undefined,
|
|
753
|
+
variables: normalizeStringRecord(source.variables),
|
|
754
|
+
secrets: normalizeStringArray(source.secrets),
|
|
755
|
+
integrity: runtimeTarget.source === "remote" ? source.integrity : undefined,
|
|
613
756
|
ui: uiRuntime
|
|
614
757
|
? {
|
|
615
758
|
name: typeof uiConfig?.name === "string" ? uiConfig.name : `${apiName}-ui`,
|
package/src/plugin.ts
CHANGED
|
@@ -236,8 +236,6 @@ async function generateCodeArtifacts(
|
|
|
236
236
|
runtimeConfig?: RuntimeConfig;
|
|
237
237
|
},
|
|
238
238
|
): Promise<GeneratedArtifacts | null> {
|
|
239
|
-
writePluginSidebarGen(configDir, config);
|
|
240
|
-
|
|
241
239
|
if (opts?.env) {
|
|
242
240
|
writeResolvedConfig(configDir, config, opts.env, opts.extendsChain);
|
|
243
241
|
}
|
|
@@ -245,6 +243,8 @@ async function generateCodeArtifacts(
|
|
|
245
243
|
const runtimeConfig = opts?.runtimeConfig ?? (await loadConfig({ cwd: configDir }))?.runtime;
|
|
246
244
|
if (!runtimeConfig) return null;
|
|
247
245
|
|
|
246
|
+
writePluginSidebarGen(configDir, runtimeConfig);
|
|
247
|
+
|
|
248
248
|
const bridge = await syncApiContractBridge({
|
|
249
249
|
configDir,
|
|
250
250
|
runtimeConfig,
|
|
@@ -653,18 +653,22 @@ export default createPlugin({
|
|
|
653
653
|
string,
|
|
654
654
|
unknown
|
|
655
655
|
>;
|
|
656
|
-
if (!pluginConfig.
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
const
|
|
660
|
-
|
|
656
|
+
if (!pluginConfig.plugins || typeof pluginConfig.plugins !== "object") {
|
|
657
|
+
pluginConfig.plugins = {};
|
|
658
|
+
}
|
|
659
|
+
const plugins = pluginConfig.plugins as Record<string, unknown>;
|
|
660
|
+
if (!plugins[input.key] || typeof plugins[input.key] !== "object") {
|
|
661
|
+
plugins[input.key] = {};
|
|
662
|
+
}
|
|
663
|
+
const entry = plugins[input.key] as Record<string, unknown>;
|
|
664
|
+
entry.production = publishedUrl;
|
|
661
665
|
if (integrity) {
|
|
662
|
-
|
|
666
|
+
entry.integrity = integrity;
|
|
663
667
|
} else {
|
|
664
|
-
delete
|
|
668
|
+
delete entry.integrity;
|
|
665
669
|
}
|
|
666
670
|
writeFileSync(pluginConfigPath, `${JSON.stringify(pluginConfig, null, 2)}\n`);
|
|
667
|
-
console.log(` ✅ Updated ${pluginConfigPath}:
|
|
671
|
+
console.log(` ✅ Updated ${pluginConfigPath}: plugins.${input.key}.production`);
|
|
668
672
|
} catch (err) {
|
|
669
673
|
console.error(
|
|
670
674
|
` ❌ Failed to update plugin bos.config.json:`,
|
|
@@ -1382,12 +1386,14 @@ export default createPlugin({
|
|
|
1382
1386
|
}
|
|
1383
1387
|
|
|
1384
1388
|
const pluginRoutes: Record<string, string[]> = {};
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1389
|
+
const parentRuntimePlugins = await buildRuntimePluginsForConfig(
|
|
1390
|
+
parentConfig as BosConfig,
|
|
1391
|
+
sourceDir,
|
|
1392
|
+
"production",
|
|
1393
|
+
);
|
|
1394
|
+
for (const [key, plugin] of Object.entries(parentRuntimePlugins ?? {})) {
|
|
1395
|
+
if (plugin.routes && plugin.routes.length > 0) {
|
|
1396
|
+
pluginRoutes[key] = plugin.routes;
|
|
1391
1397
|
}
|
|
1392
1398
|
}
|
|
1393
1399
|
|
package/src/sidebar.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
import type {
|
|
3
|
+
import type { RuntimeConfig, SidebarItem } from "./types";
|
|
4
4
|
|
|
5
5
|
const ICON_IMPORTS: Record<string, string> = {
|
|
6
6
|
Home: "lucide-react",
|
|
@@ -51,11 +51,11 @@ function collectIconImports(items: SidebarItem[]): Map<string, Set<string>> {
|
|
|
51
51
|
return moduleMap;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export function generatePluginSidebarContent(
|
|
54
|
+
export function generatePluginSidebarContent(runtimeConfig: RuntimeConfig): string {
|
|
55
55
|
const coreItems: SidebarItem[] = [{ icon: "Home", label: "home", to: "/", roleRequired: "anon" }];
|
|
56
56
|
|
|
57
|
-
if (
|
|
58
|
-
for (const item of
|
|
57
|
+
if (runtimeConfig.auth?.sidebar) {
|
|
58
|
+
for (const item of runtimeConfig.auth.sidebar) {
|
|
59
59
|
coreItems.push({
|
|
60
60
|
...item,
|
|
61
61
|
to: item.to ?? "/auth",
|
|
@@ -65,31 +65,9 @@ export function generatePluginSidebarContent(config: BosConfig, configDir?: stri
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
const pluginItems: SidebarItem[] = [];
|
|
68
|
-
if (
|
|
69
|
-
for (const [key, entry] of Object.entries(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (typeof entry === "object" && entry.sidebar) {
|
|
73
|
-
sidebar = entry.sidebar;
|
|
74
|
-
} else if (
|
|
75
|
-
typeof entry === "object" &&
|
|
76
|
-
entry.development?.startsWith("local:") &&
|
|
77
|
-
configDir
|
|
78
|
-
) {
|
|
79
|
-
const localPath = join(configDir, entry.development.slice("local:".length).trim());
|
|
80
|
-
const pluginConfigPath = join(localPath, "bos.config.json");
|
|
81
|
-
if (existsSync(pluginConfigPath)) {
|
|
82
|
-
try {
|
|
83
|
-
const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, "utf-8")) as {
|
|
84
|
-
sidebar?: SidebarItem[];
|
|
85
|
-
};
|
|
86
|
-
if (pluginConfig.sidebar) {
|
|
87
|
-
sidebar = pluginConfig.sidebar;
|
|
88
|
-
}
|
|
89
|
-
} catch {}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
68
|
+
if (runtimeConfig.plugins) {
|
|
69
|
+
for (const [key, entry] of Object.entries(runtimeConfig.plugins)) {
|
|
70
|
+
const sidebar = entry.sidebar;
|
|
93
71
|
if (!sidebar) continue;
|
|
94
72
|
for (const item of sidebar) {
|
|
95
73
|
pluginItems.push({
|
|
@@ -135,10 +113,10 @@ ${itemsCode}
|
|
|
135
113
|
`;
|
|
136
114
|
}
|
|
137
115
|
|
|
138
|
-
export function writePluginSidebarGen(configDir: string,
|
|
116
|
+
export function writePluginSidebarGen(configDir: string, runtimeConfig: RuntimeConfig): string {
|
|
139
117
|
const outputPath = join(configDir, "ui/src/lib/plugin-sidebar.gen.ts");
|
|
140
118
|
|
|
141
|
-
const content = generatePluginSidebarContent(
|
|
119
|
+
const content = generatePluginSidebarContent(runtimeConfig);
|
|
142
120
|
|
|
143
121
|
const outputDir = dirname(outputPath);
|
|
144
122
|
if (!existsSync(outputDir)) {
|
package/src/types.ts
CHANGED
|
@@ -46,8 +46,9 @@ export const SidebarItemSchema = z.object({
|
|
|
46
46
|
});
|
|
47
47
|
export type SidebarItem = z.infer<typeof SidebarItemSchema>;
|
|
48
48
|
|
|
49
|
-
export const
|
|
50
|
-
|
|
49
|
+
export const ComposableAppEntrySchema = z.object({
|
|
50
|
+
extends: ExtendsSchema.optional(),
|
|
51
|
+
name: z.string().optional(),
|
|
51
52
|
development: z.string().optional(),
|
|
52
53
|
production: z.string().optional(),
|
|
53
54
|
integrity: z.string().optional(),
|
|
@@ -55,7 +56,11 @@ export const ApiPluginConfigSchema = z.object({
|
|
|
55
56
|
variables: z.record(z.string(), z.string()).optional(),
|
|
56
57
|
secrets: z.array(z.string()).optional(),
|
|
57
58
|
sidebar: z.array(SidebarItemSchema).optional(),
|
|
59
|
+
routes: z.array(z.string()).optional(),
|
|
58
60
|
});
|
|
61
|
+
export type ComposableAppEntry = z.infer<typeof ComposableAppEntrySchema>;
|
|
62
|
+
|
|
63
|
+
export const ApiPluginConfigSchema = ComposableAppEntrySchema;
|
|
59
64
|
export type ApiPluginConfig = z.infer<typeof ApiPluginConfigSchema>;
|
|
60
65
|
|
|
61
66
|
export const PluginUiConfigSchema = z.object({
|
|
@@ -66,18 +71,8 @@ export const PluginUiConfigSchema = z.object({
|
|
|
66
71
|
});
|
|
67
72
|
export type PluginUiConfig = z.infer<typeof PluginUiConfigSchema>;
|
|
68
73
|
|
|
69
|
-
export const BosPluginRefSchema =
|
|
70
|
-
extends: ExtendsSchema.optional(),
|
|
71
|
-
development: z.string().optional(),
|
|
72
|
-
production: z.string().optional(),
|
|
73
|
-
integrity: z.string().optional(),
|
|
74
|
-
name: z.string().optional(),
|
|
74
|
+
export const BosPluginRefSchema = ComposableAppEntrySchema.extend({
|
|
75
75
|
version: z.string().optional(),
|
|
76
|
-
proxy: z.string().optional(),
|
|
77
|
-
variables: z.record(z.string(), z.string()).optional(),
|
|
78
|
-
secrets: z.array(z.string()).optional(),
|
|
79
|
-
routes: z.array(z.string()).optional(),
|
|
80
|
-
sidebar: z.array(SidebarItemSchema).optional(),
|
|
81
76
|
app: z.record(z.string(), z.unknown()).optional(),
|
|
82
77
|
shared: z.record(z.string(), z.record(z.string(), SharedConfigSchema)).optional(),
|
|
83
78
|
plugins: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -222,8 +217,8 @@ export const BosConfigSchema = z.object({
|
|
|
222
217
|
app: z.object({
|
|
223
218
|
host: HostConfigSchema,
|
|
224
219
|
ui: UiConfigSchema,
|
|
225
|
-
api:
|
|
226
|
-
auth:
|
|
220
|
+
api: ComposableAppEntrySchema,
|
|
221
|
+
auth: ComposableAppEntrySchema.optional(),
|
|
227
222
|
}),
|
|
228
223
|
});
|
|
229
224
|
export type BosConfig = z.infer<typeof BosConfigSchema>;
|