@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 +21 -0
- package/README.md +202 -0
- package/dist/index.cjs +154 -0
- package/dist/index.d.cts +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +128 -0
- package/dist/vite.cjs +229 -0
- package/dist/vite.d.cts +61 -0
- package/dist/vite.d.ts +61 -0
- package/dist/vite.js +205 -0
- package/package.json +89 -0
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
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
});
|
package/dist/vite.d.cts
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.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
|
+
}
|