@fragno-dev/core 0.1.10 → 0.2.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/.turbo/turbo-build.log +139 -131
- package/CHANGELOG.md +63 -0
- package/dist/api/api.d.ts +23 -5
- package/dist/api/api.d.ts.map +1 -1
- package/dist/api/api.js.map +1 -1
- package/dist/api/fragment-definition-builder.d.ts +17 -7
- package/dist/api/fragment-definition-builder.d.ts.map +1 -1
- package/dist/api/fragment-definition-builder.js +3 -2
- package/dist/api/fragment-definition-builder.js.map +1 -1
- package/dist/api/fragment-instantiator.d.ts +129 -32
- package/dist/api/fragment-instantiator.d.ts.map +1 -1
- package/dist/api/fragment-instantiator.js +232 -50
- package/dist/api/fragment-instantiator.js.map +1 -1
- package/dist/api/request-input-context.d.ts +57 -1
- package/dist/api/request-input-context.d.ts.map +1 -1
- package/dist/api/request-input-context.js +67 -0
- package/dist/api/request-input-context.js.map +1 -1
- package/dist/api/request-middleware.d.ts +1 -1
- package/dist/api/request-middleware.d.ts.map +1 -1
- package/dist/api/request-middleware.js.map +1 -1
- package/dist/api/route.d.ts +7 -7
- package/dist/api/route.d.ts.map +1 -1
- package/dist/api/route.js.map +1 -1
- package/dist/client/client.d.ts +4 -3
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +103 -7
- package/dist/client/client.js.map +1 -1
- package/dist/client/vue.d.ts +7 -3
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +16 -1
- package/dist/client/vue.js.map +1 -1
- package/dist/internal/trace-context.d.ts +23 -0
- package/dist/internal/trace-context.d.ts.map +1 -0
- package/dist/internal/trace-context.js +14 -0
- package/dist/internal/trace-context.js.map +1 -0
- package/dist/mod-client.d.ts +5 -27
- package/dist/mod-client.d.ts.map +1 -1
- package/dist/mod-client.js +50 -13
- package/dist/mod-client.js.map +1 -1
- package/dist/mod.d.ts +4 -3
- package/dist/mod.js +2 -1
- package/dist/runtime.d.ts +15 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +33 -0
- package/dist/runtime.js.map +1 -0
- package/dist/test/test.d.ts +2 -2
- package/dist/test/test.d.ts.map +1 -1
- package/dist/test/test.js.map +1 -1
- package/package.json +31 -18
- package/src/api/api.ts +24 -0
- package/src/api/fragment-definition-builder.ts +36 -17
- package/src/api/fragment-instantiator.test.ts +429 -1
- package/src/api/fragment-instantiator.ts +572 -58
- package/src/api/internal/path-runtime.test.ts +7 -0
- package/src/api/request-input-context.test.ts +152 -0
- package/src/api/request-input-context.ts +85 -0
- package/src/api/request-middleware.test.ts +47 -1
- package/src/api/request-middleware.ts +1 -1
- package/src/api/route.ts +7 -2
- package/src/client/client.test.ts +195 -0
- package/src/client/client.ts +185 -10
- package/src/client/vue.test.ts +253 -3
- package/src/client/vue.ts +44 -1
- package/src/internal/trace-context.ts +35 -0
- package/src/mod-client.ts +89 -9
- package/src/mod.ts +7 -1
- package/src/runtime.ts +48 -0
- package/src/test/test.ts +13 -4
- package/tsdown.config.ts +1 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolveRouteFactories } from "./route.js";
|
|
2
1
|
import { instantiatedFragmentFakeSymbol } from "../internal/symbols.js";
|
|
2
|
+
import { resolveRouteFactories } from "./route.js";
|
|
3
3
|
import { FragnoApiError } from "./error.js";
|
|
4
4
|
import { getMountRoute } from "./internal/route.js";
|
|
5
5
|
import { RequestInputContext } from "./request-input-context.js";
|
|
@@ -9,14 +9,66 @@ import { RequestMiddlewareInputContext, RequestMiddlewareOutputContext } from ".
|
|
|
9
9
|
import { parseFragnoResponse } from "./fragno-response.js";
|
|
10
10
|
import { RequestContextStorage } from "./request-context-storage.js";
|
|
11
11
|
import { bindServicesToContext } from "./bind-services.js";
|
|
12
|
+
import { recordTraceEvent } from "../internal/trace-context.js";
|
|
12
13
|
import { addRoute, createRouter, findRoute } from "rou3";
|
|
13
14
|
|
|
14
15
|
//#region src/api/fragment-instantiator.ts
|
|
16
|
+
const serializeHeadersForTrace = (headers) => Array.from(headers.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
17
|
+
const serializeQueryForTrace = (query) => Array.from(query.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
18
|
+
const serializeBodyForTrace = (body) => {
|
|
19
|
+
if (body instanceof FormData) return {
|
|
20
|
+
type: "form-data",
|
|
21
|
+
entries: Array.from(body.entries()).map(([key, value]) => {
|
|
22
|
+
if (value instanceof Blob) return [key, {
|
|
23
|
+
type: "blob",
|
|
24
|
+
size: value.size,
|
|
25
|
+
mime: value.type
|
|
26
|
+
}];
|
|
27
|
+
return [key, value];
|
|
28
|
+
})
|
|
29
|
+
};
|
|
30
|
+
if (body instanceof Blob) return {
|
|
31
|
+
type: "blob",
|
|
32
|
+
size: body.size,
|
|
33
|
+
mime: body.type
|
|
34
|
+
};
|
|
35
|
+
if (body instanceof ReadableStream) return { type: "stream" };
|
|
36
|
+
return body;
|
|
37
|
+
};
|
|
38
|
+
const INTERNAL_LINKED_FRAGMENT_NAME = "_fragno_internal";
|
|
39
|
+
const INTERNAL_ROUTE_PREFIX = "/_internal";
|
|
40
|
+
function normalizeRoutePrefix(prefix) {
|
|
41
|
+
if (!prefix.startsWith("/")) prefix = `/${prefix}`;
|
|
42
|
+
return prefix.endsWith("/") && prefix.length > 1 ? prefix.slice(0, -1) : prefix;
|
|
43
|
+
}
|
|
44
|
+
function joinRoutePath(prefix, path) {
|
|
45
|
+
const normalizedPrefix = normalizeRoutePrefix(prefix);
|
|
46
|
+
if (!path || path === "/") return normalizedPrefix;
|
|
47
|
+
return `${normalizedPrefix}${path.startsWith("/") ? path : `/${path}`}`;
|
|
48
|
+
}
|
|
49
|
+
function collectLinkedFragmentRoutes(linkedFragments) {
|
|
50
|
+
const linkedRoutes = [];
|
|
51
|
+
for (const [name, fragment] of Object.entries(linkedFragments)) {
|
|
52
|
+
if (name !== INTERNAL_LINKED_FRAGMENT_NAME) continue;
|
|
53
|
+
const internalRoutes = fragment.routes ?? [];
|
|
54
|
+
if (internalRoutes.length === 0) continue;
|
|
55
|
+
for (const route of internalRoutes) linkedRoutes.push({
|
|
56
|
+
...route,
|
|
57
|
+
path: joinRoutePath(INTERNAL_ROUTE_PREFIX, route.path),
|
|
58
|
+
__internal: {
|
|
59
|
+
fragment,
|
|
60
|
+
originalPath: route.path,
|
|
61
|
+
routes: internalRoutes
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return linkedRoutes;
|
|
66
|
+
}
|
|
15
67
|
/**
|
|
16
68
|
* Instantiated fragment class with encapsulated state.
|
|
17
69
|
* Provides the same public API as the old FragnoInstantiatedFragment but with better encapsulation.
|
|
18
70
|
*/
|
|
19
|
-
var FragnoInstantiatedFragment = class {
|
|
71
|
+
var FragnoInstantiatedFragment = class FragnoInstantiatedFragment {
|
|
20
72
|
[instantiatedFragmentFakeSymbol] = instantiatedFragmentFakeSymbol;
|
|
21
73
|
#name;
|
|
22
74
|
#routes;
|
|
@@ -31,6 +83,7 @@ var FragnoInstantiatedFragment = class {
|
|
|
31
83
|
#createRequestStorage;
|
|
32
84
|
#options;
|
|
33
85
|
#linkedFragments;
|
|
86
|
+
#internalData;
|
|
34
87
|
constructor(params) {
|
|
35
88
|
this.#name = params.name;
|
|
36
89
|
this.#routes = params.routes;
|
|
@@ -43,6 +96,7 @@ var FragnoInstantiatedFragment = class {
|
|
|
43
96
|
this.#createRequestStorage = params.createRequestStorage;
|
|
44
97
|
this.#options = params.options;
|
|
45
98
|
this.#linkedFragments = params.linkedFragments ?? {};
|
|
99
|
+
this.#internalData = params.internalData ?? {};
|
|
46
100
|
this.#router = createRouter();
|
|
47
101
|
for (const routeConfig of this.#routes) addRoute(this.#router, routeConfig.method.toUpperCase(), routeConfig.path, routeConfig);
|
|
48
102
|
this.handler = this.handler.bind(this);
|
|
@@ -66,7 +120,8 @@ var FragnoInstantiatedFragment = class {
|
|
|
66
120
|
return {
|
|
67
121
|
deps: this.#deps,
|
|
68
122
|
options: this.#options,
|
|
69
|
-
linkedFragments: this.#linkedFragments
|
|
123
|
+
linkedFragments: this.#linkedFragments,
|
|
124
|
+
...this.#internalData
|
|
70
125
|
};
|
|
71
126
|
}
|
|
72
127
|
/**
|
|
@@ -160,26 +215,65 @@ var FragnoInstantiatedFragment = class {
|
|
|
160
215
|
error: `Fragno: Route for '${this.#name}' not found`,
|
|
161
216
|
code: "ROUTE_NOT_FOUND"
|
|
162
217
|
}, { status: 404 });
|
|
218
|
+
const routeConfig = route.data;
|
|
219
|
+
const expectedContentType = routeConfig.contentType ?? "application/json";
|
|
163
220
|
let requestBody = void 0;
|
|
164
221
|
let rawBody = void 0;
|
|
165
222
|
if (req.body instanceof ReadableStream) {
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
223
|
+
const requestContentType = (req.headers.get("content-type") ?? "").toLowerCase();
|
|
224
|
+
if (expectedContentType === "multipart/form-data") {
|
|
225
|
+
if (!requestContentType.includes("multipart/form-data")) return Response.json({
|
|
226
|
+
error: `This endpoint expects multipart/form-data, but received: ${requestContentType || "no content-type"}`,
|
|
227
|
+
code: "UNSUPPORTED_MEDIA_TYPE"
|
|
228
|
+
}, { status: 415 });
|
|
229
|
+
try {
|
|
230
|
+
requestBody = await req.formData();
|
|
231
|
+
} catch {
|
|
232
|
+
return Response.json({
|
|
233
|
+
error: "Failed to parse multipart form data",
|
|
234
|
+
code: "INVALID_REQUEST_BODY"
|
|
235
|
+
}, { status: 400 });
|
|
236
|
+
}
|
|
237
|
+
} else if (expectedContentType === "application/octet-stream") {
|
|
238
|
+
if (!requestContentType.includes("application/octet-stream")) return Response.json({
|
|
239
|
+
error: `This endpoint expects application/octet-stream, but received: ${requestContentType || "no content-type"}`,
|
|
240
|
+
code: "UNSUPPORTED_MEDIA_TYPE"
|
|
241
|
+
}, { status: 415 });
|
|
242
|
+
requestBody = req.body ?? new ReadableStream();
|
|
243
|
+
} else {
|
|
244
|
+
if (requestContentType.includes("multipart/form-data")) return Response.json({
|
|
245
|
+
error: `This endpoint expects JSON, but received multipart/form-data. Use a route with contentType: "multipart/form-data" for file uploads.`,
|
|
246
|
+
code: "UNSUPPORTED_MEDIA_TYPE"
|
|
247
|
+
}, { status: 415 });
|
|
248
|
+
rawBody = await req.clone().text();
|
|
249
|
+
if (rawBody) try {
|
|
250
|
+
requestBody = JSON.parse(rawBody);
|
|
251
|
+
} catch {
|
|
252
|
+
requestBody = void 0;
|
|
253
|
+
}
|
|
171
254
|
}
|
|
172
255
|
}
|
|
256
|
+
const decodedRouteParams = {};
|
|
257
|
+
for (const [key, value] of Object.entries(route.params ?? {})) decodedRouteParams[key] = decodeURIComponent(value);
|
|
173
258
|
const requestState = new MutableRequestState({
|
|
174
|
-
pathParams:
|
|
259
|
+
pathParams: decodedRouteParams,
|
|
175
260
|
searchParams: url.searchParams,
|
|
176
261
|
body: requestBody,
|
|
177
262
|
headers: new Headers(req.headers)
|
|
178
263
|
});
|
|
179
264
|
const executeRequest = async () => {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
265
|
+
const middlewareResult = await this.#executeMiddleware(req, route, requestState);
|
|
266
|
+
if (middlewareResult !== void 0) return middlewareResult;
|
|
267
|
+
const internalMeta = routeConfig.__internal;
|
|
268
|
+
if (internalMeta) {
|
|
269
|
+
const internalResult = await FragnoInstantiatedFragment.#runMiddlewareForFragment(internalMeta.fragment, {
|
|
270
|
+
req,
|
|
271
|
+
method: routeConfig.method,
|
|
272
|
+
path: internalMeta.originalPath,
|
|
273
|
+
requestState,
|
|
274
|
+
routes: internalMeta.routes
|
|
275
|
+
});
|
|
276
|
+
if (internalResult !== void 0) return internalResult;
|
|
183
277
|
}
|
|
184
278
|
return this.#executeHandler(req, route, requestState, rawBody);
|
|
185
279
|
};
|
|
@@ -215,6 +309,15 @@ var FragnoInstantiatedFragment = class {
|
|
|
215
309
|
inputSchema: route.inputSchema,
|
|
216
310
|
shouldValidateInput: true
|
|
217
311
|
});
|
|
312
|
+
recordTraceEvent({
|
|
313
|
+
type: "route-input",
|
|
314
|
+
method: route.method,
|
|
315
|
+
path: route.path,
|
|
316
|
+
pathParams: pathParams ?? {},
|
|
317
|
+
queryParams: serializeQueryForTrace(searchParams),
|
|
318
|
+
headers: serializeHeadersForTrace(requestHeaders),
|
|
319
|
+
body: serializeBodyForTrace(body)
|
|
320
|
+
});
|
|
218
321
|
const outputContext = new RequestOutputContext(route.outputSchema);
|
|
219
322
|
const executeHandler = async () => {
|
|
220
323
|
try {
|
|
@@ -236,20 +339,43 @@ var FragnoInstantiatedFragment = class {
|
|
|
236
339
|
* Returns undefined if middleware allows the request to continue to the handler.
|
|
237
340
|
*/
|
|
238
341
|
async #executeMiddleware(req, route, requestState) {
|
|
239
|
-
if (!
|
|
342
|
+
if (!route) return;
|
|
240
343
|
const { path } = route.data;
|
|
241
|
-
|
|
344
|
+
return FragnoInstantiatedFragment.#runMiddlewareForFragment(this, {
|
|
345
|
+
req,
|
|
242
346
|
method: req.method,
|
|
243
347
|
path,
|
|
244
|
-
|
|
245
|
-
state: requestState
|
|
348
|
+
requestState
|
|
246
349
|
});
|
|
247
|
-
|
|
350
|
+
}
|
|
351
|
+
static async #runMiddlewareForFragment(fragment, options) {
|
|
352
|
+
if (!fragment.#middlewareHandler) return;
|
|
353
|
+
const middlewareInputContext = new RequestMiddlewareInputContext(options.routes ?? fragment.#routes, {
|
|
354
|
+
method: options.method,
|
|
355
|
+
path: options.path,
|
|
356
|
+
request: options.req,
|
|
357
|
+
state: options.requestState
|
|
358
|
+
});
|
|
359
|
+
const middlewareOutputContext = new RequestMiddlewareOutputContext(fragment.#deps, fragment.#services);
|
|
248
360
|
try {
|
|
249
|
-
const middlewareResult = await
|
|
361
|
+
const middlewareResult = await fragment.#middlewareHandler(middlewareInputContext, middlewareOutputContext);
|
|
362
|
+
recordTraceEvent({
|
|
363
|
+
type: "middleware-decision",
|
|
364
|
+
method: options.method,
|
|
365
|
+
path: options.path,
|
|
366
|
+
outcome: middlewareResult ? "deny" : "allow",
|
|
367
|
+
status: middlewareResult?.status
|
|
368
|
+
});
|
|
250
369
|
if (middlewareResult !== void 0) return middlewareResult;
|
|
251
370
|
} catch (error) {
|
|
252
371
|
console.error("Error in middleware", error);
|
|
372
|
+
recordTraceEvent({
|
|
373
|
+
type: "middleware-decision",
|
|
374
|
+
method: options.method,
|
|
375
|
+
path: options.path,
|
|
376
|
+
outcome: "deny",
|
|
377
|
+
status: error instanceof FragnoApiError ? error.status : 500
|
|
378
|
+
});
|
|
253
379
|
if (error instanceof FragnoApiError) return error.toResponse();
|
|
254
380
|
return Response.json({
|
|
255
381
|
error: "Internal server error",
|
|
@@ -275,6 +401,15 @@ var FragnoInstantiatedFragment = class {
|
|
|
275
401
|
state: requestState,
|
|
276
402
|
rawBody
|
|
277
403
|
});
|
|
404
|
+
recordTraceEvent({
|
|
405
|
+
type: "route-input",
|
|
406
|
+
method: req.method,
|
|
407
|
+
path,
|
|
408
|
+
pathParams: inputContext.pathParams,
|
|
409
|
+
queryParams: serializeQueryForTrace(requestState.searchParams),
|
|
410
|
+
headers: serializeHeadersForTrace(requestState.headers),
|
|
411
|
+
body: serializeBodyForTrace(requestState.body)
|
|
412
|
+
});
|
|
278
413
|
const outputContext = new RequestOutputContext(outputSchema);
|
|
279
414
|
try {
|
|
280
415
|
const contextForHandler = this.#handlerThisContext ?? {};
|
|
@@ -293,17 +428,26 @@ var FragnoInstantiatedFragment = class {
|
|
|
293
428
|
* Core instantiation function that creates a fragment instance from a definition.
|
|
294
429
|
* This function validates dependencies, calls all callbacks, and wires everything together.
|
|
295
430
|
*/
|
|
296
|
-
function instantiateFragment(definition, config, routesOrFactories, options, serviceImplementations) {
|
|
431
|
+
function instantiateFragment(definition, config, routesOrFactories, options, serviceImplementations, instantiationOptions) {
|
|
432
|
+
const { dryRun = false } = instantiationOptions ?? {};
|
|
297
433
|
const serviceDependencies = definition.serviceDependencies;
|
|
298
434
|
if (serviceDependencies) for (const [serviceName, meta] of Object.entries(serviceDependencies)) {
|
|
299
435
|
const metadata = meta;
|
|
300
436
|
const implementation = serviceImplementations?.[serviceName];
|
|
301
437
|
if (metadata.required && !implementation) throw new Error(`Fragment '${definition.name}' requires service '${metadata.name}' but it was not provided`);
|
|
302
438
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
439
|
+
let deps;
|
|
440
|
+
try {
|
|
441
|
+
deps = definition.dependencies?.({
|
|
442
|
+
config,
|
|
443
|
+
options
|
|
444
|
+
}) ?? {};
|
|
445
|
+
} catch (error) {
|
|
446
|
+
if (dryRun) {
|
|
447
|
+
console.warn("Warning: Failed to initialize dependencies in dry run mode:", error instanceof Error ? error.message : String(error));
|
|
448
|
+
deps = {};
|
|
449
|
+
} else throw error;
|
|
450
|
+
}
|
|
307
451
|
const linkedFragmentInstances = {};
|
|
308
452
|
const linkedFragmentServices = {};
|
|
309
453
|
if (definition.linkedFragments) for (const [name, callback] of Object.entries(definition.linkedFragments)) {
|
|
@@ -318,31 +462,59 @@ function instantiateFragment(definition, config, routesOrFactories, options, ser
|
|
|
318
462
|
}
|
|
319
463
|
const defineService = (services$1) => services$1;
|
|
320
464
|
const privateServices = { ...linkedFragmentServices };
|
|
321
|
-
if (definition.privateServices) for (const [serviceName, factory] of Object.entries(definition.privateServices))
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
465
|
+
if (definition.privateServices) for (const [serviceName, factory] of Object.entries(definition.privateServices)) {
|
|
466
|
+
const serviceFactory = factory;
|
|
467
|
+
try {
|
|
468
|
+
privateServices[serviceName] = serviceFactory({
|
|
469
|
+
config,
|
|
470
|
+
options,
|
|
471
|
+
deps,
|
|
472
|
+
serviceDeps: serviceImplementations ?? {},
|
|
473
|
+
privateServices,
|
|
474
|
+
defineService
|
|
475
|
+
});
|
|
476
|
+
} catch (error) {
|
|
477
|
+
if (dryRun) {
|
|
478
|
+
console.warn(`Warning: Failed to initialize private service '${serviceName}' in dry run mode:`, error instanceof Error ? error.message : String(error));
|
|
479
|
+
privateServices[serviceName] = {};
|
|
480
|
+
} else throw error;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
let baseServices;
|
|
484
|
+
try {
|
|
485
|
+
baseServices = definition.baseServices?.({
|
|
486
|
+
config,
|
|
487
|
+
options,
|
|
488
|
+
deps,
|
|
489
|
+
serviceDeps: serviceImplementations ?? {},
|
|
490
|
+
privateServices,
|
|
491
|
+
defineService
|
|
492
|
+
}) ?? {};
|
|
493
|
+
} catch (error) {
|
|
494
|
+
if (dryRun) {
|
|
495
|
+
console.warn("Warning: Failed to initialize base services in dry run mode:", error instanceof Error ? error.message : String(error));
|
|
496
|
+
baseServices = {};
|
|
497
|
+
} else throw error;
|
|
498
|
+
}
|
|
337
499
|
const namedServices = {};
|
|
338
|
-
if (definition.namedServices) for (const [serviceName, factory] of Object.entries(definition.namedServices))
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
500
|
+
if (definition.namedServices) for (const [serviceName, factory] of Object.entries(definition.namedServices)) {
|
|
501
|
+
const serviceFactory = factory;
|
|
502
|
+
try {
|
|
503
|
+
namedServices[serviceName] = serviceFactory({
|
|
504
|
+
config,
|
|
505
|
+
options,
|
|
506
|
+
deps,
|
|
507
|
+
serviceDeps: serviceImplementations ?? {},
|
|
508
|
+
privateServices,
|
|
509
|
+
defineService
|
|
510
|
+
});
|
|
511
|
+
} catch (error) {
|
|
512
|
+
if (dryRun) {
|
|
513
|
+
console.warn(`Warning: Failed to initialize service '${serviceName}' in dry run mode:`, error instanceof Error ? error.message : String(error));
|
|
514
|
+
namedServices[serviceName] = {};
|
|
515
|
+
} else throw error;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
346
518
|
const services = {
|
|
347
519
|
...baseServices,
|
|
348
520
|
...namedServices
|
|
@@ -360,6 +532,12 @@ function instantiateFragment(definition, config, routesOrFactories, options, ser
|
|
|
360
532
|
});
|
|
361
533
|
const serviceContext = contexts?.serviceContext;
|
|
362
534
|
const handlerContext = contexts?.handlerContext;
|
|
535
|
+
const internalData = definition.internalDataFactory?.({
|
|
536
|
+
config,
|
|
537
|
+
options,
|
|
538
|
+
deps,
|
|
539
|
+
linkedFragments: linkedFragmentInstances
|
|
540
|
+
}) ?? {};
|
|
363
541
|
const boundServices = serviceContext ? bindServicesToContext(services, serviceContext) : services;
|
|
364
542
|
const routes = resolveRouteFactories({
|
|
365
543
|
config,
|
|
@@ -367,6 +545,8 @@ function instantiateFragment(definition, config, routesOrFactories, options, ser
|
|
|
367
545
|
services: boundServices,
|
|
368
546
|
serviceDeps: serviceImplementations ?? {}
|
|
369
547
|
}, routesOrFactories);
|
|
548
|
+
const linkedRoutes = collectLinkedFragmentRoutes(linkedFragmentInstances);
|
|
549
|
+
const finalRoutes = linkedRoutes.length > 0 ? [...routes, ...linkedRoutes] : routes;
|
|
370
550
|
const mountRoute = getMountRoute({
|
|
371
551
|
name: definition.name,
|
|
372
552
|
mountRoute: options.mountRoute
|
|
@@ -378,7 +558,7 @@ function instantiateFragment(definition, config, routesOrFactories, options, ser
|
|
|
378
558
|
}) : void 0;
|
|
379
559
|
return new FragnoInstantiatedFragment({
|
|
380
560
|
name: definition.name,
|
|
381
|
-
routes,
|
|
561
|
+
routes: finalRoutes,
|
|
382
562
|
deps,
|
|
383
563
|
services: boundServices,
|
|
384
564
|
mountRoute,
|
|
@@ -387,7 +567,8 @@ function instantiateFragment(definition, config, routesOrFactories, options, ser
|
|
|
387
567
|
storage,
|
|
388
568
|
createRequestStorage: createRequestStorageWithContext,
|
|
389
569
|
options,
|
|
390
|
-
linkedFragments: linkedFragmentInstances
|
|
570
|
+
linkedFragments: linkedFragmentInstances,
|
|
571
|
+
internalData
|
|
391
572
|
});
|
|
392
573
|
}
|
|
393
574
|
/**
|
|
@@ -463,7 +644,8 @@ var FragmentInstantiationBuilder = class FragmentInstantiationBuilder {
|
|
|
463
644
|
* Build and return the instantiated fragment
|
|
464
645
|
*/
|
|
465
646
|
build() {
|
|
466
|
-
|
|
647
|
+
const dryRun = process.env["FRAGNO_INIT_DRY_RUN"] === "true";
|
|
648
|
+
return instantiateFragment(this.#definition, this.#config ?? {}, this.#routes ?? [], this.#options ?? {}, this.#services, { dryRun });
|
|
467
649
|
}
|
|
468
650
|
};
|
|
469
651
|
/**
|