@lorion-org/nuxt 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +578 -0
- package/dist/descriptor-schema.d.ts +4 -0
- package/dist/descriptor-schema.js +63 -0
- package/dist/extensions-vNob6d2x.d.ts +127 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +864 -0
- package/dist/runtime-config-node.d.ts +15 -0
- package/dist/runtime-config-node.js +106 -0
- package/dist/runtime-config.d.ts +22 -0
- package/dist/runtime-config.js +184 -0
- package/examples/read-runtime-config.server.ts +3 -0
- package/examples/runtime-config-source.nuxt.config.ts +13 -0
- package/examples/selected-extensions.nuxt.config.ts +30 -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,578 @@
|
|
|
1
|
+
# @lorion-org/nuxt
|
|
2
|
+
|
|
3
|
+
Nuxt 4 adapter for LORION, the Layer Orchestration Runtime for Node.js.
|
|
4
|
+
|
|
5
|
+
`@lorion-org/nuxt` lets a Nuxt application activate descriptor-selected layers
|
|
6
|
+
without hardcoding every deployment profile in `nuxt.config.ts`. It resolves a
|
|
7
|
+
LORION extension bootstrap, passes Nuxt-native layer paths to `extends`, mounts
|
|
8
|
+
file-only layer content, projects scoped runtime config into Nuxt
|
|
9
|
+
`runtimeConfig`, and exposes provider selection for active capability
|
|
10
|
+
candidates.
|
|
11
|
+
|
|
12
|
+
Use it when Nuxt is the host runtime, but the application shape belongs to
|
|
13
|
+
explicit layer descriptors: product editions, customer deployments, white-label
|
|
14
|
+
variants, optional providers, or profile-based feature sets.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```shell
|
|
19
|
+
pnpm add @lorion-org/nuxt
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What it is
|
|
23
|
+
|
|
24
|
+
- a Nuxt 4 adapter for LORION layer orchestration
|
|
25
|
+
- descriptor/profile resolution for selectable Nuxt layer compositions
|
|
26
|
+
- Nuxt layer activation through native `extends` plus module-mounted file-only layers
|
|
27
|
+
- runtime-config projection from scoped LORION fragments into Nuxt `runtimeConfig`
|
|
28
|
+
- auto-imported public/private scope-view helpers for `useRuntimeConfig()` results
|
|
29
|
+
- provider selection for descriptors that declare `providesFor`
|
|
30
|
+
|
|
31
|
+
## Why not just Nuxt layers?
|
|
32
|
+
|
|
33
|
+
Nuxt layers are the right default when an application can statically list the
|
|
34
|
+
layers it uses. `@lorion-org/nuxt` is for Nuxt 4 applications where the layer list is
|
|
35
|
+
itself a runtime architecture concern and should be selected from explicit
|
|
36
|
+
descriptors or profiles.
|
|
37
|
+
|
|
38
|
+
Use Nuxt layers directly when:
|
|
39
|
+
|
|
40
|
+
- the layer list is known at development time
|
|
41
|
+
- every deployment uses the same layer composition
|
|
42
|
+
- runtime config can live directly in `nuxt.config.ts`
|
|
43
|
+
|
|
44
|
+
Use `@lorion-org/nuxt` when:
|
|
45
|
+
|
|
46
|
+
- different deployments or profiles activate different layer sets
|
|
47
|
+
- extension descriptors should define selectable compositions
|
|
48
|
+
- runtime config fragments should stay local to each extension
|
|
49
|
+
- provider implementations should be selected from active layer candidates
|
|
50
|
+
- Nuxt should receive collision-safe projected runtime config keys
|
|
51
|
+
|
|
52
|
+
## What it is not
|
|
53
|
+
|
|
54
|
+
- not a schema validator
|
|
55
|
+
- not an application naming policy
|
|
56
|
+
|
|
57
|
+
## Compatibility
|
|
58
|
+
|
|
59
|
+
| Package version | Nuxt 3 | Nuxt 4 | Test status |
|
|
60
|
+
| --------------- | ----------------- | --------- | ---------------------------------- |
|
|
61
|
+
| `0.1.x` | not supported yet | supported | CI-tested locally against Nuxt 4.x |
|
|
62
|
+
|
|
63
|
+
## Extension model
|
|
64
|
+
|
|
65
|
+
The module uses one `lorion` config key. By default it discovers `extension.json`
|
|
66
|
+
files below `extensions/`, expands nested descriptors from the `bundles`
|
|
67
|
+
field, resolves the selected profile through `@lorion-org/composition-graph`,
|
|
68
|
+
and registers only resolved extensions that contain Nuxt layer content.
|
|
69
|
+
|
|
70
|
+
Layer content includes:
|
|
71
|
+
|
|
72
|
+
- `app`
|
|
73
|
+
- `modules`
|
|
74
|
+
- `public`
|
|
75
|
+
- `server`
|
|
76
|
+
- `shared`
|
|
77
|
+
- `nuxt.config.*`
|
|
78
|
+
|
|
79
|
+
The module adds selected extensions to Nuxt's layer list so Nuxt owns page,
|
|
80
|
+
component, composable, layout, middleware, plugin, shared, server, and other
|
|
81
|
+
layer scans. The module does not hand-build Nuxt routes or register individual
|
|
82
|
+
component, plugin, page, or server directories.
|
|
83
|
+
|
|
84
|
+
Profile-only descriptors, such as `extensions/bundles/extension.json`,
|
|
85
|
+
are resolved but not registered as layers because they do not contain Nuxt layer
|
|
86
|
+
content.
|
|
87
|
+
|
|
88
|
+
Resolved extension ids currently come from `@lorion-org/composition-graph` and
|
|
89
|
+
are deterministic, but the dependency graph is a selection mechanism rather
|
|
90
|
+
than a documented plugin execution-order guarantee. Extension plugins that need
|
|
91
|
+
Nuxt ordering should use Nuxt plugin ordering controls such as `enforce` until
|
|
92
|
+
the module exposes an explicit dependency-ordered layer contract.
|
|
93
|
+
|
|
94
|
+
Runtime config can be provided as inline fragments, as an already projected
|
|
95
|
+
runtime config object, or as a configured source directory. When a project has
|
|
96
|
+
`.runtimeconfig/runtime-config`, the module loads it with the default
|
|
97
|
+
runtime-config file conventions only when `lorion.runtimeConfig` is omitted. Set
|
|
98
|
+
`lorion.runtimeConfig.source` for an explicit source directory, or set
|
|
99
|
+
`lorion.runtimeConfig.enabled` to `false` to disable runtime-config loading.
|
|
100
|
+
Runtime config stays separate from extension descriptors.
|
|
101
|
+
|
|
102
|
+
Descriptors can also declare provider candidates with `providesFor`. After the
|
|
103
|
+
selected profile is resolved, the module uses `@lorion-org/provider-selection`
|
|
104
|
+
to choose one provider per capability and exposes the result in public runtime
|
|
105
|
+
config as `providerSelection`.
|
|
106
|
+
|
|
107
|
+
## Package shape
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
src/
|
|
111
|
+
extensions.ts
|
|
112
|
+
index.ts
|
|
113
|
+
module.ts
|
|
114
|
+
runtime-config.ts
|
|
115
|
+
runtime-config-node.ts
|
|
116
|
+
types.ts
|
|
117
|
+
examples/
|
|
118
|
+
read-runtime-config.server.ts
|
|
119
|
+
runtime-config-source.nuxt.config.ts
|
|
120
|
+
selected-extensions.nuxt.config.ts
|
|
121
|
+
playground/
|
|
122
|
+
test/
|
|
123
|
+
fixtures/
|
|
124
|
+
unit/
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- `src/module.ts` contains Nuxt module wiring: selected layer registration, provider selection, runtime-config loading, and auto-imports.
|
|
128
|
+
- `src/extensions.ts` contains descriptor discovery, selection, bootstrap, and extension-owned runtime config.
|
|
129
|
+
- `src/runtime-config.ts` contains universal runtime-config adapter helpers.
|
|
130
|
+
- `src/runtime-config-node.ts` contains Node-only source loading helpers.
|
|
131
|
+
- The published package exports only the root Nuxt module. Runtime-config composables are generated and auto-imported by the module.
|
|
132
|
+
- `examples/` contains Nuxt-focused config and server-route snippets.
|
|
133
|
+
- `playground/` is a runnable Nuxt app for manual module development.
|
|
134
|
+
- `test/fixtures/` contains Nuxt applications used by end-to-end tests, and `test/unit/` contains package unit tests.
|
|
135
|
+
|
|
136
|
+
## Nuxt module
|
|
137
|
+
|
|
138
|
+
A minimal Nuxt app only needs the module:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
export default defineNuxtConfig({
|
|
142
|
+
modules: ['@lorion-org/nuxt'],
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
With that setup the module looks for this default layout:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
extensions/
|
|
150
|
+
bundles/
|
|
151
|
+
extension.json
|
|
152
|
+
checkout/
|
|
153
|
+
extension.json
|
|
154
|
+
app/
|
|
155
|
+
server/
|
|
156
|
+
.runtimeconfig/
|
|
157
|
+
runtime-config/
|
|
158
|
+
checkout/
|
|
159
|
+
runtime.config.json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Inline runtime config is supported for static defaults, local examples, and
|
|
163
|
+
tests. Runtime and environment-specific values should live outside
|
|
164
|
+
`nuxt.config.ts`, for example in `.runtimeconfig/runtime-config`:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
export default defineNuxtConfig({
|
|
168
|
+
modules: ['@lorion-org/nuxt'],
|
|
169
|
+
lorion: {
|
|
170
|
+
runtimeConfig: {
|
|
171
|
+
fragments: {
|
|
172
|
+
billing: {
|
|
173
|
+
public: {
|
|
174
|
+
apiBase: '/api/billing',
|
|
175
|
+
},
|
|
176
|
+
private: {
|
|
177
|
+
apiSecret: 'secret',
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
For inline fragments, the module writes private values to the root Nuxt runtime
|
|
187
|
+
config object and public values below `runtimeConfig.public`. Set
|
|
188
|
+
`privateOutput: 'section'` when the target runtime should keep private values
|
|
189
|
+
below `runtimeConfig.private`.
|
|
190
|
+
|
|
191
|
+
The module also auto-imports runtime-config composables unless
|
|
192
|
+
`runtimeConfig.imports` is `false`.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const billing = usePublicRuntimeConfigScope('billing');
|
|
196
|
+
|
|
197
|
+
billing.apiBase;
|
|
198
|
+
// => '/api/billing'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Configured module options such as `contextOutputKey` and `privateOutput` are
|
|
202
|
+
used by these composables automatically.
|
|
203
|
+
|
|
204
|
+
The public package API is intentionally small: resolve extension descriptors in
|
|
205
|
+
`nuxt.config`, pass Nuxt-native layer paths to `extends`, then register the
|
|
206
|
+
module with the resolved bootstrap for runtime config, provider selection, and
|
|
207
|
+
file-only layer content.
|
|
208
|
+
|
|
209
|
+
Descriptor files are validated before they are normalized. The module uses its
|
|
210
|
+
LORION extension descriptor schema by default. Host apps with additional descriptor
|
|
211
|
+
metadata can import the schema, extend it locally, and pass the result through
|
|
212
|
+
`extensions.descriptorSchema`:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { nuxtExtensionDescriptorSchema } from '@lorion-org/nuxt/descriptor-schema';
|
|
216
|
+
import LorionNuxtModule, {
|
|
217
|
+
createNuxtExtensionBootstrap,
|
|
218
|
+
createNuxtExtensionLayerPaths,
|
|
219
|
+
} from '@lorion-org/nuxt';
|
|
220
|
+
|
|
221
|
+
const extensionBootstrap = createNuxtExtensionBootstrap({
|
|
222
|
+
rootDir: __dirname,
|
|
223
|
+
options: {
|
|
224
|
+
descriptorSchema: {
|
|
225
|
+
...nuxtExtensionDescriptorSchema,
|
|
226
|
+
// host-specific schema extension
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
export default defineNuxtConfig({
|
|
232
|
+
extends: createNuxtExtensionLayerPaths(extensionBootstrap),
|
|
233
|
+
modules: [[LorionNuxtModule, { extensionBootstrap }]],
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Extension profiles
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import LorionNuxtModule, {
|
|
241
|
+
createNuxtExtensionBootstrap,
|
|
242
|
+
createNuxtExtensionLayerPaths,
|
|
243
|
+
} from '@lorion-org/nuxt';
|
|
244
|
+
|
|
245
|
+
const extensionBootstrap = createNuxtExtensionBootstrap({
|
|
246
|
+
rootDir: __dirname,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
export default defineNuxtConfig({
|
|
250
|
+
extends: createNuxtExtensionLayerPaths(extensionBootstrap),
|
|
251
|
+
modules: [[LorionNuxtModule, { extensionBootstrap }]],
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The default descriptor path is `extensions/*/extension.json`. A profile is a
|
|
256
|
+
normal descriptor that depends on other descriptors. The bootstrap selects
|
|
257
|
+
`default` when nothing is configured. Descriptors with their own `nuxt.config`
|
|
258
|
+
are returned as native `extends`; file-only descriptors are mounted by the
|
|
259
|
+
module after Nuxt config loading.
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"id": "bundles",
|
|
264
|
+
"version": "1.0.0",
|
|
265
|
+
"bundles": [
|
|
266
|
+
{
|
|
267
|
+
"id": "default",
|
|
268
|
+
"version": "1.0.0",
|
|
269
|
+
"dependencies": {
|
|
270
|
+
"web": "^1.0.0"
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Extension descriptors should stay focused on composition data: `id`, `version`,
|
|
278
|
+
dependencies, nested `bundles`, `providesFor` for provider candidates, provider
|
|
279
|
+
preferences on profiles, and public runtime config when the extension needs to
|
|
280
|
+
expose browser-safe values. Nuxt routes, components, composables, plugins, and
|
|
281
|
+
server handlers come from Nuxt layer scanning, not from duplicated descriptor
|
|
282
|
+
metadata.
|
|
283
|
+
|
|
284
|
+
Override the selected profile with module config:
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
import LorionNuxtModule, {
|
|
288
|
+
createNuxtExtensionBootstrap,
|
|
289
|
+
createNuxtExtensionLayerPaths,
|
|
290
|
+
} from '@lorion-org/nuxt';
|
|
291
|
+
|
|
292
|
+
const extensionBootstrap = createNuxtExtensionBootstrap({
|
|
293
|
+
rootDir: __dirname,
|
|
294
|
+
options: {
|
|
295
|
+
selected: 'admin',
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
export default defineNuxtConfig({
|
|
300
|
+
extends: createNuxtExtensionLayerPaths(extensionBootstrap),
|
|
301
|
+
modules: [[LorionNuxtModule, { extensionBootstrap }]],
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Applications that want CLI or env driven selection should normalize those
|
|
306
|
+
inputs locally and pass the resulting seed ids through `options.selected`.
|
|
307
|
+
The LORION bootstrap only receives canonical selection ids and resolves the graph.
|
|
308
|
+
|
|
309
|
+
## Provider Selection
|
|
310
|
+
|
|
311
|
+
Provider extensions can declare the capability they implement:
|
|
312
|
+
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"id": "payment-provider-stripe",
|
|
316
|
+
"version": "1.0.0",
|
|
317
|
+
"providesFor": "payment-checkout"
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
The module writes a public `providerSelection` object with selected providers,
|
|
322
|
+
candidates, excluded providers, configured providers, and mismatches. Profiles
|
|
323
|
+
can declare provider preferences in descriptor metadata:
|
|
324
|
+
|
|
325
|
+
```json
|
|
326
|
+
{
|
|
327
|
+
"id": "checkout-profile",
|
|
328
|
+
"version": "1.0.0",
|
|
329
|
+
"providerPreferences": {
|
|
330
|
+
"payment-checkout": "payment-provider-invoice"
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Module options can still override the selected provider when a host app needs a
|
|
336
|
+
deployment-specific choice:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
export default defineNuxtConfig({
|
|
340
|
+
extends: createNuxtExtensionLayerPaths(extensionBootstrap),
|
|
341
|
+
modules: [
|
|
342
|
+
[
|
|
343
|
+
LorionNuxtModule,
|
|
344
|
+
{
|
|
345
|
+
extensionBootstrap,
|
|
346
|
+
providers: {
|
|
347
|
+
configuredProviders: {
|
|
348
|
+
'payment-checkout': 'payment-provider-invoice',
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
],
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Runtime Config
|
|
358
|
+
|
|
359
|
+
Runtime-config projection does not require extension discovery. It can be used
|
|
360
|
+
as a plain module option when no extension bootstrap is involved:
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
export default defineNuxtConfig({
|
|
364
|
+
modules: ['@lorion-org/nuxt'],
|
|
365
|
+
lorion: {
|
|
366
|
+
runtimeConfig: {
|
|
367
|
+
fragments: {
|
|
368
|
+
billing: {
|
|
369
|
+
public: {
|
|
370
|
+
apiBase: '/api/billing',
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Runtime Config Source
|
|
380
|
+
|
|
381
|
+
The module can load runtime-config fragments from path patterns. Pattern
|
|
382
|
+
discovery and schema validation are delegated to
|
|
383
|
+
`@lorion-org/runtime-config-node`; this package only projects the loaded
|
|
384
|
+
fragments into Nuxt `runtimeConfig`. The default is
|
|
385
|
+
`.runtimeconfig/runtime-config/*/runtime.config.json`.
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
export default defineNuxtConfig({
|
|
389
|
+
modules: ['@lorion-org/nuxt'],
|
|
390
|
+
lorion: {
|
|
391
|
+
runtimeConfig: {
|
|
392
|
+
source: {
|
|
393
|
+
paths: ['.runtimeconfig/runtime-config/*/runtime.config.json'],
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Directory shape:
|
|
401
|
+
|
|
402
|
+
```text
|
|
403
|
+
var/
|
|
404
|
+
runtime-config/
|
|
405
|
+
billing/
|
|
406
|
+
runtime.config.json
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Adapters with an existing context key can map that key without changing file
|
|
410
|
+
contents:
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
export default defineNuxtConfig({
|
|
414
|
+
modules: ['@lorion-org/nuxt'],
|
|
415
|
+
lorion: {
|
|
416
|
+
runtimeConfig: {
|
|
417
|
+
contextInputKey: 'tenants',
|
|
418
|
+
contextOutputKey: '__tenants',
|
|
419
|
+
source: {
|
|
420
|
+
paths: ['var/runtime-config/*/runtime.config.json'],
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Nuxt-focused example snippets live in [`examples/`](./examples):
|
|
428
|
+
|
|
429
|
+
- [`selected-extensions.nuxt.config.ts`](./examples/selected-extensions.nuxt.config.ts)
|
|
430
|
+
- [`runtime-config-source.nuxt.config.ts`](./examples/runtime-config-source.nuxt.config.ts)
|
|
431
|
+
- [`read-runtime-config.server.ts`](./examples/read-runtime-config.server.ts)
|
|
432
|
+
|
|
433
|
+
## Playground
|
|
434
|
+
|
|
435
|
+
Run the local playground from this package:
|
|
436
|
+
|
|
437
|
+
```shell
|
|
438
|
+
pnpm dev:playground
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Select a playground composition by passing `extensions.selected` in Nuxt config:
|
|
442
|
+
|
|
443
|
+
The playground uses the module with no manual extension list in `nuxt.config.ts`.
|
|
444
|
+
It configures only the presentation-specific descriptor paths, loads runtime
|
|
445
|
+
config from `.runtimeconfig`, and registers the selected extension profile as
|
|
446
|
+
Nuxt layers.
|
|
447
|
+
|
|
448
|
+
The playground intentionally overrides the default extension root to make the
|
|
449
|
+
demo concept visible:
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
import LorionNuxtModule from '../src/module';
|
|
453
|
+
|
|
454
|
+
export default defineNuxtConfig({
|
|
455
|
+
modules: [LorionNuxtModule],
|
|
456
|
+
lorion: {
|
|
457
|
+
extensions: {
|
|
458
|
+
defaultSelection: 'default',
|
|
459
|
+
descriptorPaths: ['layer-extensions/*/extension.json'],
|
|
460
|
+
selected: 'default',
|
|
461
|
+
},
|
|
462
|
+
providers: {
|
|
463
|
+
configuredProviders: {
|
|
464
|
+
'payment-checkout': 'payment-provider-stripe',
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
The playground shape is:
|
|
472
|
+
|
|
473
|
+
```text
|
|
474
|
+
playground/
|
|
475
|
+
app/
|
|
476
|
+
layer-extensions/
|
|
477
|
+
bundles/
|
|
478
|
+
extension.json
|
|
479
|
+
checkout/
|
|
480
|
+
payments/
|
|
481
|
+
shops/
|
|
482
|
+
shop-coffee/
|
|
483
|
+
shop-stationery/
|
|
484
|
+
admin/
|
|
485
|
+
payment-provider-stripe/
|
|
486
|
+
payment-provider-invoice/
|
|
487
|
+
.runtimeconfig/
|
|
488
|
+
runtime-config/
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
The root app lives under `playground/app`. It owns normal Nuxt application
|
|
492
|
+
code. The `shops` layer extension provides the shop home route at `/`, the tiny
|
|
493
|
+
Registry Hub plugin backed by `@lorion-org/registry-hub`, and the shop registry
|
|
494
|
+
item type. Shop extensions depend on `shops`, register small shop entries
|
|
495
|
+
through that registry, and contribute their own pages, plugins, and server
|
|
496
|
+
routes. The `admin` layer extension provides the admin home route at
|
|
497
|
+
`/` for admin profiles. The technical integration monitor lives at `/tech`.
|
|
498
|
+
|
|
499
|
+
The default profile points to a neutral `web` profile. It starts the shop home
|
|
500
|
+
with both payment-provider extensions mounted as candidates. The playground
|
|
501
|
+
config selects Stripe through `lorion.providers.configuredProviders`, and
|
|
502
|
+
`@lorion-org/provider-selection` publishes the selected provider. `admin` starts
|
|
503
|
+
the admin home without loading the shop or payment-provider extensions.
|
|
504
|
+
|
|
505
|
+
To run variants side by side, select the profile in playground config and pass
|
|
506
|
+
different Nuxt ports:
|
|
507
|
+
|
|
508
|
+
```shell
|
|
509
|
+
pnpm dev:playground -- --port 3037
|
|
510
|
+
pnpm dev:playground -- --port 3039
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Each extension contributes only the Nuxt layer content it needs. The module
|
|
514
|
+
registers selected extensions as Nuxt layers; the playground does not list them
|
|
515
|
+
in `nuxt.config.ts`.
|
|
516
|
+
Provider extensions contribute checkout pages, register a small checkout
|
|
517
|
+
provider implementation through the payments layer interface, and expose server
|
|
518
|
+
routes. They declare `providesFor: "payment-checkout"`, while the Nuxt module
|
|
519
|
+
options provide the selected preference. Runtime config for checkout, payments,
|
|
520
|
+
and providers is loaded from
|
|
521
|
+
`.runtimeconfig/runtime-config/<scope>/runtime.config.json`.
|
|
522
|
+
|
|
523
|
+
The module also exposes a public `extensionSelection` runtime-config object with
|
|
524
|
+
the selected profile, resolved descriptors, and active layer extension ids. The
|
|
525
|
+
module exposes a public `providerSelection` object with the selected provider,
|
|
526
|
+
candidate providers, selection mode, and excluded providers. The playground reads
|
|
527
|
+
those objects on `/tech` and its demo API returns a minimal view of them from
|
|
528
|
+
`/api/demo/overview`.
|
|
529
|
+
|
|
530
|
+
Demo extensions:
|
|
531
|
+
|
|
532
|
+
- `shop-coffee`
|
|
533
|
+
- `shop-stationery`
|
|
534
|
+
- `shops`
|
|
535
|
+
- `checkout`
|
|
536
|
+
- `payments`
|
|
537
|
+
- `admin`
|
|
538
|
+
- `payment-provider-stripe`
|
|
539
|
+
- `payment-provider-invoice`
|
|
540
|
+
|
|
541
|
+
The playground also shows how the wider package set can work together:
|
|
542
|
+
|
|
543
|
+
- `@lorion-org/descriptor-discovery` discovers `extension.json` files.
|
|
544
|
+
- `@lorion-org/composition-graph` resolves selected profiles to active extensions.
|
|
545
|
+
- `@lorion-org/provider-selection` selects one payment provider from the active provider candidates.
|
|
546
|
+
- `@lorion-org/registry-hub` lets extensions register the small UI entries rendered by the root app.
|
|
547
|
+
- `@lorion-org/runtime-config-node` loads runtime config fragments from disk.
|
|
548
|
+
|
|
549
|
+
The pages read public runtime config in the browser. The server API only returns
|
|
550
|
+
minimal booleans that prove private runtime config is available server-side
|
|
551
|
+
without returning secret values to the client.
|
|
552
|
+
|
|
553
|
+
## Testing
|
|
554
|
+
|
|
555
|
+
The package has three test groups:
|
|
556
|
+
|
|
557
|
+
- unit tests for the adapter helpers and explicit extension activation
|
|
558
|
+
- an end-to-end Nuxt fixture that starts a real Nuxt app with the module
|
|
559
|
+
- typechecked TypeScript examples through the workspace examples check
|
|
560
|
+
|
|
561
|
+
The e2e fixture verifies that `lorion.runtimeConfig` writes values into Nuxt
|
|
562
|
+
runtime config, that a server route can read them back through
|
|
563
|
+
`getPublicNuxtRuntimeConfigScope()`, and that the module auto-imports configured
|
|
564
|
+
runtime-config composables.
|
|
565
|
+
|
|
566
|
+
## Local commands
|
|
567
|
+
|
|
568
|
+
```shell
|
|
569
|
+
cd packages/nuxt
|
|
570
|
+
pnpm build
|
|
571
|
+
pnpm test
|
|
572
|
+
pnpm test:unit
|
|
573
|
+
pnpm test:e2e
|
|
574
|
+
pnpm typecheck
|
|
575
|
+
pnpm typecheck:playground
|
|
576
|
+
pnpm build:playground
|
|
577
|
+
pnpm package:check
|
|
578
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/extension-descriptor.schema.json
|
|
2
|
+
var extension_descriptor_schema_default = {
|
|
3
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
4
|
+
$id: "https://lorion.dev/schemas/nuxt-extension-descriptor.schema.json",
|
|
5
|
+
$ref: "#/$defs/extension",
|
|
6
|
+
$defs: {
|
|
7
|
+
semver: {
|
|
8
|
+
type: "string",
|
|
9
|
+
pattern: "^(\\^|~)?\\d+\\.\\d+\\.\\d+$"
|
|
10
|
+
},
|
|
11
|
+
dependencyMap: {
|
|
12
|
+
type: "object",
|
|
13
|
+
additionalProperties: { $ref: "#/$defs/semver" }
|
|
14
|
+
},
|
|
15
|
+
extension: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
id: {
|
|
19
|
+
type: "string",
|
|
20
|
+
minLength: 1
|
|
21
|
+
},
|
|
22
|
+
version: { $ref: "#/$defs/semver" },
|
|
23
|
+
providesFor: {
|
|
24
|
+
type: "string",
|
|
25
|
+
minLength: 1
|
|
26
|
+
},
|
|
27
|
+
capabilities: {
|
|
28
|
+
type: "array",
|
|
29
|
+
items: {
|
|
30
|
+
type: "string",
|
|
31
|
+
minLength: 1
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
dependencies: { $ref: "#/$defs/dependencyMap" },
|
|
35
|
+
disabled: { type: "boolean" },
|
|
36
|
+
location: { type: "string" },
|
|
37
|
+
providerPreferences: {
|
|
38
|
+
type: "object",
|
|
39
|
+
additionalProperties: {
|
|
40
|
+
type: "string",
|
|
41
|
+
minLength: 1
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
publicRuntimeConfig: {
|
|
45
|
+
type: "object",
|
|
46
|
+
additionalProperties: true
|
|
47
|
+
},
|
|
48
|
+
bundles: {
|
|
49
|
+
type: "array",
|
|
50
|
+
items: { $ref: "#/$defs/extension" }
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
required: ["id", "version"],
|
|
54
|
+
additionalProperties: true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// src/descriptor-schema.ts
|
|
60
|
+
var nuxtExtensionDescriptorSchema = extension_descriptor_schema_default;
|
|
61
|
+
export {
|
|
62
|
+
nuxtExtensionDescriptorSchema
|
|
63
|
+
};
|