@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.
Files changed (176) hide show
  1. package/.turbo/turbo-build.log +131 -56
  2. package/CHANGELOG.md +13 -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 -3
  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/error.js +48 -0
  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 -2
  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 -2
  71. package/dist/client/client.d.ts.map +1 -0
  72. package/dist/client/client.js +397 -5
  73. package/dist/client/client.js.map +1 -0
  74. package/dist/client/client.svelte.d.ts +5 -2
  75. package/dist/client/client.svelte.d.ts.map +1 -1
  76. package/dist/client/client.svelte.js +1 -4
  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 -2
  83. package/dist/client/react.d.ts.map +1 -1
  84. package/dist/client/react.js +3 -4
  85. package/dist/client/react.js.map +1 -1
  86. package/dist/client/solid.d.ts +5 -2
  87. package/dist/client/solid.d.ts.map +1 -1
  88. package/dist/client/solid.js +2 -4
  89. package/dist/client/solid.js.map +1 -1
  90. package/dist/client/vanilla.d.ts +5 -2
  91. package/dist/client/vanilla.d.ts.map +1 -1
  92. package/dist/client/vanilla.js +2 -42
  93. package/dist/client/vanilla.js.map +1 -1
  94. package/dist/client/vue.d.ts +5 -2
  95. package/dist/client/vue.d.ts.map +1 -1
  96. package/dist/client/vue.js +1 -4
  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 -2
  110. package/dist/mod.js +4 -4
  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 -34
  114. package/dist/test/test.d.ts.map +1 -1
  115. package/dist/test/test.js +75 -42
  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-kyKI7pqH.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 +1 -5
  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 +454 -189
  136. package/src/api/request-context-storage.ts +64 -0
  137. package/src/api/request-middleware.test.ts +301 -228
  138. package/src/api/route.test.ts +12 -36
  139. package/src/api/route.ts +167 -155
  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 +22 -15
  154. package/src/request/request.ts +8 -0
  155. package/src/test/test.test.ts +189 -375
  156. package/src/test/test.ts +186 -152
  157. package/tsdown.config.ts +8 -5
  158. package/dist/api/fragment-builder.d.ts +0 -2
  159. package/dist/api/fragment-builder.js +0 -3
  160. package/dist/api/fragment-instantiation.d.ts +0 -2
  161. package/dist/api/fragment-instantiation.js +0 -4
  162. package/dist/api-BFrUCIsF.d.ts +0 -963
  163. package/dist/api-BFrUCIsF.d.ts.map +0 -1
  164. package/dist/client-DAFHcKqA.js +0 -782
  165. package/dist/client-DAFHcKqA.js.map +0 -1
  166. package/dist/fragment-builder-Boh2vNHq.js +0 -108
  167. package/dist/fragment-builder-Boh2vNHq.js.map +0 -1
  168. package/dist/fragment-instantiation-DUT-HLl1.js +0 -898
  169. package/dist/fragment-instantiation-DUT-HLl1.js.map +0 -1
  170. package/dist/route-C4CyNHkC.js +0 -26
  171. package/dist/route-C4CyNHkC.js.map +0 -1
  172. package/dist/ssr-kyKI7pqH.js.map +0 -1
  173. package/src/api/fragment-builder.ts +0 -518
  174. package/src/api/fragment-instantiation.test.ts +0 -702
  175. package/src/api/fragment-instantiation.ts +0 -766
  176. package/src/api/fragment.test.ts +0 -585
@@ -1,518 +0,0 @@
1
- import type { RequestThisContext } from "./api";
2
- import type { FragnoPublicConfig } from "./fragment-instantiation";
3
- import type { RequestInputContext } from "./request-input-context";
4
- import type { RequestOutputContext } from "./request-output-context";
5
-
6
- /**
7
- * Metadata for a service dependency
8
- */
9
- interface ServiceMetadata {
10
- /** Name of the service */
11
- name: string;
12
- /** Whether this service is required (false means optional) */
13
- required: boolean;
14
- }
15
-
16
- export type RouteHandler = (
17
- this: RequestThisContext,
18
- inputContext: RequestInputContext,
19
- outputContext: RequestOutputContext,
20
- ) => Promise<Response>;
21
-
22
- export interface FragmentDefinition<
23
- TConfig,
24
- TDeps = {},
25
- TServices = {},
26
- TAdditionalContext extends Record<string, unknown> = {},
27
- TUsedServices = {},
28
- TProvidedServices = {},
29
- TThisContext extends RequestThisContext = RequestThisContext,
30
- > {
31
- name: string;
32
- dependencies?: (config: TConfig, options: FragnoPublicConfig) => TDeps;
33
- services?: (
34
- config: TConfig,
35
- options: FragnoPublicConfig,
36
- deps: TDeps & TUsedServices,
37
- ) => TServices;
38
- additionalContext?: TAdditionalContext;
39
- createHandlerWrapper?: (
40
- options: FragnoPublicConfig,
41
- ) => (
42
- handler: (this: TThisContext, ...args: Parameters<RouteHandler>) => ReturnType<RouteHandler>,
43
- ) => RouteHandler;
44
- /** Services that this fragment uses (can be required or optional) */
45
- usedServices?: {
46
- [K in keyof TUsedServices]: ServiceMetadata;
47
- };
48
- /** Services that this fragment provides to other fragments (can be a factory function or direct object) */
49
- providedServices?:
50
- | {
51
- [K in keyof TProvidedServices]: TProvidedServices[K];
52
- }
53
- | ((
54
- config: TConfig,
55
- options: FragnoPublicConfig,
56
- deps: TDeps & TUsedServices,
57
- ) => TProvidedServices);
58
- }
59
-
60
- export class FragmentBuilder<
61
- const TConfig,
62
- const TDeps = {},
63
- const TServices = {},
64
- const TAdditionalContext extends Record<string, unknown> = {},
65
- const TUsedServices = {},
66
- const TProvidedServices = {},
67
- const TThisContext extends RequestThisContext = RequestThisContext,
68
- > {
69
- #definition: FragmentDefinition<
70
- TConfig,
71
- TDeps,
72
- TServices,
73
- TAdditionalContext,
74
- TUsedServices,
75
- TProvidedServices,
76
- TThisContext
77
- >;
78
-
79
- constructor(
80
- definition: FragmentDefinition<
81
- TConfig,
82
- TDeps,
83
- TServices,
84
- TAdditionalContext,
85
- TUsedServices,
86
- TProvidedServices,
87
- TThisContext
88
- >,
89
- ) {
90
- this.#definition = definition;
91
- }
92
-
93
- get definition() {
94
- return this.#definition;
95
- }
96
-
97
- get $requiredOptions(): FragnoPublicConfig {
98
- throw new Error("Type only method. Do not call.");
99
- }
100
-
101
- withDependencies<TNewDeps>(
102
- fn: (
103
- context: { config: TConfig; fragnoConfig: FragnoPublicConfig } & TAdditionalContext,
104
- ) => TNewDeps,
105
- ): FragmentBuilder<
106
- TConfig,
107
- TNewDeps,
108
- {},
109
- TAdditionalContext,
110
- TUsedServices,
111
- TProvidedServices,
112
- TThisContext
113
- > {
114
- // Safe cast: If providedServices is a function, we need to update its signature to use TNewDeps.
115
- // This is safe because the function will be called with the new deps at runtime.
116
- const providedServices = this.#definition.providedServices;
117
- const recastProvidedServices =
118
- typeof providedServices === "function"
119
- ? (providedServices as unknown as (
120
- config: TConfig,
121
- options: FragnoPublicConfig,
122
- deps: TNewDeps & TUsedServices,
123
- ) => TProvidedServices)
124
- : providedServices;
125
-
126
- return new FragmentBuilder<
127
- TConfig,
128
- TNewDeps,
129
- {},
130
- TAdditionalContext,
131
- TUsedServices,
132
- TProvidedServices,
133
- TThisContext
134
- >({
135
- name: this.#definition.name,
136
- dependencies: (config: TConfig, options: FragnoPublicConfig) => {
137
- return fn({ config, fragnoConfig: options } as {
138
- config: TConfig;
139
- fragnoConfig: FragnoPublicConfig;
140
- } & TAdditionalContext);
141
- },
142
- services: undefined,
143
- additionalContext: this.#definition.additionalContext,
144
- usedServices: this.#definition.usedServices,
145
- providedServices: recastProvidedServices,
146
- });
147
- }
148
-
149
- /**
150
- * Declare that this fragment uses a service.
151
- * By default, the service is required. Pass { optional: true } to make it optional.
152
- *
153
- * @example
154
- * ```ts
155
- * // Required service
156
- * defineFragment("my-fragment")
157
- * .usesService<"email", IEmailService>("email")
158
- * .providesService(({ deps, define }) => define({
159
- * sendWelcome: () => deps.email.send(...)
160
- * }))
161
- *
162
- * // Optional service
163
- * defineFragment("my-fragment")
164
- * .usesService<"email", IEmailService>("email", { optional: true })
165
- * .providesService(({ deps, define }) => define({
166
- * sendWelcome: () => {
167
- * if (deps.email) {
168
- * deps.email.send(...)
169
- * }
170
- * }
171
- * }))
172
- * ```
173
- */
174
- usesService<TServiceName extends string, TService>(
175
- serviceName: TServiceName,
176
- options?: { optional?: false },
177
- ): FragmentBuilder<
178
- TConfig,
179
- TDeps,
180
- TServices,
181
- TAdditionalContext,
182
- TUsedServices & { [K in TServiceName]: TService },
183
- TProvidedServices,
184
- TThisContext
185
- >;
186
- usesService<TServiceName extends string, TService>(
187
- serviceName: TServiceName,
188
- options: { optional: true },
189
- ): FragmentBuilder<
190
- TConfig,
191
- TDeps,
192
- TServices,
193
- TAdditionalContext,
194
- TUsedServices & { [K in TServiceName]: TService | undefined },
195
- TProvidedServices,
196
- TThisContext
197
- >;
198
- usesService<TServiceName extends string, TService>(
199
- serviceName: TServiceName,
200
- options?: { optional?: boolean },
201
- ): FragmentBuilder<
202
- TConfig,
203
- TDeps,
204
- TServices,
205
- TAdditionalContext,
206
- TUsedServices & { [K in TServiceName]: TService | TService | undefined },
207
- TProvidedServices,
208
- TThisContext
209
- > {
210
- const isOptional = options?.optional ?? false;
211
- return new FragmentBuilder<
212
- TConfig,
213
- TDeps,
214
- TServices,
215
- TAdditionalContext,
216
- TUsedServices & { [K in TServiceName]: TService | (TService | undefined) },
217
- TProvidedServices,
218
- TThisContext
219
- >({
220
- name: this.#definition.name,
221
- dependencies: this.#definition.dependencies,
222
- services: this.#definition.services as
223
- | ((
224
- config: TConfig,
225
- options: FragnoPublicConfig,
226
- deps: TDeps &
227
- (TUsedServices & { [K in TServiceName]: TService | (TService | undefined) }),
228
- ) => TServices)
229
- | undefined,
230
- additionalContext: this.#definition.additionalContext,
231
- usedServices: {
232
- ...this.#definition.usedServices,
233
- [serviceName]: { name: serviceName, required: !isOptional },
234
- } as {
235
- [K in keyof (TUsedServices & {
236
- [K in TServiceName]: TService | (TService | undefined);
237
- })]: ServiceMetadata;
238
- },
239
- providedServices: this.#definition.providedServices,
240
- });
241
- }
242
-
243
- /**
244
- * Define services for this fragment (unnamed) using a callback.
245
- * Use the `defineService` function from the callback context for proper typing (optional).
246
- */
247
- providesService<TNewServices>(
248
- fn: (context: {
249
- config: TConfig;
250
- fragnoConfig: FragnoPublicConfig;
251
- deps: TDeps & TUsedServices;
252
- defineService: <T>(services: T) => T;
253
- }) => TNewServices,
254
- ): FragmentBuilder<
255
- TConfig,
256
- TDeps,
257
- TNewServices,
258
- TAdditionalContext,
259
- TUsedServices,
260
- TProvidedServices,
261
- TThisContext
262
- >;
263
-
264
- /**
265
- * Define services for this fragment (unnamed) using a direct object.
266
- */
267
- providesService<TNewServices>(
268
- services: TNewServices,
269
- ): FragmentBuilder<
270
- TConfig,
271
- TDeps,
272
- TNewServices,
273
- TAdditionalContext,
274
- TUsedServices,
275
- TProvidedServices,
276
- TThisContext
277
- >;
278
-
279
- /**
280
- * Provide a named service using a callback.
281
- * Use the `defineService` function from the callback context for proper typing (optional).
282
- *
283
- * @example
284
- * ```ts
285
- * interface IEmailService {
286
- * send(to: string, subject: string, body: string): Promise<void>;
287
- * }
288
- *
289
- * defineFragment("email-fragment")
290
- * .providesService<"email", IEmailService>("email", ({ defineService }) => defineService({
291
- * send: async (to, subject, body) => {
292
- * // implementation
293
- * }
294
- * }))
295
- * ```
296
- */
297
- providesService<TServiceName extends string, TService>(
298
- serviceName: TServiceName,
299
- fn: (context: {
300
- config: TConfig;
301
- fragnoConfig: FragnoPublicConfig;
302
- deps: TDeps & TUsedServices;
303
- defineService: <T>(services: T) => T;
304
- }) => TService,
305
- ): FragmentBuilder<
306
- TConfig,
307
- TDeps,
308
- TServices,
309
- TAdditionalContext,
310
- TUsedServices,
311
- TProvidedServices & { [K in TServiceName]: TService },
312
- TThisContext
313
- >;
314
-
315
- /**
316
- * Provide a named service using a direct object.
317
- */
318
- providesService<TServiceName extends string, TService>(
319
- serviceName: TServiceName,
320
- service: TService,
321
- ): FragmentBuilder<
322
- TConfig,
323
- TDeps,
324
- TServices,
325
- TAdditionalContext,
326
- TUsedServices,
327
- TProvidedServices & { [K in TServiceName]: TService },
328
- TThisContext
329
- >;
330
-
331
- providesService<TServiceName extends string, TService>(
332
- ...args:
333
- | [
334
- fnOrServices:
335
- | ((context: {
336
- config: TConfig;
337
- fragnoConfig: FragnoPublicConfig;
338
- deps: TDeps & TUsedServices;
339
- defineService: <T>(services: T) => T;
340
- }) => TService)
341
- | TService,
342
- ]
343
- | [
344
- serviceName: TServiceName,
345
- fnOrService:
346
- | ((context: {
347
- config: TConfig;
348
- fragnoConfig: FragnoPublicConfig;
349
- deps: TDeps & TUsedServices;
350
- defineService: <T>(services: T) => T;
351
- }) => TService)
352
- | TService,
353
- ]
354
- ):
355
- | FragmentBuilder<
356
- TConfig,
357
- TDeps,
358
- TService,
359
- TAdditionalContext,
360
- TUsedServices,
361
- TProvidedServices,
362
- TThisContext
363
- >
364
- | FragmentBuilder<
365
- TConfig,
366
- TDeps,
367
- TServices,
368
- TAdditionalContext,
369
- TUsedServices,
370
- TProvidedServices & { [K in TServiceName]: TService },
371
- TThisContext
372
- > {
373
- // The defineService function is just an identity function at runtime
374
- const defineService = <T>(services: T) => services;
375
-
376
- if (args.length === 1) {
377
- // Unnamed service
378
- const [fnOrServices] = args;
379
-
380
- // Create a callback that provides the full context including defineService
381
- const servicesCallback = (
382
- config: TConfig,
383
- options: FragnoPublicConfig,
384
- deps: TDeps & TUsedServices,
385
- ): TService => {
386
- if (typeof fnOrServices === "function") {
387
- // It's a factory function - call it with context
388
- const fn = fnOrServices as (context: {
389
- config: TConfig;
390
- fragnoConfig: FragnoPublicConfig;
391
- deps: TDeps & TUsedServices;
392
- defineService: <T>(services: T) => T;
393
- }) => TService;
394
- return fn({
395
- config,
396
- fragnoConfig: options,
397
- deps,
398
- defineService,
399
- });
400
- } else {
401
- // It's a direct service object
402
- return fnOrServices;
403
- }
404
- };
405
-
406
- return new FragmentBuilder<
407
- TConfig,
408
- TDeps,
409
- TService,
410
- TAdditionalContext,
411
- TUsedServices,
412
- TProvidedServices,
413
- TThisContext
414
- >({
415
- name: this.#definition.name,
416
- dependencies: this.#definition.dependencies,
417
- services: servicesCallback as (
418
- config: TConfig,
419
- options: FragnoPublicConfig,
420
- deps: TDeps & TUsedServices,
421
- ) => TService,
422
- additionalContext: this.#definition.additionalContext,
423
- usedServices: this.#definition.usedServices,
424
- providedServices: this.#definition.providedServices,
425
- });
426
- } else {
427
- // Named service
428
- const [serviceName, fnOrService] = args;
429
-
430
- // Create a callback that provides the full context including defineService
431
- const createService = (
432
- config: TConfig,
433
- options: FragnoPublicConfig,
434
- deps: TDeps & TUsedServices,
435
- ): TService => {
436
- if (typeof fnOrService === "function") {
437
- // It's a factory function - call it with context
438
- const fn = fnOrService as (context: {
439
- config: TConfig;
440
- fragnoConfig: FragnoPublicConfig;
441
- deps: TDeps & TUsedServices;
442
- defineService: <T>(services: T) => T;
443
- }) => TService;
444
- return fn({
445
- config,
446
- fragnoConfig: options,
447
- deps,
448
- defineService,
449
- });
450
- } else {
451
- // It's a direct service object
452
- return fnOrService;
453
- }
454
- };
455
-
456
- // We need to handle both function and object forms of providedServices
457
- const existingProvidedServices = this.#definition.providedServices;
458
- const newProvidedServices:
459
- | {
460
- [K in keyof (TProvidedServices & {
461
- [K in TServiceName]: TService;
462
- })]: (TProvidedServices & {
463
- [K in TServiceName]: TService;
464
- })[K];
465
- }
466
- | ((
467
- config: TConfig,
468
- options: FragnoPublicConfig,
469
- deps: TDeps & TUsedServices,
470
- ) => TProvidedServices & { [K in TServiceName]: TService }) =
471
- typeof existingProvidedServices === "function"
472
- ? // If existing is a function, create a new function that calls both
473
- (config: TConfig, options: FragnoPublicConfig, deps: TDeps & TUsedServices) => {
474
- const existing = existingProvidedServices(config, options, deps);
475
- const newService = createService(config, options, deps);
476
- return {
477
- ...existing,
478
- [serviceName]: newService,
479
- } as TProvidedServices & { [K in TServiceName]: TService };
480
- }
481
- : // If existing is an object or undefined, spread it
482
- ({
483
- ...existingProvidedServices,
484
- [serviceName]: createService,
485
- } as {
486
- [K in keyof (TProvidedServices & {
487
- [K in TServiceName]: TService;
488
- })]: (TProvidedServices & {
489
- [K in TServiceName]: TService;
490
- })[K];
491
- });
492
-
493
- return new FragmentBuilder<
494
- TConfig,
495
- TDeps,
496
- TServices,
497
- TAdditionalContext,
498
- TUsedServices,
499
- TProvidedServices & { [K in TServiceName]: TService },
500
- TThisContext
501
- >({
502
- name: this.#definition.name,
503
- dependencies: this.#definition.dependencies,
504
- services: this.#definition.services,
505
- additionalContext: this.#definition.additionalContext,
506
- usedServices: this.#definition.usedServices,
507
- providedServices: newProvidedServices,
508
- });
509
- }
510
- }
511
- }
512
- export function defineFragment<TConfig = {}>(
513
- name: string,
514
- ): FragmentBuilder<TConfig, {}, {}, {}, {}, {}, RequestThisContext> {
515
- return new FragmentBuilder({
516
- name,
517
- });
518
- }