@lorion-org/react 1.0.0-beta.2 → 1.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +304 -15
- package/dist/index.cjs +49 -38
- package/dist/index.d.cts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +53 -15
- package/dist/vite.cjs +317 -130
- package/dist/vite.d.cts +64 -6
- package/dist/vite.d.ts +64 -6
- package/dist/vite.js +325 -107
- package/package.json +15 -8
- package/src/index.ts +3 -0
- package/src/relations.ts +8 -37
- package/src/runtime-config.ts +63 -0
- package/src/vite.ts +575 -129
- package/dist/chunk-5FUI4JPB.js +0 -38
package/dist/vite.js
CHANGED
|
@@ -1,30 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createCapabilityCompositionPolicy,
|
|
3
|
-
defaultCapabilityRelationDescriptors
|
|
4
|
-
} from "./chunk-5FUI4JPB.js";
|
|
5
|
-
|
|
6
1
|
// src/vite.ts
|
|
7
2
|
import { existsSync, readFileSync } from "fs";
|
|
8
|
-
import { dirname, join, relative, resolve, sep } from "path";
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "path";
|
|
9
4
|
import process from "process";
|
|
10
|
-
import {
|
|
11
|
-
createCompositionSelection,
|
|
12
|
-
createDescriptorCatalog,
|
|
13
|
-
resolveDescriptorSelectionSeed
|
|
14
|
-
} from "@lorion-org/composition-graph";
|
|
5
|
+
import { loadEnv } from "vite";
|
|
15
6
|
import {
|
|
16
7
|
descriptorSchema,
|
|
17
|
-
discoverDescriptors
|
|
8
|
+
discoverDescriptors,
|
|
9
|
+
requirePackageName
|
|
18
10
|
} from "@lorion-org/descriptor-discovery";
|
|
11
|
+
import { resolveDescriptorSelection, selectDescriptors } from "@lorion-org/descriptor-selection";
|
|
19
12
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
createRuntimeConfigValidatorRegistry,
|
|
14
|
+
projectRuntimeConfigNamespaces,
|
|
15
|
+
resolveRuntimeConfigValidationMode,
|
|
16
|
+
toRuntimeConfigFragment,
|
|
17
|
+
toSnakeUpperCase
|
|
18
|
+
} from "@lorion-org/runtime-config";
|
|
19
|
+
import {
|
|
20
|
+
loadRuntimeConfigSourceTree,
|
|
21
|
+
readJsonFile,
|
|
22
|
+
resolveRuntimeConfigSource as resolveRuntimeConfigVarDirSource
|
|
23
|
+
} from "@lorion-org/runtime-config-node";
|
|
24
|
+
import { capabilitySpecifier } from "@lorion-org/surface-activation";
|
|
23
25
|
var virtualModuleId = "virtual:capabilities";
|
|
24
26
|
var resolvedVirtualModuleId = `\0${virtualModuleId}`;
|
|
27
|
+
var runtimeConfigModuleId = "virtual:capability-runtime-config";
|
|
28
|
+
var resolvedRuntimeConfigModuleId = `\0${runtimeConfigModuleId}`;
|
|
29
|
+
var serverRuntimeConfigModuleId = "virtual:capability-runtime-config/server";
|
|
30
|
+
var resolvedServerRuntimeConfigModuleId = `\0${serverRuntimeConfigModuleId}`;
|
|
31
|
+
var defaultRuntimeConfigFileName = "capability.runtime.json";
|
|
32
|
+
var defaultRuntimeConfigSchemaFileName = "capability.schema.json";
|
|
25
33
|
function capabilityLoader(options = {}) {
|
|
26
34
|
let config;
|
|
27
35
|
let capabilities = [];
|
|
36
|
+
let runtimeConfig = { private: {}, public: {} };
|
|
28
37
|
return {
|
|
29
38
|
name: "lorion-react-capability-loader",
|
|
30
39
|
enforce: "pre",
|
|
@@ -34,107 +43,110 @@ function capabilityLoader(options = {}) {
|
|
|
34
43
|
resolveWorkspaceRoot(config.root, options),
|
|
35
44
|
options
|
|
36
45
|
);
|
|
46
|
+
runtimeConfig = createReactRuntimeConfig(
|
|
47
|
+
capabilities,
|
|
48
|
+
resolveWorkspaceRoot(config.root, options),
|
|
49
|
+
options.runtimeConfig,
|
|
50
|
+
config
|
|
51
|
+
);
|
|
37
52
|
},
|
|
38
53
|
resolveId(id) {
|
|
39
54
|
if (id === virtualModuleId) return resolvedVirtualModuleId;
|
|
55
|
+
if (id === runtimeConfigModuleId) return resolvedRuntimeConfigModuleId;
|
|
56
|
+
if (id === serverRuntimeConfigModuleId) return resolvedServerRuntimeConfigModuleId;
|
|
40
57
|
return capabilities.find((capability) => capability.importSpecifier === id)?.entryFile;
|
|
41
58
|
},
|
|
42
|
-
load(id) {
|
|
59
|
+
load(id, loadOptions) {
|
|
60
|
+
if (id === resolvedRuntimeConfigModuleId) return renderRuntimeConfigModule(runtimeConfig);
|
|
61
|
+
if (id === resolvedServerRuntimeConfigModuleId) {
|
|
62
|
+
if (!loadOptions?.ssr) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"virtual:capability-runtime-config/server may only be imported from SSR/server code."
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return renderServerRuntimeConfigModule(runtimeConfig);
|
|
68
|
+
}
|
|
43
69
|
if (id !== resolvedVirtualModuleId) return null;
|
|
44
70
|
return renderCapabilityModule(capabilities, resolveSelectionSeed(options));
|
|
45
71
|
}
|
|
46
72
|
};
|
|
47
73
|
}
|
|
74
|
+
function createReactRuntimeConfig(capabilities, workspaceRoot, options = {}, viteConfig = {}) {
|
|
75
|
+
const normalizedOptions = normalizeRuntimeConfigOptions(options);
|
|
76
|
+
if (!normalizedOptions.enabled) return { private: {}, public: {} };
|
|
77
|
+
const runtimeEnv = resolveRuntimeConfigEnv(viteConfig, normalizedOptions.env ?? {});
|
|
78
|
+
const sourceFragments = normalizedOptions.source ? loadRuntimeConfigSourceTree(
|
|
79
|
+
resolveRuntimeConfigPatternSource(workspaceRoot, normalizedOptions, runtimeEnv)
|
|
80
|
+
) : /* @__PURE__ */ new Map();
|
|
81
|
+
const schemaEntries = readRuntimeConfigSchemas(capabilities, normalizedOptions.schemaFileName);
|
|
82
|
+
const envFragments = normalizedOptions.env === false ? /* @__PURE__ */ new Map() : createRuntimeConfigEnvFragments(
|
|
83
|
+
createRuntimeConfigEnvFragmentOptions(
|
|
84
|
+
capabilities,
|
|
85
|
+
schemaEntries.schemas,
|
|
86
|
+
runtimeEnv,
|
|
87
|
+
normalizedOptions.env
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
const fragments = mergeRuntimeConfigFragmentMaps(sourceFragments, envFragments);
|
|
91
|
+
validateReactRuntimeConfig(capabilities, fragments, schemaEntries, normalizedOptions.validation);
|
|
92
|
+
const projected = projectRuntimeConfigNamespaces(fragments, {
|
|
93
|
+
namespaceStrategy: "nested",
|
|
94
|
+
scopeIds: capabilities.map((capability) => capability.id)
|
|
95
|
+
});
|
|
96
|
+
const { public: publicConfig, ...privateConfig } = projected;
|
|
97
|
+
return {
|
|
98
|
+
public: publicConfig,
|
|
99
|
+
private: privateConfig
|
|
100
|
+
};
|
|
101
|
+
}
|
|
48
102
|
function lorionReact(options) {
|
|
49
103
|
return {
|
|
50
104
|
capabilityLoader: capabilityLoader(options),
|
|
51
105
|
routeConfig: createCapabilityRouteConfig(options)
|
|
52
106
|
};
|
|
53
107
|
}
|
|
108
|
+
function toResolveActivation(options) {
|
|
109
|
+
if (options.surface) {
|
|
110
|
+
if (options.activation) {
|
|
111
|
+
throw new Error("capabilityLoader: pass either `surface` or `activation`, not both.");
|
|
112
|
+
}
|
|
113
|
+
const { name, resolver } = options.surface;
|
|
114
|
+
return ({ capabilityDir, descriptor }) => resolver(name, { directory: capabilityDir, id: descriptor.id });
|
|
115
|
+
}
|
|
116
|
+
return options.activation;
|
|
117
|
+
}
|
|
54
118
|
function discoverCapabilities(workspaceRoot, options = {}) {
|
|
55
119
|
const capabilitiesRoot = resolve(workspaceRoot, options.capabilitiesDir ?? "capabilities");
|
|
56
120
|
if (!existsSync(capabilitiesRoot)) {
|
|
57
121
|
throw new Error(`Capabilities directory not found: ${capabilitiesRoot}`);
|
|
58
122
|
}
|
|
59
|
-
|
|
123
|
+
const resolveActivation = toResolveActivation(options);
|
|
124
|
+
return discoverCapabilityDescriptors(workspaceRoot, options).map((entry) => discoverCapability(entry, resolveActivation)).sort((left, right) => left.id.localeCompare(right.id));
|
|
60
125
|
}
|
|
61
126
|
function discoverSelectedCapabilities(workspaceRoot, options = {}) {
|
|
62
127
|
return selectCapabilities(discoverCapabilities(workspaceRoot, options), options);
|
|
63
128
|
}
|
|
64
129
|
function selectCapabilities(capabilities, options = {}) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
getCapabilityId: (capability) => capability.manifest.providesFor,
|
|
73
|
-
getProviderId: (capability) => capability.id,
|
|
74
|
-
selectedProviderIds: selected
|
|
75
|
-
});
|
|
76
|
-
const selectionCapabilities = createProviderSelectionAwareCapabilities(
|
|
77
|
-
enabledCapabilities,
|
|
78
|
-
selectedProviders
|
|
79
|
-
);
|
|
80
|
-
const catalog = createDescriptorCatalog({
|
|
81
|
-
descriptors: selectionCapabilities.map((capability) => capability.manifest),
|
|
82
|
-
relationDescriptors: [
|
|
83
|
-
...defaultCapabilityRelationDescriptors,
|
|
84
|
-
...options.relationDescriptors ?? []
|
|
85
|
-
]
|
|
86
|
-
});
|
|
87
|
-
const selection = createCompositionSelection({
|
|
88
|
-
catalog,
|
|
89
|
-
selected: [...selected],
|
|
90
|
-
baseDescriptors: [...options.baseDescriptors ?? []],
|
|
91
|
-
policy: createCapabilityCompositionPolicy(options.policy)
|
|
92
|
-
});
|
|
93
|
-
const selectedIds = new Set(selection.getResolved());
|
|
94
|
-
return selectionCapabilities.filter((capability) => selectedIds.has(capability.id));
|
|
95
|
-
}
|
|
96
|
-
function createProviderSelectionAwareCapabilities(capabilities, selectedProviders) {
|
|
97
|
-
if (!Object.keys(selectedProviders).length) return [...capabilities];
|
|
98
|
-
return capabilities.map((capability) => {
|
|
99
|
-
const manifest = { ...capability.manifest };
|
|
100
|
-
const preferences = resolveSelectedProviderRelationPreferences({
|
|
101
|
-
providerId: capability.id,
|
|
102
|
-
defaultFor: manifest.defaultFor,
|
|
103
|
-
providerPreferences: manifest.providerPreferences,
|
|
104
|
-
selectedProviders
|
|
105
|
-
});
|
|
106
|
-
delete manifest.defaultFor;
|
|
107
|
-
delete manifest.providerPreferences;
|
|
108
|
-
return {
|
|
109
|
-
...capability,
|
|
110
|
-
manifest: {
|
|
111
|
-
...manifest,
|
|
112
|
-
...preferences
|
|
113
|
-
}
|
|
114
|
-
};
|
|
130
|
+
return selectDescriptors({
|
|
131
|
+
items: capabilities,
|
|
132
|
+
getDescriptor: (capability) => capability.manifest,
|
|
133
|
+
withDescriptor: (capability, manifest) => ({ ...capability, manifest }),
|
|
134
|
+
seed: options,
|
|
135
|
+
...options.relationDescriptors ? { relationDescriptors: options.relationDescriptors } : {},
|
|
136
|
+
...options.policy ? { policy: options.policy } : {}
|
|
115
137
|
});
|
|
116
138
|
}
|
|
117
139
|
function resolveSelectionSeed(options) {
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
function resolveCapabilitySelectionSeed(options) {
|
|
121
|
-
if (options.selected?.length) return [...options.selected];
|
|
122
|
-
if (options.selectionSeed === false) return [...options.defaultSelection ?? []];
|
|
123
|
-
const seedOptions = options.selectionSeed ?? {};
|
|
124
|
-
const selected = resolveDescriptorSelectionSeed({
|
|
125
|
-
argv: seedOptions.argv ?? process.argv,
|
|
126
|
-
env: seedOptions.env ?? process.env,
|
|
127
|
-
key: seedOptions.key ?? "capability",
|
|
128
|
-
...seedOptions.cliKeys ? { cliKeys: seedOptions.cliKeys } : {},
|
|
129
|
-
...seedOptions.envKeys ? { envKeys: seedOptions.envKeys } : {}
|
|
130
|
-
});
|
|
131
|
-
return selected.length ? selected : [...options.defaultSelection ?? []];
|
|
140
|
+
return resolveDescriptorSelection(options);
|
|
132
141
|
}
|
|
133
142
|
function renderCapabilityModule(capabilities, selected = []) {
|
|
134
|
-
const
|
|
135
|
-
(capability) =>
|
|
143
|
+
const activated = capabilities.filter(
|
|
144
|
+
(capability) => capability.exportName && capability.importSpecifier
|
|
145
|
+
);
|
|
146
|
+
const imports = activated.map(
|
|
147
|
+
(capability) => `import { ${capability.exportName} as ${capability.variableName} } from '${capability.importSpecifier}'`
|
|
136
148
|
).join("\n");
|
|
137
|
-
const variables =
|
|
149
|
+
const variables = activated.map((capability) => ` ${capability.variableName},`).join("\n");
|
|
138
150
|
const capabilityIds = capabilities.map((capability) => capability.id);
|
|
139
151
|
return `${imports}
|
|
140
152
|
|
|
@@ -147,6 +159,16 @@ ${variables}
|
|
|
147
159
|
]
|
|
148
160
|
`;
|
|
149
161
|
}
|
|
162
|
+
function renderRuntimeConfigModule(runtimeConfig) {
|
|
163
|
+
return `export const capabilityRuntimeConfig = ${JSON.stringify({ public: runtimeConfig.public })}
|
|
164
|
+
|
|
165
|
+
export const publicCapabilityRuntimeConfig = capabilityRuntimeConfig.public
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
function renderServerRuntimeConfigModule(runtimeConfig) {
|
|
169
|
+
return `export const capabilityServerRuntimeConfig = ${JSON.stringify(runtimeConfig)}
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
150
172
|
function createCapabilityRouteConfig(options) {
|
|
151
173
|
if (!options?.workspaceRoot) {
|
|
152
174
|
throw new Error("createCapabilityRouteConfig requires a workspaceRoot option.");
|
|
@@ -185,7 +207,7 @@ function discoverCapabilityDescriptors(workspaceRoot, options) {
|
|
|
185
207
|
}
|
|
186
208
|
});
|
|
187
209
|
}
|
|
188
|
-
function discoverCapability(entry) {
|
|
210
|
+
function discoverCapability(entry, resolveActivation) {
|
|
189
211
|
const capabilityDir = entry.cwd;
|
|
190
212
|
const packagePath = resolve(capabilityDir, "package.json");
|
|
191
213
|
if (!existsSync(packagePath)) {
|
|
@@ -194,43 +216,236 @@ function discoverCapability(entry) {
|
|
|
194
216
|
);
|
|
195
217
|
}
|
|
196
218
|
const packageJson = readJson(packagePath);
|
|
197
|
-
const packageName = packageJson
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
219
|
+
const packageName = requirePackageName(packageJson, packagePath);
|
|
220
|
+
const activationEntry = resolveActivationEntry(
|
|
221
|
+
capabilityDir,
|
|
222
|
+
packageJson,
|
|
223
|
+
packageName,
|
|
224
|
+
entry.descriptor,
|
|
225
|
+
resolveActivation
|
|
226
|
+
);
|
|
202
227
|
const routesDirectory = resolveRouteDirectory(capabilityDir);
|
|
203
228
|
return {
|
|
229
|
+
capabilityDir,
|
|
204
230
|
id: entry.descriptor.id,
|
|
205
231
|
disabled: entry.descriptor.disabled === true,
|
|
206
|
-
entryFile: activationEntry.entryFile,
|
|
207
|
-
importSpecifier: activationEntry.importSpecifier,
|
|
208
232
|
manifest: entry.descriptor,
|
|
209
233
|
packageName,
|
|
234
|
+
...activationEntry ? {
|
|
235
|
+
exportName: activationEntry.exportName,
|
|
236
|
+
importSpecifier: activationEntry.importSpecifier,
|
|
237
|
+
...activationEntry.entryFile ? { entryFile: activationEntry.entryFile } : {}
|
|
238
|
+
} : {},
|
|
210
239
|
...routesDirectory ? { routesDirectory } : {},
|
|
211
240
|
variableName: toVariableName(entry.descriptor.id)
|
|
212
241
|
};
|
|
213
242
|
}
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
243
|
+
function normalizeRuntimeConfigOptions(options) {
|
|
244
|
+
if (options === false) {
|
|
245
|
+
return {
|
|
246
|
+
configFileName: defaultRuntimeConfigFileName,
|
|
247
|
+
enabled: false,
|
|
248
|
+
env: false,
|
|
249
|
+
schemaFileName: defaultRuntimeConfigSchemaFileName,
|
|
250
|
+
validation: false
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const configFileName = options.configFileName ?? defaultRuntimeConfigFileName;
|
|
254
|
+
return {
|
|
255
|
+
configFileName,
|
|
256
|
+
enabled: options.enabled !== false,
|
|
257
|
+
env: options.env ?? {},
|
|
258
|
+
schemaFileName: options.schemaFileName ?? defaultRuntimeConfigSchemaFileName,
|
|
259
|
+
...options.source === false ? {} : {
|
|
260
|
+
source: options.source ?? { paths: [] }
|
|
261
|
+
},
|
|
262
|
+
validation: options.validation === false ? false : options.validation ?? {},
|
|
263
|
+
...options.varDir ? { varDir: options.varDir } : {}
|
|
264
|
+
};
|
|
217
265
|
}
|
|
218
|
-
function
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
);
|
|
266
|
+
function resolveRuntimeConfigPatternSource(workspaceRoot, options, env) {
|
|
267
|
+
if (!options.source?.paths.length) {
|
|
268
|
+
const varDir = resolveRuntimeConfigVarDir(workspaceRoot, options.varDir, env);
|
|
269
|
+
return {
|
|
270
|
+
paths: [join(varDir, "runtime-config", "*", options.configFileName)]
|
|
271
|
+
};
|
|
225
272
|
}
|
|
226
|
-
|
|
227
|
-
|
|
273
|
+
return {
|
|
274
|
+
paths: options.source.paths.map(
|
|
275
|
+
(entry) => isAbsolute(entry) ? entry : resolve(workspaceRoot, entry)
|
|
276
|
+
)
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function resolveRuntimeConfigVarDir(workspaceRoot, options, env) {
|
|
280
|
+
const rawVarDir = typeof options === "string" ? options : resolveRuntimeConfigVarDirSource({
|
|
281
|
+
defaultVarDir: resolve(workspaceRoot, ".data"),
|
|
282
|
+
env: options?.env ?? env,
|
|
283
|
+
envKey: options?.envKey ?? "RUNTIME_CONFIG_VAR_DIR",
|
|
284
|
+
...options?.value ? { varDir: options.value } : {},
|
|
285
|
+
...options?.defaultValue ? { defaultVarDir: options.defaultValue } : {}
|
|
286
|
+
}).varDir;
|
|
287
|
+
return isAbsolute(rawVarDir) ? rawVarDir : resolve(workspaceRoot, rawVarDir);
|
|
288
|
+
}
|
|
289
|
+
function resolveRuntimeConfigEnv(viteConfig, options) {
|
|
290
|
+
if (options === false) return {};
|
|
291
|
+
if (options.env) return options.env;
|
|
292
|
+
const mode = viteConfig.mode ?? process.env.NODE_ENV ?? "development";
|
|
293
|
+
const envDir = typeof viteConfig.envDir === "string" ? viteConfig.envDir : viteConfig.root ?? process.cwd();
|
|
294
|
+
return {
|
|
295
|
+
...loadEnv(mode, envDir, ""),
|
|
296
|
+
...process.env,
|
|
297
|
+
...viteConfig.env ?? {}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function readRuntimeConfigSchemas(capabilities, schemaFileName) {
|
|
301
|
+
const paths = /* @__PURE__ */ new Map();
|
|
302
|
+
const schemas = {};
|
|
303
|
+
for (const capability of capabilities) {
|
|
304
|
+
const schemaPath = resolve(capability.capabilityDir, schemaFileName);
|
|
305
|
+
const schema = readJsonFile(schemaPath, {
|
|
306
|
+
onParseError: (error, filePath) => {
|
|
307
|
+
throw new Error(`RuntimeConfig schema JSON parse error in "${filePath}": ${String(error)}`);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
if (!schema) continue;
|
|
311
|
+
paths.set(capability.id, schemaPath);
|
|
312
|
+
schemas[capability.id] = schema;
|
|
228
313
|
}
|
|
314
|
+
return { paths, schemas };
|
|
315
|
+
}
|
|
316
|
+
function isJsonSchemaObject(value) {
|
|
317
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
318
|
+
}
|
|
319
|
+
function getRuntimeConfigSchemaSectionKeys(schema, visibility) {
|
|
320
|
+
if (!isJsonSchemaObject(schema)) return [];
|
|
321
|
+
const section = schema.properties?.[visibility];
|
|
322
|
+
if (!isJsonSchemaObject(section) || !isJsonSchemaObject(section.properties)) return [];
|
|
323
|
+
return Object.keys(section.properties).sort();
|
|
324
|
+
}
|
|
325
|
+
function createRuntimeConfigEnvKey(input) {
|
|
326
|
+
return toSnakeUpperCase([input.prefix, input.scopeId, input.key].filter(Boolean).join("_"));
|
|
327
|
+
}
|
|
328
|
+
function createRuntimeConfigEnvFragments(input) {
|
|
329
|
+
const fragments = /* @__PURE__ */ new Map();
|
|
330
|
+
for (const capability of input.capabilities) {
|
|
331
|
+
const schema = input.schemas[capability.id];
|
|
332
|
+
const publicConfig = {};
|
|
333
|
+
const privateConfig = {};
|
|
334
|
+
for (const key of getRuntimeConfigSchemaSectionKeys(schema, "public")) {
|
|
335
|
+
const envKey = createRuntimeConfigEnvKey({
|
|
336
|
+
key,
|
|
337
|
+
prefix: input.publicPrefix ?? "VITE",
|
|
338
|
+
scopeId: capability.id
|
|
339
|
+
});
|
|
340
|
+
const value = input.env[envKey];
|
|
341
|
+
if (value !== void 0) publicConfig[key] = value;
|
|
342
|
+
}
|
|
343
|
+
for (const key of getRuntimeConfigSchemaSectionKeys(schema, "private")) {
|
|
344
|
+
const envKey = createRuntimeConfigEnvKey({
|
|
345
|
+
key,
|
|
346
|
+
scopeId: capability.id,
|
|
347
|
+
...input.privatePrefix !== void 0 ? { prefix: input.privatePrefix } : {}
|
|
348
|
+
});
|
|
349
|
+
const value = input.env[envKey];
|
|
350
|
+
if (value !== void 0) privateConfig[key] = value;
|
|
351
|
+
}
|
|
352
|
+
if (Object.keys(publicConfig).length || Object.keys(privateConfig).length) {
|
|
353
|
+
fragments.set(capability.id, {
|
|
354
|
+
...Object.keys(publicConfig).length ? { public: publicConfig } : {},
|
|
355
|
+
...Object.keys(privateConfig).length ? { private: privateConfig } : {}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return fragments;
|
|
360
|
+
}
|
|
361
|
+
function createRuntimeConfigEnvFragmentOptions(capabilities, schemas, env, options) {
|
|
229
362
|
return {
|
|
230
|
-
|
|
231
|
-
|
|
363
|
+
capabilities,
|
|
364
|
+
env,
|
|
365
|
+
...options.privatePrefix !== void 0 ? { privatePrefix: options.privatePrefix } : {},
|
|
366
|
+
...options.publicPrefix !== void 0 ? { publicPrefix: options.publicPrefix } : {},
|
|
367
|
+
schemas
|
|
232
368
|
};
|
|
233
369
|
}
|
|
370
|
+
function mergeRuntimeConfigSections(left, right) {
|
|
371
|
+
const section = {
|
|
372
|
+
...left ?? {},
|
|
373
|
+
...right ?? {}
|
|
374
|
+
};
|
|
375
|
+
return Object.keys(section).length ? section : void 0;
|
|
376
|
+
}
|
|
377
|
+
function mergeRuntimeConfigFragment(left, right) {
|
|
378
|
+
const publicConfig = mergeRuntimeConfigSections(left?.public, right?.public);
|
|
379
|
+
const privateConfig = mergeRuntimeConfigSections(left?.private, right?.private);
|
|
380
|
+
return toRuntimeConfigFragment({
|
|
381
|
+
...publicConfig ? { public: publicConfig } : {},
|
|
382
|
+
...privateConfig ? { private: privateConfig } : {}
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
function mergeRuntimeConfigFragmentMaps(left, right) {
|
|
386
|
+
const fragments = new Map(left);
|
|
387
|
+
for (const [scopeId, config] of right.entries()) {
|
|
388
|
+
fragments.set(scopeId, mergeRuntimeConfigFragment(fragments.get(scopeId), config));
|
|
389
|
+
}
|
|
390
|
+
return fragments;
|
|
391
|
+
}
|
|
392
|
+
function getCapabilityRuntimeConfigPolicy(capability, validation) {
|
|
393
|
+
return capability.manifest.runtimeConfig ?? validation.policy ?? "optional";
|
|
394
|
+
}
|
|
395
|
+
function shouldValidateRuntimeConfigFragment(input) {
|
|
396
|
+
if (!input.schema) return false;
|
|
397
|
+
const mode = resolveRuntimeConfigValidationMode(
|
|
398
|
+
getCapabilityRuntimeConfigPolicy(input.capability, input.validation)
|
|
399
|
+
);
|
|
400
|
+
if (mode === "none" || mode === "onUse") return false;
|
|
401
|
+
if (mode === "startup") return true;
|
|
402
|
+
return Boolean(input.fragment);
|
|
403
|
+
}
|
|
404
|
+
function validateReactRuntimeConfig(capabilities, fragments, schemas, validation) {
|
|
405
|
+
if (validation === false) return;
|
|
406
|
+
const registry = createRuntimeConfigValidatorRegistry(schemas.schemas, {
|
|
407
|
+
...validation.formatError ? {
|
|
408
|
+
formatError: (target, validationError) => validation.formatError(
|
|
409
|
+
{
|
|
410
|
+
configPath: `${target.scopeId} runtime config`,
|
|
411
|
+
schemaPath: schemas.paths.get(target.scopeId) ?? "",
|
|
412
|
+
scopeId: target.scopeId
|
|
413
|
+
},
|
|
414
|
+
validationError
|
|
415
|
+
)
|
|
416
|
+
} : {}
|
|
417
|
+
});
|
|
418
|
+
for (const capability of capabilities) {
|
|
419
|
+
const fragment = fragments.get(capability.id);
|
|
420
|
+
const schema = schemas.schemas[capability.id];
|
|
421
|
+
if (!shouldValidateRuntimeConfigFragment({ capability, fragment, schema, validation })) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
registry.assert(capability.id, fragment ?? {});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function resolveRouteDirectory(capabilityDir) {
|
|
428
|
+
const routesDirectory = resolve(capabilityDir, "src", "routes");
|
|
429
|
+
return existsSync(routesDirectory) ? routesDirectory : void 0;
|
|
430
|
+
}
|
|
431
|
+
function resolveActivationEntry(capabilityDir, packageJson, packageName, descriptor, resolveActivation) {
|
|
432
|
+
if (!resolveActivation) {
|
|
433
|
+
const packageExports = packageJson.exports;
|
|
434
|
+
if (!isRecord(packageExports) || typeof packageExports["./capability"] !== "string") {
|
|
435
|
+
throw new Error(`Capability package is missing a "./capability" export: ${capabilityDir}`);
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
entryFile: resolve(capabilityDir, packageExports["./capability"]),
|
|
439
|
+
exportName: "capability",
|
|
440
|
+
importSpecifier: capabilitySpecifier(packageName, "./capability")
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
const activation = resolveActivation({ capabilityDir, descriptor, packageJson, packageName });
|
|
444
|
+
if (!activation) return null;
|
|
445
|
+
const exportName = activation.exportName ?? "capability";
|
|
446
|
+
const exportSubpath = activation.exportSubpath ?? "./capability";
|
|
447
|
+
return { exportName, importSpecifier: capabilitySpecifier(packageName, exportSubpath) };
|
|
448
|
+
}
|
|
234
449
|
function hasRouteDirectory(capability) {
|
|
235
450
|
return typeof capability.routesDirectory === "string";
|
|
236
451
|
}
|
|
@@ -266,8 +481,11 @@ function toPosixPath(path) {
|
|
|
266
481
|
export {
|
|
267
482
|
capabilityLoader,
|
|
268
483
|
createCapabilityRouteConfig,
|
|
484
|
+
createReactRuntimeConfig,
|
|
269
485
|
discoverCapabilities,
|
|
270
486
|
discoverSelectedCapabilities,
|
|
271
487
|
lorionReact,
|
|
272
|
-
renderCapabilityModule
|
|
488
|
+
renderCapabilityModule,
|
|
489
|
+
renderRuntimeConfigModule,
|
|
490
|
+
renderServerRuntimeConfigModule
|
|
273
491
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lorion-org/react",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.4",
|
|
4
4
|
"description": "React capability runtime and Vite helpers for LORION descriptor-based applications.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -58,11 +58,21 @@
|
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@lorion-org/composition-graph": "^1.0.0-beta.2",
|
|
61
|
-
"@lorion-org/descriptor-discovery": "^1.0.0-beta.
|
|
62
|
-
"@lorion-org/
|
|
61
|
+
"@lorion-org/descriptor-discovery": "^1.0.0-beta.3",
|
|
62
|
+
"@lorion-org/descriptor-selection": "^1.0.0-beta.3",
|
|
63
|
+
"@lorion-org/runtime-config": "^1.0.0-beta.1",
|
|
64
|
+
"@lorion-org/provider-selection": "^1.0.0-beta.2",
|
|
65
|
+
"@lorion-org/runtime-config-node": "^1.0.0-beta.1",
|
|
66
|
+
"@lorion-org/surface-activation": "^1.0.0-beta.3"
|
|
63
67
|
},
|
|
64
68
|
"peerDependencies": {
|
|
65
|
-
"react": "^19.0.0"
|
|
69
|
+
"react": "^19.0.0",
|
|
70
|
+
"vite": "^7.0.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"vite": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
66
76
|
},
|
|
67
77
|
"devDependencies": {
|
|
68
78
|
"@tanstack/react-router": "^1.168.25",
|
|
@@ -90,10 +100,7 @@
|
|
|
90
100
|
"clean": "rimraf coverage dist tsconfig.tsbuildinfo",
|
|
91
101
|
"lint": "eslint src --ext .ts",
|
|
92
102
|
"package:check": "pnpm build && pnpm pack --dry-run && publint",
|
|
93
|
-
"build:playground": "node ../../tools/run-source-condition.mjs vite build --config playground/vite.config.ts --",
|
|
94
|
-
"dev:playground": "node ../../tools/run-source-condition.mjs vite dev --config playground/vite.config.ts --host 0.0.0.0 --",
|
|
95
103
|
"test": "vitest run --root ../.. --config vitest.config.mts packages/react/src/index.spec.ts packages/react/src/vite.spec.ts",
|
|
96
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
97
|
-
"typecheck:playground": "tsc -p playground/tsconfig.json --noEmit"
|
|
104
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
98
105
|
}
|
|
99
106
|
}
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type ProviderPreferenceMap,
|
|
13
13
|
type ProviderSelectionResolution,
|
|
14
14
|
} from '@lorion-org/provider-selection';
|
|
15
|
+
import type { RuntimeConfigValidationPolicy } from '@lorion-org/runtime-config';
|
|
15
16
|
import { defaultCapabilityRelationDescriptors } from './relations';
|
|
16
17
|
|
|
17
18
|
export {
|
|
@@ -19,11 +20,13 @@ export {
|
|
|
19
20
|
defaultCapabilityRelationDescriptors,
|
|
20
21
|
defaultCapabilityResolutionRelations,
|
|
21
22
|
} from './relations';
|
|
23
|
+
export * from './runtime-config';
|
|
22
24
|
|
|
23
25
|
export type CapabilityManifest = Descriptor & {
|
|
24
26
|
defaultFor?: string | string[];
|
|
25
27
|
description?: string;
|
|
26
28
|
providerPreferences?: ProviderPreferenceMap;
|
|
29
|
+
runtimeConfig?: RuntimeConfigValidationPolicy;
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
export type ExtensionPoint<T> = {
|
package/src/relations.ts
CHANGED
|
@@ -1,37 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export const defaultCapabilityRelationDescriptors: RelationDescriptor[] = [
|
|
10
|
-
{
|
|
11
|
-
direction: 'incoming',
|
|
12
|
-
field: 'defaultFor',
|
|
13
|
-
id: 'defaultProviders',
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
field: 'providerPreferences',
|
|
17
|
-
id: 'providerPreferences',
|
|
18
|
-
targetMode: 'values',
|
|
19
|
-
},
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
export function createCapabilityCompositionPolicy(
|
|
23
|
-
policy?: Partial<CompositionPolicy>,
|
|
24
|
-
): Partial<CompositionPolicy> {
|
|
25
|
-
return {
|
|
26
|
-
...policy,
|
|
27
|
-
inspectionRelationIds: policy?.inspectionRelationIds ?? [
|
|
28
|
-
...defaultCapabilityResolutionRelations,
|
|
29
|
-
],
|
|
30
|
-
provenanceRelationIds: policy?.provenanceRelationIds ?? [
|
|
31
|
-
...defaultCapabilityResolutionRelations,
|
|
32
|
-
],
|
|
33
|
-
resolutionRelationIds: policy?.resolutionRelationIds ?? [
|
|
34
|
-
...defaultCapabilityResolutionRelations,
|
|
35
|
-
],
|
|
36
|
-
};
|
|
37
|
-
}
|
|
1
|
+
// The capability relations and composition policy are owned by
|
|
2
|
+
// @lorion-org/descriptor-selection. They are re-exported here under the React
|
|
3
|
+
// adapter's public names for backward compatibility; no logic is duplicated.
|
|
4
|
+
export {
|
|
5
|
+
providerRelationDescriptors as defaultCapabilityRelationDescriptors,
|
|
6
|
+
descriptorSelectionPolicy as createCapabilityCompositionPolicy,
|
|
7
|
+
defaultResolutionRelations as defaultCapabilityResolutionRelations,
|
|
8
|
+
} from '@lorion-org/descriptor-selection';
|