@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/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
- collectSelectedProviderPreferences,
21
- resolveSelectedProviderRelationPreferences
22
- } from "@lorion-org/provider-selection";
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
- return discoverCapabilityDescriptors(workspaceRoot, options).map(discoverCapability).sort((left, right) => left.id.localeCompare(right.id));
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
- const enabledCapabilities = capabilities.filter((capability) => capability.disabled !== true);
66
- const selected = resolveCapabilitySelectionSeed(options);
67
- if (!selected.length && !options.baseDescriptors?.length) {
68
- return [...enabledCapabilities];
69
- }
70
- const selectedProviders = collectSelectedProviderPreferences({
71
- items: enabledCapabilities,
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 resolveCapabilitySelectionSeed(options);
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 imports = capabilities.map(
135
- (capability) => `import { capability as ${capability.variableName} } from '${capability.importSpecifier}'`
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 = capabilities.map((capability) => ` ${capability.variableName},`).join("\n");
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.name;
198
- if (typeof packageName !== "string") {
199
- throw new Error(`Capability package is missing "name": ${packagePath}`);
200
- }
201
- const activationEntry = resolveActivationEntry(capabilityDir, packageJson);
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 resolveRouteDirectory(capabilityDir) {
215
- const routesDirectory = resolve(capabilityDir, "src", "routes");
216
- return existsSync(routesDirectory) ? routesDirectory : void 0;
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 resolveActivationEntry(capabilityDir, packageJson) {
219
- const packageName = packageJson.name;
220
- const packageExports = packageJson.exports;
221
- if (typeof packageName !== "string") {
222
- throw new Error(
223
- `Capability package is missing "name": ${resolve(capabilityDir, "package.json")}`
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
- if (!isRecord(packageExports) || typeof packageExports["./capability"] !== "string") {
227
- throw new Error(`Capability package is missing a "./capability" export: ${capabilityDir}`);
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
- entryFile: resolve(capabilityDir, packageExports["./capability"]),
231
- importSpecifier: `${packageName}/capability`
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.2",
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.2",
62
- "@lorion-org/provider-selection": "^1.0.0-beta.2"
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
- import type { CompositionPolicy, RelationDescriptor } from '@lorion-org/composition-graph';
2
-
3
- export const defaultCapabilityResolutionRelations = [
4
- 'dependencies',
5
- 'defaultProviders',
6
- 'providerPreferences',
7
- ] as const;
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';