@fragno-dev/core 0.1.7 → 0.1.9
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 +131 -64
- package/CHANGELOG.md +19 -0
- package/dist/api/api.d.ts +38 -2
- package/dist/api/api.d.ts.map +1 -0
- package/dist/api/api.js +9 -2
- package/dist/api/api.js.map +1 -0
- package/dist/api/bind-services.d.ts +6 -0
- package/dist/api/bind-services.d.ts.map +1 -0
- package/dist/api/bind-services.js +20 -0
- package/dist/api/bind-services.js.map +1 -0
- package/dist/api/error.d.ts +26 -0
- package/dist/api/error.d.ts.map +1 -0
- package/dist/{api-DngJDcmO.js → api/error.js} +2 -8
- package/dist/api/error.js.map +1 -0
- package/dist/api/fragment-definition-builder.d.ts +313 -0
- package/dist/api/fragment-definition-builder.d.ts.map +1 -0
- package/dist/api/fragment-definition-builder.js +326 -0
- package/dist/api/fragment-definition-builder.js.map +1 -0
- package/dist/api/fragment-instantiator.d.ts +216 -0
- package/dist/api/fragment-instantiator.d.ts.map +1 -0
- package/dist/api/fragment-instantiator.js +487 -0
- package/dist/api/fragment-instantiator.js.map +1 -0
- package/dist/api/fragno-response.d.ts +30 -0
- package/dist/api/fragno-response.d.ts.map +1 -0
- package/dist/api/fragno-response.js +73 -0
- package/dist/api/fragno-response.js.map +1 -0
- package/dist/api/internal/path.d.ts +50 -0
- package/dist/api/internal/path.d.ts.map +1 -0
- package/dist/api/internal/path.js +76 -0
- package/dist/api/internal/path.js.map +1 -0
- package/dist/api/internal/response-stream.d.ts +43 -0
- package/dist/api/internal/response-stream.d.ts.map +1 -0
- package/dist/api/internal/response-stream.js +81 -0
- package/dist/api/internal/response-stream.js.map +1 -0
- package/dist/api/internal/route.js +10 -0
- package/dist/api/internal/route.js.map +1 -0
- package/dist/api/mutable-request-state.d.ts +82 -0
- package/dist/api/mutable-request-state.d.ts.map +1 -0
- package/dist/api/mutable-request-state.js +97 -0
- package/dist/api/mutable-request-state.js.map +1 -0
- package/dist/api/request-context-storage.d.ts +42 -0
- package/dist/api/request-context-storage.d.ts.map +1 -0
- package/dist/api/request-context-storage.js +43 -0
- package/dist/api/request-context-storage.js.map +1 -0
- package/dist/api/request-input-context.d.ts +89 -0
- package/dist/api/request-input-context.d.ts.map +1 -0
- package/dist/api/request-input-context.js +118 -0
- package/dist/api/request-input-context.js.map +1 -0
- package/dist/api/request-middleware.d.ts +50 -0
- package/dist/api/request-middleware.d.ts.map +1 -0
- package/dist/api/request-middleware.js +83 -0
- package/dist/api/request-middleware.js.map +1 -0
- package/dist/api/request-output-context.d.ts +41 -0
- package/dist/api/request-output-context.d.ts.map +1 -0
- package/dist/api/request-output-context.js +119 -0
- package/dist/api/request-output-context.js.map +1 -0
- package/dist/api/route-handler-input-options.d.ts +21 -0
- package/dist/api/route-handler-input-options.d.ts.map +1 -0
- package/dist/api/route.d.ts +54 -3
- package/dist/api/route.d.ts.map +1 -0
- package/dist/api/route.js +29 -2
- package/dist/api/route.js.map +1 -0
- package/dist/api/shared-types.d.ts +47 -0
- package/dist/api/shared-types.d.ts.map +1 -0
- package/dist/api/shared-types.js +1 -0
- package/dist/client/client-error.d.ts +60 -0
- package/dist/client/client-error.d.ts.map +1 -0
- package/dist/client/client-error.js +92 -0
- package/dist/client/client-error.js.map +1 -0
- package/dist/client/client.d.ts +210 -4
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +397 -6
- package/dist/client/client.js.map +1 -0
- package/dist/client/client.svelte.d.ts +5 -3
- package/dist/client/client.svelte.d.ts.map +1 -1
- package/dist/client/client.svelte.js +1 -5
- package/dist/client/client.svelte.js.map +1 -1
- package/dist/client/internal/fetcher-merge.js +36 -0
- package/dist/client/internal/fetcher-merge.js.map +1 -0
- package/dist/client/internal/ndjson-streaming.js +139 -0
- package/dist/client/internal/ndjson-streaming.js.map +1 -0
- package/dist/client/react.d.ts +5 -3
- package/dist/client/react.d.ts.map +1 -1
- package/dist/client/react.js +3 -5
- package/dist/client/react.js.map +1 -1
- package/dist/client/solid.d.ts +5 -3
- package/dist/client/solid.d.ts.map +1 -1
- package/dist/client/solid.js +2 -5
- package/dist/client/solid.js.map +1 -1
- package/dist/client/vanilla.d.ts +5 -3
- package/dist/client/vanilla.d.ts.map +1 -1
- package/dist/client/vanilla.js +2 -43
- package/dist/client/vanilla.js.map +1 -1
- package/dist/client/vue.d.ts +5 -3
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +1 -5
- package/dist/client/vue.js.map +1 -1
- package/dist/http/http-status.d.ts +26 -0
- package/dist/http/http-status.d.ts.map +1 -0
- package/dist/integrations/react-ssr.js +1 -1
- package/dist/internal/symbols.d.ts +9 -0
- package/dist/internal/symbols.d.ts.map +1 -0
- package/dist/internal/symbols.js +10 -0
- package/dist/internal/symbols.js.map +1 -0
- package/dist/mod-client.d.ts +36 -0
- package/dist/mod-client.d.ts.map +1 -0
- package/dist/mod-client.js +21 -0
- package/dist/mod-client.js.map +1 -0
- package/dist/mod.d.ts +7 -4
- package/dist/mod.js +4 -6
- package/dist/request/request.d.ts +4 -0
- package/dist/request/request.js +5 -0
- package/dist/test/test.d.ts +62 -35
- package/dist/test/test.d.ts.map +1 -1
- package/dist/test/test.js +75 -40
- package/dist/test/test.js.map +1 -1
- package/dist/util/async.js +40 -0
- package/dist/util/async.js.map +1 -0
- package/dist/util/content-type.js +49 -0
- package/dist/util/content-type.js.map +1 -0
- package/dist/util/nanostores.js +31 -0
- package/dist/util/nanostores.js.map +1 -0
- package/dist/{ssr-BByDVfFD.js → util/ssr.js} +2 -2
- package/dist/util/ssr.js.map +1 -0
- package/dist/util/types-util.d.ts +8 -0
- package/dist/util/types-util.d.ts.map +1 -0
- package/package.json +19 -12
- package/src/api/api.ts +41 -6
- package/src/api/bind-services.ts +42 -0
- package/src/api/fragment-definition-builder.extend.test.ts +810 -0
- package/src/api/fragment-definition-builder.test.ts +499 -0
- package/src/api/fragment-definition-builder.ts +1088 -0
- package/src/api/fragment-instantiator.test.ts +1488 -0
- package/src/api/fragment-instantiator.ts +1053 -0
- package/src/api/fragment-services.test.ts +727 -0
- package/src/api/request-context-storage.ts +64 -0
- package/src/api/request-middleware.test.ts +301 -225
- package/src/api/route.test.ts +87 -1
- package/src/api/route.ts +345 -24
- package/src/api/shared-types.ts +43 -0
- package/src/client/client-builder.test.ts +23 -23
- package/src/client/client.ssr.test.ts +3 -3
- package/src/client/client.svelte.test.ts +15 -15
- package/src/client/client.test.ts +22 -22
- package/src/client/client.ts +72 -12
- package/src/client/internal/fetcher-merge.ts +1 -1
- package/src/client/react.test.ts +2 -2
- package/src/client/solid.test.ts +2 -2
- package/src/client/vanilla.test.ts +2 -2
- package/src/client/vue.test.ts +2 -2
- package/src/internal/symbols.ts +5 -0
- package/src/mod-client.ts +59 -0
- package/src/mod.ts +26 -9
- package/src/request/request.ts +8 -0
- package/src/test/test.test.ts +200 -381
- package/src/test/test.ts +190 -117
- package/tsdown.config.ts +8 -5
- package/dist/api/fragment-builder.d.ts +0 -4
- package/dist/api/fragment-builder.js +0 -3
- package/dist/api/fragment-instantiation.d.ts +0 -4
- package/dist/api/fragment-instantiation.js +0 -6
- package/dist/api-BWN97TOr.d.ts +0 -377
- package/dist/api-BWN97TOr.d.ts.map +0 -1
- package/dist/api-DngJDcmO.js.map +0 -1
- package/dist/client-C5LsYHEI.js +0 -782
- package/dist/client-C5LsYHEI.js.map +0 -1
- package/dist/fragment-builder-DOnCVBqc.js +0 -47
- package/dist/fragment-builder-DOnCVBqc.js.map +0 -1
- package/dist/fragment-builder-MGr68GNb.d.ts +0 -409
- package/dist/fragment-builder-MGr68GNb.d.ts.map +0 -1
- package/dist/fragment-instantiation-C4wvwl6V.js +0 -446
- package/dist/fragment-instantiation-C4wvwl6V.js.map +0 -1
- package/dist/request-output-context-CdIjwmEN.js +0 -320
- package/dist/request-output-context-CdIjwmEN.js.map +0 -1
- package/dist/route-Bl9Zr1Yv.d.ts +0 -26
- package/dist/route-Bl9Zr1Yv.d.ts.map +0 -1
- package/dist/route-C5Uryylh.js +0 -21
- package/dist/route-C5Uryylh.js.map +0 -1
- package/dist/ssr-BByDVfFD.js.map +0 -1
- package/src/api/fragment-builder.ts +0 -80
- package/src/api/fragment-instantiation.test.ts +0 -460
- package/src/api/fragment-instantiation.ts +0 -499
- package/src/api/fragment.test.ts +0 -537
package/src/api/route.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { test, expect, expectTypeOf, describe } from "vitest";
|
|
2
|
-
import { defineRoute } from "./route";
|
|
2
|
+
import { defineRoute, defineRoutes } from "./route";
|
|
3
|
+
import { defineFragment } from "./fragment-definition-builder";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
|
|
5
6
|
describe("defineRoute", () => {
|
|
@@ -174,3 +175,88 @@ describe("defineRoute", () => {
|
|
|
174
175
|
// Currently defineRoute doesn't enforce ValidPath constraints
|
|
175
176
|
});
|
|
176
177
|
});
|
|
178
|
+
|
|
179
|
+
// ExtractFragmentServices tests removed - use ExtractFragmentServices instead
|
|
180
|
+
|
|
181
|
+
describe("defineRoutes", () => {
|
|
182
|
+
test("defineRoutes extracts services correctly for route factory", () => {
|
|
183
|
+
const fragment = defineFragment<{}>("test-fragment")
|
|
184
|
+
.providesBaseService(({ defineService }) =>
|
|
185
|
+
defineService({
|
|
186
|
+
getUserById: async (id: string) => ({ id, name: "John" }),
|
|
187
|
+
createUser: async (name: string) => ({ id: "123", name }),
|
|
188
|
+
}),
|
|
189
|
+
)
|
|
190
|
+
.build();
|
|
191
|
+
|
|
192
|
+
const routeFactory = defineRoutes(fragment).create(({ services, config, deps }) => {
|
|
193
|
+
// Type check that services are properly extracted
|
|
194
|
+
expectTypeOf(services).toMatchObjectType<{
|
|
195
|
+
getUserById: (id: string) => Promise<{ id: string; name: string }>;
|
|
196
|
+
createUser: (name: string) => Promise<{ id: string; name: string }>;
|
|
197
|
+
}>();
|
|
198
|
+
|
|
199
|
+
expectTypeOf(config).toEqualTypeOf<{}>();
|
|
200
|
+
expectTypeOf(deps).toEqualTypeOf<{}>();
|
|
201
|
+
|
|
202
|
+
return [
|
|
203
|
+
defineRoute({
|
|
204
|
+
method: "GET",
|
|
205
|
+
path: "/users/:id",
|
|
206
|
+
outputSchema: z.object({ id: z.string(), name: z.string() }),
|
|
207
|
+
handler: async ({ pathParams }, { json }) => {
|
|
208
|
+
// Services should be accessible here via closure
|
|
209
|
+
const user = await services.getUserById(pathParams.id);
|
|
210
|
+
return json(user);
|
|
211
|
+
},
|
|
212
|
+
}),
|
|
213
|
+
];
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// routeFactory is a function that returns routes when called
|
|
217
|
+
expect(routeFactory).toBeDefined();
|
|
218
|
+
expect(typeof routeFactory).toBe("function");
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("defineRoutes with dependencies and services", () => {
|
|
222
|
+
const fragment = defineFragment<{ apiKey: string }>("auth-fragment")
|
|
223
|
+
.withDependencies(({ config }) => ({
|
|
224
|
+
authClient: { apiKey: config.apiKey },
|
|
225
|
+
}))
|
|
226
|
+
.providesBaseService(({ deps, defineService }) =>
|
|
227
|
+
defineService({
|
|
228
|
+
validateToken: async (_token: string) => {
|
|
229
|
+
return { valid: true, apiKey: deps.authClient.apiKey };
|
|
230
|
+
},
|
|
231
|
+
}),
|
|
232
|
+
)
|
|
233
|
+
.build();
|
|
234
|
+
|
|
235
|
+
const routeFactory = defineRoutes(fragment).create(({ services, config, deps }) => {
|
|
236
|
+
// Type check all context properties
|
|
237
|
+
expectTypeOf(config).toEqualTypeOf<{ apiKey: string }>();
|
|
238
|
+
expectTypeOf(deps).toMatchObjectType<{ authClient: { apiKey: string } }>();
|
|
239
|
+
expectTypeOf(services).toMatchObjectType<{
|
|
240
|
+
validateToken: (token: string) => Promise<{ valid: boolean; apiKey: string }>;
|
|
241
|
+
}>();
|
|
242
|
+
|
|
243
|
+
return [
|
|
244
|
+
defineRoute({
|
|
245
|
+
method: "POST",
|
|
246
|
+
path: "/auth/validate",
|
|
247
|
+
inputSchema: z.object({ token: z.string() }),
|
|
248
|
+
outputSchema: z.object({ valid: z.boolean() }),
|
|
249
|
+
handler: async ({ input }, { json }) => {
|
|
250
|
+
const { token } = await input!.valid();
|
|
251
|
+
const result = await services.validateToken(token);
|
|
252
|
+
return json({ valid: result.valid });
|
|
253
|
+
},
|
|
254
|
+
}),
|
|
255
|
+
];
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// routeFactory is a function that returns routes when called
|
|
259
|
+
expect(routeFactory).toBeDefined();
|
|
260
|
+
expect(typeof routeFactory).toBe("function");
|
|
261
|
+
});
|
|
262
|
+
});
|
package/src/api/route.ts
CHANGED
|
@@ -1,53 +1,66 @@
|
|
|
1
|
+
// oxlint-disable no-explicit-any
|
|
2
|
+
|
|
1
3
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
-
import type { FragnoRouteConfig, HTTPMethod } from "./api";
|
|
4
|
+
import type { FragnoRouteConfig, HTTPMethod, RequestThisContext } from "./api";
|
|
5
|
+
import type { FragmentDefinition } from "./fragment-definition-builder";
|
|
6
|
+
import type { BoundServices } from "./bind-services";
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
export type AnyFragnoRouteConfig = FragnoRouteConfig<HTTPMethod, string, any, any, any, any>;
|
|
8
|
+
export type AnyFragnoRouteConfig = FragnoRouteConfig<HTTPMethod, string, any, any, any, any, any>;
|
|
6
9
|
|
|
7
|
-
export interface RouteFactoryContext<TConfig, TDeps, TServices> {
|
|
10
|
+
export interface RouteFactoryContext<TConfig, TDeps, TServices, TServiceDeps = {}> {
|
|
8
11
|
config: TConfig;
|
|
9
12
|
deps: TDeps;
|
|
10
13
|
services: TServices;
|
|
14
|
+
serviceDeps: TServiceDeps;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export type RouteFactory<
|
|
14
18
|
TConfig,
|
|
15
19
|
TDeps,
|
|
16
20
|
TServices,
|
|
21
|
+
TServiceDeps,
|
|
17
22
|
TRoutes extends readonly FragnoRouteConfig<
|
|
18
23
|
HTTPMethod,
|
|
19
24
|
string,
|
|
20
25
|
StandardSchemaV1 | undefined,
|
|
21
26
|
StandardSchemaV1 | undefined,
|
|
22
27
|
string,
|
|
23
|
-
string
|
|
28
|
+
string,
|
|
29
|
+
RequestThisContext
|
|
24
30
|
>[],
|
|
25
|
-
> = (context: RouteFactoryContext<TConfig, TDeps, TServices>) => TRoutes;
|
|
31
|
+
> = (context: RouteFactoryContext<TConfig, TDeps, TServices, TServiceDeps>) => TRoutes;
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
/**
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
export type AnyRouteOrFactory = AnyFragnoRouteConfig | RouteFactory<any, any, any, any, any>;
|
|
29
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
30
41
|
export type FlattenRouteFactories<T extends readonly AnyRouteOrFactory[]> = T extends readonly [
|
|
31
42
|
infer First,
|
|
32
43
|
...infer Rest extends readonly AnyRouteOrFactory[],
|
|
33
44
|
]
|
|
34
|
-
?
|
|
35
|
-
First extends RouteFactory<any, any, any, infer TRoutes>
|
|
45
|
+
? First extends RouteFactory<any, any, any, any, infer TRoutes>
|
|
36
46
|
? [...TRoutes, ...FlattenRouteFactories<Rest>]
|
|
37
47
|
: [First, ...FlattenRouteFactories<Rest>]
|
|
38
48
|
: [];
|
|
39
49
|
|
|
40
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Helper to resolve route factories into routes
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
41
54
|
export function resolveRouteFactories<
|
|
42
55
|
TConfig,
|
|
43
56
|
TDeps,
|
|
44
57
|
TServices,
|
|
58
|
+
TServiceDeps,
|
|
45
59
|
const TRoutesOrFactories extends readonly AnyRouteOrFactory[],
|
|
46
60
|
>(
|
|
47
|
-
context: RouteFactoryContext<TConfig, TDeps, TServices>,
|
|
61
|
+
context: RouteFactoryContext<TConfig, TDeps, TServices, TServiceDeps>,
|
|
48
62
|
routesOrFactories: TRoutesOrFactories,
|
|
49
63
|
): FlattenRouteFactories<TRoutesOrFactories> {
|
|
50
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
64
|
const routes: any[] = [];
|
|
52
65
|
|
|
53
66
|
for (const item of routesOrFactories) {
|
|
@@ -74,6 +87,7 @@ export function defineRoute<
|
|
|
74
87
|
const TOutputSchema extends StandardSchemaV1 | undefined,
|
|
75
88
|
const TErrorCode extends string = string,
|
|
76
89
|
const TQueryParameters extends string = string,
|
|
90
|
+
const TThisContext extends RequestThisContext = RequestThisContext,
|
|
77
91
|
>(
|
|
78
92
|
config: FragnoRouteConfig<
|
|
79
93
|
TMethod,
|
|
@@ -81,9 +95,18 @@ export function defineRoute<
|
|
|
81
95
|
undefined,
|
|
82
96
|
TOutputSchema,
|
|
83
97
|
TErrorCode,
|
|
84
|
-
TQueryParameters
|
|
98
|
+
TQueryParameters,
|
|
99
|
+
TThisContext
|
|
85
100
|
> & { inputSchema?: undefined },
|
|
86
|
-
): FragnoRouteConfig<
|
|
101
|
+
): FragnoRouteConfig<
|
|
102
|
+
TMethod,
|
|
103
|
+
TPath,
|
|
104
|
+
undefined,
|
|
105
|
+
TOutputSchema,
|
|
106
|
+
TErrorCode,
|
|
107
|
+
TQueryParameters,
|
|
108
|
+
TThisContext
|
|
109
|
+
>;
|
|
87
110
|
|
|
88
111
|
// Overload for routes with inputSchema
|
|
89
112
|
export function defineRoute<
|
|
@@ -93,6 +116,7 @@ export function defineRoute<
|
|
|
93
116
|
const TOutputSchema extends StandardSchemaV1 | undefined,
|
|
94
117
|
const TErrorCode extends string = string,
|
|
95
118
|
const TQueryParameters extends string = string,
|
|
119
|
+
const TThisContext extends RequestThisContext = RequestThisContext,
|
|
96
120
|
>(
|
|
97
121
|
config: FragnoRouteConfig<
|
|
98
122
|
TMethod,
|
|
@@ -100,9 +124,18 @@ export function defineRoute<
|
|
|
100
124
|
TInputSchema,
|
|
101
125
|
TOutputSchema,
|
|
102
126
|
TErrorCode,
|
|
103
|
-
TQueryParameters
|
|
127
|
+
TQueryParameters,
|
|
128
|
+
TThisContext
|
|
104
129
|
> & { inputSchema: TInputSchema },
|
|
105
|
-
): FragnoRouteConfig<
|
|
130
|
+
): FragnoRouteConfig<
|
|
131
|
+
TMethod,
|
|
132
|
+
TPath,
|
|
133
|
+
TInputSchema,
|
|
134
|
+
TOutputSchema,
|
|
135
|
+
TErrorCode,
|
|
136
|
+
TQueryParameters,
|
|
137
|
+
TThisContext
|
|
138
|
+
>;
|
|
106
139
|
|
|
107
140
|
// implementation
|
|
108
141
|
export function defineRoute<
|
|
@@ -112,6 +145,7 @@ export function defineRoute<
|
|
|
112
145
|
const TOutputSchema extends StandardSchemaV1 | undefined,
|
|
113
146
|
const TErrorCode extends string = string,
|
|
114
147
|
const TQueryParameters extends string = string,
|
|
148
|
+
const TThisContext extends RequestThisContext = RequestThisContext,
|
|
115
149
|
>(
|
|
116
150
|
config: FragnoRouteConfig<
|
|
117
151
|
TMethod,
|
|
@@ -119,13 +153,246 @@ export function defineRoute<
|
|
|
119
153
|
TInputSchema,
|
|
120
154
|
TOutputSchema,
|
|
121
155
|
TErrorCode,
|
|
122
|
-
TQueryParameters
|
|
156
|
+
TQueryParameters,
|
|
157
|
+
TThisContext
|
|
123
158
|
>,
|
|
124
|
-
): FragnoRouteConfig<
|
|
159
|
+
): FragnoRouteConfig<
|
|
160
|
+
TMethod,
|
|
161
|
+
TPath,
|
|
162
|
+
TInputSchema,
|
|
163
|
+
TOutputSchema,
|
|
164
|
+
TErrorCode,
|
|
165
|
+
TQueryParameters,
|
|
166
|
+
TThisContext
|
|
167
|
+
> {
|
|
125
168
|
return config;
|
|
126
169
|
}
|
|
127
170
|
|
|
128
|
-
|
|
171
|
+
// ============================================================================
|
|
172
|
+
// Type extractors for FragmentDefinition
|
|
173
|
+
// ============================================================================
|
|
174
|
+
|
|
175
|
+
export type AnyFragmentDefinition = FragmentDefinition<
|
|
176
|
+
any,
|
|
177
|
+
any,
|
|
178
|
+
any,
|
|
179
|
+
any,
|
|
180
|
+
any,
|
|
181
|
+
any,
|
|
182
|
+
any,
|
|
183
|
+
any,
|
|
184
|
+
any,
|
|
185
|
+
any
|
|
186
|
+
>;
|
|
187
|
+
|
|
188
|
+
// Extract config from FragmentDefinition
|
|
189
|
+
export type ExtractFragmentConfig<T> =
|
|
190
|
+
T extends FragmentDefinition<infer TConfig, any, any, any, any, any, any, any, any, any>
|
|
191
|
+
? TConfig
|
|
192
|
+
: never;
|
|
193
|
+
|
|
194
|
+
// Extract deps from FragmentDefinition
|
|
195
|
+
export type ExtractFragmentDeps<T> =
|
|
196
|
+
T extends FragmentDefinition<any, any, infer TDeps, any, any, any, any, any, any, any>
|
|
197
|
+
? TDeps
|
|
198
|
+
: never;
|
|
199
|
+
|
|
200
|
+
// Extract services from FragmentDefinition
|
|
201
|
+
// This extracts both base services (flat) and named services (nested)
|
|
202
|
+
// The result matches the structure of fragment.services at runtime
|
|
203
|
+
export type ExtractFragmentServices<T> =
|
|
204
|
+
T extends FragmentDefinition<
|
|
205
|
+
any,
|
|
206
|
+
any,
|
|
207
|
+
any,
|
|
208
|
+
infer TBaseServices,
|
|
209
|
+
infer TServices,
|
|
210
|
+
any,
|
|
211
|
+
any,
|
|
212
|
+
any,
|
|
213
|
+
any,
|
|
214
|
+
any
|
|
215
|
+
>
|
|
216
|
+
? BoundServices<TBaseServices & TServices>
|
|
217
|
+
: never;
|
|
218
|
+
|
|
219
|
+
// Extract service dependencies from FragmentDefinition
|
|
220
|
+
export type ExtractFragmentServiceDeps<T> =
|
|
221
|
+
T extends FragmentDefinition<
|
|
222
|
+
any,
|
|
223
|
+
any,
|
|
224
|
+
any,
|
|
225
|
+
any,
|
|
226
|
+
any,
|
|
227
|
+
infer TServiceDependencies,
|
|
228
|
+
any,
|
|
229
|
+
any,
|
|
230
|
+
any,
|
|
231
|
+
any
|
|
232
|
+
>
|
|
233
|
+
? TServiceDependencies
|
|
234
|
+
: never;
|
|
235
|
+
|
|
236
|
+
// Extract service this context from FragmentDefinition (used by services)
|
|
237
|
+
export type ExtractFragmentServiceThisContext<T> =
|
|
238
|
+
T extends FragmentDefinition<
|
|
239
|
+
any,
|
|
240
|
+
any,
|
|
241
|
+
any,
|
|
242
|
+
any,
|
|
243
|
+
any,
|
|
244
|
+
any,
|
|
245
|
+
any,
|
|
246
|
+
infer TServiceThisContext,
|
|
247
|
+
any,
|
|
248
|
+
any
|
|
249
|
+
>
|
|
250
|
+
? TServiceThisContext
|
|
251
|
+
: RequestThisContext;
|
|
252
|
+
|
|
253
|
+
// Extract handler this context from FragmentDefinition (used by route handlers)
|
|
254
|
+
export type ExtractFragmentHandlerThisContext<T> =
|
|
255
|
+
T extends FragmentDefinition<
|
|
256
|
+
any,
|
|
257
|
+
any,
|
|
258
|
+
any,
|
|
259
|
+
any,
|
|
260
|
+
any,
|
|
261
|
+
any,
|
|
262
|
+
any,
|
|
263
|
+
any,
|
|
264
|
+
infer THandlerThisContext,
|
|
265
|
+
any
|
|
266
|
+
>
|
|
267
|
+
? THandlerThisContext
|
|
268
|
+
: RequestThisContext;
|
|
269
|
+
|
|
270
|
+
// Legacy: Extract this context from FragmentDefinition (defaults to service context for backwards compatibility)
|
|
271
|
+
export type ExtractFragmentThisContext<T> = ExtractFragmentServiceThisContext<T>;
|
|
272
|
+
|
|
273
|
+
// Overload that infers types from FragmentDefinition (runtime value)
|
|
274
|
+
export function defineRoutes<const TDefinition extends AnyFragmentDefinition>(
|
|
275
|
+
definition: TDefinition,
|
|
276
|
+
): {
|
|
277
|
+
create: <
|
|
278
|
+
const TRoutes extends readonly FragnoRouteConfig<
|
|
279
|
+
HTTPMethod,
|
|
280
|
+
string,
|
|
281
|
+
StandardSchemaV1 | undefined,
|
|
282
|
+
StandardSchemaV1 | undefined,
|
|
283
|
+
string,
|
|
284
|
+
string,
|
|
285
|
+
ExtractFragmentHandlerThisContext<TDefinition>
|
|
286
|
+
>[],
|
|
287
|
+
>(
|
|
288
|
+
fn: (
|
|
289
|
+
context: RouteFactoryContext<
|
|
290
|
+
ExtractFragmentConfig<TDefinition>,
|
|
291
|
+
ExtractFragmentDeps<TDefinition>,
|
|
292
|
+
ExtractFragmentServices<TDefinition>,
|
|
293
|
+
ExtractFragmentServiceDeps<TDefinition>
|
|
294
|
+
> & {
|
|
295
|
+
defineRoute: <
|
|
296
|
+
const TMethod extends HTTPMethod,
|
|
297
|
+
const TPath extends string,
|
|
298
|
+
const TInputSchema extends StandardSchemaV1 | undefined,
|
|
299
|
+
const TOutputSchema extends StandardSchemaV1 | undefined,
|
|
300
|
+
const TErrorCode extends string = string,
|
|
301
|
+
const TQueryParameters extends string = string,
|
|
302
|
+
>(
|
|
303
|
+
config: FragnoRouteConfig<
|
|
304
|
+
TMethod,
|
|
305
|
+
TPath,
|
|
306
|
+
TInputSchema,
|
|
307
|
+
TOutputSchema,
|
|
308
|
+
TErrorCode,
|
|
309
|
+
TQueryParameters,
|
|
310
|
+
ExtractFragmentHandlerThisContext<TDefinition>
|
|
311
|
+
>,
|
|
312
|
+
) => FragnoRouteConfig<
|
|
313
|
+
TMethod,
|
|
314
|
+
TPath,
|
|
315
|
+
TInputSchema,
|
|
316
|
+
TOutputSchema,
|
|
317
|
+
TErrorCode,
|
|
318
|
+
TQueryParameters,
|
|
319
|
+
ExtractFragmentHandlerThisContext<TDefinition>
|
|
320
|
+
>;
|
|
321
|
+
},
|
|
322
|
+
) => TRoutes,
|
|
323
|
+
) => RouteFactory<
|
|
324
|
+
ExtractFragmentConfig<TDefinition>,
|
|
325
|
+
ExtractFragmentDeps<TDefinition>,
|
|
326
|
+
ExtractFragmentServices<TDefinition>,
|
|
327
|
+
ExtractFragmentServiceDeps<TDefinition>,
|
|
328
|
+
TRoutes
|
|
329
|
+
>;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// Overload that infers types from FragmentDefinition (type parameter only)
|
|
333
|
+
export function defineRoutes<const TDefinition extends AnyFragmentDefinition>(): {
|
|
334
|
+
create: <
|
|
335
|
+
const TRoutes extends readonly FragnoRouteConfig<
|
|
336
|
+
HTTPMethod,
|
|
337
|
+
string,
|
|
338
|
+
StandardSchemaV1 | undefined,
|
|
339
|
+
StandardSchemaV1 | undefined,
|
|
340
|
+
string,
|
|
341
|
+
string,
|
|
342
|
+
ExtractFragmentHandlerThisContext<TDefinition>
|
|
343
|
+
>[],
|
|
344
|
+
>(
|
|
345
|
+
fn: (
|
|
346
|
+
context: RouteFactoryContext<
|
|
347
|
+
ExtractFragmentConfig<TDefinition>,
|
|
348
|
+
ExtractFragmentDeps<TDefinition>,
|
|
349
|
+
ExtractFragmentServices<TDefinition>,
|
|
350
|
+
ExtractFragmentServiceDeps<TDefinition>
|
|
351
|
+
> & {
|
|
352
|
+
defineRoute: <
|
|
353
|
+
const TMethod extends HTTPMethod,
|
|
354
|
+
const TPath extends string,
|
|
355
|
+
const TInputSchema extends StandardSchemaV1 | undefined,
|
|
356
|
+
const TOutputSchema extends StandardSchemaV1 | undefined,
|
|
357
|
+
const TErrorCode extends string = string,
|
|
358
|
+
const TQueryParameters extends string = string,
|
|
359
|
+
>(
|
|
360
|
+
config: FragnoRouteConfig<
|
|
361
|
+
TMethod,
|
|
362
|
+
TPath,
|
|
363
|
+
TInputSchema,
|
|
364
|
+
TOutputSchema,
|
|
365
|
+
TErrorCode,
|
|
366
|
+
TQueryParameters,
|
|
367
|
+
ExtractFragmentHandlerThisContext<TDefinition>
|
|
368
|
+
>,
|
|
369
|
+
) => FragnoRouteConfig<
|
|
370
|
+
TMethod,
|
|
371
|
+
TPath,
|
|
372
|
+
TInputSchema,
|
|
373
|
+
TOutputSchema,
|
|
374
|
+
TErrorCode,
|
|
375
|
+
TQueryParameters,
|
|
376
|
+
ExtractFragmentHandlerThisContext<TDefinition>
|
|
377
|
+
>;
|
|
378
|
+
},
|
|
379
|
+
) => TRoutes,
|
|
380
|
+
) => RouteFactory<
|
|
381
|
+
ExtractFragmentConfig<TDefinition>,
|
|
382
|
+
ExtractFragmentDeps<TDefinition>,
|
|
383
|
+
ExtractFragmentServices<TDefinition>,
|
|
384
|
+
ExtractFragmentServiceDeps<TDefinition>,
|
|
385
|
+
TRoutes
|
|
386
|
+
>;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// Implementation
|
|
390
|
+
export function defineRoutes<
|
|
391
|
+
const TDefinition extends AnyFragmentDefinition | undefined = undefined,
|
|
392
|
+
>(
|
|
393
|
+
// Parameter is only used for type inference, not runtime
|
|
394
|
+
_definition?: TDefinition,
|
|
395
|
+
) {
|
|
129
396
|
return {
|
|
130
397
|
create: <
|
|
131
398
|
const TRoutes extends readonly FragnoRouteConfig<
|
|
@@ -134,12 +401,66 @@ export function defineRoutes<TConfig = {}, TDeps = {}, TServices = {}>() {
|
|
|
134
401
|
StandardSchemaV1 | undefined,
|
|
135
402
|
StandardSchemaV1 | undefined,
|
|
136
403
|
string,
|
|
137
|
-
string
|
|
404
|
+
string,
|
|
405
|
+
TDefinition extends AnyFragmentDefinition
|
|
406
|
+
? ExtractFragmentThisContext<TDefinition>
|
|
407
|
+
: RequestThisContext
|
|
138
408
|
>[],
|
|
139
409
|
>(
|
|
140
|
-
fn: (
|
|
141
|
-
|
|
142
|
-
|
|
410
|
+
fn: (
|
|
411
|
+
context: RouteFactoryContext<
|
|
412
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentConfig<TDefinition> : {},
|
|
413
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentDeps<TDefinition> : {},
|
|
414
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentServices<TDefinition> : {},
|
|
415
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentServiceDeps<TDefinition> : {}
|
|
416
|
+
> & {
|
|
417
|
+
defineRoute: <
|
|
418
|
+
const TMethod extends HTTPMethod,
|
|
419
|
+
const TPath extends string,
|
|
420
|
+
const TInputSchema extends StandardSchemaV1 | undefined,
|
|
421
|
+
const TOutputSchema extends StandardSchemaV1 | undefined,
|
|
422
|
+
const TErrorCode extends string = string,
|
|
423
|
+
const TQueryParameters extends string = string,
|
|
424
|
+
>(
|
|
425
|
+
config: FragnoRouteConfig<
|
|
426
|
+
TMethod,
|
|
427
|
+
TPath,
|
|
428
|
+
TInputSchema,
|
|
429
|
+
TOutputSchema,
|
|
430
|
+
TErrorCode,
|
|
431
|
+
TQueryParameters,
|
|
432
|
+
TDefinition extends AnyFragmentDefinition
|
|
433
|
+
? ExtractFragmentThisContext<TDefinition>
|
|
434
|
+
: RequestThisContext
|
|
435
|
+
>,
|
|
436
|
+
) => FragnoRouteConfig<
|
|
437
|
+
TMethod,
|
|
438
|
+
TPath,
|
|
439
|
+
TInputSchema,
|
|
440
|
+
TOutputSchema,
|
|
441
|
+
TErrorCode,
|
|
442
|
+
TQueryParameters,
|
|
443
|
+
TDefinition extends AnyFragmentDefinition
|
|
444
|
+
? ExtractFragmentThisContext<TDefinition>
|
|
445
|
+
: RequestThisContext
|
|
446
|
+
>;
|
|
447
|
+
},
|
|
448
|
+
) => TRoutes,
|
|
449
|
+
): RouteFactory<
|
|
450
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentConfig<TDefinition> : {},
|
|
451
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentDeps<TDefinition> : {},
|
|
452
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentServices<TDefinition> : {},
|
|
453
|
+
TDefinition extends AnyFragmentDefinition ? ExtractFragmentServiceDeps<TDefinition> : {},
|
|
454
|
+
TRoutes
|
|
455
|
+
> => {
|
|
456
|
+
// Create a wrapper around the callback that adds the defineRoute function
|
|
457
|
+
return (ctx: RouteFactoryContext<unknown, unknown, unknown, unknown>) => {
|
|
458
|
+
const extendedCtx = {
|
|
459
|
+
...ctx,
|
|
460
|
+
defineRoute,
|
|
461
|
+
};
|
|
462
|
+
return fn(extendedCtx as any);
|
|
463
|
+
};
|
|
143
464
|
},
|
|
144
465
|
};
|
|
145
466
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { HTTPMethod } from "./api";
|
|
2
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Public configuration for Fragno fragments on the server side.
|
|
6
|
+
*/
|
|
7
|
+
export interface FragnoPublicConfig {
|
|
8
|
+
mountRoute?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for custom fetch behavior in client-side fragments.
|
|
13
|
+
*/
|
|
14
|
+
export type FetcherConfig =
|
|
15
|
+
| { type: "options"; options: RequestInit }
|
|
16
|
+
| { type: "function"; fetcher: typeof fetch };
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Public configuration for Fragno fragments on the client side.
|
|
20
|
+
*/
|
|
21
|
+
export interface FragnoPublicClientConfig {
|
|
22
|
+
mountRoute?: string;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
fetcherConfig?: FetcherConfig;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Shared configuration for fragment routes.
|
|
29
|
+
*/
|
|
30
|
+
export interface FragnoFragmentSharedConfig<
|
|
31
|
+
TRoutes extends readonly {
|
|
32
|
+
method: HTTPMethod;
|
|
33
|
+
path: string;
|
|
34
|
+
inputSchema?: StandardSchemaV1 | undefined;
|
|
35
|
+
outputSchema?: StandardSchemaV1 | undefined;
|
|
36
|
+
errorCodes?: readonly string[];
|
|
37
|
+
queryParameters?: readonly string[];
|
|
38
|
+
pathParameters?: readonly string[];
|
|
39
|
+
}[] = [],
|
|
40
|
+
> {
|
|
41
|
+
name: string;
|
|
42
|
+
routes: TRoutes;
|
|
43
|
+
}
|