@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.
Files changed (183) hide show
  1. package/.turbo/turbo-build.log +131 -64
  2. package/CHANGELOG.md +19 -0
  3. package/dist/api/api.d.ts +38 -2
  4. package/dist/api/api.d.ts.map +1 -0
  5. package/dist/api/api.js +9 -2
  6. package/dist/api/api.js.map +1 -0
  7. package/dist/api/bind-services.d.ts +6 -0
  8. package/dist/api/bind-services.d.ts.map +1 -0
  9. package/dist/api/bind-services.js +20 -0
  10. package/dist/api/bind-services.js.map +1 -0
  11. package/dist/api/error.d.ts +26 -0
  12. package/dist/api/error.d.ts.map +1 -0
  13. package/dist/{api-DngJDcmO.js → api/error.js} +2 -8
  14. package/dist/api/error.js.map +1 -0
  15. package/dist/api/fragment-definition-builder.d.ts +313 -0
  16. package/dist/api/fragment-definition-builder.d.ts.map +1 -0
  17. package/dist/api/fragment-definition-builder.js +326 -0
  18. package/dist/api/fragment-definition-builder.js.map +1 -0
  19. package/dist/api/fragment-instantiator.d.ts +216 -0
  20. package/dist/api/fragment-instantiator.d.ts.map +1 -0
  21. package/dist/api/fragment-instantiator.js +487 -0
  22. package/dist/api/fragment-instantiator.js.map +1 -0
  23. package/dist/api/fragno-response.d.ts +30 -0
  24. package/dist/api/fragno-response.d.ts.map +1 -0
  25. package/dist/api/fragno-response.js +73 -0
  26. package/dist/api/fragno-response.js.map +1 -0
  27. package/dist/api/internal/path.d.ts +50 -0
  28. package/dist/api/internal/path.d.ts.map +1 -0
  29. package/dist/api/internal/path.js +76 -0
  30. package/dist/api/internal/path.js.map +1 -0
  31. package/dist/api/internal/response-stream.d.ts +43 -0
  32. package/dist/api/internal/response-stream.d.ts.map +1 -0
  33. package/dist/api/internal/response-stream.js +81 -0
  34. package/dist/api/internal/response-stream.js.map +1 -0
  35. package/dist/api/internal/route.js +10 -0
  36. package/dist/api/internal/route.js.map +1 -0
  37. package/dist/api/mutable-request-state.d.ts +82 -0
  38. package/dist/api/mutable-request-state.d.ts.map +1 -0
  39. package/dist/api/mutable-request-state.js +97 -0
  40. package/dist/api/mutable-request-state.js.map +1 -0
  41. package/dist/api/request-context-storage.d.ts +42 -0
  42. package/dist/api/request-context-storage.d.ts.map +1 -0
  43. package/dist/api/request-context-storage.js +43 -0
  44. package/dist/api/request-context-storage.js.map +1 -0
  45. package/dist/api/request-input-context.d.ts +89 -0
  46. package/dist/api/request-input-context.d.ts.map +1 -0
  47. package/dist/api/request-input-context.js +118 -0
  48. package/dist/api/request-input-context.js.map +1 -0
  49. package/dist/api/request-middleware.d.ts +50 -0
  50. package/dist/api/request-middleware.d.ts.map +1 -0
  51. package/dist/api/request-middleware.js +83 -0
  52. package/dist/api/request-middleware.js.map +1 -0
  53. package/dist/api/request-output-context.d.ts +41 -0
  54. package/dist/api/request-output-context.d.ts.map +1 -0
  55. package/dist/api/request-output-context.js +119 -0
  56. package/dist/api/request-output-context.js.map +1 -0
  57. package/dist/api/route-handler-input-options.d.ts +21 -0
  58. package/dist/api/route-handler-input-options.d.ts.map +1 -0
  59. package/dist/api/route.d.ts +54 -3
  60. package/dist/api/route.d.ts.map +1 -0
  61. package/dist/api/route.js +29 -2
  62. package/dist/api/route.js.map +1 -0
  63. package/dist/api/shared-types.d.ts +47 -0
  64. package/dist/api/shared-types.d.ts.map +1 -0
  65. package/dist/api/shared-types.js +1 -0
  66. package/dist/client/client-error.d.ts +60 -0
  67. package/dist/client/client-error.d.ts.map +1 -0
  68. package/dist/client/client-error.js +92 -0
  69. package/dist/client/client-error.js.map +1 -0
  70. package/dist/client/client.d.ts +210 -4
  71. package/dist/client/client.d.ts.map +1 -0
  72. package/dist/client/client.js +397 -6
  73. package/dist/client/client.js.map +1 -0
  74. package/dist/client/client.svelte.d.ts +5 -3
  75. package/dist/client/client.svelte.d.ts.map +1 -1
  76. package/dist/client/client.svelte.js +1 -5
  77. package/dist/client/client.svelte.js.map +1 -1
  78. package/dist/client/internal/fetcher-merge.js +36 -0
  79. package/dist/client/internal/fetcher-merge.js.map +1 -0
  80. package/dist/client/internal/ndjson-streaming.js +139 -0
  81. package/dist/client/internal/ndjson-streaming.js.map +1 -0
  82. package/dist/client/react.d.ts +5 -3
  83. package/dist/client/react.d.ts.map +1 -1
  84. package/dist/client/react.js +3 -5
  85. package/dist/client/react.js.map +1 -1
  86. package/dist/client/solid.d.ts +5 -3
  87. package/dist/client/solid.d.ts.map +1 -1
  88. package/dist/client/solid.js +2 -5
  89. package/dist/client/solid.js.map +1 -1
  90. package/dist/client/vanilla.d.ts +5 -3
  91. package/dist/client/vanilla.d.ts.map +1 -1
  92. package/dist/client/vanilla.js +2 -43
  93. package/dist/client/vanilla.js.map +1 -1
  94. package/dist/client/vue.d.ts +5 -3
  95. package/dist/client/vue.d.ts.map +1 -1
  96. package/dist/client/vue.js +1 -5
  97. package/dist/client/vue.js.map +1 -1
  98. package/dist/http/http-status.d.ts +26 -0
  99. package/dist/http/http-status.d.ts.map +1 -0
  100. package/dist/integrations/react-ssr.js +1 -1
  101. package/dist/internal/symbols.d.ts +9 -0
  102. package/dist/internal/symbols.d.ts.map +1 -0
  103. package/dist/internal/symbols.js +10 -0
  104. package/dist/internal/symbols.js.map +1 -0
  105. package/dist/mod-client.d.ts +36 -0
  106. package/dist/mod-client.d.ts.map +1 -0
  107. package/dist/mod-client.js +21 -0
  108. package/dist/mod-client.js.map +1 -0
  109. package/dist/mod.d.ts +7 -4
  110. package/dist/mod.js +4 -6
  111. package/dist/request/request.d.ts +4 -0
  112. package/dist/request/request.js +5 -0
  113. package/dist/test/test.d.ts +62 -35
  114. package/dist/test/test.d.ts.map +1 -1
  115. package/dist/test/test.js +75 -40
  116. package/dist/test/test.js.map +1 -1
  117. package/dist/util/async.js +40 -0
  118. package/dist/util/async.js.map +1 -0
  119. package/dist/util/content-type.js +49 -0
  120. package/dist/util/content-type.js.map +1 -0
  121. package/dist/util/nanostores.js +31 -0
  122. package/dist/util/nanostores.js.map +1 -0
  123. package/dist/{ssr-BByDVfFD.js → util/ssr.js} +2 -2
  124. package/dist/util/ssr.js.map +1 -0
  125. package/dist/util/types-util.d.ts +8 -0
  126. package/dist/util/types-util.d.ts.map +1 -0
  127. package/package.json +19 -12
  128. package/src/api/api.ts +41 -6
  129. package/src/api/bind-services.ts +42 -0
  130. package/src/api/fragment-definition-builder.extend.test.ts +810 -0
  131. package/src/api/fragment-definition-builder.test.ts +499 -0
  132. package/src/api/fragment-definition-builder.ts +1088 -0
  133. package/src/api/fragment-instantiator.test.ts +1488 -0
  134. package/src/api/fragment-instantiator.ts +1053 -0
  135. package/src/api/fragment-services.test.ts +727 -0
  136. package/src/api/request-context-storage.ts +64 -0
  137. package/src/api/request-middleware.test.ts +301 -225
  138. package/src/api/route.test.ts +87 -1
  139. package/src/api/route.ts +345 -24
  140. package/src/api/shared-types.ts +43 -0
  141. package/src/client/client-builder.test.ts +23 -23
  142. package/src/client/client.ssr.test.ts +3 -3
  143. package/src/client/client.svelte.test.ts +15 -15
  144. package/src/client/client.test.ts +22 -22
  145. package/src/client/client.ts +72 -12
  146. package/src/client/internal/fetcher-merge.ts +1 -1
  147. package/src/client/react.test.ts +2 -2
  148. package/src/client/solid.test.ts +2 -2
  149. package/src/client/vanilla.test.ts +2 -2
  150. package/src/client/vue.test.ts +2 -2
  151. package/src/internal/symbols.ts +5 -0
  152. package/src/mod-client.ts +59 -0
  153. package/src/mod.ts +26 -9
  154. package/src/request/request.ts +8 -0
  155. package/src/test/test.test.ts +200 -381
  156. package/src/test/test.ts +190 -117
  157. package/tsdown.config.ts +8 -5
  158. package/dist/api/fragment-builder.d.ts +0 -4
  159. package/dist/api/fragment-builder.js +0 -3
  160. package/dist/api/fragment-instantiation.d.ts +0 -4
  161. package/dist/api/fragment-instantiation.js +0 -6
  162. package/dist/api-BWN97TOr.d.ts +0 -377
  163. package/dist/api-BWN97TOr.d.ts.map +0 -1
  164. package/dist/api-DngJDcmO.js.map +0 -1
  165. package/dist/client-C5LsYHEI.js +0 -782
  166. package/dist/client-C5LsYHEI.js.map +0 -1
  167. package/dist/fragment-builder-DOnCVBqc.js +0 -47
  168. package/dist/fragment-builder-DOnCVBqc.js.map +0 -1
  169. package/dist/fragment-builder-MGr68GNb.d.ts +0 -409
  170. package/dist/fragment-builder-MGr68GNb.d.ts.map +0 -1
  171. package/dist/fragment-instantiation-C4wvwl6V.js +0 -446
  172. package/dist/fragment-instantiation-C4wvwl6V.js.map +0 -1
  173. package/dist/request-output-context-CdIjwmEN.js +0 -320
  174. package/dist/request-output-context-CdIjwmEN.js.map +0 -1
  175. package/dist/route-Bl9Zr1Yv.d.ts +0 -26
  176. package/dist/route-Bl9Zr1Yv.d.ts.map +0 -1
  177. package/dist/route-C5Uryylh.js +0 -21
  178. package/dist/route-C5Uryylh.js.map +0 -1
  179. package/dist/ssr-BByDVfFD.js.map +0 -1
  180. package/src/api/fragment-builder.ts +0 -80
  181. package/src/api/fragment-instantiation.test.ts +0 -460
  182. package/src/api/fragment-instantiation.ts +0 -499
  183. package/src/api/fragment.test.ts +0 -537
@@ -0,0 +1,1088 @@
1
+ import type { RequestThisContext } from "./api";
2
+ import type { FragnoPublicConfig } from "./shared-types";
3
+ import type { RequestContextStorage } from "./request-context-storage";
4
+ import type {
5
+ FragnoInstantiatedFragment,
6
+ AnyFragnoInstantiatedFragment,
7
+ } from "./fragment-instantiator";
8
+
9
+ /**
10
+ * Metadata for a service dependency
11
+ */
12
+ interface ServiceMetadata {
13
+ /** Name of the service */
14
+ name: string;
15
+ /** Whether this service is required (false means optional) */
16
+ required: boolean;
17
+ }
18
+
19
+ /**
20
+ * Callback that instantiates a linked fragment.
21
+ * Receives the same context as the main fragment and returns an instantiated fragment.
22
+ */
23
+ export type LinkedFragmentCallback<
24
+ TConfig,
25
+ TOptions extends FragnoPublicConfig,
26
+ TServiceDependencies,
27
+ > = (context: {
28
+ config: TConfig;
29
+ options: TOptions;
30
+ serviceDependencies?: TServiceDependencies;
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ }) => FragnoInstantiatedFragment<any, any, any, any, any, any, any>;
33
+
34
+ /**
35
+ * Extract the services type from a FragnoInstantiatedFragment
36
+ */
37
+ export type ExtractLinkedServices<T> = T extends (
38
+ ...args: never[]
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ ) => FragnoInstantiatedFragment<any, any, infer TServices, any, any, any, any>
41
+ ? TServices
42
+ : never;
43
+
44
+ /**
45
+ * Context passed to the request context factory function.
46
+ */
47
+ export type RequestContextFactoryContext<
48
+ TConfig,
49
+ TOptions extends FragnoPublicConfig,
50
+ TDeps,
51
+ TRequestStorage,
52
+ > = {
53
+ config: TConfig;
54
+ options: TOptions;
55
+ deps: TDeps;
56
+ storage: RequestContextStorage<TRequestStorage>;
57
+ };
58
+
59
+ /**
60
+ * Context object passed to service constructor functions
61
+ */
62
+ export type ServiceContext<
63
+ TConfig,
64
+ TOptions,
65
+ TDeps,
66
+ TServiceDependencies,
67
+ TPrivateServices,
68
+ TServiceThisContext extends RequestThisContext,
69
+ > = {
70
+ config: TConfig;
71
+ options: TOptions;
72
+ deps: TDeps;
73
+ serviceDeps: TServiceDependencies;
74
+ privateServices: TPrivateServices;
75
+ /**
76
+ * Helper to define services with proper `this` context typing.
77
+ * Use this to wrap your service methods when they need access to `this`.
78
+ */
79
+ defineService: <T>(svc: T & ThisType<TServiceThisContext>) => T;
80
+ };
81
+
82
+ /**
83
+ * Service constructor function type
84
+ */
85
+ export type ServiceConstructorFn<
86
+ TConfig,
87
+ TOptions,
88
+ TDeps,
89
+ TServiceDependencies,
90
+ TPrivateServices,
91
+ TService,
92
+ TServiceThisContext extends RequestThisContext,
93
+ > = (
94
+ context: ServiceContext<
95
+ TConfig,
96
+ TOptions,
97
+ TDeps,
98
+ TServiceDependencies,
99
+ TPrivateServices,
100
+ TServiceThisContext
101
+ >,
102
+ ) => TService;
103
+
104
+ /**
105
+ * Fragment definition interface that supports both regular and database fragments.
106
+ * This is the core definition that will be used for fragment instantiation.
107
+ */
108
+ export interface FragmentDefinition<
109
+ TConfig,
110
+ TOptions extends FragnoPublicConfig,
111
+ TDeps,
112
+ TBaseServices,
113
+ TServices,
114
+ TServiceDependencies,
115
+ TPrivateServices,
116
+ TServiceThisContext extends RequestThisContext,
117
+ THandlerThisContext extends RequestThisContext,
118
+ TRequestStorage = {},
119
+ TLinkedFragments extends Record<string, AnyFragnoInstantiatedFragment> = {},
120
+ > {
121
+ name: string;
122
+
123
+ // Core callbacks - all take context objects with separate deps and serviceDeps
124
+ dependencies?: (context: { config: TConfig; options: TOptions }) => TDeps;
125
+
126
+ baseServices?: ServiceConstructorFn<
127
+ TConfig,
128
+ TOptions,
129
+ TDeps,
130
+ TServiceDependencies,
131
+ TPrivateServices,
132
+ TBaseServices,
133
+ TServiceThisContext
134
+ >;
135
+
136
+ // Named services stored as factory functions
137
+ namedServices?: {
138
+ [K in keyof TServices]: ServiceConstructorFn<
139
+ TConfig,
140
+ TOptions,
141
+ TDeps,
142
+ TServiceDependencies,
143
+ TPrivateServices,
144
+ TServices[K],
145
+ TServiceThisContext
146
+ >;
147
+ };
148
+
149
+ // Private services - only accessible internally when defining other services
150
+ privateServices?: {
151
+ [K in keyof TPrivateServices]: ServiceConstructorFn<
152
+ TConfig,
153
+ TOptions,
154
+ TDeps,
155
+ TServiceDependencies,
156
+ TPrivateServices, // Private services can access other private services
157
+ TPrivateServices[K],
158
+ TServiceThisContext
159
+ >;
160
+ };
161
+
162
+ // Service dependency metadata
163
+ serviceDependencies?: {
164
+ [K in keyof TServiceDependencies]: ServiceMetadata;
165
+ };
166
+
167
+ /**
168
+ * Optional factory function to create the initial request storage data.
169
+ * This is called at the start of each request to initialize the storage.
170
+ * The returned object can be mutated throughout the request lifecycle.
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * createRequestStorage: ({ config, options, deps }) => ({
175
+ * counter: 0,
176
+ * userId: deps.currentUserId
177
+ * })
178
+ * ```
179
+ */
180
+ createRequestStorage?: (context: {
181
+ config: TConfig;
182
+ options: TOptions;
183
+ deps: TDeps;
184
+ }) => TRequestStorage;
185
+
186
+ /**
187
+ * Optional factory function to create the this contexts for services and handlers.
188
+ * Returns separate contexts: serviceContext (may be restricted) and handlerContext (full access).
189
+ * Both contexts should contain only methods or getters that read from storage.
190
+ *
191
+ * @example
192
+ * ```ts
193
+ * createThisContext: ({ storage }) => ({
194
+ * serviceContext: {
195
+ * getUnitOfWork: () => restrictedUOW // Without execute methods
196
+ * },
197
+ * handlerContext: {
198
+ * getUnitOfWork: () => fullUOW // With execute methods
199
+ * }
200
+ * })
201
+ * ```
202
+ */
203
+ createThisContext?: (
204
+ context: RequestContextFactoryContext<TConfig, TOptions, TDeps, TRequestStorage>,
205
+ ) => {
206
+ serviceContext: TServiceThisContext;
207
+ handlerContext: THandlerThisContext;
208
+ };
209
+
210
+ /**
211
+ * Optional factory function to get an external RequestContextStorage instance.
212
+ * When provided, this storage will be used instead of creating a new one.
213
+ * This allows multiple fragments to share the same storage (e.g., database fragments sharing adapter storage).
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * getExternalStorage: ({ options }) => options.databaseAdapter.contextStorage
218
+ * ```
219
+ */
220
+ getExternalStorage?: (context: {
221
+ config: TConfig;
222
+ options: TOptions;
223
+ deps: TDeps;
224
+ }) => RequestContextStorage<TRequestStorage>;
225
+
226
+ /**
227
+ * Optional linked fragments that will be automatically instantiated with this fragment.
228
+ * Linked fragments are service-only and share the same config/options as the parent.
229
+ */
230
+ linkedFragments?: {
231
+ [K in keyof TLinkedFragments]: LinkedFragmentCallback<TConfig, TOptions, TServiceDependencies>;
232
+ };
233
+
234
+ $serviceThisContext?: TServiceThisContext;
235
+ $handlerThisContext?: THandlerThisContext;
236
+ $requestStorage?: TRequestStorage;
237
+ $linkedFragments?: TLinkedFragments;
238
+ }
239
+
240
+ /**
241
+ * Builder class for creating fragment definitions.
242
+ * This provides a fluent API for defining fragments with type safety.
243
+ */
244
+ export class FragmentDefinitionBuilder<
245
+ TConfig,
246
+ TOptions extends FragnoPublicConfig,
247
+ TDeps,
248
+ TBaseServices,
249
+ TServices,
250
+ TServiceDependencies,
251
+ TPrivateServices,
252
+ TServiceThisContext extends RequestThisContext,
253
+ THandlerThisContext extends RequestThisContext,
254
+ TRequestStorage = {},
255
+ TLinkedFragments extends Record<string, AnyFragnoInstantiatedFragment> = {},
256
+ > {
257
+ #name: string;
258
+ #dependencies?: (context: { config: TConfig; options: TOptions }) => TDeps;
259
+ #baseServices?: ServiceConstructorFn<
260
+ TConfig,
261
+ TOptions,
262
+ TDeps,
263
+ TServiceDependencies,
264
+ TPrivateServices,
265
+ TBaseServices,
266
+ TServiceThisContext
267
+ >;
268
+ #namedServices?: {
269
+ [K in keyof TServices]: ServiceConstructorFn<
270
+ TConfig,
271
+ TOptions,
272
+ TDeps,
273
+ TServiceDependencies,
274
+ TPrivateServices,
275
+ TServices[K],
276
+ TServiceThisContext
277
+ >;
278
+ };
279
+ #privateServices?: {
280
+ [K in keyof TPrivateServices]: ServiceConstructorFn<
281
+ TConfig,
282
+ TOptions,
283
+ TDeps,
284
+ TServiceDependencies,
285
+ TPrivateServices,
286
+ TPrivateServices[K],
287
+ TServiceThisContext
288
+ >;
289
+ };
290
+ #serviceDependencies?: {
291
+ [K in keyof TServiceDependencies]: ServiceMetadata;
292
+ };
293
+ #createRequestStorage?: (context: {
294
+ config: TConfig;
295
+ options: TOptions;
296
+ deps: TDeps;
297
+ }) => TRequestStorage;
298
+ #createThisContext?: (
299
+ context: RequestContextFactoryContext<TConfig, TOptions, TDeps, TRequestStorage>,
300
+ ) => {
301
+ serviceContext: TServiceThisContext;
302
+ handlerContext: THandlerThisContext;
303
+ };
304
+ #getExternalStorage?: (context: {
305
+ config: TConfig;
306
+ options: TOptions;
307
+ deps: TDeps;
308
+ }) => RequestContextStorage<TRequestStorage>;
309
+ #linkedFragments?: {
310
+ [K in keyof TLinkedFragments]: LinkedFragmentCallback<TConfig, TOptions, TServiceDependencies>;
311
+ };
312
+
313
+ constructor(
314
+ name: string,
315
+ state?: {
316
+ dependencies?: (context: { config: TConfig; options: TOptions }) => TDeps;
317
+ baseServices?: ServiceConstructorFn<
318
+ TConfig,
319
+ TOptions,
320
+ TDeps,
321
+ TServiceDependencies,
322
+ TPrivateServices,
323
+ TBaseServices,
324
+ TServiceThisContext
325
+ >;
326
+ namedServices?: {
327
+ [K in keyof TServices]: ServiceConstructorFn<
328
+ TConfig,
329
+ TOptions,
330
+ TDeps,
331
+ TServiceDependencies,
332
+ TPrivateServices,
333
+ TServices[K],
334
+ TServiceThisContext
335
+ >;
336
+ };
337
+ privateServices?: {
338
+ [K in keyof TPrivateServices]: ServiceConstructorFn<
339
+ TConfig,
340
+ TOptions,
341
+ TDeps,
342
+ TServiceDependencies,
343
+ TPrivateServices,
344
+ TPrivateServices[K],
345
+ TServiceThisContext
346
+ >;
347
+ };
348
+ serviceDependencies?: {
349
+ [K in keyof TServiceDependencies]: ServiceMetadata;
350
+ };
351
+ createRequestStorage?: (context: {
352
+ config: TConfig;
353
+ options: TOptions;
354
+ deps: TDeps;
355
+ }) => TRequestStorage;
356
+ createThisContext?: (
357
+ context: RequestContextFactoryContext<TConfig, TOptions, TDeps, TRequestStorage>,
358
+ ) => {
359
+ serviceContext: TServiceThisContext;
360
+ handlerContext: THandlerThisContext;
361
+ };
362
+ getExternalStorage?: (context: {
363
+ config: TConfig;
364
+ options: TOptions;
365
+ deps: TDeps;
366
+ }) => RequestContextStorage<TRequestStorage>;
367
+ linkedFragments?: {
368
+ [K in keyof TLinkedFragments]: LinkedFragmentCallback<
369
+ TConfig,
370
+ TOptions,
371
+ TServiceDependencies
372
+ >;
373
+ };
374
+ },
375
+ ) {
376
+ this.#name = name;
377
+ if (state) {
378
+ this.#dependencies = state.dependencies;
379
+ this.#baseServices = state.baseServices;
380
+ this.#namedServices = state.namedServices;
381
+ this.#privateServices = state.privateServices;
382
+ this.#serviceDependencies = state.serviceDependencies;
383
+ this.#createRequestStorage = state.createRequestStorage;
384
+ this.#createThisContext = state.createThisContext;
385
+ this.#getExternalStorage = state.getExternalStorage;
386
+ this.#linkedFragments = state.linkedFragments;
387
+ }
388
+ }
389
+
390
+ get name(): string {
391
+ return this.#name;
392
+ }
393
+
394
+ /**
395
+ * Define dependencies for this fragment.
396
+ * Dependencies are available to services and handlers.
397
+ *
398
+ * **IMPORTANT**: This method resets all services, storage, and context configurations.
399
+ * Always call `withDependencies` early in the builder chain, before defining services
400
+ * or request storage/context.
401
+ *
402
+ * @example
403
+ * ```typescript
404
+ * // ✅ GOOD: Dependencies set first
405
+ * defineFragment("my-fragment")
406
+ * .withDependencies(() => ({ apiKey: "..." }))
407
+ * .withRequestStorage(({ deps }) => ({ userId: deps.apiKey }))
408
+ * .providesService("myService", ...)
409
+ *
410
+ * // ❌ BAD: Dependencies set late (erases storage setup)
411
+ * defineFragment("my-fragment")
412
+ * .withRequestStorage(() => ({ userId: "..." })) // This gets erased!
413
+ * .withDependencies(() => ({ apiKey: "..." }))
414
+ * ```
415
+ */
416
+ withDependencies<TNewDeps>(
417
+ fn: (context: { config: TConfig; options: TOptions }) => TNewDeps,
418
+ ): FragmentDefinitionBuilder<
419
+ TConfig,
420
+ TOptions,
421
+ TNewDeps,
422
+ {},
423
+ {},
424
+ TServiceDependencies,
425
+ {},
426
+ TServiceThisContext,
427
+ THandlerThisContext,
428
+ TRequestStorage,
429
+ TLinkedFragments
430
+ > {
431
+ // Warn if we're discarding existing configuration
432
+ if (
433
+ this.#baseServices ||
434
+ this.#namedServices ||
435
+ this.#privateServices ||
436
+ this.#createRequestStorage ||
437
+ this.#createThisContext ||
438
+ this.#getExternalStorage
439
+ ) {
440
+ console.warn(
441
+ `[Fragno] Warning: withDependencies() on fragment "${this.#name}" is resetting previously configured services, request storage, or request context. ` +
442
+ `To avoid this, call withDependencies() earlier in the builder chain, before configuring services or storage.`,
443
+ );
444
+ }
445
+
446
+ return new FragmentDefinitionBuilder<
447
+ TConfig,
448
+ TOptions,
449
+ TNewDeps,
450
+ {},
451
+ {},
452
+ TServiceDependencies,
453
+ {},
454
+ TServiceThisContext,
455
+ THandlerThisContext,
456
+ TRequestStorage,
457
+ TLinkedFragments
458
+ >(this.#name, {
459
+ dependencies: fn,
460
+ baseServices: undefined,
461
+ namedServices: undefined,
462
+ privateServices: undefined,
463
+ serviceDependencies: this.#serviceDependencies,
464
+ // Reset storage/context functions since deps type changed - they must be reconfigured
465
+ createRequestStorage: undefined,
466
+ createThisContext: undefined,
467
+ getExternalStorage: undefined,
468
+ linkedFragments: this.#linkedFragments,
469
+ });
470
+ }
471
+
472
+ /**
473
+ * Define base (unnamed) services for this fragment.
474
+ * Base services are accessible directly on the fragment instance.
475
+ */
476
+ providesBaseService<TNewService>(
477
+ fn: ServiceConstructorFn<
478
+ TConfig,
479
+ TOptions,
480
+ TDeps,
481
+ TServiceDependencies,
482
+ TPrivateServices,
483
+ TNewService,
484
+ TServiceThisContext
485
+ >,
486
+ ): FragmentDefinitionBuilder<
487
+ TConfig,
488
+ TOptions,
489
+ TDeps,
490
+ TNewService,
491
+ TServices,
492
+ TServiceDependencies,
493
+ TPrivateServices,
494
+ TServiceThisContext,
495
+ THandlerThisContext,
496
+ TRequestStorage,
497
+ TLinkedFragments
498
+ > {
499
+ return new FragmentDefinitionBuilder<
500
+ TConfig,
501
+ TOptions,
502
+ TDeps,
503
+ TNewService,
504
+ TServices,
505
+ TServiceDependencies,
506
+ TPrivateServices,
507
+ TServiceThisContext,
508
+ THandlerThisContext,
509
+ TRequestStorage,
510
+ TLinkedFragments
511
+ >(this.#name, {
512
+ dependencies: this.#dependencies,
513
+ baseServices: fn,
514
+ namedServices: this.#namedServices,
515
+ privateServices: this.#privateServices,
516
+ serviceDependencies: this.#serviceDependencies,
517
+ createRequestStorage: this.#createRequestStorage,
518
+ createThisContext: this.#createThisContext,
519
+ getExternalStorage: this.#getExternalStorage,
520
+ linkedFragments: this.#linkedFragments,
521
+ });
522
+ }
523
+
524
+ /**
525
+ * Provide a named service that other fragments or users can use.
526
+ * Named services are accessible as fragment.serviceName.method()
527
+ */
528
+ providesService<TServiceName extends string, TService>(
529
+ serviceName: TServiceName,
530
+ fn: ServiceConstructorFn<
531
+ TConfig,
532
+ TOptions,
533
+ TDeps,
534
+ TServiceDependencies,
535
+ TPrivateServices,
536
+ TService,
537
+ TServiceThisContext
538
+ >,
539
+ ): FragmentDefinitionBuilder<
540
+ TConfig,
541
+ TOptions,
542
+ TDeps,
543
+ TBaseServices,
544
+ TServices & { [K in TServiceName]: TService },
545
+ TServiceDependencies,
546
+ TPrivateServices,
547
+ TServiceThisContext,
548
+ THandlerThisContext,
549
+ TRequestStorage,
550
+ TLinkedFragments
551
+ > {
552
+ // Type assertion needed because TypeScript can't verify object spread with mapped types
553
+ const newNamedServices = {
554
+ ...this.#namedServices,
555
+ [serviceName]: fn,
556
+ } as {
557
+ [K in keyof (TServices & { [K in TServiceName]: TService })]: ServiceConstructorFn<
558
+ TConfig,
559
+ TOptions,
560
+ TDeps,
561
+ TServiceDependencies,
562
+ TPrivateServices,
563
+ (TServices & { [K in TServiceName]: TService })[K],
564
+ TServiceThisContext
565
+ >;
566
+ };
567
+
568
+ return new FragmentDefinitionBuilder<
569
+ TConfig,
570
+ TOptions,
571
+ TDeps,
572
+ TBaseServices,
573
+ TServices & { [K in TServiceName]: TService },
574
+ TServiceDependencies,
575
+ TPrivateServices,
576
+ TServiceThisContext,
577
+ THandlerThisContext,
578
+ TRequestStorage,
579
+ TLinkedFragments
580
+ >(this.#name, {
581
+ dependencies: this.#dependencies,
582
+ baseServices: this.#baseServices,
583
+ namedServices: newNamedServices,
584
+ privateServices: this.#privateServices,
585
+ serviceDependencies: this.#serviceDependencies,
586
+ createRequestStorage: this.#createRequestStorage,
587
+ createThisContext: this.#createThisContext,
588
+ getExternalStorage: this.#getExternalStorage,
589
+ linkedFragments: this.#linkedFragments,
590
+ });
591
+ }
592
+
593
+ /**
594
+ * Provide a private service that is only accessible to the fragment author.
595
+ * Private services are NOT exposed on the fragment instance, but can be used
596
+ * when defining other services (baseServices, namedServices, and other privateServices).
597
+ * Private services are instantiated in order, so earlier private services are available
598
+ * to later ones.
599
+ */
600
+ providesPrivateService<TServiceName extends string, TService>(
601
+ serviceName: TServiceName,
602
+ fn: ServiceConstructorFn<
603
+ TConfig,
604
+ TOptions,
605
+ TDeps,
606
+ TServiceDependencies,
607
+ TPrivateServices,
608
+ TService,
609
+ TServiceThisContext
610
+ >,
611
+ ): FragmentDefinitionBuilder<
612
+ TConfig,
613
+ TOptions,
614
+ TDeps,
615
+ TBaseServices,
616
+ TServices,
617
+ TServiceDependencies,
618
+ TPrivateServices & { [K in TServiceName]: TService },
619
+ TServiceThisContext,
620
+ THandlerThisContext,
621
+ TRequestStorage,
622
+ TLinkedFragments
623
+ > {
624
+ // Type assertion needed because TypeScript can't verify object spread with mapped types
625
+ const newPrivateServices = {
626
+ ...this.#privateServices,
627
+ [serviceName]: fn,
628
+ } as {
629
+ [K in keyof (TPrivateServices & { [K in TServiceName]: TService })]: ServiceConstructorFn<
630
+ TConfig,
631
+ TOptions,
632
+ TDeps,
633
+ TServiceDependencies,
634
+ TPrivateServices & { [K in TServiceName]: TService },
635
+ (TPrivateServices & { [K in TServiceName]: TService })[K],
636
+ TServiceThisContext
637
+ >;
638
+ };
639
+
640
+ return new FragmentDefinitionBuilder<
641
+ TConfig,
642
+ TOptions,
643
+ TDeps,
644
+ TBaseServices,
645
+ TServices,
646
+ TServiceDependencies,
647
+ TPrivateServices & { [K in TServiceName]: TService },
648
+ TServiceThisContext,
649
+ THandlerThisContext,
650
+ TRequestStorage,
651
+ TLinkedFragments
652
+ >(this.#name, {
653
+ dependencies: this.#dependencies,
654
+ baseServices: this.#baseServices,
655
+ namedServices: this.#namedServices,
656
+ privateServices: newPrivateServices,
657
+ serviceDependencies: this.#serviceDependencies,
658
+ createRequestStorage: this.#createRequestStorage,
659
+ createThisContext: this.#createThisContext,
660
+ linkedFragments: this.#linkedFragments,
661
+ });
662
+ }
663
+
664
+ /**
665
+ * Declare that this fragment uses a required service provided by the runtime.
666
+ */
667
+ usesService<TServiceName extends string, TService>(
668
+ serviceName: TServiceName,
669
+ ): FragmentDefinitionBuilder<
670
+ TConfig,
671
+ TOptions,
672
+ TDeps,
673
+ TBaseServices,
674
+ TServices,
675
+ TServiceDependencies & { [K in TServiceName]: TService },
676
+ TPrivateServices,
677
+ TServiceThisContext,
678
+ THandlerThisContext,
679
+ TRequestStorage,
680
+ TLinkedFragments
681
+ > {
682
+ // Type assertion needed because TypeScript can't verify object spread with mapped types
683
+ const newServiceDependencies = {
684
+ ...this.#serviceDependencies,
685
+ [serviceName]: { name: serviceName, required: true },
686
+ } as {
687
+ [K in keyof (TServiceDependencies & { [K in TServiceName]: TService })]: ServiceMetadata;
688
+ };
689
+
690
+ return new FragmentDefinitionBuilder<
691
+ TConfig,
692
+ TOptions,
693
+ TDeps,
694
+ TBaseServices,
695
+ TServices,
696
+ TServiceDependencies & { [K in TServiceName]: TService },
697
+ TPrivateServices,
698
+ TServiceThisContext,
699
+ THandlerThisContext,
700
+ TRequestStorage,
701
+ TLinkedFragments
702
+ >(this.#name, {
703
+ dependencies: this.#dependencies,
704
+ baseServices: this.#baseServices,
705
+ namedServices: this.#namedServices,
706
+ privateServices: this.#privateServices,
707
+ serviceDependencies: newServiceDependencies,
708
+ createRequestStorage: this.#createRequestStorage,
709
+ createThisContext: this.#createThisContext,
710
+ linkedFragments: this.#linkedFragments,
711
+ });
712
+ }
713
+
714
+ /**
715
+ * Declare that this fragment uses an optional service provided by the runtime.
716
+ */
717
+ usesOptionalService<TServiceName extends string, TService>(
718
+ serviceName: TServiceName,
719
+ ): FragmentDefinitionBuilder<
720
+ TConfig,
721
+ TOptions,
722
+ TDeps,
723
+ TBaseServices,
724
+ TServices,
725
+ TServiceDependencies & { [K in TServiceName]: TService | undefined },
726
+ TPrivateServices,
727
+ TServiceThisContext,
728
+ THandlerThisContext,
729
+ TRequestStorage,
730
+ TLinkedFragments
731
+ > {
732
+ // Type assertion needed because TypeScript can't verify object spread with mapped types
733
+ const newServiceDependencies = {
734
+ ...this.#serviceDependencies,
735
+ [serviceName]: { name: serviceName, required: false },
736
+ } as {
737
+ [K in keyof (TServiceDependencies & {
738
+ [K in TServiceName]: TService | undefined;
739
+ })]: ServiceMetadata;
740
+ };
741
+
742
+ return new FragmentDefinitionBuilder<
743
+ TConfig,
744
+ TOptions,
745
+ TDeps,
746
+ TBaseServices,
747
+ TServices,
748
+ TServiceDependencies & { [K in TServiceName]: TService | undefined },
749
+ TPrivateServices,
750
+ TServiceThisContext,
751
+ THandlerThisContext,
752
+ TRequestStorage,
753
+ TLinkedFragments
754
+ >(this.#name, {
755
+ dependencies: this.#dependencies,
756
+ baseServices: this.#baseServices,
757
+ namedServices: this.#namedServices,
758
+ privateServices: this.#privateServices,
759
+ serviceDependencies: newServiceDependencies,
760
+ createRequestStorage: this.#createRequestStorage,
761
+ createThisContext: this.#createThisContext,
762
+ linkedFragments: this.#linkedFragments,
763
+ });
764
+ }
765
+
766
+ /**
767
+ * Define the type and initial data stored in AsyncLocalStorage for per-request isolation.
768
+ * This should be called before withThisContext if you need to store request-specific data.
769
+ *
770
+ * @param initializer Function that returns the initial storage data for each request
771
+ *
772
+ * @example
773
+ * ```typescript
774
+ * .withRequestStorage(({ config, options, deps }) => ({
775
+ * counter: 0,
776
+ * userId: deps.currentUserId
777
+ * }))
778
+ * .withThisContext(({ storage }) => ({
779
+ * serviceContext: {
780
+ * get counter() { return storage.getStore()!.counter; }
781
+ * },
782
+ * handlerContext: {
783
+ * get counter() { return storage.getStore()!.counter; }
784
+ * }
785
+ * }))
786
+ * ```
787
+ */
788
+ withRequestStorage<TNewRequestStorage>(
789
+ initializer: (context: {
790
+ config: TConfig;
791
+ options: TOptions;
792
+ deps: TDeps;
793
+ }) => TNewRequestStorage,
794
+ ): FragmentDefinitionBuilder<
795
+ TConfig,
796
+ TOptions,
797
+ TDeps,
798
+ TBaseServices,
799
+ TServices,
800
+ TServiceDependencies,
801
+ TPrivateServices,
802
+ TServiceThisContext,
803
+ THandlerThisContext,
804
+ TNewRequestStorage,
805
+ TLinkedFragments
806
+ > {
807
+ // getExternalStorage can coexist with createRequestStorage (they work together)
808
+ // Cast is safe when storage type changes: the external storage container adapts to hold the new type
809
+ const preservedExternalStorage = this.#getExternalStorage
810
+ ? (this.#getExternalStorage as unknown as (context: {
811
+ config: TConfig;
812
+ options: TOptions;
813
+ deps: TDeps;
814
+ }) => RequestContextStorage<TNewRequestStorage>)
815
+ : undefined;
816
+
817
+ return new FragmentDefinitionBuilder<
818
+ TConfig,
819
+ TOptions,
820
+ TDeps,
821
+ TBaseServices,
822
+ TServices,
823
+ TServiceDependencies,
824
+ TPrivateServices,
825
+ TServiceThisContext,
826
+ THandlerThisContext,
827
+ TNewRequestStorage,
828
+ TLinkedFragments
829
+ >(this.#name, {
830
+ dependencies: this.#dependencies,
831
+ baseServices: this.#baseServices,
832
+ namedServices: this.#namedServices,
833
+ privateServices: this.#privateServices,
834
+ serviceDependencies: this.#serviceDependencies,
835
+ createRequestStorage: initializer,
836
+ // Reset context function since storage type changed - it must be reconfigured
837
+ createThisContext: undefined,
838
+ getExternalStorage: preservedExternalStorage,
839
+ linkedFragments: this.#linkedFragments,
840
+ });
841
+ }
842
+
843
+ /**
844
+ * Use an externally-provided RequestContextStorage instance.
845
+ * This allows multiple fragments to share the same storage instance.
846
+ * Useful when fragments need to coordinate (e.g., database fragments sharing adapter storage).
847
+ * Note: You must still call withRequestStorage to provide the initial storage data.
848
+ *
849
+ * @example
850
+ * ```typescript
851
+ * .withExternalRequestStorage(({ options }) =>
852
+ * options.databaseAdapter.contextStorage
853
+ * )
854
+ * .withRequestStorage(({ options }) => ({
855
+ * uow: options.databaseAdapter.db.createUnitOfWork()
856
+ * }))
857
+ * ```
858
+ */
859
+ withExternalRequestStorage<TNewStorage>(
860
+ getStorage: (context: {
861
+ config: TConfig;
862
+ options: TOptions;
863
+ deps: TDeps;
864
+ }) => RequestContextStorage<TNewStorage>,
865
+ ): FragmentDefinitionBuilder<
866
+ TConfig,
867
+ TOptions,
868
+ TDeps,
869
+ TBaseServices,
870
+ TServices,
871
+ TServiceDependencies,
872
+ TPrivateServices,
873
+ TServiceThisContext,
874
+ THandlerThisContext,
875
+ TNewStorage,
876
+ TLinkedFragments
877
+ > {
878
+ return new FragmentDefinitionBuilder<
879
+ TConfig,
880
+ TOptions,
881
+ TDeps,
882
+ TBaseServices,
883
+ TServices,
884
+ TServiceDependencies,
885
+ TPrivateServices,
886
+ TServiceThisContext,
887
+ THandlerThisContext,
888
+ TNewStorage,
889
+ TLinkedFragments
890
+ >(this.#name, {
891
+ dependencies: this.#dependencies,
892
+ baseServices: this.#baseServices,
893
+ namedServices: this.#namedServices,
894
+ privateServices: this.#privateServices,
895
+ serviceDependencies: this.#serviceDependencies,
896
+ // Reset storage/context functions since storage type changed - they must be reconfigured
897
+ createRequestStorage: undefined,
898
+ createThisContext: undefined,
899
+ getExternalStorage: getStorage,
900
+ linkedFragments: this.#linkedFragments,
901
+ });
902
+ }
903
+
904
+ /**
905
+ * Set the this contexts for services and handlers in this fragment.
906
+ * Both contexts should contain only methods or getters that read from storage.
907
+ * This ensures proper per-request isolation via AsyncLocalStorage.
908
+ *
909
+ * @example
910
+ * ```ts
911
+ * .withThisContext(({ storage }) => ({
912
+ * serviceContext: {
913
+ * get myNumber() { return storage.getStore()?.myNumber ?? 0; }
914
+ * },
915
+ * handlerContext: {
916
+ * get myNumber() { return storage.getStore()?.myNumber ?? 0; }
917
+ * }
918
+ * }))
919
+ * ```
920
+ */
921
+ withThisContext<
922
+ TNewServiceThisContext extends RequestThisContext,
923
+ TNewHandlerThisContext extends RequestThisContext,
924
+ >(
925
+ fn: (context: RequestContextFactoryContext<TConfig, TOptions, TDeps, TRequestStorage>) => {
926
+ serviceContext: TNewServiceThisContext;
927
+ handlerContext: TNewHandlerThisContext;
928
+ },
929
+ ): FragmentDefinitionBuilder<
930
+ TConfig,
931
+ TOptions,
932
+ TDeps,
933
+ TBaseServices,
934
+ TServices,
935
+ TServiceDependencies,
936
+ TPrivateServices,
937
+ TNewServiceThisContext,
938
+ TNewHandlerThisContext,
939
+ TRequestStorage,
940
+ TLinkedFragments
941
+ > {
942
+ return new FragmentDefinitionBuilder<
943
+ TConfig,
944
+ TOptions,
945
+ TDeps,
946
+ TBaseServices,
947
+ TServices,
948
+ TServiceDependencies,
949
+ TPrivateServices,
950
+ TNewServiceThisContext,
951
+ TNewHandlerThisContext,
952
+ TRequestStorage,
953
+ TLinkedFragments
954
+ >(this.#name, {
955
+ dependencies: this.#dependencies,
956
+ baseServices: this.#baseServices,
957
+ namedServices: this.#namedServices,
958
+ privateServices: this.#privateServices,
959
+ serviceDependencies: this.#serviceDependencies,
960
+ createRequestStorage: this.#createRequestStorage,
961
+ createThisContext: fn,
962
+ getExternalStorage: this.#getExternalStorage,
963
+ linkedFragments: this.#linkedFragments,
964
+ });
965
+ }
966
+
967
+ /**
968
+ * Register a linked fragment that will be automatically instantiated.
969
+ * Linked fragments are service-only (no routes) and share the same config/options as the parent.
970
+ * All services from the linked fragment will be available as private services.
971
+ */
972
+ withLinkedFragment<
973
+ const TName extends string,
974
+ TCallback extends LinkedFragmentCallback<TConfig, TOptions, TServiceDependencies>,
975
+ >(
976
+ name: TName,
977
+ callback: TCallback,
978
+ ): FragmentDefinitionBuilder<
979
+ TConfig,
980
+ TOptions,
981
+ TDeps,
982
+ TBaseServices,
983
+ TServices,
984
+ TServiceDependencies,
985
+ TPrivateServices & ExtractLinkedServices<TCallback>,
986
+ TServiceThisContext,
987
+ THandlerThisContext,
988
+ TRequestStorage,
989
+ TLinkedFragments & { [K in TName]: ReturnType<TCallback> }
990
+ > {
991
+ const newLinkedFragments = {
992
+ ...this.#linkedFragments,
993
+ [name]: callback,
994
+ };
995
+
996
+ // Cast is safe: We're declaring that the returned builder has TPrivateServices & ExtractLinkedServices<TCallback>,
997
+ // even though the runtime privateServices hasn't changed yet. The linked fragment services will be
998
+ // merged into privateServices at instantiation time by the instantiator.
999
+ return new FragmentDefinitionBuilder(this.#name, {
1000
+ dependencies: this.#dependencies,
1001
+ baseServices: this.#baseServices,
1002
+ namedServices: this.#namedServices,
1003
+ privateServices: this.#privateServices,
1004
+ serviceDependencies: this.#serviceDependencies,
1005
+ createRequestStorage: this.#createRequestStorage,
1006
+ createThisContext: this.#createThisContext,
1007
+ getExternalStorage: this.#getExternalStorage,
1008
+ linkedFragments: newLinkedFragments,
1009
+ }) as FragmentDefinitionBuilder<
1010
+ TConfig,
1011
+ TOptions,
1012
+ TDeps,
1013
+ TBaseServices,
1014
+ TServices,
1015
+ TServiceDependencies,
1016
+ TPrivateServices & ExtractLinkedServices<TCallback>,
1017
+ TServiceThisContext,
1018
+ THandlerThisContext,
1019
+ TRequestStorage,
1020
+ TLinkedFragments & { [K in TName]: ReturnType<TCallback> }
1021
+ >;
1022
+ }
1023
+
1024
+ /**
1025
+ * Extend this builder with a transformation function.
1026
+ * This enables fluent API extensions like `.extend(withDatabase(schema))`.
1027
+ */
1028
+ extend<const TNewBuilder>(transformer: (builder: this) => TNewBuilder): TNewBuilder {
1029
+ return transformer(this);
1030
+ }
1031
+
1032
+ /**
1033
+ * Build the final fragment definition
1034
+ */
1035
+ build(): FragmentDefinition<
1036
+ TConfig,
1037
+ TOptions,
1038
+ TDeps,
1039
+ TBaseServices,
1040
+ TServices,
1041
+ TServiceDependencies,
1042
+ TPrivateServices,
1043
+ TServiceThisContext,
1044
+ THandlerThisContext,
1045
+ TRequestStorage,
1046
+ TLinkedFragments
1047
+ > {
1048
+ return {
1049
+ name: this.#name,
1050
+ dependencies: this.#dependencies,
1051
+ baseServices: this.#baseServices,
1052
+ namedServices: this.#namedServices,
1053
+ privateServices: this.#privateServices,
1054
+ serviceDependencies: this.#serviceDependencies,
1055
+ createRequestStorage: this.#createRequestStorage,
1056
+ createThisContext: this.#createThisContext,
1057
+ getExternalStorage: this.#getExternalStorage,
1058
+ linkedFragments: this.#linkedFragments,
1059
+ };
1060
+ }
1061
+ }
1062
+
1063
+ /**
1064
+ * Create a new fragment definition builder
1065
+ */
1066
+ export function defineFragment<
1067
+ TConfig = {},
1068
+ TOptions extends FragnoPublicConfig = FragnoPublicConfig,
1069
+ TServiceThisContext extends RequestThisContext = RequestThisContext,
1070
+ THandlerThisContext extends RequestThisContext = RequestThisContext,
1071
+ TRequestStorage = {},
1072
+ >(
1073
+ name: string,
1074
+ ): FragmentDefinitionBuilder<
1075
+ TConfig,
1076
+ TOptions,
1077
+ {},
1078
+ {},
1079
+ {},
1080
+ {},
1081
+ {},
1082
+ TServiceThisContext,
1083
+ THandlerThisContext,
1084
+ TRequestStorage,
1085
+ {}
1086
+ > {
1087
+ return new FragmentDefinitionBuilder(name);
1088
+ }