@fragno-dev/core 0.1.8 → 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 -56
- package/CHANGELOG.md +13 -0
- package/dist/api/api.d.ts +38 -2
- package/dist/api/api.d.ts.map +1 -0
- package/dist/api/api.js +9 -3
- 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/error.js +48 -0
- 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 -2
- 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 -2
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +397 -5
- package/dist/client/client.js.map +1 -0
- package/dist/client/client.svelte.d.ts +5 -2
- package/dist/client/client.svelte.d.ts.map +1 -1
- package/dist/client/client.svelte.js +1 -4
- 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 -2
- package/dist/client/react.d.ts.map +1 -1
- package/dist/client/react.js +3 -4
- package/dist/client/react.js.map +1 -1
- package/dist/client/solid.d.ts +5 -2
- package/dist/client/solid.d.ts.map +1 -1
- package/dist/client/solid.js +2 -4
- package/dist/client/solid.js.map +1 -1
- package/dist/client/vanilla.d.ts +5 -2
- package/dist/client/vanilla.d.ts.map +1 -1
- package/dist/client/vanilla.js +2 -42
- package/dist/client/vanilla.js.map +1 -1
- package/dist/client/vue.d.ts +5 -2
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +1 -4
- 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 -2
- package/dist/mod.js +4 -4
- package/dist/request/request.d.ts +4 -0
- package/dist/request/request.js +5 -0
- package/dist/test/test.d.ts +62 -34
- package/dist/test/test.d.ts.map +1 -1
- package/dist/test/test.js +75 -42
- 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-kyKI7pqH.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 +1 -5
- 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 +454 -189
- package/src/api/request-context-storage.ts +64 -0
- package/src/api/request-middleware.test.ts +301 -228
- package/src/api/route.test.ts +12 -36
- package/src/api/route.ts +167 -155
- 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 +22 -15
- package/src/request/request.ts +8 -0
- package/src/test/test.test.ts +189 -375
- package/src/test/test.ts +186 -152
- package/tsdown.config.ts +8 -5
- package/dist/api/fragment-builder.d.ts +0 -2
- package/dist/api/fragment-builder.js +0 -3
- package/dist/api/fragment-instantiation.d.ts +0 -2
- package/dist/api/fragment-instantiation.js +0 -4
- package/dist/api-BFrUCIsF.d.ts +0 -963
- package/dist/api-BFrUCIsF.d.ts.map +0 -1
- package/dist/client-DAFHcKqA.js +0 -782
- package/dist/client-DAFHcKqA.js.map +0 -1
- package/dist/fragment-builder-Boh2vNHq.js +0 -108
- package/dist/fragment-builder-Boh2vNHq.js.map +0 -1
- package/dist/fragment-instantiation-DUT-HLl1.js +0 -898
- package/dist/fragment-instantiation-DUT-HLl1.js.map +0 -1
- package/dist/route-C4CyNHkC.js +0 -26
- package/dist/route-C4CyNHkC.js.map +0 -1
- package/dist/ssr-kyKI7pqH.js.map +0 -1
- package/src/api/fragment-builder.ts +0 -518
- package/src/api/fragment-instantiation.test.ts +0 -702
- package/src/api/fragment-instantiation.ts +0 -766
- package/src/api/fragment.test.ts +0 -585
|
@@ -1,766 +0,0 @@
|
|
|
1
|
-
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
-
import { type FragnoRouteConfig, type HTTPMethod, type RequestThisContext } from "./api";
|
|
3
|
-
import { FragnoApiError } from "./error";
|
|
4
|
-
import { getMountRoute } from "./internal/route";
|
|
5
|
-
import { addRoute, createRouter, findRoute } from "rou3";
|
|
6
|
-
import { RequestInputContext, type RequestBodyType } from "./request-input-context";
|
|
7
|
-
import type { ExtractPathParams } from "./internal/path";
|
|
8
|
-
import { RequestOutputContext } from "./request-output-context";
|
|
9
|
-
import {
|
|
10
|
-
type AnyFragnoRouteConfig,
|
|
11
|
-
type AnyRouteOrFactory,
|
|
12
|
-
type FlattenRouteFactories,
|
|
13
|
-
resolveRouteFactories,
|
|
14
|
-
} from "./route";
|
|
15
|
-
import {
|
|
16
|
-
RequestMiddlewareInputContext,
|
|
17
|
-
RequestMiddlewareOutputContext,
|
|
18
|
-
type FragnoMiddlewareCallback,
|
|
19
|
-
} from "./request-middleware";
|
|
20
|
-
import type { FragmentDefinition, RouteHandler } from "./fragment-builder";
|
|
21
|
-
import { MutableRequestState } from "./mutable-request-state";
|
|
22
|
-
import type { RouteHandlerInputOptions } from "./route-handler-input-options";
|
|
23
|
-
import type { ExtractRouteByPath, ExtractRoutePath } from "../client/client";
|
|
24
|
-
import { type FragnoResponse, parseFragnoResponse } from "./fragno-response";
|
|
25
|
-
import type { InferOrUnknown } from "../util/types-util";
|
|
26
|
-
|
|
27
|
-
export interface FragnoPublicConfig {
|
|
28
|
-
mountRoute?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type FetcherConfig =
|
|
32
|
-
| { type: "options"; options: RequestInit }
|
|
33
|
-
| { type: "function"; fetcher: typeof fetch };
|
|
34
|
-
|
|
35
|
-
export interface FragnoPublicClientConfig {
|
|
36
|
-
mountRoute?: string;
|
|
37
|
-
baseUrl?: string;
|
|
38
|
-
fetcherConfig?: FetcherConfig;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
type AstroHandlers = {
|
|
42
|
-
ALL: (req: Request) => Promise<Response>;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
type ReactRouterHandlers = {
|
|
46
|
-
loader: (args: { request: Request }) => Promise<Response>;
|
|
47
|
-
action: (args: { request: Request }) => Promise<Response>;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
type SolidStartHandlers = {
|
|
51
|
-
GET: (args: { request: Request }) => Promise<Response>;
|
|
52
|
-
POST: (args: { request: Request }) => Promise<Response>;
|
|
53
|
-
PUT: (args: { request: Request }) => Promise<Response>;
|
|
54
|
-
DELETE: (args: { request: Request }) => Promise<Response>;
|
|
55
|
-
PATCH: (args: { request: Request }) => Promise<Response>;
|
|
56
|
-
HEAD: (args: { request: Request }) => Promise<Response>;
|
|
57
|
-
OPTIONS: (args: { request: Request }) => Promise<Response>;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
type TanStackStartHandlers = SolidStartHandlers;
|
|
61
|
-
|
|
62
|
-
type StandardHandlers = {
|
|
63
|
-
GET: (req: Request) => Promise<Response>;
|
|
64
|
-
POST: (req: Request) => Promise<Response>;
|
|
65
|
-
PUT: (req: Request) => Promise<Response>;
|
|
66
|
-
DELETE: (req: Request) => Promise<Response>;
|
|
67
|
-
PATCH: (req: Request) => Promise<Response>;
|
|
68
|
-
HEAD: (req: Request) => Promise<Response>;
|
|
69
|
-
OPTIONS: (req: Request) => Promise<Response>;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
type HandlersByFramework = {
|
|
73
|
-
astro: AstroHandlers;
|
|
74
|
-
"react-router": ReactRouterHandlers;
|
|
75
|
-
"next-js": StandardHandlers;
|
|
76
|
-
"svelte-kit": StandardHandlers;
|
|
77
|
-
"solid-start": SolidStartHandlers;
|
|
78
|
-
"tanstack-start": TanStackStartHandlers;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// Not actually a symbol, since we might be dealing with multiple instances of this code.
|
|
82
|
-
export const instantiatedFragmentFakeSymbol = "$fragno-instantiated-fragment" as const;
|
|
83
|
-
|
|
84
|
-
type FullstackFrameworks = keyof HandlersByFramework;
|
|
85
|
-
|
|
86
|
-
export interface FragnoInstantiatedFragment<
|
|
87
|
-
TRoutes extends readonly AnyFragnoRouteConfig[] = [],
|
|
88
|
-
TDeps = {},
|
|
89
|
-
TServices extends Record<string, unknown> = Record<string, unknown>,
|
|
90
|
-
TAdditionalContext extends Record<string, unknown> = {},
|
|
91
|
-
> {
|
|
92
|
-
[instantiatedFragmentFakeSymbol]: typeof instantiatedFragmentFakeSymbol;
|
|
93
|
-
|
|
94
|
-
config: FragnoFragmentSharedConfig<TRoutes>;
|
|
95
|
-
deps: TDeps;
|
|
96
|
-
services: TServices;
|
|
97
|
-
additionalContext?: TAdditionalContext;
|
|
98
|
-
handlersFor: <T extends FullstackFrameworks>(framework: T) => HandlersByFramework[T];
|
|
99
|
-
handler: (req: Request) => Promise<Response>;
|
|
100
|
-
mountRoute: string;
|
|
101
|
-
callRoute: <TMethod extends HTTPMethod, TPath extends ExtractRoutePath<TRoutes, TMethod>>(
|
|
102
|
-
method: TMethod,
|
|
103
|
-
path: TPath,
|
|
104
|
-
inputOptions?: RouteHandlerInputOptions<
|
|
105
|
-
TPath,
|
|
106
|
-
ExtractRouteByPath<TRoutes, TPath, TMethod>["inputSchema"]
|
|
107
|
-
>,
|
|
108
|
-
) => Promise<
|
|
109
|
-
FragnoResponse<
|
|
110
|
-
InferOrUnknown<NonNullable<ExtractRouteByPath<TRoutes, TPath, TMethod>["outputSchema"]>>
|
|
111
|
-
>
|
|
112
|
-
>;
|
|
113
|
-
callRouteRaw: <TMethod extends HTTPMethod, TPath extends ExtractRoutePath<TRoutes, TMethod>>(
|
|
114
|
-
method: TMethod,
|
|
115
|
-
path: TPath,
|
|
116
|
-
inputOptions?: RouteHandlerInputOptions<
|
|
117
|
-
TPath,
|
|
118
|
-
ExtractRouteByPath<TRoutes, TPath, TMethod>["inputSchema"]
|
|
119
|
-
>,
|
|
120
|
-
) => Promise<Response>;
|
|
121
|
-
withMiddleware: (
|
|
122
|
-
handler: FragnoMiddlewareCallback<TRoutes, TDeps, TServices>,
|
|
123
|
-
) => FragnoInstantiatedFragment<TRoutes, TDeps, TServices, TAdditionalContext>;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export interface FragnoFragmentSharedConfig<
|
|
127
|
-
TRoutes extends readonly FragnoRouteConfig<
|
|
128
|
-
HTTPMethod,
|
|
129
|
-
string,
|
|
130
|
-
StandardSchemaV1 | undefined,
|
|
131
|
-
StandardSchemaV1 | undefined,
|
|
132
|
-
string,
|
|
133
|
-
string
|
|
134
|
-
>[],
|
|
135
|
-
> {
|
|
136
|
-
name: string;
|
|
137
|
-
routes: TRoutes;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export type AnyFragnoFragmentSharedConfig = FragnoFragmentSharedConfig<
|
|
141
|
-
readonly AnyFragnoRouteConfig[]
|
|
142
|
-
>;
|
|
143
|
-
|
|
144
|
-
export function createFragment<
|
|
145
|
-
const TConfig,
|
|
146
|
-
const TDeps,
|
|
147
|
-
const TServices extends Record<string, unknown>,
|
|
148
|
-
const TRoutesOrFactories extends readonly AnyRouteOrFactory[],
|
|
149
|
-
const TAdditionalContext extends Record<string, unknown>,
|
|
150
|
-
const TRequiredInterfaces extends Record<string, unknown>,
|
|
151
|
-
const TProvidedInterfaces extends Record<string, unknown>,
|
|
152
|
-
const TOptions extends FragnoPublicConfig,
|
|
153
|
-
const TThisContext extends RequestThisContext = RequestThisContext,
|
|
154
|
-
>(
|
|
155
|
-
fragmentBuilder: {
|
|
156
|
-
definition: FragmentDefinition<
|
|
157
|
-
TConfig,
|
|
158
|
-
TDeps,
|
|
159
|
-
TServices,
|
|
160
|
-
TAdditionalContext,
|
|
161
|
-
TRequiredInterfaces,
|
|
162
|
-
TProvidedInterfaces,
|
|
163
|
-
TThisContext
|
|
164
|
-
>;
|
|
165
|
-
$requiredOptions: TOptions;
|
|
166
|
-
},
|
|
167
|
-
config: TConfig,
|
|
168
|
-
routesOrFactories: TRoutesOrFactories,
|
|
169
|
-
options: TOptions,
|
|
170
|
-
interfaceImplementations?: TRequiredInterfaces,
|
|
171
|
-
): FragnoInstantiatedFragment<
|
|
172
|
-
FlattenRouteFactories<TRoutesOrFactories>,
|
|
173
|
-
TDeps & TRequiredInterfaces,
|
|
174
|
-
TServices & TProvidedInterfaces & TRequiredInterfaces,
|
|
175
|
-
TAdditionalContext
|
|
176
|
-
> {
|
|
177
|
-
type TRoutes = FlattenRouteFactories<TRoutesOrFactories>;
|
|
178
|
-
|
|
179
|
-
const definition = fragmentBuilder.definition;
|
|
180
|
-
|
|
181
|
-
// Validate required services are satisfied
|
|
182
|
-
if (definition.usedServices) {
|
|
183
|
-
for (const [serviceName, serviceMeta] of Object.entries(definition.usedServices)) {
|
|
184
|
-
const implementation = interfaceImplementations?.[serviceName];
|
|
185
|
-
if (serviceMeta.required && !implementation) {
|
|
186
|
-
throw new Error(
|
|
187
|
-
`Fragment '${definition.name}' requires service '${serviceMeta.name}' but it was not provided`,
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const dependencies = definition.dependencies?.(config, options) ?? ({} as TDeps);
|
|
194
|
-
|
|
195
|
-
// Merge interface implementations into dependencies
|
|
196
|
-
const depsWithInterfaces = {
|
|
197
|
-
...dependencies,
|
|
198
|
-
...interfaceImplementations,
|
|
199
|
-
} as TDeps & TRequiredInterfaces;
|
|
200
|
-
|
|
201
|
-
const servicesFromWithServices =
|
|
202
|
-
definition.services?.(config, options, depsWithInterfaces) ?? ({} as TServices);
|
|
203
|
-
|
|
204
|
-
// Handle providedServices - can be:
|
|
205
|
-
// 1. A function that returns all services
|
|
206
|
-
// 2. An object where each value is a factory function
|
|
207
|
-
// 3. undefined
|
|
208
|
-
let providedServicesResolved: TProvidedInterfaces | undefined;
|
|
209
|
-
|
|
210
|
-
if (typeof definition.providedServices === "function") {
|
|
211
|
-
// Case 1: It's a function, call it to get the services
|
|
212
|
-
providedServicesResolved = definition.providedServices(config, options, depsWithInterfaces);
|
|
213
|
-
} else if (definition.providedServices && typeof definition.providedServices === "object") {
|
|
214
|
-
// Case 2: It's an object where each value might be a factory function
|
|
215
|
-
providedServicesResolved = {} as TProvidedInterfaces;
|
|
216
|
-
for (const [serviceName, serviceOrFactory] of Object.entries(definition.providedServices)) {
|
|
217
|
-
if (typeof serviceOrFactory === "function") {
|
|
218
|
-
// Call the factory function
|
|
219
|
-
(providedServicesResolved as Record<string, unknown>)[serviceName] = serviceOrFactory(
|
|
220
|
-
config,
|
|
221
|
-
options,
|
|
222
|
-
depsWithInterfaces,
|
|
223
|
-
);
|
|
224
|
-
} else {
|
|
225
|
-
// It's already a resolved service
|
|
226
|
-
(providedServicesResolved as Record<string, unknown>)[serviceName] = serviceOrFactory;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const services = {
|
|
232
|
-
...servicesFromWithServices,
|
|
233
|
-
...providedServicesResolved,
|
|
234
|
-
...interfaceImplementations,
|
|
235
|
-
} as TServices & TProvidedInterfaces & TRequiredInterfaces;
|
|
236
|
-
|
|
237
|
-
const context = { config, deps: depsWithInterfaces, services };
|
|
238
|
-
const routes = resolveRouteFactories(context, routesOrFactories);
|
|
239
|
-
|
|
240
|
-
const mountRoute = getMountRoute({
|
|
241
|
-
name: definition.name,
|
|
242
|
-
mountRoute: options.mountRoute,
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
const router =
|
|
246
|
-
createRouter<
|
|
247
|
-
FragnoRouteConfig<
|
|
248
|
-
HTTPMethod,
|
|
249
|
-
string,
|
|
250
|
-
StandardSchemaV1 | undefined,
|
|
251
|
-
StandardSchemaV1 | undefined,
|
|
252
|
-
string,
|
|
253
|
-
string,
|
|
254
|
-
RequestThisContext
|
|
255
|
-
>
|
|
256
|
-
>();
|
|
257
|
-
|
|
258
|
-
let middlewareHandler:
|
|
259
|
-
| FragnoMiddlewareCallback<
|
|
260
|
-
FlattenRouteFactories<TRoutesOrFactories>,
|
|
261
|
-
TDeps & TRequiredInterfaces,
|
|
262
|
-
TServices & TProvidedInterfaces & TRequiredInterfaces
|
|
263
|
-
>
|
|
264
|
-
| undefined;
|
|
265
|
-
|
|
266
|
-
// Store the handler wrapper if provided (e.g., for database support)
|
|
267
|
-
const handlerWrapper = definition.createHandlerWrapper?.(options);
|
|
268
|
-
|
|
269
|
-
for (const routeConfig of routes) {
|
|
270
|
-
addRoute(router, routeConfig.method.toUpperCase(), routeConfig.path, routeConfig);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const fragment: FragnoInstantiatedFragment<
|
|
274
|
-
FlattenRouteFactories<TRoutesOrFactories>,
|
|
275
|
-
TDeps & TRequiredInterfaces,
|
|
276
|
-
TServices & TProvidedInterfaces & TRequiredInterfaces,
|
|
277
|
-
TAdditionalContext & TOptions
|
|
278
|
-
> = {
|
|
279
|
-
[instantiatedFragmentFakeSymbol]: instantiatedFragmentFakeSymbol,
|
|
280
|
-
mountRoute,
|
|
281
|
-
config: {
|
|
282
|
-
name: definition.name,
|
|
283
|
-
routes,
|
|
284
|
-
},
|
|
285
|
-
services,
|
|
286
|
-
deps: depsWithInterfaces,
|
|
287
|
-
additionalContext: {
|
|
288
|
-
...definition.additionalContext,
|
|
289
|
-
...options,
|
|
290
|
-
} as TAdditionalContext & TOptions,
|
|
291
|
-
withMiddleware: (handler) => {
|
|
292
|
-
if (middlewareHandler) {
|
|
293
|
-
throw new Error("Middleware already set");
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
middlewareHandler = handler;
|
|
297
|
-
|
|
298
|
-
return fragment;
|
|
299
|
-
},
|
|
300
|
-
callRoute: async <TMethod extends HTTPMethod, TPath extends ExtractRoutePath<TRoutes, TMethod>>(
|
|
301
|
-
method: TMethod,
|
|
302
|
-
path: TPath,
|
|
303
|
-
inputOptions?: RouteHandlerInputOptions<
|
|
304
|
-
TPath,
|
|
305
|
-
ExtractRouteByPath<TRoutes, TPath, TMethod>["inputSchema"]
|
|
306
|
-
>,
|
|
307
|
-
): Promise<
|
|
308
|
-
FragnoResponse<
|
|
309
|
-
InferOrUnknown<NonNullable<ExtractRouteByPath<TRoutes, TPath, TMethod>["outputSchema"]>>
|
|
310
|
-
>
|
|
311
|
-
> => {
|
|
312
|
-
const response = await fragment.callRouteRaw(method, path, inputOptions);
|
|
313
|
-
return parseFragnoResponse(response);
|
|
314
|
-
},
|
|
315
|
-
callRouteRaw: async <
|
|
316
|
-
TMethod extends HTTPMethod,
|
|
317
|
-
TPath extends ExtractRoutePath<TRoutes, TMethod>,
|
|
318
|
-
>(
|
|
319
|
-
method: TMethod,
|
|
320
|
-
path: TPath,
|
|
321
|
-
inputOptions?: RouteHandlerInputOptions<
|
|
322
|
-
TPath,
|
|
323
|
-
ExtractRouteByPath<TRoutes, TPath, TMethod>["inputSchema"]
|
|
324
|
-
>,
|
|
325
|
-
): Promise<Response> => {
|
|
326
|
-
// Find the route configuration
|
|
327
|
-
const route = routes.find((r) => r.method === method && r.path === path);
|
|
328
|
-
|
|
329
|
-
if (!route) {
|
|
330
|
-
return Response.json(
|
|
331
|
-
{
|
|
332
|
-
error: `Route ${method} ${path} not found`,
|
|
333
|
-
code: "ROUTE_NOT_FOUND",
|
|
334
|
-
},
|
|
335
|
-
{ status: 404 },
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const {
|
|
340
|
-
pathParams = {} as ExtractPathParams<TPath>,
|
|
341
|
-
body,
|
|
342
|
-
query,
|
|
343
|
-
headers,
|
|
344
|
-
} = inputOptions || {};
|
|
345
|
-
|
|
346
|
-
// Convert query to URLSearchParams if needed
|
|
347
|
-
const searchParams =
|
|
348
|
-
query instanceof URLSearchParams
|
|
349
|
-
? query
|
|
350
|
-
: query
|
|
351
|
-
? new URLSearchParams(query)
|
|
352
|
-
: new URLSearchParams();
|
|
353
|
-
|
|
354
|
-
// Convert headers to Headers if needed
|
|
355
|
-
const requestHeaders =
|
|
356
|
-
headers instanceof Headers ? headers : headers ? new Headers(headers) : new Headers();
|
|
357
|
-
|
|
358
|
-
// Construct RequestInputContext
|
|
359
|
-
const inputContext = new RequestInputContext({
|
|
360
|
-
path: route.path,
|
|
361
|
-
method: route.method,
|
|
362
|
-
pathParams,
|
|
363
|
-
searchParams,
|
|
364
|
-
headers: requestHeaders,
|
|
365
|
-
parsedBody: body,
|
|
366
|
-
inputSchema: route.inputSchema,
|
|
367
|
-
shouldValidateInput: true, // Enable validation for production use
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
// Construct RequestOutputContext
|
|
371
|
-
const outputContext = new RequestOutputContext(route.outputSchema);
|
|
372
|
-
|
|
373
|
-
// Call the route handler (wrap with handlerWrapper if provided)
|
|
374
|
-
try {
|
|
375
|
-
let response: Response;
|
|
376
|
-
const thisContext: RequestThisContext = {};
|
|
377
|
-
|
|
378
|
-
if (handlerWrapper) {
|
|
379
|
-
// Wrapper handles binding the this context internally for database fragments
|
|
380
|
-
// Safe: wrapper knows how to handle the specific this type (DatabaseRequestThisContext)
|
|
381
|
-
const wrappedHandler = handlerWrapper(route.handler as unknown as RouteHandler);
|
|
382
|
-
response = await wrappedHandler.call(thisContext, inputContext, outputContext);
|
|
383
|
-
} else {
|
|
384
|
-
// For standard fragments, bind to an empty RequestThisContext
|
|
385
|
-
// Safe: we know route.handler expects RequestThisContext for standard fragments
|
|
386
|
-
response = await (route.handler as RouteHandler).call(
|
|
387
|
-
thisContext,
|
|
388
|
-
inputContext,
|
|
389
|
-
outputContext,
|
|
390
|
-
);
|
|
391
|
-
}
|
|
392
|
-
return response;
|
|
393
|
-
} catch (error) {
|
|
394
|
-
console.error("Error in callRoute handler", error);
|
|
395
|
-
|
|
396
|
-
if (error instanceof FragnoApiError) {
|
|
397
|
-
return error.toResponse();
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return Response.json(
|
|
401
|
-
{ error: "Internal server error", code: "INTERNAL_SERVER_ERROR" },
|
|
402
|
-
{ status: 500 },
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
},
|
|
406
|
-
handlersFor: <T extends FullstackFrameworks>(framework: T): HandlersByFramework[T] => {
|
|
407
|
-
const handler = fragment.handler;
|
|
408
|
-
|
|
409
|
-
// LLMs hallucinate these values sometimes, solution isn't obvious so we throw this error
|
|
410
|
-
// @ts-expect-error TS2367
|
|
411
|
-
if (framework === "h3" || framework === "nuxt") {
|
|
412
|
-
throw new Error(`To get handlers for h3, use the 'fromWebHandler' utility function:
|
|
413
|
-
import { fromWebHandler } from "h3";
|
|
414
|
-
export default fromWebHandler(myFragment().handler);`);
|
|
415
|
-
}
|
|
416
|
-
const allHandlers = {
|
|
417
|
-
astro: { ALL: handler },
|
|
418
|
-
"react-router": {
|
|
419
|
-
loader: ({ request }: { request: Request }) => handler(request),
|
|
420
|
-
action: ({ request }: { request: Request }) => handler(request),
|
|
421
|
-
},
|
|
422
|
-
"next-js": {
|
|
423
|
-
GET: handler,
|
|
424
|
-
POST: handler,
|
|
425
|
-
PUT: handler,
|
|
426
|
-
DELETE: handler,
|
|
427
|
-
PATCH: handler,
|
|
428
|
-
HEAD: handler,
|
|
429
|
-
OPTIONS: handler,
|
|
430
|
-
},
|
|
431
|
-
"svelte-kit": {
|
|
432
|
-
GET: handler,
|
|
433
|
-
POST: handler,
|
|
434
|
-
PUT: handler,
|
|
435
|
-
DELETE: handler,
|
|
436
|
-
PATCH: handler,
|
|
437
|
-
HEAD: handler,
|
|
438
|
-
OPTIONS: handler,
|
|
439
|
-
},
|
|
440
|
-
"solid-start": {
|
|
441
|
-
GET: ({ request }: { request: Request }) => handler(request),
|
|
442
|
-
POST: ({ request }: { request: Request }) => handler(request),
|
|
443
|
-
PUT: ({ request }: { request: Request }) => handler(request),
|
|
444
|
-
DELETE: ({ request }: { request: Request }) => handler(request),
|
|
445
|
-
PATCH: ({ request }: { request: Request }) => handler(request),
|
|
446
|
-
HEAD: ({ request }: { request: Request }) => handler(request),
|
|
447
|
-
OPTIONS: ({ request }: { request: Request }) => handler(request),
|
|
448
|
-
},
|
|
449
|
-
"tanstack-start": {
|
|
450
|
-
GET: ({ request }: { request: Request }) => handler(request),
|
|
451
|
-
POST: ({ request }: { request: Request }) => handler(request),
|
|
452
|
-
PUT: ({ request }: { request: Request }) => handler(request),
|
|
453
|
-
DELETE: ({ request }: { request: Request }) => handler(request),
|
|
454
|
-
PATCH: ({ request }: { request: Request }) => handler(request),
|
|
455
|
-
HEAD: ({ request }: { request: Request }) => handler(request),
|
|
456
|
-
OPTIONS: ({ request }: { request: Request }) => handler(request),
|
|
457
|
-
},
|
|
458
|
-
} satisfies HandlersByFramework;
|
|
459
|
-
|
|
460
|
-
return allHandlers[framework];
|
|
461
|
-
},
|
|
462
|
-
handler: async (req: Request) => {
|
|
463
|
-
const url = new URL(req.url);
|
|
464
|
-
const pathname = url.pathname;
|
|
465
|
-
|
|
466
|
-
const matchRoute = pathname.startsWith(mountRoute) ? pathname.slice(mountRoute.length) : null;
|
|
467
|
-
|
|
468
|
-
if (matchRoute === null) {
|
|
469
|
-
return Response.json(
|
|
470
|
-
{
|
|
471
|
-
error:
|
|
472
|
-
`Fragno: Route for '${definition.name}' not found. Is the fragment mounted on the right route? ` +
|
|
473
|
-
`Expecting: '${mountRoute}'.`,
|
|
474
|
-
code: "ROUTE_NOT_FOUND",
|
|
475
|
-
},
|
|
476
|
-
{ status: 404 },
|
|
477
|
-
);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
const route = findRoute(router, req.method, matchRoute);
|
|
481
|
-
|
|
482
|
-
if (!route) {
|
|
483
|
-
return Response.json(
|
|
484
|
-
{ error: `Fragno: Route for '${definition.name}' not found`, code: "ROUTE_NOT_FOUND" },
|
|
485
|
-
{ status: 404 },
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
const { handler, inputSchema, outputSchema, path } = route.data;
|
|
490
|
-
|
|
491
|
-
const outputContext = new RequestOutputContext(outputSchema);
|
|
492
|
-
|
|
493
|
-
// Create mutable request state that can be modified by middleware
|
|
494
|
-
// Clone the request to read body as both text and JSON without consuming original stream
|
|
495
|
-
let requestBody: RequestBodyType = undefined;
|
|
496
|
-
let rawBody: string | undefined = undefined;
|
|
497
|
-
|
|
498
|
-
if (req.body instanceof ReadableStream) {
|
|
499
|
-
// Clone request to make sure we don't consume body stream
|
|
500
|
-
const clonedReq = req.clone();
|
|
501
|
-
|
|
502
|
-
// Get raw text
|
|
503
|
-
rawBody = await clonedReq.text();
|
|
504
|
-
|
|
505
|
-
// Parse JSON if body is not empty
|
|
506
|
-
if (rawBody) {
|
|
507
|
-
try {
|
|
508
|
-
requestBody = JSON.parse(rawBody);
|
|
509
|
-
} catch {
|
|
510
|
-
// If JSON parsing fails, keep body as undefined
|
|
511
|
-
// This handles cases where body is not JSON
|
|
512
|
-
requestBody = undefined;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const requestState = new MutableRequestState({
|
|
518
|
-
pathParams: route.params ?? {},
|
|
519
|
-
searchParams: url.searchParams,
|
|
520
|
-
body: requestBody,
|
|
521
|
-
headers: new Headers(req.headers),
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
if (middlewareHandler) {
|
|
525
|
-
const middlewareInputContext = new RequestMiddlewareInputContext(routes, {
|
|
526
|
-
method: req.method as HTTPMethod,
|
|
527
|
-
path,
|
|
528
|
-
request: req,
|
|
529
|
-
state: requestState,
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
const middlewareOutputContext = new RequestMiddlewareOutputContext(
|
|
533
|
-
depsWithInterfaces,
|
|
534
|
-
services,
|
|
535
|
-
);
|
|
536
|
-
|
|
537
|
-
try {
|
|
538
|
-
const middlewareResult = await middlewareHandler(
|
|
539
|
-
middlewareInputContext,
|
|
540
|
-
middlewareOutputContext,
|
|
541
|
-
);
|
|
542
|
-
if (middlewareResult !== undefined) {
|
|
543
|
-
return middlewareResult;
|
|
544
|
-
}
|
|
545
|
-
} catch (error) {
|
|
546
|
-
console.error("Error in middleware", error);
|
|
547
|
-
|
|
548
|
-
if (error instanceof FragnoApiError) {
|
|
549
|
-
// TODO: If a validation error occurs in middleware (when calling `await input.valid()`)
|
|
550
|
-
// the processing is short-circuited and a potential `catch` block around the call
|
|
551
|
-
// to `input.valid()` in the actual handler will not be executed.
|
|
552
|
-
return error.toResponse();
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
return Response.json(
|
|
556
|
-
{ error: "Internal server error", code: "INTERNAL_SERVER_ERROR" },
|
|
557
|
-
{ status: 500 },
|
|
558
|
-
);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
const inputContext = await RequestInputContext.fromRequest({
|
|
563
|
-
request: req,
|
|
564
|
-
method: req.method,
|
|
565
|
-
path,
|
|
566
|
-
pathParams: (route.params ?? {}) as ExtractPathParams<typeof path>,
|
|
567
|
-
inputSchema,
|
|
568
|
-
state: requestState,
|
|
569
|
-
rawBody,
|
|
570
|
-
});
|
|
571
|
-
|
|
572
|
-
try {
|
|
573
|
-
// Apply handler wrapper if provided (e.g., for database support)
|
|
574
|
-
// Safe cast: handler wrapper preserves handler signature
|
|
575
|
-
const actualHandler = handlerWrapper
|
|
576
|
-
? (handlerWrapper(handler as RouteHandler) as typeof handler)
|
|
577
|
-
: handler;
|
|
578
|
-
|
|
579
|
-
// Create base this context (empty object for standard fragments)
|
|
580
|
-
// Database fragments will provide their own context via handler wrapper
|
|
581
|
-
const thisContext = {} as RequestThisContext;
|
|
582
|
-
const result = await actualHandler.call(thisContext, inputContext, outputContext);
|
|
583
|
-
return result;
|
|
584
|
-
} catch (error) {
|
|
585
|
-
console.error("Error in handler", error);
|
|
586
|
-
|
|
587
|
-
if (error instanceof FragnoApiError) {
|
|
588
|
-
return error.toResponse();
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
return Response.json(
|
|
592
|
-
{ error: "Internal server error", code: "INTERNAL_SERVER_ERROR" },
|
|
593
|
-
{ status: 500 },
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
},
|
|
597
|
-
};
|
|
598
|
-
|
|
599
|
-
return fragment;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Builder class for fluent fragment instantiation API
|
|
604
|
-
*/
|
|
605
|
-
export class FragmentInstantiationBuilder<
|
|
606
|
-
TConfig,
|
|
607
|
-
TDeps,
|
|
608
|
-
TServices extends Record<string, unknown>,
|
|
609
|
-
TRoutesOrFactories extends readonly AnyRouteOrFactory[],
|
|
610
|
-
TAdditionalContext extends Record<string, unknown>,
|
|
611
|
-
TRequiredInterfaces extends Record<string, unknown>,
|
|
612
|
-
TProvidedInterfaces extends Record<string, unknown>,
|
|
613
|
-
TOptions extends FragnoPublicConfig,
|
|
614
|
-
TThisContext extends RequestThisContext,
|
|
615
|
-
> {
|
|
616
|
-
#fragmentBuilder: {
|
|
617
|
-
definition: FragmentDefinition<
|
|
618
|
-
TConfig,
|
|
619
|
-
TDeps,
|
|
620
|
-
TServices,
|
|
621
|
-
TAdditionalContext,
|
|
622
|
-
TRequiredInterfaces,
|
|
623
|
-
TProvidedInterfaces,
|
|
624
|
-
TThisContext
|
|
625
|
-
>;
|
|
626
|
-
$requiredOptions: TOptions;
|
|
627
|
-
};
|
|
628
|
-
#config?: TConfig;
|
|
629
|
-
#routes?: TRoutesOrFactories;
|
|
630
|
-
#options?: TOptions;
|
|
631
|
-
#services?: TRequiredInterfaces;
|
|
632
|
-
|
|
633
|
-
constructor(fragmentBuilder: {
|
|
634
|
-
definition: FragmentDefinition<
|
|
635
|
-
TConfig,
|
|
636
|
-
TDeps,
|
|
637
|
-
TServices,
|
|
638
|
-
TAdditionalContext,
|
|
639
|
-
TRequiredInterfaces,
|
|
640
|
-
TProvidedInterfaces,
|
|
641
|
-
TThisContext
|
|
642
|
-
>;
|
|
643
|
-
$requiredOptions: TOptions;
|
|
644
|
-
}) {
|
|
645
|
-
this.#fragmentBuilder = fragmentBuilder;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* Set the configuration for the fragment
|
|
650
|
-
*/
|
|
651
|
-
withConfig(config: TConfig): this {
|
|
652
|
-
this.#config = config;
|
|
653
|
-
return this;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* Set the routes for the fragment
|
|
658
|
-
*/
|
|
659
|
-
withRoutes<const TNewRoutes extends readonly AnyRouteOrFactory[]>(
|
|
660
|
-
routes: TNewRoutes,
|
|
661
|
-
): FragmentInstantiationBuilder<
|
|
662
|
-
TConfig,
|
|
663
|
-
TDeps,
|
|
664
|
-
TServices,
|
|
665
|
-
TNewRoutes,
|
|
666
|
-
TAdditionalContext,
|
|
667
|
-
TRequiredInterfaces,
|
|
668
|
-
TProvidedInterfaces,
|
|
669
|
-
TOptions,
|
|
670
|
-
TThisContext
|
|
671
|
-
> {
|
|
672
|
-
this.#routes = routes as unknown as TRoutesOrFactories;
|
|
673
|
-
// Safe cast: We're changing the route type parameter
|
|
674
|
-
return this as unknown as FragmentInstantiationBuilder<
|
|
675
|
-
TConfig,
|
|
676
|
-
TDeps,
|
|
677
|
-
TServices,
|
|
678
|
-
TNewRoutes,
|
|
679
|
-
TAdditionalContext,
|
|
680
|
-
TRequiredInterfaces,
|
|
681
|
-
TProvidedInterfaces,
|
|
682
|
-
TOptions,
|
|
683
|
-
TThisContext
|
|
684
|
-
>;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
/**
|
|
688
|
-
* Set the options for the fragment (e.g., mountRoute, databaseAdapter)
|
|
689
|
-
*/
|
|
690
|
-
withOptions(options: TOptions): this {
|
|
691
|
-
this.#options = options;
|
|
692
|
-
return this;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
/**
|
|
696
|
-
* Provide implementations for services that this fragment uses
|
|
697
|
-
*/
|
|
698
|
-
withServices(services: TRequiredInterfaces): this {
|
|
699
|
-
this.#services = services;
|
|
700
|
-
return this;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
/**
|
|
704
|
-
* Build and return the instantiated fragment
|
|
705
|
-
*/
|
|
706
|
-
build(): FragnoInstantiatedFragment<
|
|
707
|
-
FlattenRouteFactories<TRoutesOrFactories>,
|
|
708
|
-
TDeps & TRequiredInterfaces,
|
|
709
|
-
TServices & TProvidedInterfaces & TRequiredInterfaces,
|
|
710
|
-
TAdditionalContext
|
|
711
|
-
> {
|
|
712
|
-
return createFragment(
|
|
713
|
-
this.#fragmentBuilder,
|
|
714
|
-
this.#config ?? ({} as TConfig),
|
|
715
|
-
this.#routes ?? ([] as const as unknown as TRoutesOrFactories),
|
|
716
|
-
this.#options ?? ({} as TOptions),
|
|
717
|
-
this.#services,
|
|
718
|
-
);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* Create a fluent builder for instantiating a fragment
|
|
724
|
-
*
|
|
725
|
-
* @example
|
|
726
|
-
* ```ts
|
|
727
|
-
* const fragment = instantiateFragment(myFragmentBuilder)
|
|
728
|
-
* .withConfig({ apiKey: "key" })
|
|
729
|
-
* .withRoutes([route1, route2])
|
|
730
|
-
* .withOptions({ mountRoute: "/api" })
|
|
731
|
-
* .build();
|
|
732
|
-
* ```
|
|
733
|
-
*/
|
|
734
|
-
export function instantiateFragment<
|
|
735
|
-
TConfig,
|
|
736
|
-
TDeps,
|
|
737
|
-
TServices extends Record<string, unknown>,
|
|
738
|
-
TAdditionalContext extends Record<string, unknown>,
|
|
739
|
-
TRequiredInterfaces extends Record<string, unknown>,
|
|
740
|
-
TProvidedInterfaces extends Record<string, unknown>,
|
|
741
|
-
TOptions extends FragnoPublicConfig,
|
|
742
|
-
TThisContext extends RequestThisContext = RequestThisContext,
|
|
743
|
-
>(fragmentBuilder: {
|
|
744
|
-
definition: FragmentDefinition<
|
|
745
|
-
TConfig,
|
|
746
|
-
TDeps,
|
|
747
|
-
TServices,
|
|
748
|
-
TAdditionalContext,
|
|
749
|
-
TRequiredInterfaces,
|
|
750
|
-
TProvidedInterfaces,
|
|
751
|
-
TThisContext
|
|
752
|
-
>;
|
|
753
|
-
$requiredOptions: TOptions;
|
|
754
|
-
}): FragmentInstantiationBuilder<
|
|
755
|
-
TConfig,
|
|
756
|
-
TDeps,
|
|
757
|
-
TServices,
|
|
758
|
-
readonly [],
|
|
759
|
-
TAdditionalContext,
|
|
760
|
-
TRequiredInterfaces,
|
|
761
|
-
TProvidedInterfaces,
|
|
762
|
-
TOptions,
|
|
763
|
-
TThisContext
|
|
764
|
-
> {
|
|
765
|
-
return new FragmentInstantiationBuilder(fragmentBuilder);
|
|
766
|
-
}
|