@fragno-dev/db 0.1.13 → 0.1.15
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 +179 -132
- package/CHANGELOG.md +30 -0
- package/dist/adapters/adapters.d.ts +27 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +5 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +15 -3
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +7 -5
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +76 -44
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +23 -16
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-executor.js +18 -7
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
- package/dist/adapters/drizzle/generate.d.ts +4 -1
- package/dist/adapters/drizzle/generate.d.ts.map +1 -1
- package/dist/adapters/drizzle/generate.js +11 -18
- package/dist/adapters/drizzle/generate.js.map +1 -1
- package/dist/adapters/drizzle/shared.d.ts +14 -1
- package/dist/adapters/drizzle/shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +5 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +14 -3
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/kysely/kysely-query-builder.js +1 -1
- package/dist/adapters/kysely/kysely-query-compiler.js +3 -2
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-query.d.ts +1 -0
- package/dist/adapters/kysely/kysely-query.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-query.js +28 -19
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.d.ts +14 -0
- package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-shared.js +16 -1
- package/dist/adapters/kysely/kysely-shared.js.map +1 -1
- package/dist/adapters/kysely/kysely-uow-compiler.js +68 -16
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-uow-executor.js +8 -4
- package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -1
- package/dist/adapters/kysely/migration/execute-base.js +1 -1
- package/dist/adapters/kysely/migration/execute-base.js.map +1 -1
- package/dist/db-fragment-definition-builder.d.ts +152 -0
- package/dist/db-fragment-definition-builder.d.ts.map +1 -0
- package/dist/db-fragment-definition-builder.js +137 -0
- package/dist/db-fragment-definition-builder.js.map +1 -0
- package/dist/fragments/internal-fragment.d.ts +19 -0
- package/dist/fragments/internal-fragment.d.ts.map +1 -0
- package/dist/fragments/internal-fragment.js +39 -0
- package/dist/fragments/internal-fragment.js.map +1 -0
- package/dist/migration-engine/generation-engine.d.ts.map +1 -1
- package/dist/migration-engine/generation-engine.js +35 -15
- package/dist/migration-engine/generation-engine.js.map +1 -1
- package/dist/mod.d.ts +8 -18
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +7 -34
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js +165 -0
- package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +1 -0
- package/dist/packages/fragno/dist/api/bind-services.js +20 -0
- package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
- package/dist/packages/fragno/dist/api/error.js +48 -0
- package/dist/packages/fragno/dist/api/error.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
- package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js +487 -0
- package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
- package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
- package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
- package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
- package/dist/packages/fragno/dist/api/internal/route.js +10 -0
- package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
- package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
- package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
- package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
- package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
- package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
- package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
- package/dist/packages/fragno/dist/api/route.js +17 -0
- package/dist/packages/fragno/dist/api/route.js.map +1 -0
- package/dist/packages/fragno/dist/internal/symbols.js +10 -0
- package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
- package/dist/query/cursor.d.ts +10 -2
- package/dist/query/cursor.d.ts.map +1 -1
- package/dist/query/cursor.js +11 -4
- package/dist/query/cursor.js.map +1 -1
- package/dist/query/execute-unit-of-work.d.ts +123 -0
- package/dist/query/execute-unit-of-work.d.ts.map +1 -0
- package/dist/query/execute-unit-of-work.js +184 -0
- package/dist/query/execute-unit-of-work.js.map +1 -0
- package/dist/query/query.d.ts +3 -3
- package/dist/query/query.d.ts.map +1 -1
- package/dist/query/result-transform.js +4 -2
- package/dist/query/result-transform.js.map +1 -1
- package/dist/query/retry-policy.d.ts +88 -0
- package/dist/query/retry-policy.d.ts.map +1 -0
- package/dist/query/retry-policy.js +61 -0
- package/dist/query/retry-policy.js.map +1 -0
- package/dist/query/unit-of-work.d.ts +171 -32
- package/dist/query/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work.js +530 -133
- package/dist/query/unit-of-work.js.map +1 -1
- package/dist/schema/serialize.js +12 -7
- package/dist/schema/serialize.js.map +1 -1
- package/dist/with-database.d.ts +28 -0
- package/dist/with-database.d.ts.map +1 -0
- package/dist/with-database.js +34 -0
- package/dist/with-database.js.map +1 -0
- package/package.json +10 -3
- package/src/adapters/adapters.ts +30 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +86 -17
- package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +291 -7
- package/src/adapters/drizzle/drizzle-adapter.test.ts +3 -51
- package/src/adapters/drizzle/drizzle-adapter.ts +35 -7
- package/src/adapters/drizzle/drizzle-query.ts +25 -15
- package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +1442 -0
- package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +1414 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +78 -61
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +123 -42
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +34 -27
- package/src/adapters/drizzle/drizzle-uow-executor.ts +41 -8
- package/src/adapters/drizzle/generate.test.ts +102 -269
- package/src/adapters/drizzle/generate.ts +12 -30
- package/src/adapters/drizzle/test-utils.ts +36 -5
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +66 -22
- package/src/adapters/kysely/kysely-adapter-sqlite.test.ts +156 -0
- package/src/adapters/kysely/kysely-adapter.ts +25 -2
- package/src/adapters/kysely/kysely-query-compiler.ts +3 -8
- package/src/adapters/kysely/kysely-query.ts +57 -37
- package/src/adapters/kysely/kysely-shared.ts +34 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +62 -74
- package/src/adapters/kysely/kysely-uow-compiler.ts +92 -24
- package/src/adapters/kysely/kysely-uow-executor.ts +26 -7
- package/src/adapters/kysely/kysely-uow-joins.test.ts +33 -50
- package/src/adapters/kysely/migration/execute-base.ts +1 -1
- package/src/db-fragment-definition-builder.test.ts +887 -0
- package/src/db-fragment-definition-builder.ts +506 -0
- package/src/db-fragment-instantiator.test.ts +467 -0
- package/src/db-fragment-integration.test.ts +408 -0
- package/src/fragments/internal-fragment.test.ts +160 -0
- package/src/fragments/internal-fragment.ts +85 -0
- package/src/migration-engine/generation-engine.test.ts +58 -15
- package/src/migration-engine/generation-engine.ts +78 -25
- package/src/mod.ts +35 -43
- package/src/query/cursor.test.ts +119 -0
- package/src/query/cursor.ts +17 -4
- package/src/query/execute-unit-of-work.test.ts +1310 -0
- package/src/query/execute-unit-of-work.ts +463 -0
- package/src/query/query.ts +4 -4
- package/src/query/result-transform.test.ts +129 -0
- package/src/query/result-transform.ts +4 -1
- package/src/query/retry-policy.test.ts +217 -0
- package/src/query/retry-policy.ts +141 -0
- package/src/query/unit-of-work-coordinator.test.ts +833 -0
- package/src/query/unit-of-work-types.test.ts +15 -2
- package/src/query/unit-of-work.test.ts +878 -200
- package/src/query/unit-of-work.ts +963 -321
- package/src/schema/serialize.ts +22 -11
- package/src/with-database.ts +140 -0
- package/tsdown.config.ts +1 -0
- package/dist/fragment.d.ts +0 -54
- package/dist/fragment.d.ts.map +0 -1
- package/dist/fragment.js +0 -92
- package/dist/fragment.js.map +0 -1
- package/dist/shared/settings-schema.js +0 -36
- package/dist/shared/settings-schema.js.map +0 -1
- package/src/fragment.test.ts +0 -341
- package/src/fragment.ts +0 -198
- package/src/shared/settings-schema.ts +0 -61
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { resolveRouteFactories } from "./route.js";
|
|
2
|
+
import { instantiatedFragmentFakeSymbol } from "../internal/symbols.js";
|
|
3
|
+
import { FragnoApiError } from "./error.js";
|
|
4
|
+
import { getMountRoute } from "./internal/route.js";
|
|
5
|
+
import { RequestInputContext } from "./request-input-context.js";
|
|
6
|
+
import { RequestOutputContext } from "./request-output-context.js";
|
|
7
|
+
import { MutableRequestState } from "./mutable-request-state.js";
|
|
8
|
+
import { RequestMiddlewareInputContext, RequestMiddlewareOutputContext } from "./request-middleware.js";
|
|
9
|
+
import { parseFragnoResponse } from "./fragno-response.js";
|
|
10
|
+
import { RequestContextStorage } from "./request-context-storage.js";
|
|
11
|
+
import { bindServicesToContext } from "./bind-services.js";
|
|
12
|
+
import { addRoute, createRouter, findRoute } from "../../../../node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js";
|
|
13
|
+
|
|
14
|
+
//#region ../fragno/dist/api/fragment-instantiator.js
|
|
15
|
+
/**
|
|
16
|
+
* Instantiated fragment class with encapsulated state.
|
|
17
|
+
* Provides the same public API as the old FragnoInstantiatedFragment but with better encapsulation.
|
|
18
|
+
*/
|
|
19
|
+
var FragnoInstantiatedFragment = class {
|
|
20
|
+
[instantiatedFragmentFakeSymbol] = instantiatedFragmentFakeSymbol;
|
|
21
|
+
#name;
|
|
22
|
+
#routes;
|
|
23
|
+
#deps;
|
|
24
|
+
#services;
|
|
25
|
+
#mountRoute;
|
|
26
|
+
#router;
|
|
27
|
+
#middlewareHandler;
|
|
28
|
+
#serviceThisContext;
|
|
29
|
+
#handlerThisContext;
|
|
30
|
+
#contextStorage;
|
|
31
|
+
#createRequestStorage;
|
|
32
|
+
#options;
|
|
33
|
+
#linkedFragments;
|
|
34
|
+
constructor(params) {
|
|
35
|
+
this.#name = params.name;
|
|
36
|
+
this.#routes = params.routes;
|
|
37
|
+
this.#deps = params.deps;
|
|
38
|
+
this.#services = params.services;
|
|
39
|
+
this.#mountRoute = params.mountRoute;
|
|
40
|
+
this.#serviceThisContext = params.serviceThisContext;
|
|
41
|
+
this.#handlerThisContext = params.handlerThisContext;
|
|
42
|
+
this.#contextStorage = params.storage;
|
|
43
|
+
this.#createRequestStorage = params.createRequestStorage;
|
|
44
|
+
this.#options = params.options;
|
|
45
|
+
this.#linkedFragments = params.linkedFragments ?? {};
|
|
46
|
+
this.#router = createRouter();
|
|
47
|
+
for (const routeConfig of this.#routes) addRoute(this.#router, routeConfig.method.toUpperCase(), routeConfig.path, routeConfig);
|
|
48
|
+
this.handler = this.handler.bind(this);
|
|
49
|
+
}
|
|
50
|
+
get name() {
|
|
51
|
+
return this.#name;
|
|
52
|
+
}
|
|
53
|
+
get routes() {
|
|
54
|
+
return this.#routes;
|
|
55
|
+
}
|
|
56
|
+
get services() {
|
|
57
|
+
return this.#services;
|
|
58
|
+
}
|
|
59
|
+
get mountRoute() {
|
|
60
|
+
return this.#mountRoute;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
get $internal() {
|
|
66
|
+
return {
|
|
67
|
+
deps: this.#deps,
|
|
68
|
+
options: this.#options,
|
|
69
|
+
linkedFragments: this.#linkedFragments
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Add middleware to this fragment.
|
|
74
|
+
* Middleware can inspect and modify requests before they reach handlers.
|
|
75
|
+
*/
|
|
76
|
+
withMiddleware(handler) {
|
|
77
|
+
if (this.#middlewareHandler) throw new Error("Middleware already set");
|
|
78
|
+
this.#middlewareHandler = handler;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
#withRequestStorage(callback) {
|
|
82
|
+
if (!this.#serviceThisContext && !this.#handlerThisContext) return callback();
|
|
83
|
+
const storageData = this.#createRequestStorage ? this.#createRequestStorage() : {};
|
|
84
|
+
return this.#contextStorage.run(storageData, callback);
|
|
85
|
+
}
|
|
86
|
+
inContext(callback) {
|
|
87
|
+
if (this.#handlerThisContext) {
|
|
88
|
+
const boundCallback = callback.bind(this.#handlerThisContext);
|
|
89
|
+
return this.#withRequestStorage(boundCallback);
|
|
90
|
+
}
|
|
91
|
+
return this.#withRequestStorage(callback);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get framework-specific handlers for this fragment.
|
|
95
|
+
* Use this to integrate the fragment with different fullstack frameworks.
|
|
96
|
+
*/
|
|
97
|
+
handlersFor(framework) {
|
|
98
|
+
const handler = this.handler.bind(this);
|
|
99
|
+
if (framework === "h3" || framework === "nuxt") throw new Error(`To get handlers for h3, use the 'fromWebHandler' utility function:
|
|
100
|
+
import { fromWebHandler } from "h3";
|
|
101
|
+
export default fromWebHandler(myFragment().handler);`);
|
|
102
|
+
return {
|
|
103
|
+
astro: { ALL: handler },
|
|
104
|
+
"react-router": {
|
|
105
|
+
loader: ({ request }) => handler(request),
|
|
106
|
+
action: ({ request }) => handler(request)
|
|
107
|
+
},
|
|
108
|
+
"next-js": {
|
|
109
|
+
GET: handler,
|
|
110
|
+
POST: handler,
|
|
111
|
+
PUT: handler,
|
|
112
|
+
DELETE: handler,
|
|
113
|
+
PATCH: handler,
|
|
114
|
+
HEAD: handler,
|
|
115
|
+
OPTIONS: handler
|
|
116
|
+
},
|
|
117
|
+
"svelte-kit": {
|
|
118
|
+
GET: handler,
|
|
119
|
+
POST: handler,
|
|
120
|
+
PUT: handler,
|
|
121
|
+
DELETE: handler,
|
|
122
|
+
PATCH: handler,
|
|
123
|
+
HEAD: handler,
|
|
124
|
+
OPTIONS: handler
|
|
125
|
+
},
|
|
126
|
+
"solid-start": {
|
|
127
|
+
GET: ({ request }) => handler(request),
|
|
128
|
+
POST: ({ request }) => handler(request),
|
|
129
|
+
PUT: ({ request }) => handler(request),
|
|
130
|
+
DELETE: ({ request }) => handler(request),
|
|
131
|
+
PATCH: ({ request }) => handler(request),
|
|
132
|
+
HEAD: ({ request }) => handler(request),
|
|
133
|
+
OPTIONS: ({ request }) => handler(request)
|
|
134
|
+
},
|
|
135
|
+
"tanstack-start": {
|
|
136
|
+
GET: ({ request }) => handler(request),
|
|
137
|
+
POST: ({ request }) => handler(request),
|
|
138
|
+
PUT: ({ request }) => handler(request),
|
|
139
|
+
DELETE: ({ request }) => handler(request),
|
|
140
|
+
PATCH: ({ request }) => handler(request),
|
|
141
|
+
HEAD: ({ request }) => handler(request),
|
|
142
|
+
OPTIONS: ({ request }) => handler(request)
|
|
143
|
+
}
|
|
144
|
+
}[framework];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Main request handler for this fragment.
|
|
148
|
+
* Handles routing, middleware, and error handling.
|
|
149
|
+
*/
|
|
150
|
+
async handler(req) {
|
|
151
|
+
const url = new URL(req.url);
|
|
152
|
+
const pathname = url.pathname;
|
|
153
|
+
const matchRoute = pathname.startsWith(this.#mountRoute) ? pathname.slice(this.#mountRoute.length) : null;
|
|
154
|
+
if (matchRoute === null) return Response.json({
|
|
155
|
+
error: `Fragno: Route for '${this.#name}' not found. Is the fragment mounted on the right route? Expecting: '${this.#mountRoute}'.`,
|
|
156
|
+
code: "ROUTE_NOT_FOUND"
|
|
157
|
+
}, { status: 404 });
|
|
158
|
+
const route = findRoute(this.#router, req.method, matchRoute);
|
|
159
|
+
if (!route) return Response.json({
|
|
160
|
+
error: `Fragno: Route for '${this.#name}' not found`,
|
|
161
|
+
code: "ROUTE_NOT_FOUND"
|
|
162
|
+
}, { status: 404 });
|
|
163
|
+
let requestBody = void 0;
|
|
164
|
+
let rawBody = void 0;
|
|
165
|
+
if (req.body instanceof ReadableStream) {
|
|
166
|
+
rawBody = await req.clone().text();
|
|
167
|
+
if (rawBody) try {
|
|
168
|
+
requestBody = JSON.parse(rawBody);
|
|
169
|
+
} catch {
|
|
170
|
+
requestBody = void 0;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const requestState = new MutableRequestState({
|
|
174
|
+
pathParams: route.params ?? {},
|
|
175
|
+
searchParams: url.searchParams,
|
|
176
|
+
body: requestBody,
|
|
177
|
+
headers: new Headers(req.headers)
|
|
178
|
+
});
|
|
179
|
+
const executeRequest = async () => {
|
|
180
|
+
if (this.#middlewareHandler) {
|
|
181
|
+
const middlewareResult = await this.#executeMiddleware(req, route, requestState);
|
|
182
|
+
if (middlewareResult !== void 0) return middlewareResult;
|
|
183
|
+
}
|
|
184
|
+
return this.#executeHandler(req, route, requestState, rawBody);
|
|
185
|
+
};
|
|
186
|
+
return this.#withRequestStorage(executeRequest);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Call a route directly with typed inputs and outputs.
|
|
190
|
+
* Useful for testing and server-side route calls.
|
|
191
|
+
*/
|
|
192
|
+
async callRoute(method, path, inputOptions) {
|
|
193
|
+
return parseFragnoResponse(await this.callRouteRaw(method, path, inputOptions));
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Call a route directly and get the raw Response object.
|
|
197
|
+
* Useful for testing and server-side route calls.
|
|
198
|
+
*/
|
|
199
|
+
async callRouteRaw(method, path, inputOptions) {
|
|
200
|
+
const route = this.#routes.find((r) => r.method === method && r.path === path);
|
|
201
|
+
if (!route) return Response.json({
|
|
202
|
+
error: `Route ${method} ${path} not found`,
|
|
203
|
+
code: "ROUTE_NOT_FOUND"
|
|
204
|
+
}, { status: 404 });
|
|
205
|
+
const { pathParams = {}, body, query, headers } = inputOptions || {};
|
|
206
|
+
const searchParams = query instanceof URLSearchParams ? query : query ? new URLSearchParams(query) : new URLSearchParams();
|
|
207
|
+
const requestHeaders = headers instanceof Headers ? headers : headers ? new Headers(headers) : new Headers();
|
|
208
|
+
const inputContext = new RequestInputContext({
|
|
209
|
+
path: route.path,
|
|
210
|
+
method: route.method,
|
|
211
|
+
pathParams,
|
|
212
|
+
searchParams,
|
|
213
|
+
headers: requestHeaders,
|
|
214
|
+
parsedBody: body,
|
|
215
|
+
inputSchema: route.inputSchema,
|
|
216
|
+
shouldValidateInput: true
|
|
217
|
+
});
|
|
218
|
+
const outputContext = new RequestOutputContext(route.outputSchema);
|
|
219
|
+
const executeHandler = async () => {
|
|
220
|
+
try {
|
|
221
|
+
const thisContext = this.#handlerThisContext ?? {};
|
|
222
|
+
return await route.handler.call(thisContext, inputContext, outputContext);
|
|
223
|
+
} catch (error) {
|
|
224
|
+
console.error("Error in callRoute handler", error);
|
|
225
|
+
if (error instanceof FragnoApiError) return error.toResponse();
|
|
226
|
+
return Response.json({
|
|
227
|
+
error: "Internal server error",
|
|
228
|
+
code: "INTERNAL_SERVER_ERROR"
|
|
229
|
+
}, { status: 500 });
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
return this.#withRequestStorage(executeHandler);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Execute middleware for a request.
|
|
236
|
+
* Returns undefined if middleware allows the request to continue to the handler.
|
|
237
|
+
*/
|
|
238
|
+
async #executeMiddleware(req, route, requestState) {
|
|
239
|
+
if (!this.#middlewareHandler || !route) return;
|
|
240
|
+
const { path } = route.data;
|
|
241
|
+
const middlewareInputContext = new RequestMiddlewareInputContext(this.#routes, {
|
|
242
|
+
method: req.method,
|
|
243
|
+
path,
|
|
244
|
+
request: req,
|
|
245
|
+
state: requestState
|
|
246
|
+
});
|
|
247
|
+
const middlewareOutputContext = new RequestMiddlewareOutputContext(this.#deps, this.#services);
|
|
248
|
+
try {
|
|
249
|
+
const middlewareResult = await this.#middlewareHandler(middlewareInputContext, middlewareOutputContext);
|
|
250
|
+
if (middlewareResult !== void 0) return middlewareResult;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error("Error in middleware", error);
|
|
253
|
+
if (error instanceof FragnoApiError) return error.toResponse();
|
|
254
|
+
return Response.json({
|
|
255
|
+
error: "Internal server error",
|
|
256
|
+
code: "INTERNAL_SERVER_ERROR"
|
|
257
|
+
}, { status: 500 });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Execute a route handler with proper error handling.
|
|
262
|
+
*/
|
|
263
|
+
async #executeHandler(req, route, requestState, rawBody) {
|
|
264
|
+
if (!route) return Response.json({
|
|
265
|
+
error: "Route not found",
|
|
266
|
+
code: "ROUTE_NOT_FOUND"
|
|
267
|
+
}, { status: 404 });
|
|
268
|
+
const { handler, inputSchema, outputSchema, path } = route.data;
|
|
269
|
+
const inputContext = await RequestInputContext.fromRequest({
|
|
270
|
+
request: req,
|
|
271
|
+
method: req.method,
|
|
272
|
+
path,
|
|
273
|
+
pathParams: route.params ?? {},
|
|
274
|
+
inputSchema,
|
|
275
|
+
state: requestState,
|
|
276
|
+
rawBody
|
|
277
|
+
});
|
|
278
|
+
const outputContext = new RequestOutputContext(outputSchema);
|
|
279
|
+
try {
|
|
280
|
+
const contextForHandler = this.#handlerThisContext ?? {};
|
|
281
|
+
return await handler.call(contextForHandler, inputContext, outputContext);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error("Error in handler", error);
|
|
284
|
+
if (error instanceof FragnoApiError) return error.toResponse();
|
|
285
|
+
return Response.json({
|
|
286
|
+
error: "Internal server error",
|
|
287
|
+
code: "INTERNAL_SERVER_ERROR"
|
|
288
|
+
}, { status: 500 });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Core instantiation function that creates a fragment instance from a definition.
|
|
294
|
+
* This function validates dependencies, calls all callbacks, and wires everything together.
|
|
295
|
+
*/
|
|
296
|
+
function instantiateFragment(definition, config, routesOrFactories, options, serviceImplementations) {
|
|
297
|
+
const serviceDependencies = definition.serviceDependencies;
|
|
298
|
+
if (serviceDependencies) for (const [serviceName, meta] of Object.entries(serviceDependencies)) {
|
|
299
|
+
const metadata = meta;
|
|
300
|
+
const implementation = serviceImplementations?.[serviceName];
|
|
301
|
+
if (metadata.required && !implementation) throw new Error(`Fragment '${definition.name}' requires service '${metadata.name}' but it was not provided`);
|
|
302
|
+
}
|
|
303
|
+
const deps = definition.dependencies?.({
|
|
304
|
+
config,
|
|
305
|
+
options
|
|
306
|
+
}) ?? {};
|
|
307
|
+
const linkedFragmentInstances = {};
|
|
308
|
+
const linkedFragmentServices = {};
|
|
309
|
+
if (definition.linkedFragments) for (const [name, callback] of Object.entries(definition.linkedFragments)) {
|
|
310
|
+
const linkedFragment = callback({
|
|
311
|
+
config,
|
|
312
|
+
options,
|
|
313
|
+
serviceDependencies: serviceImplementations
|
|
314
|
+
});
|
|
315
|
+
linkedFragmentInstances[name] = linkedFragment;
|
|
316
|
+
const services$1 = linkedFragment.services;
|
|
317
|
+
for (const [serviceName, service] of Object.entries(services$1)) linkedFragmentServices[serviceName] = service;
|
|
318
|
+
}
|
|
319
|
+
const defineService = (services$1) => services$1;
|
|
320
|
+
const privateServices = { ...linkedFragmentServices };
|
|
321
|
+
if (definition.privateServices) for (const [serviceName, factory] of Object.entries(definition.privateServices)) privateServices[serviceName] = factory({
|
|
322
|
+
config,
|
|
323
|
+
options,
|
|
324
|
+
deps,
|
|
325
|
+
serviceDeps: serviceImplementations ?? {},
|
|
326
|
+
privateServices,
|
|
327
|
+
defineService
|
|
328
|
+
});
|
|
329
|
+
const baseServices = definition.baseServices?.({
|
|
330
|
+
config,
|
|
331
|
+
options,
|
|
332
|
+
deps,
|
|
333
|
+
serviceDeps: serviceImplementations ?? {},
|
|
334
|
+
privateServices,
|
|
335
|
+
defineService
|
|
336
|
+
}) ?? {};
|
|
337
|
+
const namedServices = {};
|
|
338
|
+
if (definition.namedServices) for (const [serviceName, factory] of Object.entries(definition.namedServices)) namedServices[serviceName] = factory({
|
|
339
|
+
config,
|
|
340
|
+
options,
|
|
341
|
+
deps,
|
|
342
|
+
serviceDeps: serviceImplementations ?? {},
|
|
343
|
+
privateServices,
|
|
344
|
+
defineService
|
|
345
|
+
});
|
|
346
|
+
const services = {
|
|
347
|
+
...baseServices,
|
|
348
|
+
...namedServices
|
|
349
|
+
};
|
|
350
|
+
const storage = definition.getExternalStorage ? definition.getExternalStorage({
|
|
351
|
+
config,
|
|
352
|
+
options,
|
|
353
|
+
deps
|
|
354
|
+
}) : new RequestContextStorage();
|
|
355
|
+
const contexts = definition.createThisContext?.({
|
|
356
|
+
config,
|
|
357
|
+
options,
|
|
358
|
+
deps,
|
|
359
|
+
storage
|
|
360
|
+
});
|
|
361
|
+
const serviceContext = contexts?.serviceContext;
|
|
362
|
+
const handlerContext = contexts?.handlerContext;
|
|
363
|
+
const boundServices = serviceContext ? bindServicesToContext(services, serviceContext) : services;
|
|
364
|
+
const routes = resolveRouteFactories({
|
|
365
|
+
config,
|
|
366
|
+
deps,
|
|
367
|
+
services: boundServices,
|
|
368
|
+
serviceDeps: serviceImplementations ?? {}
|
|
369
|
+
}, routesOrFactories);
|
|
370
|
+
const mountRoute = getMountRoute({
|
|
371
|
+
name: definition.name,
|
|
372
|
+
mountRoute: options.mountRoute
|
|
373
|
+
});
|
|
374
|
+
const createRequestStorageWithContext = definition.createRequestStorage ? () => definition.createRequestStorage({
|
|
375
|
+
config,
|
|
376
|
+
options,
|
|
377
|
+
deps
|
|
378
|
+
}) : void 0;
|
|
379
|
+
return new FragnoInstantiatedFragment({
|
|
380
|
+
name: definition.name,
|
|
381
|
+
routes,
|
|
382
|
+
deps,
|
|
383
|
+
services: boundServices,
|
|
384
|
+
mountRoute,
|
|
385
|
+
serviceThisContext: serviceContext,
|
|
386
|
+
handlerThisContext: handlerContext,
|
|
387
|
+
storage,
|
|
388
|
+
createRequestStorage: createRequestStorageWithContext,
|
|
389
|
+
options,
|
|
390
|
+
linkedFragments: linkedFragmentInstances
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Fluent builder for instantiating fragments.
|
|
395
|
+
* Provides a type-safe API for configuring and building fragment instances.
|
|
396
|
+
*/
|
|
397
|
+
var FragmentInstantiationBuilder = class FragmentInstantiationBuilder$1 {
|
|
398
|
+
#definition;
|
|
399
|
+
#config;
|
|
400
|
+
#routes;
|
|
401
|
+
#options;
|
|
402
|
+
#services;
|
|
403
|
+
constructor(definition, routes) {
|
|
404
|
+
this.#definition = definition;
|
|
405
|
+
this.#routes = routes;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get the fragment definition
|
|
409
|
+
*/
|
|
410
|
+
get definition() {
|
|
411
|
+
return this.#definition;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Get the configured routes
|
|
415
|
+
*/
|
|
416
|
+
get routes() {
|
|
417
|
+
return this.#routes ?? [];
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Get the configuration
|
|
421
|
+
*/
|
|
422
|
+
get config() {
|
|
423
|
+
return this.#config;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get the options
|
|
427
|
+
*/
|
|
428
|
+
get options() {
|
|
429
|
+
return this.#options;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Set the configuration for the fragment
|
|
433
|
+
*/
|
|
434
|
+
withConfig(config) {
|
|
435
|
+
this.#config = config;
|
|
436
|
+
return this;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Set the routes for the fragment
|
|
440
|
+
*/
|
|
441
|
+
withRoutes(routes) {
|
|
442
|
+
const newBuilder = new FragmentInstantiationBuilder$1(this.#definition, routes);
|
|
443
|
+
newBuilder.#config = this.#config;
|
|
444
|
+
newBuilder.#options = this.#options;
|
|
445
|
+
newBuilder.#services = this.#services;
|
|
446
|
+
return newBuilder;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Set the options for the fragment (e.g., mountRoute, databaseAdapter)
|
|
450
|
+
*/
|
|
451
|
+
withOptions(options) {
|
|
452
|
+
this.#options = options;
|
|
453
|
+
return this;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Provide implementations for services that this fragment uses
|
|
457
|
+
*/
|
|
458
|
+
withServices(services) {
|
|
459
|
+
this.#services = services;
|
|
460
|
+
return this;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Build and return the instantiated fragment
|
|
464
|
+
*/
|
|
465
|
+
build() {
|
|
466
|
+
return instantiateFragment(this.#definition, this.#config ?? {}, this.#routes ?? [], this.#options ?? {}, this.#services);
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
/**
|
|
470
|
+
* Create a fluent builder for instantiating a fragment.
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* ```ts
|
|
474
|
+
* const fragment = instantiate(myFragmentDefinition)
|
|
475
|
+
* .withConfig({ apiKey: "key" })
|
|
476
|
+
* .withRoutes([route1, route2])
|
|
477
|
+
* .withOptions({ mountRoute: "/api" })
|
|
478
|
+
* .build();
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
function instantiate(definition) {
|
|
482
|
+
return new FragmentInstantiationBuilder(definition);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
//#endregion
|
|
486
|
+
export { instantiate };
|
|
487
|
+
//# sourceMappingURL=fragment-instantiator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragment-instantiator.js","names":["#name","#routes","#deps","#services","#mountRoute","#serviceThisContext","#handlerThisContext","#contextStorage","#createRequestStorage","#options","#linkedFragments","#router","#middlewareHandler","#withRequestStorage","#executeMiddleware","#executeHandler","FragmentInstantiationBuilder","#definition","#config"],"sources":["../../../../../../fragno/dist/api/fragment-instantiator.js"],"sourcesContent":["import { resolveRouteFactories } from \"./route.js\";\nimport { instantiatedFragmentFakeSymbol } from \"../internal/symbols.js\";\nimport { FragnoApiError } from \"./error.js\";\nimport { getMountRoute } from \"./internal/route.js\";\nimport { RequestInputContext } from \"./request-input-context.js\";\nimport { RequestOutputContext } from \"./request-output-context.js\";\nimport { MutableRequestState } from \"./mutable-request-state.js\";\nimport { RequestMiddlewareInputContext, RequestMiddlewareOutputContext } from \"./request-middleware.js\";\nimport { parseFragnoResponse } from \"./fragno-response.js\";\nimport { RequestContextStorage } from \"./request-context-storage.js\";\nimport { bindServicesToContext } from \"./bind-services.js\";\nimport { addRoute, createRouter, findRoute } from \"rou3\";\n\n//#region src/api/fragment-instantiator.ts\n/**\n* Instantiated fragment class with encapsulated state.\n* Provides the same public API as the old FragnoInstantiatedFragment but with better encapsulation.\n*/\nvar FragnoInstantiatedFragment = class {\n\t[instantiatedFragmentFakeSymbol] = instantiatedFragmentFakeSymbol;\n\t#name;\n\t#routes;\n\t#deps;\n\t#services;\n\t#mountRoute;\n\t#router;\n\t#middlewareHandler;\n\t#serviceThisContext;\n\t#handlerThisContext;\n\t#contextStorage;\n\t#createRequestStorage;\n\t#options;\n\t#linkedFragments;\n\tconstructor(params) {\n\t\tthis.#name = params.name;\n\t\tthis.#routes = params.routes;\n\t\tthis.#deps = params.deps;\n\t\tthis.#services = params.services;\n\t\tthis.#mountRoute = params.mountRoute;\n\t\tthis.#serviceThisContext = params.serviceThisContext;\n\t\tthis.#handlerThisContext = params.handlerThisContext;\n\t\tthis.#contextStorage = params.storage;\n\t\tthis.#createRequestStorage = params.createRequestStorage;\n\t\tthis.#options = params.options;\n\t\tthis.#linkedFragments = params.linkedFragments ?? {};\n\t\tthis.#router = createRouter();\n\t\tfor (const routeConfig of this.#routes) addRoute(this.#router, routeConfig.method.toUpperCase(), routeConfig.path, routeConfig);\n\t\tthis.handler = this.handler.bind(this);\n\t}\n\tget name() {\n\t\treturn this.#name;\n\t}\n\tget routes() {\n\t\treturn this.#routes;\n\t}\n\tget services() {\n\t\treturn this.#services;\n\t}\n\tget mountRoute() {\n\t\treturn this.#mountRoute;\n\t}\n\t/**\n\t* @internal\n\t*/\n\tget $internal() {\n\t\treturn {\n\t\t\tdeps: this.#deps,\n\t\t\toptions: this.#options,\n\t\t\tlinkedFragments: this.#linkedFragments\n\t\t};\n\t}\n\t/**\n\t* Add middleware to this fragment.\n\t* Middleware can inspect and modify requests before they reach handlers.\n\t*/\n\twithMiddleware(handler) {\n\t\tif (this.#middlewareHandler) throw new Error(\"Middleware already set\");\n\t\tthis.#middlewareHandler = handler;\n\t\treturn this;\n\t}\n\t#withRequestStorage(callback) {\n\t\tif (!this.#serviceThisContext && !this.#handlerThisContext) return callback();\n\t\tconst storageData = this.#createRequestStorage ? this.#createRequestStorage() : {};\n\t\treturn this.#contextStorage.run(storageData, callback);\n\t}\n\tinContext(callback) {\n\t\tif (this.#handlerThisContext) {\n\t\t\tconst boundCallback = callback.bind(this.#handlerThisContext);\n\t\t\treturn this.#withRequestStorage(boundCallback);\n\t\t}\n\t\treturn this.#withRequestStorage(callback);\n\t}\n\t/**\n\t* Get framework-specific handlers for this fragment.\n\t* Use this to integrate the fragment with different fullstack frameworks.\n\t*/\n\thandlersFor(framework) {\n\t\tconst handler = this.handler.bind(this);\n\t\tif (framework === \"h3\" || framework === \"nuxt\") throw new Error(`To get handlers for h3, use the 'fromWebHandler' utility function:\n import { fromWebHandler } from \"h3\";\n export default fromWebHandler(myFragment().handler);`);\n\t\treturn {\n\t\t\tastro: { ALL: handler },\n\t\t\t\"react-router\": {\n\t\t\t\tloader: ({ request }) => handler(request),\n\t\t\t\taction: ({ request }) => handler(request)\n\t\t\t},\n\t\t\t\"next-js\": {\n\t\t\t\tGET: handler,\n\t\t\t\tPOST: handler,\n\t\t\t\tPUT: handler,\n\t\t\t\tDELETE: handler,\n\t\t\t\tPATCH: handler,\n\t\t\t\tHEAD: handler,\n\t\t\t\tOPTIONS: handler\n\t\t\t},\n\t\t\t\"svelte-kit\": {\n\t\t\t\tGET: handler,\n\t\t\t\tPOST: handler,\n\t\t\t\tPUT: handler,\n\t\t\t\tDELETE: handler,\n\t\t\t\tPATCH: handler,\n\t\t\t\tHEAD: handler,\n\t\t\t\tOPTIONS: handler\n\t\t\t},\n\t\t\t\"solid-start\": {\n\t\t\t\tGET: ({ request }) => handler(request),\n\t\t\t\tPOST: ({ request }) => handler(request),\n\t\t\t\tPUT: ({ request }) => handler(request),\n\t\t\t\tDELETE: ({ request }) => handler(request),\n\t\t\t\tPATCH: ({ request }) => handler(request),\n\t\t\t\tHEAD: ({ request }) => handler(request),\n\t\t\t\tOPTIONS: ({ request }) => handler(request)\n\t\t\t},\n\t\t\t\"tanstack-start\": {\n\t\t\t\tGET: ({ request }) => handler(request),\n\t\t\t\tPOST: ({ request }) => handler(request),\n\t\t\t\tPUT: ({ request }) => handler(request),\n\t\t\t\tDELETE: ({ request }) => handler(request),\n\t\t\t\tPATCH: ({ request }) => handler(request),\n\t\t\t\tHEAD: ({ request }) => handler(request),\n\t\t\t\tOPTIONS: ({ request }) => handler(request)\n\t\t\t}\n\t\t}[framework];\n\t}\n\t/**\n\t* Main request handler for this fragment.\n\t* Handles routing, middleware, and error handling.\n\t*/\n\tasync handler(req) {\n\t\tconst url = new URL(req.url);\n\t\tconst pathname = url.pathname;\n\t\tconst matchRoute = pathname.startsWith(this.#mountRoute) ? pathname.slice(this.#mountRoute.length) : null;\n\t\tif (matchRoute === null) return Response.json({\n\t\t\terror: `Fragno: Route for '${this.#name}' not found. Is the fragment mounted on the right route? Expecting: '${this.#mountRoute}'.`,\n\t\t\tcode: \"ROUTE_NOT_FOUND\"\n\t\t}, { status: 404 });\n\t\tconst route = findRoute(this.#router, req.method, matchRoute);\n\t\tif (!route) return Response.json({\n\t\t\terror: `Fragno: Route for '${this.#name}' not found`,\n\t\t\tcode: \"ROUTE_NOT_FOUND\"\n\t\t}, { status: 404 });\n\t\tlet requestBody = void 0;\n\t\tlet rawBody = void 0;\n\t\tif (req.body instanceof ReadableStream) {\n\t\t\trawBody = await req.clone().text();\n\t\t\tif (rawBody) try {\n\t\t\t\trequestBody = JSON.parse(rawBody);\n\t\t\t} catch {\n\t\t\t\trequestBody = void 0;\n\t\t\t}\n\t\t}\n\t\tconst requestState = new MutableRequestState({\n\t\t\tpathParams: route.params ?? {},\n\t\t\tsearchParams: url.searchParams,\n\t\t\tbody: requestBody,\n\t\t\theaders: new Headers(req.headers)\n\t\t});\n\t\tconst executeRequest = async () => {\n\t\t\tif (this.#middlewareHandler) {\n\t\t\t\tconst middlewareResult = await this.#executeMiddleware(req, route, requestState);\n\t\t\t\tif (middlewareResult !== void 0) return middlewareResult;\n\t\t\t}\n\t\t\treturn this.#executeHandler(req, route, requestState, rawBody);\n\t\t};\n\t\treturn this.#withRequestStorage(executeRequest);\n\t}\n\t/**\n\t* Call a route directly with typed inputs and outputs.\n\t* Useful for testing and server-side route calls.\n\t*/\n\tasync callRoute(method, path, inputOptions) {\n\t\treturn parseFragnoResponse(await this.callRouteRaw(method, path, inputOptions));\n\t}\n\t/**\n\t* Call a route directly and get the raw Response object.\n\t* Useful for testing and server-side route calls.\n\t*/\n\tasync callRouteRaw(method, path, inputOptions) {\n\t\tconst route = this.#routes.find((r) => r.method === method && r.path === path);\n\t\tif (!route) return Response.json({\n\t\t\terror: `Route ${method} ${path} not found`,\n\t\t\tcode: \"ROUTE_NOT_FOUND\"\n\t\t}, { status: 404 });\n\t\tconst { pathParams = {}, body, query, headers } = inputOptions || {};\n\t\tconst searchParams = query instanceof URLSearchParams ? query : query ? new URLSearchParams(query) : new URLSearchParams();\n\t\tconst requestHeaders = headers instanceof Headers ? headers : headers ? new Headers(headers) : new Headers();\n\t\tconst inputContext = new RequestInputContext({\n\t\t\tpath: route.path,\n\t\t\tmethod: route.method,\n\t\t\tpathParams,\n\t\t\tsearchParams,\n\t\t\theaders: requestHeaders,\n\t\t\tparsedBody: body,\n\t\t\tinputSchema: route.inputSchema,\n\t\t\tshouldValidateInput: true\n\t\t});\n\t\tconst outputContext = new RequestOutputContext(route.outputSchema);\n\t\tconst executeHandler = async () => {\n\t\t\ttry {\n\t\t\t\tconst thisContext = this.#handlerThisContext ?? {};\n\t\t\t\treturn await route.handler.call(thisContext, inputContext, outputContext);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error in callRoute handler\", error);\n\t\t\t\tif (error instanceof FragnoApiError) return error.toResponse();\n\t\t\t\treturn Response.json({\n\t\t\t\t\terror: \"Internal server error\",\n\t\t\t\t\tcode: \"INTERNAL_SERVER_ERROR\"\n\t\t\t\t}, { status: 500 });\n\t\t\t}\n\t\t};\n\t\treturn this.#withRequestStorage(executeHandler);\n\t}\n\t/**\n\t* Execute middleware for a request.\n\t* Returns undefined if middleware allows the request to continue to the handler.\n\t*/\n\tasync #executeMiddleware(req, route, requestState) {\n\t\tif (!this.#middlewareHandler || !route) return;\n\t\tconst { path } = route.data;\n\t\tconst middlewareInputContext = new RequestMiddlewareInputContext(this.#routes, {\n\t\t\tmethod: req.method,\n\t\t\tpath,\n\t\t\trequest: req,\n\t\t\tstate: requestState\n\t\t});\n\t\tconst middlewareOutputContext = new RequestMiddlewareOutputContext(this.#deps, this.#services);\n\t\ttry {\n\t\t\tconst middlewareResult = await this.#middlewareHandler(middlewareInputContext, middlewareOutputContext);\n\t\t\tif (middlewareResult !== void 0) return middlewareResult;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error in middleware\", error);\n\t\t\tif (error instanceof FragnoApiError) return error.toResponse();\n\t\t\treturn Response.json({\n\t\t\t\terror: \"Internal server error\",\n\t\t\t\tcode: \"INTERNAL_SERVER_ERROR\"\n\t\t\t}, { status: 500 });\n\t\t}\n\t}\n\t/**\n\t* Execute a route handler with proper error handling.\n\t*/\n\tasync #executeHandler(req, route, requestState, rawBody) {\n\t\tif (!route) return Response.json({\n\t\t\terror: \"Route not found\",\n\t\t\tcode: \"ROUTE_NOT_FOUND\"\n\t\t}, { status: 404 });\n\t\tconst { handler, inputSchema, outputSchema, path } = route.data;\n\t\tconst inputContext = await RequestInputContext.fromRequest({\n\t\t\trequest: req,\n\t\t\tmethod: req.method,\n\t\t\tpath,\n\t\t\tpathParams: route.params ?? {},\n\t\t\tinputSchema,\n\t\t\tstate: requestState,\n\t\t\trawBody\n\t\t});\n\t\tconst outputContext = new RequestOutputContext(outputSchema);\n\t\ttry {\n\t\t\tconst contextForHandler = this.#handlerThisContext ?? {};\n\t\t\treturn await handler.call(contextForHandler, inputContext, outputContext);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error in handler\", error);\n\t\t\tif (error instanceof FragnoApiError) return error.toResponse();\n\t\t\treturn Response.json({\n\t\t\t\terror: \"Internal server error\",\n\t\t\t\tcode: \"INTERNAL_SERVER_ERROR\"\n\t\t\t}, { status: 500 });\n\t\t}\n\t}\n};\n/**\n* Core instantiation function that creates a fragment instance from a definition.\n* This function validates dependencies, calls all callbacks, and wires everything together.\n*/\nfunction instantiateFragment(definition, config, routesOrFactories, options, serviceImplementations) {\n\tconst serviceDependencies = definition.serviceDependencies;\n\tif (serviceDependencies) for (const [serviceName, meta] of Object.entries(serviceDependencies)) {\n\t\tconst metadata = meta;\n\t\tconst implementation = serviceImplementations?.[serviceName];\n\t\tif (metadata.required && !implementation) throw new Error(`Fragment '${definition.name}' requires service '${metadata.name}' but it was not provided`);\n\t}\n\tconst deps = definition.dependencies?.({\n\t\tconfig,\n\t\toptions\n\t}) ?? {};\n\tconst linkedFragmentInstances = {};\n\tconst linkedFragmentServices = {};\n\tif (definition.linkedFragments) for (const [name, callback] of Object.entries(definition.linkedFragments)) {\n\t\tconst linkedFragment = callback({\n\t\t\tconfig,\n\t\t\toptions,\n\t\t\tserviceDependencies: serviceImplementations\n\t\t});\n\t\tlinkedFragmentInstances[name] = linkedFragment;\n\t\tconst services$1 = linkedFragment.services;\n\t\tfor (const [serviceName, service] of Object.entries(services$1)) linkedFragmentServices[serviceName] = service;\n\t}\n\tconst defineService = (services$1) => services$1;\n\tconst privateServices = { ...linkedFragmentServices };\n\tif (definition.privateServices) for (const [serviceName, factory] of Object.entries(definition.privateServices)) privateServices[serviceName] = factory({\n\t\tconfig,\n\t\toptions,\n\t\tdeps,\n\t\tserviceDeps: serviceImplementations ?? {},\n\t\tprivateServices,\n\t\tdefineService\n\t});\n\tconst baseServices = definition.baseServices?.({\n\t\tconfig,\n\t\toptions,\n\t\tdeps,\n\t\tserviceDeps: serviceImplementations ?? {},\n\t\tprivateServices,\n\t\tdefineService\n\t}) ?? {};\n\tconst namedServices = {};\n\tif (definition.namedServices) for (const [serviceName, factory] of Object.entries(definition.namedServices)) namedServices[serviceName] = factory({\n\t\tconfig,\n\t\toptions,\n\t\tdeps,\n\t\tserviceDeps: serviceImplementations ?? {},\n\t\tprivateServices,\n\t\tdefineService\n\t});\n\tconst services = {\n\t\t...baseServices,\n\t\t...namedServices\n\t};\n\tconst storage = definition.getExternalStorage ? definition.getExternalStorage({\n\t\tconfig,\n\t\toptions,\n\t\tdeps\n\t}) : new RequestContextStorage();\n\tconst contexts = definition.createThisContext?.({\n\t\tconfig,\n\t\toptions,\n\t\tdeps,\n\t\tstorage\n\t});\n\tconst serviceContext = contexts?.serviceContext;\n\tconst handlerContext = contexts?.handlerContext;\n\tconst boundServices = serviceContext ? bindServicesToContext(services, serviceContext) : services;\n\tconst routes = resolveRouteFactories({\n\t\tconfig,\n\t\tdeps,\n\t\tservices: boundServices,\n\t\tserviceDeps: serviceImplementations ?? {}\n\t}, routesOrFactories);\n\tconst mountRoute = getMountRoute({\n\t\tname: definition.name,\n\t\tmountRoute: options.mountRoute\n\t});\n\tconst createRequestStorageWithContext = definition.createRequestStorage ? () => definition.createRequestStorage({\n\t\tconfig,\n\t\toptions,\n\t\tdeps\n\t}) : void 0;\n\treturn new FragnoInstantiatedFragment({\n\t\tname: definition.name,\n\t\troutes,\n\t\tdeps,\n\t\tservices: boundServices,\n\t\tmountRoute,\n\t\tserviceThisContext: serviceContext,\n\t\thandlerThisContext: handlerContext,\n\t\tstorage,\n\t\tcreateRequestStorage: createRequestStorageWithContext,\n\t\toptions,\n\t\tlinkedFragments: linkedFragmentInstances\n\t});\n}\n/**\n* Fluent builder for instantiating fragments.\n* Provides a type-safe API for configuring and building fragment instances.\n*/\nvar FragmentInstantiationBuilder = class FragmentInstantiationBuilder {\n\t#definition;\n\t#config;\n\t#routes;\n\t#options;\n\t#services;\n\tconstructor(definition, routes) {\n\t\tthis.#definition = definition;\n\t\tthis.#routes = routes;\n\t}\n\t/**\n\t* Get the fragment definition\n\t*/\n\tget definition() {\n\t\treturn this.#definition;\n\t}\n\t/**\n\t* Get the configured routes\n\t*/\n\tget routes() {\n\t\treturn this.#routes ?? [];\n\t}\n\t/**\n\t* Get the configuration\n\t*/\n\tget config() {\n\t\treturn this.#config;\n\t}\n\t/**\n\t* Get the options\n\t*/\n\tget options() {\n\t\treturn this.#options;\n\t}\n\t/**\n\t* Set the configuration for the fragment\n\t*/\n\twithConfig(config) {\n\t\tthis.#config = config;\n\t\treturn this;\n\t}\n\t/**\n\t* Set the routes for the fragment\n\t*/\n\twithRoutes(routes) {\n\t\tconst newBuilder = new FragmentInstantiationBuilder(this.#definition, routes);\n\t\tnewBuilder.#config = this.#config;\n\t\tnewBuilder.#options = this.#options;\n\t\tnewBuilder.#services = this.#services;\n\t\treturn newBuilder;\n\t}\n\t/**\n\t* Set the options for the fragment (e.g., mountRoute, databaseAdapter)\n\t*/\n\twithOptions(options) {\n\t\tthis.#options = options;\n\t\treturn this;\n\t}\n\t/**\n\t* Provide implementations for services that this fragment uses\n\t*/\n\twithServices(services) {\n\t\tthis.#services = services;\n\t\treturn this;\n\t}\n\t/**\n\t* Build and return the instantiated fragment\n\t*/\n\tbuild() {\n\t\treturn instantiateFragment(this.#definition, this.#config ?? {}, this.#routes ?? [], this.#options ?? {}, this.#services);\n\t}\n};\n/**\n* Create a fluent builder for instantiating a fragment.\n*\n* @example\n* ```ts\n* const fragment = instantiate(myFragmentDefinition)\n* .withConfig({ apiKey: \"key\" })\n* .withRoutes([route1, route2])\n* .withOptions({ mountRoute: \"/api\" })\n* .build();\n* ```\n*/\nfunction instantiate(definition) {\n\treturn new FragmentInstantiationBuilder(definition);\n}\n\n//#endregion\nexport { FragmentInstantiationBuilder, FragnoInstantiatedFragment, instantiate, instantiateFragment };\n//# sourceMappingURL=fragment-instantiator.js.map"],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region ../fragno/dist/api/fragno-response.js
|
|
2
|
+
/**
|
|
3
|
+
* Parse a Response object into a FragnoResponse discriminated union
|
|
4
|
+
*/
|
|
5
|
+
async function parseFragnoResponse(response) {
|
|
6
|
+
const status = response.status;
|
|
7
|
+
const headers = response.headers;
|
|
8
|
+
if ((headers.get("content-type") || "").includes("application/x-ndjson")) return {
|
|
9
|
+
type: "jsonStream",
|
|
10
|
+
status,
|
|
11
|
+
headers,
|
|
12
|
+
stream: parseNDJSONStream(response)
|
|
13
|
+
};
|
|
14
|
+
const text = await response.text();
|
|
15
|
+
if (!text || text === "null") return {
|
|
16
|
+
type: "empty",
|
|
17
|
+
status,
|
|
18
|
+
headers
|
|
19
|
+
};
|
|
20
|
+
const data = JSON.parse(text);
|
|
21
|
+
if (data && typeof data === "object" && "code" in data) {
|
|
22
|
+
if ("message" in data) return {
|
|
23
|
+
type: "error",
|
|
24
|
+
status,
|
|
25
|
+
headers,
|
|
26
|
+
error: {
|
|
27
|
+
message: data.message,
|
|
28
|
+
code: data.code
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
if ("error" in data) return {
|
|
32
|
+
type: "error",
|
|
33
|
+
status,
|
|
34
|
+
headers,
|
|
35
|
+
error: {
|
|
36
|
+
message: data.error,
|
|
37
|
+
code: data.code
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
type: "json",
|
|
43
|
+
status,
|
|
44
|
+
headers,
|
|
45
|
+
data
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Parse an NDJSON stream into an async generator
|
|
50
|
+
*/
|
|
51
|
+
async function* parseNDJSONStream(response) {
|
|
52
|
+
if (!response.body) return;
|
|
53
|
+
const reader = response.body.getReader();
|
|
54
|
+
const decoder = new TextDecoder();
|
|
55
|
+
let buffer = "";
|
|
56
|
+
try {
|
|
57
|
+
while (true) {
|
|
58
|
+
const { done, value } = await reader.read();
|
|
59
|
+
if (done) break;
|
|
60
|
+
buffer += decoder.decode(value, { stream: true });
|
|
61
|
+
const lines = buffer.split("\n");
|
|
62
|
+
buffer = lines.pop() || "";
|
|
63
|
+
for (const line of lines) if (line.trim()) yield JSON.parse(line);
|
|
64
|
+
}
|
|
65
|
+
if (buffer.trim()) yield JSON.parse(buffer);
|
|
66
|
+
} finally {
|
|
67
|
+
reader.releaseLock();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { parseFragnoResponse };
|
|
73
|
+
//# sourceMappingURL=fragno-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragno-response.js","names":[],"sources":["../../../../../../fragno/dist/api/fragno-response.js"],"sourcesContent":["//#region src/api/fragno-response.ts\n/**\n* Parse a Response object into a FragnoResponse discriminated union\n*/\nasync function parseFragnoResponse(response) {\n\tconst status = response.status;\n\tconst headers = response.headers;\n\tif ((headers.get(\"content-type\") || \"\").includes(\"application/x-ndjson\")) return {\n\t\ttype: \"jsonStream\",\n\t\tstatus,\n\t\theaders,\n\t\tstream: parseNDJSONStream(response)\n\t};\n\tconst text = await response.text();\n\tif (!text || text === \"null\") return {\n\t\ttype: \"empty\",\n\t\tstatus,\n\t\theaders\n\t};\n\tconst data = JSON.parse(text);\n\tif (data && typeof data === \"object\" && \"code\" in data) {\n\t\tif (\"message\" in data) return {\n\t\t\ttype: \"error\",\n\t\t\tstatus,\n\t\t\theaders,\n\t\t\terror: {\n\t\t\t\tmessage: data.message,\n\t\t\t\tcode: data.code\n\t\t\t}\n\t\t};\n\t\tif (\"error\" in data) return {\n\t\t\ttype: \"error\",\n\t\t\tstatus,\n\t\t\theaders,\n\t\t\terror: {\n\t\t\t\tmessage: data.error,\n\t\t\t\tcode: data.code\n\t\t\t}\n\t\t};\n\t}\n\treturn {\n\t\ttype: \"json\",\n\t\tstatus,\n\t\theaders,\n\t\tdata\n\t};\n}\n/**\n* Parse an NDJSON stream into an async generator\n*/\nasync function* parseNDJSONStream(response) {\n\tif (!response.body) return;\n\tconst reader = response.body.getReader();\n\tconst decoder = new TextDecoder();\n\tlet buffer = \"\";\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\tbuffer = lines.pop() || \"\";\n\t\t\tfor (const line of lines) if (line.trim()) yield JSON.parse(line);\n\t\t}\n\t\tif (buffer.trim()) yield JSON.parse(buffer);\n\t} finally {\n\t\treader.releaseLock();\n\t}\n}\n\n//#endregion\nexport { parseFragnoResponse };\n//# sourceMappingURL=fragno-response.js.map"],"mappings":";;;;AAIA,eAAe,oBAAoB,UAAU;CAC5C,MAAM,SAAS,SAAS;CACxB,MAAM,UAAU,SAAS;AACzB,MAAK,QAAQ,IAAI,eAAe,IAAI,IAAI,SAAS,uBAAuB,CAAE,QAAO;EAChF,MAAM;EACN;EACA;EACA,QAAQ,kBAAkB,SAAS;EACnC;CACD,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,KAAI,CAAC,QAAQ,SAAS,OAAQ,QAAO;EACpC,MAAM;EACN;EACA;EACA;CACD,MAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,KAAI,QAAQ,OAAO,SAAS,YAAY,UAAU,MAAM;AACvD,MAAI,aAAa,KAAM,QAAO;GAC7B,MAAM;GACN;GACA;GACA,OAAO;IACN,SAAS,KAAK;IACd,MAAM,KAAK;IACX;GACD;AACD,MAAI,WAAW,KAAM,QAAO;GAC3B,MAAM;GACN;GACA;GACA,OAAO;IACN,SAAS,KAAK;IACd,MAAM,KAAK;IACX;GACD;;AAEF,QAAO;EACN,MAAM;EACN;EACA;EACA;EACA;;;;;AAKF,gBAAgB,kBAAkB,UAAU;AAC3C,KAAI,CAAC,SAAS,KAAM;CACpB,MAAM,SAAS,SAAS,KAAK,WAAW;CACxC,MAAM,UAAU,IAAI,aAAa;CACjC,IAAI,SAAS;AACb,KAAI;AACH,SAAO,MAAM;GACZ,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,OAAI,KAAM;AACV,aAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC;GACjD,MAAM,QAAQ,OAAO,MAAM,KAAK;AAChC,YAAS,MAAM,KAAK,IAAI;AACxB,QAAK,MAAM,QAAQ,MAAO,KAAI,KAAK,MAAM,CAAE,OAAM,KAAK,MAAM,KAAK;;AAElE,MAAI,OAAO,MAAM,CAAE,OAAM,KAAK,MAAM,OAAO;WAClC;AACT,SAAO,aAAa"}
|