@lorion-org/react 1.0.0-beta.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # @lorion-org/react
2
+
3
+ React capability runtime and Vite helpers for LORION descriptor-based applications.
4
+
5
+ Use this package when a React application is assembled from local capability packages that expose a `capability.json` descriptor and a `./capability` activation export.
6
+
7
+ ## Install
8
+
9
+ ```shell
10
+ pnpm add @lorion-org/react react
11
+ ```
12
+
13
+ Add Vite, TanStack Router, or another router in the host application as needed.
14
+ The runtime helpers do not own routing; the Vite entry point only prepares
15
+ capability discovery and TanStack-compatible virtual route config.
16
+
17
+ ## What It Is
18
+
19
+ - a small React binding for immutable capability contributions
20
+ - a Vite virtual module helper for active capability activation exports
21
+ - a TanStack virtual route config helper for capability-owned route folders
22
+ - a React adapter over LORION descriptor discovery and composition graph packages
23
+
24
+ ## What It Is Not
25
+
26
+ - not a UI component library
27
+ - not a router
28
+ - not a package manager
29
+ - not an application naming convention
30
+
31
+ ## Basic Runtime
32
+
33
+ ```ts
34
+ import { CapabilityRuntimeProvider, createCapabilityRuntime } from '@lorion-org/react';
35
+ import { capabilityModules } from 'virtual:capabilities';
36
+
37
+ const capabilityRuntime = createCapabilityRuntime(capabilityModules);
38
+ ```
39
+
40
+ Render the provider once around the application tree:
41
+
42
+ ```tsx
43
+ import { CapabilityRuntimeProvider } from '@lorion-org/react';
44
+
45
+ root.render(
46
+ <CapabilityRuntimeProvider runtime={capabilityRuntime}>
47
+ <App />
48
+ </CapabilityRuntimeProvider>,
49
+ );
50
+ ```
51
+
52
+ Capability contracts can define extension points and read contributions:
53
+
54
+ ```ts
55
+ import { createContributionContract } from '@lorion-org/react';
56
+
57
+ type Tool = {
58
+ id: string;
59
+ label: string;
60
+ };
61
+
62
+ const toolContract = createContributionContract<Tool>('tools');
63
+
64
+ export function defineTools(tools: readonly Tool[]) {
65
+ return toolContract.define(tools);
66
+ }
67
+
68
+ export function useTools(): Tool[] {
69
+ return toolContract.use();
70
+ }
71
+ ```
72
+
73
+ ## Capability Packages
74
+
75
+ Each local capability package needs a descriptor and an activation export:
76
+
77
+ ```text
78
+ capabilities/
79
+ my-capability/
80
+ capability.json
81
+ package.json
82
+ src/
83
+ capability.ts
84
+ routes/
85
+ index.tsx
86
+ ```
87
+
88
+ ```json
89
+ {
90
+ "id": "my-capability",
91
+ "version": "1.0.0",
92
+ "dependencies": {
93
+ "other-capability": "^1.0.0"
94
+ }
95
+ }
96
+ ```
97
+
98
+ ```json
99
+ {
100
+ "name": "@my-app/my-capability",
101
+ "type": "module",
102
+ "exports": {
103
+ "./capability": "./src/capability.ts"
104
+ }
105
+ }
106
+ ```
107
+
108
+ The `src/routes` folder is optional. If present, `lorionReact()` can expose it
109
+ to TanStack Router as a capability-owned route subtree.
110
+
111
+ ## Vite
112
+
113
+ ```ts
114
+ import { lorionReact } from '@lorion-org/react/vite';
115
+ ```
116
+
117
+ The Vite helper discovers `capabilities/*/capability.json`, validates the descriptor shape with LORION, resolves selected descriptors through the LORION composition graph, resolves each package `./capability` export, and exposes `virtual:capabilities`.
118
+
119
+ ```ts
120
+ const capabilityComposition = {
121
+ selected: ['default'],
122
+ };
123
+ const lorion = lorionReact({
124
+ workspaceRoot,
125
+ routesDirectory,
126
+ ...capabilityComposition,
127
+ });
128
+
129
+ export default defineConfig({
130
+ plugins: [
131
+ lorion.capabilityLoader,
132
+ tanstackStart({
133
+ router: {
134
+ virtualRouteConfig: lorion.routeConfig,
135
+ },
136
+ }),
137
+ ],
138
+ });
139
+ ```
140
+
141
+ Route config generation stays TanStack-focused and only includes enabled, selected capability route directories. If no `selected` or `baseDescriptors` are provided, every enabled local capability remains active. Use `indexRouteFile: false` when `/` is owned by a capability route.
142
+
143
+ ## Provider Selection
144
+
145
+ Capabilities that implement another capability can declare `providesFor`:
146
+
147
+ ```json
148
+ {
149
+ "id": "payment-provider-stripe",
150
+ "version": "1.0.0",
151
+ "providesFor": "payment-checkout"
152
+ }
153
+ ```
154
+
155
+ Any active descriptor can declare preferences with `providerPreferences`:
156
+
157
+ ```json
158
+ {
159
+ "id": "web",
160
+ "version": "1.0.0",
161
+ "providerPreferences": {
162
+ "payment-checkout": "payment-provider-stripe"
163
+ }
164
+ }
165
+ ```
166
+
167
+ Read the resolved provider selection from the runtime:
168
+
169
+ ```ts
170
+ import { getCapabilityProviderSelection } from '@lorion-org/react';
171
+
172
+ const selection = getCapabilityProviderSelection(capabilityRuntime);
173
+ ```
174
+
175
+ Explicit `configuredProviders` passed to `getCapabilityProviderSelection()` override descriptor preferences. `fallbackProviders` are only used when no configured provider exists.
176
+
177
+ ## API
178
+
179
+ The package exposes two public entry points:
180
+
181
+ - `@lorion-org/react` for runtime, contribution contracts, provider selection, and React context helpers
182
+ - `@lorion-org/react/vite` for capability discovery, the Vite virtual module, and TanStack-compatible route config
183
+
184
+ ## Playground
185
+
186
+ The package includes a React playground that mirrors the Nuxt package playground with a demo shop, checkout providers, and a tech monitor.
187
+
188
+ ```sh
189
+ pnpm --filter @lorion-org/react dev:playground
190
+ ```
191
+
192
+ The playground runs on `http://localhost:3200` and uses local demo capabilities under `playground/capabilities`.
193
+
194
+ ## Local Commands
195
+
196
+ ```shell
197
+ cd packages/react
198
+ pnpm build
199
+ pnpm test
200
+ pnpm typecheck
201
+ pnpm package:check
202
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ CapabilityRuntimeProvider: () => CapabilityRuntimeProvider,
24
+ createCapabilityRuntime: () => createCapabilityRuntime,
25
+ createContributionContract: () => createContributionContract,
26
+ defineCapability: () => defineCapability,
27
+ defineContribution: () => defineContribution,
28
+ defineExtensionPoint: () => defineExtensionPoint,
29
+ getCapabilityProviderSelection: () => getCapabilityProviderSelection,
30
+ useCapabilityRuntime: () => useCapabilityRuntime
31
+ });
32
+ module.exports = __toCommonJS(index_exports);
33
+ var import_react = require("react");
34
+ var import_composition_graph = require("@lorion-org/composition-graph");
35
+ var import_provider_selection = require("@lorion-org/provider-selection");
36
+ function defineExtensionPoint(id) {
37
+ return { id };
38
+ }
39
+ function defineContribution(extensionPoint, values) {
40
+ return { extensionPoint, values };
41
+ }
42
+ function createContributionContract(id) {
43
+ const extensionPoint = defineExtensionPoint(id);
44
+ return {
45
+ extensionPoint,
46
+ define: (values) => defineContribution(extensionPoint, values),
47
+ get: (runtime) => runtime.getContributions(extensionPoint),
48
+ use: () => useCapabilityRuntime().getContributions(extensionPoint)
49
+ };
50
+ }
51
+ function getCapabilityProviderSelection(runtime, options = {}) {
52
+ const descriptors = runtime.catalog.getAllDescriptors();
53
+ const descriptorPreferences = (0, import_provider_selection.collectProviderPreferences)({
54
+ items: descriptors,
55
+ getProviderPreferences: (descriptor) => descriptor.providerPreferences
56
+ });
57
+ const configuredProviders = {
58
+ ...descriptorPreferences,
59
+ ...options.configuredProviders ?? {}
60
+ };
61
+ const resolution = (0, import_provider_selection.resolveItemProviderSelection)({
62
+ items: descriptors,
63
+ getCapabilityId: (descriptor) => descriptor.providesFor,
64
+ getProviderId: (descriptor) => descriptor.id,
65
+ configuredProviders,
66
+ ...options.fallbackProviders ? { fallbackProviders: options.fallbackProviders } : {}
67
+ });
68
+ return {
69
+ excludedProviderIds: resolution.excludedProviderIds,
70
+ mismatches: resolution.mismatches,
71
+ selections: resolution.selections
72
+ };
73
+ }
74
+ function defineCapability(capability) {
75
+ if (capability.id !== capability.manifest.id) {
76
+ throw new Error(
77
+ `Capability "${capability.id}" must match capability.json id "${capability.manifest.id}".`
78
+ );
79
+ }
80
+ return capability;
81
+ }
82
+ function createCapabilityRuntime(capabilities) {
83
+ const enabledCapabilities = capabilities.filter(
84
+ (capability) => capability.manifest.disabled !== true
85
+ );
86
+ const catalog = createCapabilityCatalog(enabledCapabilities);
87
+ assertUniqueCapabilities(enabledCapabilities);
88
+ assertKnownCapabilityDependencies(enabledCapabilities, catalog);
89
+ const contributions = collectContributions(enabledCapabilities);
90
+ return {
91
+ capabilities: Object.freeze([...enabledCapabilities]),
92
+ catalog,
93
+ getContributions: (extensionPoint) => [...contributions.get(extensionPoint.id) ?? []]
94
+ };
95
+ }
96
+ var CapabilityRuntimeContext = (0, import_react.createContext)(null);
97
+ function CapabilityRuntimeProvider({
98
+ children,
99
+ runtime
100
+ }) {
101
+ return (0, import_react.createElement)(CapabilityRuntimeContext.Provider, { value: runtime }, children);
102
+ }
103
+ function useCapabilityRuntime() {
104
+ const runtime = (0, import_react.useContext)(CapabilityRuntimeContext);
105
+ if (!runtime) {
106
+ throw new Error("useCapabilityRuntime must be used inside CapabilityRuntimeProvider.");
107
+ }
108
+ return runtime;
109
+ }
110
+ function assertUniqueCapabilities(capabilities) {
111
+ const seen = /* @__PURE__ */ new Set();
112
+ for (const capability of capabilities) {
113
+ if (seen.has(capability.id)) {
114
+ throw new Error(`Duplicate capability id "${capability.id}".`);
115
+ }
116
+ seen.add(capability.id);
117
+ }
118
+ }
119
+ function assertKnownCapabilityDependencies(capabilities, catalog) {
120
+ for (const capability of capabilities) {
121
+ (0, import_composition_graph.assertKnownDescriptorIds)(
122
+ catalog.getDescriptorMap(),
123
+ Object.keys(capability.manifest.dependencies ?? {}),
124
+ `capability "${capability.id}" dependencies`
125
+ );
126
+ }
127
+ }
128
+ function collectContributions(capabilities) {
129
+ const contributions = /* @__PURE__ */ new Map();
130
+ for (const capability of capabilities) {
131
+ for (const contribution of capability.contributions ?? []) {
132
+ const bucket = contributions.get(contribution.extensionPoint.id) ?? [];
133
+ bucket.push(...contribution.values);
134
+ contributions.set(contribution.extensionPoint.id, bucket);
135
+ }
136
+ }
137
+ return contributions;
138
+ }
139
+ function createCapabilityCatalog(capabilities) {
140
+ return (0, import_composition_graph.createDescriptorCatalog)({
141
+ descriptors: capabilities.map((capability) => capability.manifest)
142
+ });
143
+ }
144
+ // Annotate the CommonJS export names for ESM import in node:
145
+ 0 && (module.exports = {
146
+ CapabilityRuntimeProvider,
147
+ createCapabilityRuntime,
148
+ createContributionContract,
149
+ defineCapability,
150
+ defineContribution,
151
+ defineExtensionPoint,
152
+ getCapabilityProviderSelection,
153
+ useCapabilityRuntime
154
+ });
@@ -0,0 +1,50 @@
1
+ import { ReactNode, ReactElement } from 'react';
2
+ import { Descriptor, DescriptorCatalog } from '@lorion-org/composition-graph';
3
+ import { ProviderPreferenceMap, ProviderSelectionResolution } from '@lorion-org/provider-selection';
4
+
5
+ type CapabilityManifest = Descriptor & {
6
+ description?: string;
7
+ providerPreferences?: ProviderPreferenceMap;
8
+ };
9
+ type ExtensionPoint<T> = {
10
+ id: string;
11
+ readonly value?: T;
12
+ };
13
+ type CapabilityContribution<T = unknown> = {
14
+ extensionPoint: ExtensionPoint<T>;
15
+ values: readonly T[];
16
+ };
17
+ type RuntimeCapability = {
18
+ id: string;
19
+ manifest: CapabilityManifest;
20
+ contributions?: readonly CapabilityContribution[];
21
+ };
22
+ type CapabilityRuntime = {
23
+ capabilities: readonly RuntimeCapability[];
24
+ catalog: DescriptorCatalog;
25
+ getContributions: <T>(extensionPoint: ExtensionPoint<T>) => T[];
26
+ };
27
+ type ContributionContract<T> = {
28
+ define: (values: readonly T[]) => CapabilityContribution<T>;
29
+ extensionPoint: ExtensionPoint<T>;
30
+ get: (runtime: CapabilityRuntime) => T[];
31
+ use: () => T[];
32
+ };
33
+ declare function defineExtensionPoint<T>(id: string): ExtensionPoint<T>;
34
+ declare function defineContribution<T>(extensionPoint: ExtensionPoint<T>, values: readonly T[]): CapabilityContribution<T>;
35
+ declare function createContributionContract<T>(id: string): ContributionContract<T>;
36
+ type CapabilityProviderSelectionOptions = {
37
+ configuredProviders?: ProviderPreferenceMap;
38
+ fallbackProviders?: ProviderPreferenceMap;
39
+ };
40
+ declare function getCapabilityProviderSelection(runtime: CapabilityRuntime, options?: CapabilityProviderSelectionOptions): ProviderSelectionResolution;
41
+ declare function defineCapability(capability: RuntimeCapability): RuntimeCapability;
42
+ declare function createCapabilityRuntime(capabilities: readonly RuntimeCapability[]): CapabilityRuntime;
43
+ type CapabilityRuntimeProviderProps = {
44
+ children: ReactNode;
45
+ runtime: CapabilityRuntime;
46
+ };
47
+ declare function CapabilityRuntimeProvider({ children, runtime, }: CapabilityRuntimeProviderProps): ReactElement;
48
+ declare function useCapabilityRuntime(): CapabilityRuntime;
49
+
50
+ export { type CapabilityContribution, type CapabilityManifest, type CapabilityProviderSelectionOptions, type CapabilityRuntime, CapabilityRuntimeProvider, type CapabilityRuntimeProviderProps, type ContributionContract, type ExtensionPoint, type RuntimeCapability, createCapabilityRuntime, createContributionContract, defineCapability, defineContribution, defineExtensionPoint, getCapabilityProviderSelection, useCapabilityRuntime };
@@ -0,0 +1,50 @@
1
+ import { ReactNode, ReactElement } from 'react';
2
+ import { Descriptor, DescriptorCatalog } from '@lorion-org/composition-graph';
3
+ import { ProviderPreferenceMap, ProviderSelectionResolution } from '@lorion-org/provider-selection';
4
+
5
+ type CapabilityManifest = Descriptor & {
6
+ description?: string;
7
+ providerPreferences?: ProviderPreferenceMap;
8
+ };
9
+ type ExtensionPoint<T> = {
10
+ id: string;
11
+ readonly value?: T;
12
+ };
13
+ type CapabilityContribution<T = unknown> = {
14
+ extensionPoint: ExtensionPoint<T>;
15
+ values: readonly T[];
16
+ };
17
+ type RuntimeCapability = {
18
+ id: string;
19
+ manifest: CapabilityManifest;
20
+ contributions?: readonly CapabilityContribution[];
21
+ };
22
+ type CapabilityRuntime = {
23
+ capabilities: readonly RuntimeCapability[];
24
+ catalog: DescriptorCatalog;
25
+ getContributions: <T>(extensionPoint: ExtensionPoint<T>) => T[];
26
+ };
27
+ type ContributionContract<T> = {
28
+ define: (values: readonly T[]) => CapabilityContribution<T>;
29
+ extensionPoint: ExtensionPoint<T>;
30
+ get: (runtime: CapabilityRuntime) => T[];
31
+ use: () => T[];
32
+ };
33
+ declare function defineExtensionPoint<T>(id: string): ExtensionPoint<T>;
34
+ declare function defineContribution<T>(extensionPoint: ExtensionPoint<T>, values: readonly T[]): CapabilityContribution<T>;
35
+ declare function createContributionContract<T>(id: string): ContributionContract<T>;
36
+ type CapabilityProviderSelectionOptions = {
37
+ configuredProviders?: ProviderPreferenceMap;
38
+ fallbackProviders?: ProviderPreferenceMap;
39
+ };
40
+ declare function getCapabilityProviderSelection(runtime: CapabilityRuntime, options?: CapabilityProviderSelectionOptions): ProviderSelectionResolution;
41
+ declare function defineCapability(capability: RuntimeCapability): RuntimeCapability;
42
+ declare function createCapabilityRuntime(capabilities: readonly RuntimeCapability[]): CapabilityRuntime;
43
+ type CapabilityRuntimeProviderProps = {
44
+ children: ReactNode;
45
+ runtime: CapabilityRuntime;
46
+ };
47
+ declare function CapabilityRuntimeProvider({ children, runtime, }: CapabilityRuntimeProviderProps): ReactElement;
48
+ declare function useCapabilityRuntime(): CapabilityRuntime;
49
+
50
+ export { type CapabilityContribution, type CapabilityManifest, type CapabilityProviderSelectionOptions, type CapabilityRuntime, CapabilityRuntimeProvider, type CapabilityRuntimeProviderProps, type ContributionContract, type ExtensionPoint, type RuntimeCapability, createCapabilityRuntime, createContributionContract, defineCapability, defineContribution, defineExtensionPoint, getCapabilityProviderSelection, useCapabilityRuntime };
package/dist/index.js ADDED
@@ -0,0 +1,128 @@
1
+ // src/index.ts
2
+ import { createContext, createElement, useContext } from "react";
3
+ import {
4
+ assertKnownDescriptorIds,
5
+ createDescriptorCatalog
6
+ } from "@lorion-org/composition-graph";
7
+ import {
8
+ collectProviderPreferences,
9
+ resolveItemProviderSelection
10
+ } from "@lorion-org/provider-selection";
11
+ function defineExtensionPoint(id) {
12
+ return { id };
13
+ }
14
+ function defineContribution(extensionPoint, values) {
15
+ return { extensionPoint, values };
16
+ }
17
+ function createContributionContract(id) {
18
+ const extensionPoint = defineExtensionPoint(id);
19
+ return {
20
+ extensionPoint,
21
+ define: (values) => defineContribution(extensionPoint, values),
22
+ get: (runtime) => runtime.getContributions(extensionPoint),
23
+ use: () => useCapabilityRuntime().getContributions(extensionPoint)
24
+ };
25
+ }
26
+ function getCapabilityProviderSelection(runtime, options = {}) {
27
+ const descriptors = runtime.catalog.getAllDescriptors();
28
+ const descriptorPreferences = collectProviderPreferences({
29
+ items: descriptors,
30
+ getProviderPreferences: (descriptor) => descriptor.providerPreferences
31
+ });
32
+ const configuredProviders = {
33
+ ...descriptorPreferences,
34
+ ...options.configuredProviders ?? {}
35
+ };
36
+ const resolution = resolveItemProviderSelection({
37
+ items: descriptors,
38
+ getCapabilityId: (descriptor) => descriptor.providesFor,
39
+ getProviderId: (descriptor) => descriptor.id,
40
+ configuredProviders,
41
+ ...options.fallbackProviders ? { fallbackProviders: options.fallbackProviders } : {}
42
+ });
43
+ return {
44
+ excludedProviderIds: resolution.excludedProviderIds,
45
+ mismatches: resolution.mismatches,
46
+ selections: resolution.selections
47
+ };
48
+ }
49
+ function defineCapability(capability) {
50
+ if (capability.id !== capability.manifest.id) {
51
+ throw new Error(
52
+ `Capability "${capability.id}" must match capability.json id "${capability.manifest.id}".`
53
+ );
54
+ }
55
+ return capability;
56
+ }
57
+ function createCapabilityRuntime(capabilities) {
58
+ const enabledCapabilities = capabilities.filter(
59
+ (capability) => capability.manifest.disabled !== true
60
+ );
61
+ const catalog = createCapabilityCatalog(enabledCapabilities);
62
+ assertUniqueCapabilities(enabledCapabilities);
63
+ assertKnownCapabilityDependencies(enabledCapabilities, catalog);
64
+ const contributions = collectContributions(enabledCapabilities);
65
+ return {
66
+ capabilities: Object.freeze([...enabledCapabilities]),
67
+ catalog,
68
+ getContributions: (extensionPoint) => [...contributions.get(extensionPoint.id) ?? []]
69
+ };
70
+ }
71
+ var CapabilityRuntimeContext = createContext(null);
72
+ function CapabilityRuntimeProvider({
73
+ children,
74
+ runtime
75
+ }) {
76
+ return createElement(CapabilityRuntimeContext.Provider, { value: runtime }, children);
77
+ }
78
+ function useCapabilityRuntime() {
79
+ const runtime = useContext(CapabilityRuntimeContext);
80
+ if (!runtime) {
81
+ throw new Error("useCapabilityRuntime must be used inside CapabilityRuntimeProvider.");
82
+ }
83
+ return runtime;
84
+ }
85
+ function assertUniqueCapabilities(capabilities) {
86
+ const seen = /* @__PURE__ */ new Set();
87
+ for (const capability of capabilities) {
88
+ if (seen.has(capability.id)) {
89
+ throw new Error(`Duplicate capability id "${capability.id}".`);
90
+ }
91
+ seen.add(capability.id);
92
+ }
93
+ }
94
+ function assertKnownCapabilityDependencies(capabilities, catalog) {
95
+ for (const capability of capabilities) {
96
+ assertKnownDescriptorIds(
97
+ catalog.getDescriptorMap(),
98
+ Object.keys(capability.manifest.dependencies ?? {}),
99
+ `capability "${capability.id}" dependencies`
100
+ );
101
+ }
102
+ }
103
+ function collectContributions(capabilities) {
104
+ const contributions = /* @__PURE__ */ new Map();
105
+ for (const capability of capabilities) {
106
+ for (const contribution of capability.contributions ?? []) {
107
+ const bucket = contributions.get(contribution.extensionPoint.id) ?? [];
108
+ bucket.push(...contribution.values);
109
+ contributions.set(contribution.extensionPoint.id, bucket);
110
+ }
111
+ }
112
+ return contributions;
113
+ }
114
+ function createCapabilityCatalog(capabilities) {
115
+ return createDescriptorCatalog({
116
+ descriptors: capabilities.map((capability) => capability.manifest)
117
+ });
118
+ }
119
+ export {
120
+ CapabilityRuntimeProvider,
121
+ createCapabilityRuntime,
122
+ createContributionContract,
123
+ defineCapability,
124
+ defineContribution,
125
+ defineExtensionPoint,
126
+ getCapabilityProviderSelection,
127
+ useCapabilityRuntime
128
+ };
package/dist/vite.cjs ADDED
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/vite.ts
21
+ var vite_exports = {};
22
+ __export(vite_exports, {
23
+ capabilityLoader: () => capabilityLoader,
24
+ createCapabilityRouteConfig: () => createCapabilityRouteConfig,
25
+ discoverCapabilities: () => discoverCapabilities,
26
+ discoverSelectedCapabilities: () => discoverSelectedCapabilities,
27
+ lorionReact: () => lorionReact,
28
+ renderCapabilityModule: () => renderCapabilityModule
29
+ });
30
+ module.exports = __toCommonJS(vite_exports);
31
+ var import_node_fs = require("fs");
32
+ var import_node_path = require("path");
33
+ var import_composition_graph = require("@lorion-org/composition-graph");
34
+ var import_descriptor_discovery = require("@lorion-org/descriptor-discovery");
35
+ var virtualModuleId = "virtual:capabilities";
36
+ var resolvedVirtualModuleId = `\0${virtualModuleId}`;
37
+ function capabilityLoader(options = {}) {
38
+ let config;
39
+ let capabilities = [];
40
+ return {
41
+ name: "lorion-react-capability-loader",
42
+ enforce: "pre",
43
+ configResolved(resolvedConfig) {
44
+ config = resolvedConfig;
45
+ capabilities = discoverSelectedCapabilities(
46
+ resolveWorkspaceRoot(config.root, options),
47
+ options
48
+ );
49
+ },
50
+ resolveId(id) {
51
+ if (id === virtualModuleId) return resolvedVirtualModuleId;
52
+ return capabilities.find((capability) => capability.importSpecifier === id)?.entryFile;
53
+ },
54
+ load(id) {
55
+ if (id !== resolvedVirtualModuleId) return null;
56
+ return renderCapabilityModule(capabilities);
57
+ }
58
+ };
59
+ }
60
+ function lorionReact(options) {
61
+ return {
62
+ capabilityLoader: capabilityLoader(options),
63
+ routeConfig: createCapabilityRouteConfig(options)
64
+ };
65
+ }
66
+ function discoverCapabilities(workspaceRoot, options = {}) {
67
+ const capabilitiesRoot = (0, import_node_path.resolve)(workspaceRoot, options.capabilitiesDir ?? "capabilities");
68
+ if (!(0, import_node_fs.existsSync)(capabilitiesRoot)) {
69
+ throw new Error(`Capabilities directory not found: ${capabilitiesRoot}`);
70
+ }
71
+ return discoverCapabilityDescriptors(workspaceRoot, options).map(discoverCapability).sort((left, right) => left.id.localeCompare(right.id));
72
+ }
73
+ function discoverSelectedCapabilities(workspaceRoot, options = {}) {
74
+ return selectCapabilities(discoverCapabilities(workspaceRoot, options), options);
75
+ }
76
+ function selectCapabilities(capabilities, options = {}) {
77
+ const enabledCapabilities = capabilities.filter((capability) => capability.disabled !== true);
78
+ if (!options.selected?.length && !options.baseDescriptors?.length) {
79
+ return [...enabledCapabilities];
80
+ }
81
+ const catalog = (0, import_composition_graph.createDescriptorCatalog)({
82
+ descriptors: enabledCapabilities.map((capability) => capability.manifest)
83
+ });
84
+ const selection = (0, import_composition_graph.createCompositionSelection)({
85
+ catalog,
86
+ selected: [...options.selected ?? []],
87
+ baseDescriptors: [...options.baseDescriptors ?? []],
88
+ ...options.policy ? { policy: options.policy } : {}
89
+ });
90
+ const selectedIds = new Set(selection.getResolved());
91
+ return enabledCapabilities.filter((capability) => selectedIds.has(capability.id));
92
+ }
93
+ function renderCapabilityModule(capabilities) {
94
+ const imports = capabilities.map(
95
+ (capability) => `import { capability as ${capability.variableName} } from '${capability.importSpecifier}'`
96
+ ).join("\n");
97
+ const variables = capabilities.map((capability) => ` ${capability.variableName},`).join("\n");
98
+ return `${imports}
99
+
100
+ export const capabilityModules = [
101
+ ${variables}
102
+ ]
103
+ `;
104
+ }
105
+ function createCapabilityRouteConfig(options) {
106
+ if (!options?.workspaceRoot) {
107
+ throw new Error("createCapabilityRouteConfig requires a workspaceRoot option.");
108
+ }
109
+ if (!options?.routesDirectory) {
110
+ throw new Error("createCapabilityRouteConfig requires a routesDirectory option.");
111
+ }
112
+ const routesDirectory = (0, import_node_path.resolve)(options.routesDirectory);
113
+ const capabilities = discoverSelectedCapabilities(options.workspaceRoot, options);
114
+ const capabilityRouteSubtrees = capabilities.filter(hasRouteDirectory).filter((capability) => capability.disabled !== true).map((capability) => ({
115
+ type: "physical",
116
+ pathPrefix: "",
117
+ directory: toPosixPath((0, import_node_path.relative)(routesDirectory, capability.routesDirectory))
118
+ }));
119
+ return {
120
+ type: "root",
121
+ file: "__root.tsx",
122
+ children: [
123
+ ...options.indexRouteFile === false ? [] : [
124
+ {
125
+ type: "index",
126
+ file: options.indexRouteFile ?? "index.tsx"
127
+ }
128
+ ],
129
+ ...capabilityRouteSubtrees
130
+ ]
131
+ };
132
+ }
133
+ function discoverCapabilityDescriptors(workspaceRoot, options) {
134
+ const capabilitiesDir = options.capabilitiesDir ?? "capabilities";
135
+ return (0, import_descriptor_discovery.discoverDescriptors)({
136
+ cwd: workspaceRoot,
137
+ descriptorPaths: [`${capabilitiesDir}/*/capability.json`],
138
+ validation: {
139
+ schema: import_descriptor_discovery.descriptorSchema
140
+ }
141
+ });
142
+ }
143
+ function discoverCapability(entry) {
144
+ const capabilityDir = entry.cwd;
145
+ const packagePath = (0, import_node_path.resolve)(capabilityDir, "package.json");
146
+ if (!(0, import_node_fs.existsSync)(packagePath)) {
147
+ throw new Error(
148
+ `Capability must define both capability.json and package.json: ${capabilityDir}`
149
+ );
150
+ }
151
+ const packageJson = readJson(packagePath);
152
+ const packageName = packageJson.name;
153
+ if (typeof packageName !== "string") {
154
+ throw new Error(`Capability package is missing "name": ${packagePath}`);
155
+ }
156
+ const activationEntry = resolveActivationEntry(capabilityDir, packageJson);
157
+ const routesDirectory = resolveRouteDirectory(capabilityDir);
158
+ return {
159
+ id: entry.descriptor.id,
160
+ disabled: entry.descriptor.disabled === true,
161
+ entryFile: activationEntry.entryFile,
162
+ importSpecifier: activationEntry.importSpecifier,
163
+ manifest: entry.descriptor,
164
+ packageName,
165
+ ...routesDirectory ? { routesDirectory } : {},
166
+ variableName: toVariableName(entry.descriptor.id)
167
+ };
168
+ }
169
+ function resolveRouteDirectory(capabilityDir) {
170
+ const routesDirectory = (0, import_node_path.resolve)(capabilityDir, "src", "routes");
171
+ return (0, import_node_fs.existsSync)(routesDirectory) ? routesDirectory : void 0;
172
+ }
173
+ function resolveActivationEntry(capabilityDir, packageJson) {
174
+ const packageName = packageJson.name;
175
+ const packageExports = packageJson.exports;
176
+ if (typeof packageName !== "string") {
177
+ throw new Error(
178
+ `Capability package is missing "name": ${(0, import_node_path.resolve)(capabilityDir, "package.json")}`
179
+ );
180
+ }
181
+ if (!isRecord(packageExports) || typeof packageExports["./capability"] !== "string") {
182
+ throw new Error(`Capability package is missing a "./capability" export: ${capabilityDir}`);
183
+ }
184
+ return {
185
+ entryFile: (0, import_node_path.resolve)(capabilityDir, packageExports["./capability"]),
186
+ importSpecifier: `${packageName}/capability`
187
+ };
188
+ }
189
+ function hasRouteDirectory(capability) {
190
+ return typeof capability.routesDirectory === "string";
191
+ }
192
+ function isRecord(value) {
193
+ return typeof value === "object" && value !== null && !Array.isArray(value);
194
+ }
195
+ function resolveWorkspaceRoot(configRoot, options) {
196
+ if (options.workspaceRoot) return (0, import_node_path.resolve)(options.workspaceRoot);
197
+ return findWorkspaceRoot(configRoot);
198
+ }
199
+ function findWorkspaceRoot(startDir) {
200
+ let current = (0, import_node_path.resolve)(startDir);
201
+ while (true) {
202
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(current, "pnpm-workspace.yaml")) && (0, import_node_fs.existsSync)((0, import_node_path.join)(current, "capabilities"))) {
203
+ return current;
204
+ }
205
+ const parent = (0, import_node_path.dirname)(current);
206
+ if (parent === current) {
207
+ throw new Error(`Could not find React workspace root from: ${startDir}`);
208
+ }
209
+ current = parent;
210
+ }
211
+ }
212
+ function readJson(path) {
213
+ return JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
214
+ }
215
+ function toVariableName(name) {
216
+ return `${name.replace(/[^a-zA-Z0-9]+/g, " ").trim().replace(/(?:^|\s)([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()).replace(/^([A-Z])/, (char) => char.toLowerCase())}Capability`;
217
+ }
218
+ function toPosixPath(path) {
219
+ return path.split(import_node_path.sep).join("/");
220
+ }
221
+ // Annotate the CommonJS export names for ESM import in node:
222
+ 0 && (module.exports = {
223
+ capabilityLoader,
224
+ createCapabilityRouteConfig,
225
+ discoverCapabilities,
226
+ discoverSelectedCapabilities,
227
+ lorionReact,
228
+ renderCapabilityModule
229
+ });
@@ -0,0 +1,61 @@
1
+ import { DescriptorId, CompositionPolicy, Descriptor } from '@lorion-org/composition-graph';
2
+
3
+ type CapabilityLoaderOptions = {
4
+ capabilitiesDir?: string;
5
+ baseDescriptors?: readonly DescriptorId[];
6
+ policy?: Partial<CompositionPolicy>;
7
+ selected?: readonly DescriptorId[];
8
+ workspaceRoot?: string;
9
+ };
10
+ type CapabilityRouteConfigOptions = CapabilityLoaderOptions & {
11
+ indexRouteFile?: false | string;
12
+ routesDirectory: string;
13
+ workspaceRoot: string;
14
+ };
15
+ type LorionReactViteOptions = CapabilityRouteConfigOptions;
16
+ type LorionReactViteSetup = {
17
+ capabilityLoader: VitePlugin;
18
+ routeConfig: VirtualRootRoute;
19
+ };
20
+ type DiscoveredCapability = {
21
+ disabled: boolean;
22
+ entryFile: string;
23
+ id: string;
24
+ importSpecifier: string;
25
+ manifest: Descriptor;
26
+ packageName: string;
27
+ routesDirectory?: string;
28
+ variableName: string;
29
+ };
30
+ type VirtualIndexRoute = {
31
+ file: string;
32
+ type: 'index';
33
+ };
34
+ type VirtualPhysicalRouteSubtree = {
35
+ directory: string;
36
+ pathPrefix: string;
37
+ type: 'physical';
38
+ };
39
+ type VirtualRootRoute = {
40
+ children: Array<VirtualIndexRoute | VirtualPhysicalRouteSubtree>;
41
+ file: string;
42
+ type: 'root';
43
+ };
44
+ type ViteResolvedConfig = {
45
+ root: string;
46
+ };
47
+ type VitePlugin = {
48
+ configResolved: (resolvedConfig: ViteResolvedConfig) => void;
49
+ enforce: 'pre';
50
+ load: (id: string) => string | null;
51
+ name: string;
52
+ resolveId: (id: string) => string | undefined;
53
+ };
54
+ declare function capabilityLoader(options?: CapabilityLoaderOptions): VitePlugin;
55
+ declare function lorionReact(options: LorionReactViteOptions): LorionReactViteSetup;
56
+ declare function discoverCapabilities(workspaceRoot: string, options?: Pick<CapabilityLoaderOptions, 'capabilitiesDir'>): DiscoveredCapability[];
57
+ declare function discoverSelectedCapabilities(workspaceRoot: string, options?: CapabilityLoaderOptions): DiscoveredCapability[];
58
+ declare function renderCapabilityModule(capabilities: readonly DiscoveredCapability[]): string;
59
+ declare function createCapabilityRouteConfig(options: CapabilityRouteConfigOptions): VirtualRootRoute;
60
+
61
+ export { type CapabilityLoaderOptions, type CapabilityRouteConfigOptions, type DiscoveredCapability, type LorionReactViteOptions, type LorionReactViteSetup, type VirtualIndexRoute, type VirtualPhysicalRouteSubtree, type VirtualRootRoute, type VitePlugin, type ViteResolvedConfig, capabilityLoader, createCapabilityRouteConfig, discoverCapabilities, discoverSelectedCapabilities, lorionReact, renderCapabilityModule };
package/dist/vite.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { DescriptorId, CompositionPolicy, Descriptor } from '@lorion-org/composition-graph';
2
+
3
+ type CapabilityLoaderOptions = {
4
+ capabilitiesDir?: string;
5
+ baseDescriptors?: readonly DescriptorId[];
6
+ policy?: Partial<CompositionPolicy>;
7
+ selected?: readonly DescriptorId[];
8
+ workspaceRoot?: string;
9
+ };
10
+ type CapabilityRouteConfigOptions = CapabilityLoaderOptions & {
11
+ indexRouteFile?: false | string;
12
+ routesDirectory: string;
13
+ workspaceRoot: string;
14
+ };
15
+ type LorionReactViteOptions = CapabilityRouteConfigOptions;
16
+ type LorionReactViteSetup = {
17
+ capabilityLoader: VitePlugin;
18
+ routeConfig: VirtualRootRoute;
19
+ };
20
+ type DiscoveredCapability = {
21
+ disabled: boolean;
22
+ entryFile: string;
23
+ id: string;
24
+ importSpecifier: string;
25
+ manifest: Descriptor;
26
+ packageName: string;
27
+ routesDirectory?: string;
28
+ variableName: string;
29
+ };
30
+ type VirtualIndexRoute = {
31
+ file: string;
32
+ type: 'index';
33
+ };
34
+ type VirtualPhysicalRouteSubtree = {
35
+ directory: string;
36
+ pathPrefix: string;
37
+ type: 'physical';
38
+ };
39
+ type VirtualRootRoute = {
40
+ children: Array<VirtualIndexRoute | VirtualPhysicalRouteSubtree>;
41
+ file: string;
42
+ type: 'root';
43
+ };
44
+ type ViteResolvedConfig = {
45
+ root: string;
46
+ };
47
+ type VitePlugin = {
48
+ configResolved: (resolvedConfig: ViteResolvedConfig) => void;
49
+ enforce: 'pre';
50
+ load: (id: string) => string | null;
51
+ name: string;
52
+ resolveId: (id: string) => string | undefined;
53
+ };
54
+ declare function capabilityLoader(options?: CapabilityLoaderOptions): VitePlugin;
55
+ declare function lorionReact(options: LorionReactViteOptions): LorionReactViteSetup;
56
+ declare function discoverCapabilities(workspaceRoot: string, options?: Pick<CapabilityLoaderOptions, 'capabilitiesDir'>): DiscoveredCapability[];
57
+ declare function discoverSelectedCapabilities(workspaceRoot: string, options?: CapabilityLoaderOptions): DiscoveredCapability[];
58
+ declare function renderCapabilityModule(capabilities: readonly DiscoveredCapability[]): string;
59
+ declare function createCapabilityRouteConfig(options: CapabilityRouteConfigOptions): VirtualRootRoute;
60
+
61
+ export { type CapabilityLoaderOptions, type CapabilityRouteConfigOptions, type DiscoveredCapability, type LorionReactViteOptions, type LorionReactViteSetup, type VirtualIndexRoute, type VirtualPhysicalRouteSubtree, type VirtualRootRoute, type VitePlugin, type ViteResolvedConfig, capabilityLoader, createCapabilityRouteConfig, discoverCapabilities, discoverSelectedCapabilities, lorionReact, renderCapabilityModule };
package/dist/vite.js ADDED
@@ -0,0 +1,205 @@
1
+ // src/vite.ts
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { dirname, join, relative, resolve, sep } from "path";
4
+ import {
5
+ createCompositionSelection,
6
+ createDescriptorCatalog
7
+ } from "@lorion-org/composition-graph";
8
+ import {
9
+ descriptorSchema,
10
+ discoverDescriptors
11
+ } from "@lorion-org/descriptor-discovery";
12
+ var virtualModuleId = "virtual:capabilities";
13
+ var resolvedVirtualModuleId = `\0${virtualModuleId}`;
14
+ function capabilityLoader(options = {}) {
15
+ let config;
16
+ let capabilities = [];
17
+ return {
18
+ name: "lorion-react-capability-loader",
19
+ enforce: "pre",
20
+ configResolved(resolvedConfig) {
21
+ config = resolvedConfig;
22
+ capabilities = discoverSelectedCapabilities(
23
+ resolveWorkspaceRoot(config.root, options),
24
+ options
25
+ );
26
+ },
27
+ resolveId(id) {
28
+ if (id === virtualModuleId) return resolvedVirtualModuleId;
29
+ return capabilities.find((capability) => capability.importSpecifier === id)?.entryFile;
30
+ },
31
+ load(id) {
32
+ if (id !== resolvedVirtualModuleId) return null;
33
+ return renderCapabilityModule(capabilities);
34
+ }
35
+ };
36
+ }
37
+ function lorionReact(options) {
38
+ return {
39
+ capabilityLoader: capabilityLoader(options),
40
+ routeConfig: createCapabilityRouteConfig(options)
41
+ };
42
+ }
43
+ function discoverCapabilities(workspaceRoot, options = {}) {
44
+ const capabilitiesRoot = resolve(workspaceRoot, options.capabilitiesDir ?? "capabilities");
45
+ if (!existsSync(capabilitiesRoot)) {
46
+ throw new Error(`Capabilities directory not found: ${capabilitiesRoot}`);
47
+ }
48
+ return discoverCapabilityDescriptors(workspaceRoot, options).map(discoverCapability).sort((left, right) => left.id.localeCompare(right.id));
49
+ }
50
+ function discoverSelectedCapabilities(workspaceRoot, options = {}) {
51
+ return selectCapabilities(discoverCapabilities(workspaceRoot, options), options);
52
+ }
53
+ function selectCapabilities(capabilities, options = {}) {
54
+ const enabledCapabilities = capabilities.filter((capability) => capability.disabled !== true);
55
+ if (!options.selected?.length && !options.baseDescriptors?.length) {
56
+ return [...enabledCapabilities];
57
+ }
58
+ const catalog = createDescriptorCatalog({
59
+ descriptors: enabledCapabilities.map((capability) => capability.manifest)
60
+ });
61
+ const selection = createCompositionSelection({
62
+ catalog,
63
+ selected: [...options.selected ?? []],
64
+ baseDescriptors: [...options.baseDescriptors ?? []],
65
+ ...options.policy ? { policy: options.policy } : {}
66
+ });
67
+ const selectedIds = new Set(selection.getResolved());
68
+ return enabledCapabilities.filter((capability) => selectedIds.has(capability.id));
69
+ }
70
+ function renderCapabilityModule(capabilities) {
71
+ const imports = capabilities.map(
72
+ (capability) => `import { capability as ${capability.variableName} } from '${capability.importSpecifier}'`
73
+ ).join("\n");
74
+ const variables = capabilities.map((capability) => ` ${capability.variableName},`).join("\n");
75
+ return `${imports}
76
+
77
+ export const capabilityModules = [
78
+ ${variables}
79
+ ]
80
+ `;
81
+ }
82
+ function createCapabilityRouteConfig(options) {
83
+ if (!options?.workspaceRoot) {
84
+ throw new Error("createCapabilityRouteConfig requires a workspaceRoot option.");
85
+ }
86
+ if (!options?.routesDirectory) {
87
+ throw new Error("createCapabilityRouteConfig requires a routesDirectory option.");
88
+ }
89
+ const routesDirectory = resolve(options.routesDirectory);
90
+ const capabilities = discoverSelectedCapabilities(options.workspaceRoot, options);
91
+ const capabilityRouteSubtrees = capabilities.filter(hasRouteDirectory).filter((capability) => capability.disabled !== true).map((capability) => ({
92
+ type: "physical",
93
+ pathPrefix: "",
94
+ directory: toPosixPath(relative(routesDirectory, capability.routesDirectory))
95
+ }));
96
+ return {
97
+ type: "root",
98
+ file: "__root.tsx",
99
+ children: [
100
+ ...options.indexRouteFile === false ? [] : [
101
+ {
102
+ type: "index",
103
+ file: options.indexRouteFile ?? "index.tsx"
104
+ }
105
+ ],
106
+ ...capabilityRouteSubtrees
107
+ ]
108
+ };
109
+ }
110
+ function discoverCapabilityDescriptors(workspaceRoot, options) {
111
+ const capabilitiesDir = options.capabilitiesDir ?? "capabilities";
112
+ return discoverDescriptors({
113
+ cwd: workspaceRoot,
114
+ descriptorPaths: [`${capabilitiesDir}/*/capability.json`],
115
+ validation: {
116
+ schema: descriptorSchema
117
+ }
118
+ });
119
+ }
120
+ function discoverCapability(entry) {
121
+ const capabilityDir = entry.cwd;
122
+ const packagePath = resolve(capabilityDir, "package.json");
123
+ if (!existsSync(packagePath)) {
124
+ throw new Error(
125
+ `Capability must define both capability.json and package.json: ${capabilityDir}`
126
+ );
127
+ }
128
+ const packageJson = readJson(packagePath);
129
+ const packageName = packageJson.name;
130
+ if (typeof packageName !== "string") {
131
+ throw new Error(`Capability package is missing "name": ${packagePath}`);
132
+ }
133
+ const activationEntry = resolveActivationEntry(capabilityDir, packageJson);
134
+ const routesDirectory = resolveRouteDirectory(capabilityDir);
135
+ return {
136
+ id: entry.descriptor.id,
137
+ disabled: entry.descriptor.disabled === true,
138
+ entryFile: activationEntry.entryFile,
139
+ importSpecifier: activationEntry.importSpecifier,
140
+ manifest: entry.descriptor,
141
+ packageName,
142
+ ...routesDirectory ? { routesDirectory } : {},
143
+ variableName: toVariableName(entry.descriptor.id)
144
+ };
145
+ }
146
+ function resolveRouteDirectory(capabilityDir) {
147
+ const routesDirectory = resolve(capabilityDir, "src", "routes");
148
+ return existsSync(routesDirectory) ? routesDirectory : void 0;
149
+ }
150
+ function resolveActivationEntry(capabilityDir, packageJson) {
151
+ const packageName = packageJson.name;
152
+ const packageExports = packageJson.exports;
153
+ if (typeof packageName !== "string") {
154
+ throw new Error(
155
+ `Capability package is missing "name": ${resolve(capabilityDir, "package.json")}`
156
+ );
157
+ }
158
+ if (!isRecord(packageExports) || typeof packageExports["./capability"] !== "string") {
159
+ throw new Error(`Capability package is missing a "./capability" export: ${capabilityDir}`);
160
+ }
161
+ return {
162
+ entryFile: resolve(capabilityDir, packageExports["./capability"]),
163
+ importSpecifier: `${packageName}/capability`
164
+ };
165
+ }
166
+ function hasRouteDirectory(capability) {
167
+ return typeof capability.routesDirectory === "string";
168
+ }
169
+ function isRecord(value) {
170
+ return typeof value === "object" && value !== null && !Array.isArray(value);
171
+ }
172
+ function resolveWorkspaceRoot(configRoot, options) {
173
+ if (options.workspaceRoot) return resolve(options.workspaceRoot);
174
+ return findWorkspaceRoot(configRoot);
175
+ }
176
+ function findWorkspaceRoot(startDir) {
177
+ let current = resolve(startDir);
178
+ while (true) {
179
+ if (existsSync(join(current, "pnpm-workspace.yaml")) && existsSync(join(current, "capabilities"))) {
180
+ return current;
181
+ }
182
+ const parent = dirname(current);
183
+ if (parent === current) {
184
+ throw new Error(`Could not find React workspace root from: ${startDir}`);
185
+ }
186
+ current = parent;
187
+ }
188
+ }
189
+ function readJson(path) {
190
+ return JSON.parse(readFileSync(path, "utf8"));
191
+ }
192
+ function toVariableName(name) {
193
+ return `${name.replace(/[^a-zA-Z0-9]+/g, " ").trim().replace(/(?:^|\s)([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()).replace(/^([A-Z])/, (char) => char.toLowerCase())}Capability`;
194
+ }
195
+ function toPosixPath(path) {
196
+ return path.split(sep).join("/");
197
+ }
198
+ export {
199
+ capabilityLoader,
200
+ createCapabilityRouteConfig,
201
+ discoverCapabilities,
202
+ discoverSelectedCapabilities,
203
+ lorionReact,
204
+ renderCapabilityModule
205
+ };
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@lorion-org/react",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "React capability runtime and Vite helpers for LORION descriptor-based applications.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/lorion-org/lorion.git",
9
+ "directory": "packages/react"
10
+ },
11
+ "homepage": "https://github.com/lorion-org/lorion/tree/main/packages/react#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/lorion-org/lorion/issues"
14
+ },
15
+ "type": "module",
16
+ "sideEffects": false,
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "exports": {
24
+ ".": {
25
+ "import": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "require": {
30
+ "types": "./dist/index.d.cts",
31
+ "default": "./dist/index.cjs"
32
+ }
33
+ },
34
+ "./vite": {
35
+ "import": {
36
+ "types": "./dist/vite.d.ts",
37
+ "default": "./dist/vite.js"
38
+ },
39
+ "require": {
40
+ "types": "./dist/vite.d.cts",
41
+ "default": "./dist/vite.cjs"
42
+ }
43
+ }
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "LICENSE"
48
+ ],
49
+ "dependencies": {
50
+ "@lorion-org/composition-graph": "^1.0.0-beta.1",
51
+ "@lorion-org/provider-selection": "^1.0.0-beta.1",
52
+ "@lorion-org/descriptor-discovery": "^1.0.0-beta.1"
53
+ },
54
+ "peerDependencies": {
55
+ "react": "^19.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@tanstack/react-router": "^1.168.25",
59
+ "@tanstack/router-plugin": "^1.167.28",
60
+ "@types/node": "^22.15.17",
61
+ "@types/react": "^19.0.0",
62
+ "@types/react-dom": "^19.0.0",
63
+ "@vitejs/plugin-react": "^5.1.0",
64
+ "react-dom": "^19.0.0",
65
+ "typescript": "^5.8.3",
66
+ "vite": "^7.3.2",
67
+ "vitest": "^3.1.3"
68
+ },
69
+ "keywords": [
70
+ "lorion",
71
+ "react",
72
+ "capability",
73
+ "vite"
74
+ ],
75
+ "engines": {
76
+ "node": "^20.19.0 || >=22.12.0"
77
+ },
78
+ "scripts": {
79
+ "build": "tsup src/index.ts src/vite.ts --format esm,cjs --dts",
80
+ "clean": "rimraf coverage dist tsconfig.tsbuildinfo",
81
+ "lint": "eslint src --ext .ts",
82
+ "package:check": "pnpm build && pnpm pack --dry-run && publint",
83
+ "build:playground": "vite build --config playground/vite.config.ts",
84
+ "dev:playground": "vite dev --config playground/vite.config.ts --host 0.0.0.0",
85
+ "test": "vitest run --root ../.. --config vitest.config.mts packages/react/src/index.spec.ts packages/react/src/vite.spec.ts",
86
+ "typecheck": "tsc -p tsconfig.json --noEmit",
87
+ "typecheck:playground": "tsc -p playground/tsconfig.json --noEmit"
88
+ }
89
+ }