@fragno-dev/core 0.1.7 → 0.1.8

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 (79) hide show
  1. package/.turbo/turbo-build.log +45 -53
  2. package/CHANGELOG.md +6 -0
  3. package/dist/api/api.d.ts +2 -2
  4. package/dist/api/api.js +3 -2
  5. package/dist/api/fragment-builder.d.ts +2 -4
  6. package/dist/api/fragment-builder.js +1 -1
  7. package/dist/api/fragment-instantiation.d.ts +2 -4
  8. package/dist/api/fragment-instantiation.js +3 -5
  9. package/dist/api/route.d.ts +2 -3
  10. package/dist/api/route.js +1 -1
  11. package/dist/api-BFrUCIsF.d.ts +963 -0
  12. package/dist/api-BFrUCIsF.d.ts.map +1 -0
  13. package/dist/client/client.d.ts +1 -3
  14. package/dist/client/client.js +4 -5
  15. package/dist/client/client.svelte.d.ts +2 -3
  16. package/dist/client/client.svelte.d.ts.map +1 -1
  17. package/dist/client/client.svelte.js +4 -5
  18. package/dist/client/client.svelte.js.map +1 -1
  19. package/dist/client/react.d.ts +2 -3
  20. package/dist/client/react.d.ts.map +1 -1
  21. package/dist/client/react.js +4 -5
  22. package/dist/client/react.js.map +1 -1
  23. package/dist/client/solid.d.ts +2 -3
  24. package/dist/client/solid.d.ts.map +1 -1
  25. package/dist/client/solid.js +4 -5
  26. package/dist/client/solid.js.map +1 -1
  27. package/dist/client/vanilla.d.ts +2 -3
  28. package/dist/client/vanilla.d.ts.map +1 -1
  29. package/dist/client/vanilla.js +4 -5
  30. package/dist/client/vanilla.js.map +1 -1
  31. package/dist/client/vue.d.ts +2 -3
  32. package/dist/client/vue.d.ts.map +1 -1
  33. package/dist/client/vue.js +4 -5
  34. package/dist/client/vue.js.map +1 -1
  35. package/dist/{client-C5LsYHEI.js → client-DAFHcKqA.js} +4 -4
  36. package/dist/{client-C5LsYHEI.js.map → client-DAFHcKqA.js.map} +1 -1
  37. package/dist/fragment-builder-Boh2vNHq.js +108 -0
  38. package/dist/fragment-builder-Boh2vNHq.js.map +1 -0
  39. package/dist/fragment-instantiation-DUT-HLl1.js +898 -0
  40. package/dist/fragment-instantiation-DUT-HLl1.js.map +1 -0
  41. package/dist/integrations/react-ssr.js +1 -1
  42. package/dist/mod.d.ts +2 -4
  43. package/dist/mod.js +4 -6
  44. package/dist/{route-C5Uryylh.js → route-C4CyNHkC.js} +8 -3
  45. package/dist/route-C4CyNHkC.js.map +1 -0
  46. package/dist/{ssr-BByDVfFD.js → ssr-kyKI7pqH.js} +1 -1
  47. package/dist/{ssr-BByDVfFD.js.map → ssr-kyKI7pqH.js.map} +1 -1
  48. package/dist/test/test.d.ts +6 -7
  49. package/dist/test/test.d.ts.map +1 -1
  50. package/dist/test/test.js +9 -7
  51. package/dist/test/test.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/api/api.ts +45 -6
  54. package/src/api/fragment-builder.ts +463 -25
  55. package/src/api/fragment-instantiation.test.ts +249 -7
  56. package/src/api/fragment-instantiation.ts +283 -16
  57. package/src/api/fragment-services.test.ts +462 -0
  58. package/src/api/fragment.test.ts +65 -17
  59. package/src/api/request-middleware.test.ts +6 -3
  60. package/src/api/route.test.ts +111 -1
  61. package/src/api/route.ts +323 -14
  62. package/src/mod.ts +11 -1
  63. package/src/test/test.test.ts +20 -15
  64. package/src/test/test.ts +48 -9
  65. package/dist/api-BWN97TOr.d.ts +0 -377
  66. package/dist/api-BWN97TOr.d.ts.map +0 -1
  67. package/dist/api-DngJDcmO.js +0 -54
  68. package/dist/api-DngJDcmO.js.map +0 -1
  69. package/dist/fragment-builder-DOnCVBqc.js +0 -47
  70. package/dist/fragment-builder-DOnCVBqc.js.map +0 -1
  71. package/dist/fragment-builder-MGr68GNb.d.ts +0 -409
  72. package/dist/fragment-builder-MGr68GNb.d.ts.map +0 -1
  73. package/dist/fragment-instantiation-C4wvwl6V.js +0 -446
  74. package/dist/fragment-instantiation-C4wvwl6V.js.map +0 -1
  75. package/dist/request-output-context-CdIjwmEN.js +0 -320
  76. package/dist/request-output-context-CdIjwmEN.js.map +0 -1
  77. package/dist/route-Bl9Zr1Yv.d.ts +0 -26
  78. package/dist/route-Bl9Zr1Yv.d.ts.map +0 -1
  79. package/dist/route-C5Uryylh.js.map +0 -1
@@ -0,0 +1,963 @@
1
+ import { ReadableAtom, Store } from "nanostores";
2
+ import { FetcherStore, MutatorStore } from "@nanostores/query";
3
+ import { StandardSchemaV1 } from "@standard-schema/spec";
4
+
5
+ //#region src/api/internal/path.d.ts
6
+ type SplitPath<T extends string> = T extends `${infer First}/${infer Rest}` ? First extends "" ? SplitPath<Rest> : [First, ...SplitPath<Rest>] : T extends "" ? [] : [T];
7
+ type ExtractParam<T extends string> = T extends `:${infer Name}` ? Name : T extends `**:${infer Name}` ? Name : T extends "**" ? "**" : never;
8
+ type ExtractParamsFromSegments<T extends readonly string[]> = T extends readonly [infer First, ...infer Rest] ? First extends string ? Rest extends readonly string[] ? ExtractParam<First> | ExtractParamsFromSegments<Rest> : ExtractParam<First> : never : never;
9
+ /**
10
+ * Type helper to extract path parameters from a const string path
11
+ *
12
+ * Supports:
13
+ * - Regular paths: "/path" -> never
14
+ * - Named parameters: "/path/:name" -> "name"
15
+ * - Wildcard paths: "/path/foo/**" -> "**"
16
+ * - Named wildcard paths: "/path/foo/**:name" -> "name"
17
+ * - String (narrows): string -> never
18
+ */
19
+ type ExtractPathParams<T extends string, ValueType = string> = ExtractParamsFromSegments<SplitPath<T>> extends never ? Record<string, never> : Record<ExtractParamsFromSegments<SplitPath<T>>, ValueType>;
20
+ /**
21
+ * Same as @see ExtractPathParams, but returns `Record<string, ValueType>` when a string is
22
+ * passed in.
23
+ */
24
+ type ExtractPathParamsOrWiden<T extends string, ValueType = string> = string extends T ? Record<string, ValueType> : ExtractPathParams<T, ValueType>;
25
+ /**
26
+ * Same as @see ExtractPathParamsOrWiden, but returns `undefined` when no path parameters in the
27
+ * const.
28
+ */
29
+ type MaybeExtractPathParamsOrWiden<T extends string, ValueType = string> = HasPathParams<T> extends true ? ExtractPathParamsOrWiden<T, ValueType> : undefined;
30
+ type ExtractPathParamNames<T extends string> = ExtractParamsFromSegments<SplitPath<T>>;
31
+ type HasPathParams<T extends string> = ExtractPathParamNames<T> extends never ? false : true;
32
+ /**
33
+ * Creates a query parameters type where the specified keys are hints (optional)
34
+ * and additional string keys are also allowed.
35
+ *
36
+ * This allows for flexible query parameter typing where:
37
+ * - All hinted parameters are optional
38
+ * - Additional parameters beyond the hints are allowed
39
+ * - Values can be of any specified type (defaults to string)
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * type MyQuery = QueryParamsHint<"page" | "limit", string>;
44
+ * // Allows: { page?: string, limit?: string, [key: string]: string }
45
+ *
46
+ * const query1: MyQuery = {}; // Valid - no params required
47
+ * const query2: MyQuery = { page: "1" }; // Valid - hinted param
48
+ * const query3: MyQuery = { page: "1", sort: "asc" }; // Valid - additional param
49
+ * ```
50
+ */
51
+ type QueryParamsHint<TQueryParameters extends string, ValueType = string> = Partial<Record<TQueryParameters, ValueType>> & Record<string, ValueType | undefined>;
52
+ //#endregion
53
+ //#region src/api/mutable-request-state.d.ts
54
+ /**
55
+ * Holds mutable request state that can be modified by middleware and consumed by handlers.
56
+ *
57
+ * This class provides a structural way for middleware to modify request data:
58
+ * - Path parameters can be modified
59
+ * - Query/search parameters can be modified
60
+ * - Request body can be overridden
61
+ * - Request headers can be modified
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * // In middleware
66
+ * const state = new MutableRequestState({
67
+ * pathParams: { id: "123" },
68
+ * searchParams: new URLSearchParams("?role=user"),
69
+ * body: { name: "John" },
70
+ * headers: new Headers()
71
+ * });
72
+ *
73
+ * // Modify query parameters
74
+ * state.searchParams.set("role", "admin");
75
+ *
76
+ * // Override body
77
+ * state.setBody({ name: "Jane" });
78
+ *
79
+ * // Modify headers
80
+ * state.headers.set("X-Custom", "value");
81
+ * ```
82
+ */
83
+ declare class MutableRequestState {
84
+ #private;
85
+ constructor(config: {
86
+ pathParams: Record<string, string>;
87
+ searchParams: URLSearchParams;
88
+ body: RequestBodyType;
89
+ headers: Headers;
90
+ });
91
+ /**
92
+ * Path parameters extracted from the route.
93
+ * Can be modified directly (e.g., `state.pathParams.id = "456"`).
94
+ */
95
+ get pathParams(): Record<string, string>;
96
+ /**
97
+ * URLSearchParams for query parameters.
98
+ * Can be modified using URLSearchParams API (e.g., `state.searchParams.set("key", "value")`).
99
+ */
100
+ get searchParams(): URLSearchParams;
101
+ /**
102
+ * Request headers.
103
+ * Can be modified using Headers API (e.g., `state.headers.set("X-Custom", "value")`).
104
+ */
105
+ get headers(): Headers;
106
+ /**
107
+ * Get the current body value.
108
+ * Returns the override if set, otherwise the initial body.
109
+ */
110
+ get body(): RequestBodyType;
111
+ /**
112
+ * Override the request body.
113
+ * This allows middleware to replace the body that will be seen by the handler.
114
+ *
115
+ * @param body - The new body value
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // In middleware
120
+ * state.setBody({ modifiedField: "new value" });
121
+ * ```
122
+ */
123
+ setBody(body: RequestBodyType): void;
124
+ /**
125
+ * Check if the body has been overridden by middleware.
126
+ */
127
+ get hasBodyOverride(): boolean;
128
+ }
129
+ //#endregion
130
+ //#region src/api/request-input-context.d.ts
131
+ type RequestBodyType = unknown | FormData | Blob | null | undefined;
132
+ declare class RequestInputContext<TPath extends string = string, TInputSchema extends StandardSchemaV1 | undefined = undefined> {
133
+ #private;
134
+ constructor(config: {
135
+ path: TPath;
136
+ method: string;
137
+ pathParams: ExtractPathParams<TPath>;
138
+ searchParams: URLSearchParams;
139
+ parsedBody: RequestBodyType;
140
+ rawBody?: string;
141
+ headers: Headers;
142
+ request?: Request;
143
+ inputSchema?: TInputSchema;
144
+ shouldValidateInput?: boolean;
145
+ });
146
+ /**
147
+ * Create a RequestContext from a Request object for server-side handling
148
+ */
149
+ static fromRequest<TPath extends string, TInputSchema extends StandardSchemaV1 | undefined = undefined>(config: {
150
+ request: Request;
151
+ method: string;
152
+ path: TPath;
153
+ pathParams: ExtractPathParams<TPath>;
154
+ inputSchema?: TInputSchema;
155
+ shouldValidateInput?: boolean;
156
+ state: MutableRequestState;
157
+ rawBody?: string;
158
+ }): Promise<RequestInputContext<TPath, TInputSchema>>;
159
+ /**
160
+ * Create a RequestContext for server-side rendering contexts (no Request object)
161
+ */
162
+ static fromSSRContext<TPath extends string, TInputSchema extends StandardSchemaV1 | undefined = undefined>(config: {
163
+ method: "GET";
164
+ path: TPath;
165
+ pathParams: ExtractPathParams<TPath>;
166
+ searchParams?: URLSearchParams;
167
+ headers?: Headers;
168
+ } | {
169
+ method: Exclude<HTTPMethod, "GET">;
170
+ path: TPath;
171
+ pathParams: ExtractPathParams<TPath>;
172
+ searchParams?: URLSearchParams;
173
+ headers?: Headers;
174
+ body: RequestBodyType;
175
+ inputSchema?: TInputSchema;
176
+ }): RequestInputContext<TPath, TInputSchema>;
177
+ /**
178
+ * The HTTP method as string (e.g., `GET`, `POST`)
179
+ */
180
+ get method(): string;
181
+ /**
182
+ * The matched route path (e.g., `/users/:id`)
183
+ * @remarks `string`
184
+ */
185
+ get path(): TPath;
186
+ /**
187
+ * Extracted path parameters as object (e.g., `{ id: '123' }`)
188
+ * @remarks `Record<string, string>`
189
+ */
190
+ get pathParams(): ExtractPathParams<TPath>;
191
+ /**
192
+ * [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object for query parameters
193
+ * @remarks `URLSearchParams`
194
+ */
195
+ get query(): URLSearchParams;
196
+ /**
197
+ * [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object for request headers
198
+ * @remarks `Headers`
199
+ */
200
+ get headers(): Headers;
201
+ get rawBody(): string | undefined;
202
+ /**
203
+ * Input validation context (only if inputSchema is defined)
204
+ * @remarks `InputContext`
205
+ */
206
+ get input(): TInputSchema extends undefined ? undefined : {
207
+ schema: TInputSchema;
208
+ valid: () => Promise<TInputSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TInputSchema> : unknown>;
209
+ };
210
+ }
211
+ //#endregion
212
+ //#region src/http/http-status.d.ts
213
+ /**
214
+ * @module
215
+ * HTTP Status utility.
216
+ *
217
+ * Modified from honojs/hono
218
+ * Original source: https://github.com/honojs/hono/blob/0e3db674ad3f40be215a55a18062dd8e387ce525/src/utils/http-status.ts
219
+ * License: MIT
220
+ * Date obtained: August 28 2025
221
+ * Copyright (c) 2021-present Yusuke Wada and Hono contributors
222
+ *
223
+ */
224
+ type InfoStatusCode = 100 | 101 | 102 | 103;
225
+ type SuccessStatusCode = 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226;
226
+ type DeprecatedStatusCode = 305 | 306;
227
+ type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | DeprecatedStatusCode | 307 | 308;
228
+ type ClientErrorStatusCode = 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451;
229
+ type ServerErrorStatusCode = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511;
230
+ /**
231
+ * If you want to use an unofficial status, use `UnofficialStatusCode`.
232
+ */
233
+ type StatusCode = InfoStatusCode | SuccessStatusCode | RedirectStatusCode | ClientErrorStatusCode | ServerErrorStatusCode;
234
+ type ContentlessStatusCode = 101 | 204 | 205 | 304;
235
+ //#endregion
236
+ //#region src/api/internal/response-stream.d.ts
237
+ /**
238
+ * @module
239
+ * Stream utility.
240
+ *
241
+ * Modified from honojs/hono
242
+ * Original source: https://github.com/honojs/hono/blob/0e3db674ad3f40be215a55a18062dd8e387ce525/src/utils/stream.ts
243
+ * License: MIT
244
+ * Date obtained: August 28 2025
245
+ * Copyright (c) 2021-present Yusuke Wada and Hono contributors
246
+ */
247
+ type Error$1<Message extends string> = {
248
+ __errorMessage: Message;
249
+ };
250
+ declare class ResponseStream<TArray> {
251
+ #private;
252
+ /**
253
+ * Whether the stream has been aborted.
254
+ */
255
+ get aborted(): boolean;
256
+ /**
257
+ * Whether the stream has been closed normally.
258
+ */
259
+ get closed(): boolean;
260
+ /**
261
+ * The readable stream that the response is piped to.
262
+ */
263
+ get responseReadable(): ReadableStream;
264
+ constructor(writable: WritableStream, readable: ReadableStream);
265
+ writeRaw(input: Uint8Array | string): Promise<void>;
266
+ write(input: TArray extends (infer U)[] ? U : Error$1<"To use a streaming response, outputSchema must be an array.">): Promise<void>;
267
+ sleep(ms: number): Promise<unknown>;
268
+ close(): Promise<void>;
269
+ onAbort(listener: () => void | Promise<void>): void;
270
+ /**
271
+ * Abort the stream.
272
+ * You can call this method when stream is aborted by external event.
273
+ */
274
+ abort(): void;
275
+ }
276
+ //#endregion
277
+ //#region src/util/types-util.d.ts
278
+ type InferOr<T, U$1> = T extends NonNullable<StandardSchemaV1> ? StandardSchemaV1.InferOutput<T> : T extends undefined ? U$1 : U$1;
279
+ type InferOrUnknown<T> = InferOr<T, unknown>;
280
+ //#endregion
281
+ //#region src/api/request-output-context.d.ts
282
+ interface ResponseInit<T extends StatusCode = StatusCode> {
283
+ headers?: HeadersInit;
284
+ status?: T;
285
+ statusText?: string;
286
+ }
287
+ declare abstract class OutputContext<const TOutput, const TErrorCode extends string> {
288
+ /**
289
+ * Creates an error response.
290
+ *
291
+ * Shortcut for `throw new FragnoApiError(...)`
292
+ */
293
+ error: ({
294
+ message,
295
+ code
296
+ }: {
297
+ message: string;
298
+ code: TErrorCode;
299
+ }, initOrStatus?: ResponseInit | StatusCode, headers?: HeadersInit) => Response;
300
+ empty: (initOrStatus?: ResponseInit<ContentlessStatusCode> | ContentlessStatusCode, headers?: HeadersInit) => Response;
301
+ json: (object: TOutput, initOrStatus?: ResponseInit | StatusCode, headers?: HeadersInit) => Response;
302
+ jsonStream: (cb: (stream: ResponseStream<TOutput>) => void | Promise<void>, {
303
+ onError,
304
+ headers
305
+ }?: {
306
+ onError?: (error: Error, stream: ResponseStream<TOutput>) => void | Promise<void>;
307
+ headers?: HeadersInit;
308
+ }) => Response;
309
+ }
310
+ declare class RequestOutputContext<const TOutputSchema extends StandardSchemaV1 | undefined = undefined, const TErrorCode extends string = string> extends OutputContext<InferOrUnknown<TOutputSchema>, TErrorCode> {
311
+ #private;
312
+ constructor(outputSchema?: TOutputSchema);
313
+ }
314
+ //#endregion
315
+ //#region src/api/error.d.ts
316
+ declare class FragnoApiError extends Error {
317
+ #private;
318
+ constructor({
319
+ message,
320
+ code
321
+ }: {
322
+ message: string;
323
+ code: string;
324
+ }, status: StatusCode);
325
+ get status(): StatusCode;
326
+ get code(): string;
327
+ toResponse(): Response;
328
+ }
329
+ declare class FragnoApiValidationError extends FragnoApiError {
330
+ #private;
331
+ constructor(message: string, issues: readonly StandardSchemaV1.Issue[]);
332
+ get issues(): readonly StandardSchemaV1.Issue[];
333
+ toResponse(): Response;
334
+ }
335
+ //#endregion
336
+ //#region src/api/route-handler-input-options.d.ts
337
+ /**
338
+ * Options for calling a route handler
339
+ */
340
+ type RouteHandlerInputOptions<TPath extends string, TInputSchema extends StandardSchemaV1 | undefined> = {
341
+ pathParams?: ExtractPathParams<TPath>;
342
+ query?: URLSearchParams | Record<string, string>;
343
+ headers?: Headers | Record<string, string>;
344
+ } & (TInputSchema extends undefined ? {
345
+ body?: never;
346
+ } : {
347
+ body: InferOr<TInputSchema, unknown>;
348
+ });
349
+ //#endregion
350
+ //#region src/api/fragment-builder.d.ts
351
+ /**
352
+ * Metadata for a service dependency
353
+ */
354
+ interface ServiceMetadata {
355
+ /** Name of the service */
356
+ name: string;
357
+ /** Whether this service is required (false means optional) */
358
+ required: boolean;
359
+ }
360
+ type RouteHandler = (this: RequestThisContext, inputContext: RequestInputContext, outputContext: RequestOutputContext) => Promise<Response>;
361
+ interface FragmentDefinition<TConfig$1, TDeps$1 = {}, TServices$1 = {}, TAdditionalContext extends Record<string, unknown> = {}, TUsedServices$1 = {}, TProvidedServices$1 = {}, TThisContext$1 extends RequestThisContext = RequestThisContext> {
362
+ name: string;
363
+ dependencies?: (config: TConfig$1, options: FragnoPublicConfig) => TDeps$1;
364
+ services?: (config: TConfig$1, options: FragnoPublicConfig, deps: TDeps$1 & TUsedServices$1) => TServices$1;
365
+ additionalContext?: TAdditionalContext;
366
+ createHandlerWrapper?: (options: FragnoPublicConfig) => (handler: (this: TThisContext$1, ...args: Parameters<RouteHandler>) => ReturnType<RouteHandler>) => RouteHandler;
367
+ /** Services that this fragment uses (can be required or optional) */
368
+ usedServices?: { [K in keyof TUsedServices$1]: ServiceMetadata };
369
+ /** Services that this fragment provides to other fragments (can be a factory function or direct object) */
370
+ providedServices?: { [K in keyof TProvidedServices$1]: TProvidedServices$1[K] } | ((config: TConfig$1, options: FragnoPublicConfig, deps: TDeps$1 & TUsedServices$1) => TProvidedServices$1);
371
+ }
372
+ declare class FragmentBuilder<const TConfig$1, const TDeps$1 = {}, const TServices$1 = {}, const TAdditionalContext extends Record<string, unknown> = {}, const TUsedServices$1 = {}, const TProvidedServices$1 = {}, const TThisContext$1 extends RequestThisContext = RequestThisContext> {
373
+ #private;
374
+ constructor(definition: FragmentDefinition<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TUsedServices$1, TProvidedServices$1, TThisContext$1>);
375
+ get definition(): FragmentDefinition<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TUsedServices$1, TProvidedServices$1, TThisContext$1>;
376
+ get $requiredOptions(): FragnoPublicConfig;
377
+ withDependencies<TNewDeps>(fn: (context: {
378
+ config: TConfig$1;
379
+ fragnoConfig: FragnoPublicConfig;
380
+ } & TAdditionalContext) => TNewDeps): FragmentBuilder<TConfig$1, TNewDeps, {}, TAdditionalContext, TUsedServices$1, TProvidedServices$1, TThisContext$1>;
381
+ /**
382
+ * Declare that this fragment uses a service.
383
+ * By default, the service is required. Pass { optional: true } to make it optional.
384
+ *
385
+ * @example
386
+ * ```ts
387
+ * // Required service
388
+ * defineFragment("my-fragment")
389
+ * .usesService<"email", IEmailService>("email")
390
+ * .providesService(({ deps, define }) => define({
391
+ * sendWelcome: () => deps.email.send(...)
392
+ * }))
393
+ *
394
+ * // Optional service
395
+ * defineFragment("my-fragment")
396
+ * .usesService<"email", IEmailService>("email", { optional: true })
397
+ * .providesService(({ deps, define }) => define({
398
+ * sendWelcome: () => {
399
+ * if (deps.email) {
400
+ * deps.email.send(...)
401
+ * }
402
+ * }
403
+ * }))
404
+ * ```
405
+ */
406
+ usesService<TServiceName extends string, TService>(serviceName: TServiceName, options?: {
407
+ optional?: false;
408
+ }): FragmentBuilder<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TUsedServices$1 & { [K in TServiceName]: TService }, TProvidedServices$1, TThisContext$1>;
409
+ usesService<TServiceName extends string, TService>(serviceName: TServiceName, options: {
410
+ optional: true;
411
+ }): FragmentBuilder<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TUsedServices$1 & { [K in TServiceName]: TService | undefined }, TProvidedServices$1, TThisContext$1>;
412
+ /**
413
+ * Define services for this fragment (unnamed) using a callback.
414
+ * Use the `defineService` function from the callback context for proper typing (optional).
415
+ */
416
+ providesService<TNewServices>(fn: (context: {
417
+ config: TConfig$1;
418
+ fragnoConfig: FragnoPublicConfig;
419
+ deps: TDeps$1 & TUsedServices$1;
420
+ defineService: <T>(services: T) => T;
421
+ }) => TNewServices): FragmentBuilder<TConfig$1, TDeps$1, TNewServices, TAdditionalContext, TUsedServices$1, TProvidedServices$1, TThisContext$1>;
422
+ /**
423
+ * Define services for this fragment (unnamed) using a direct object.
424
+ */
425
+ providesService<TNewServices>(services: TNewServices): FragmentBuilder<TConfig$1, TDeps$1, TNewServices, TAdditionalContext, TUsedServices$1, TProvidedServices$1, TThisContext$1>;
426
+ /**
427
+ * Provide a named service using a callback.
428
+ * Use the `defineService` function from the callback context for proper typing (optional).
429
+ *
430
+ * @example
431
+ * ```ts
432
+ * interface IEmailService {
433
+ * send(to: string, subject: string, body: string): Promise<void>;
434
+ * }
435
+ *
436
+ * defineFragment("email-fragment")
437
+ * .providesService<"email", IEmailService>("email", ({ defineService }) => defineService({
438
+ * send: async (to, subject, body) => {
439
+ * // implementation
440
+ * }
441
+ * }))
442
+ * ```
443
+ */
444
+ providesService<TServiceName extends string, TService>(serviceName: TServiceName, fn: (context: {
445
+ config: TConfig$1;
446
+ fragnoConfig: FragnoPublicConfig;
447
+ deps: TDeps$1 & TUsedServices$1;
448
+ defineService: <T>(services: T) => T;
449
+ }) => TService): FragmentBuilder<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TUsedServices$1, TProvidedServices$1 & { [K in TServiceName]: TService }, TThisContext$1>;
450
+ /**
451
+ * Provide a named service using a direct object.
452
+ */
453
+ providesService<TServiceName extends string, TService>(serviceName: TServiceName, service: TService): FragmentBuilder<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TUsedServices$1, TProvidedServices$1 & { [K in TServiceName]: TService }, TThisContext$1>;
454
+ }
455
+ declare function defineFragment<TConfig$1 = {}>(name: string): FragmentBuilder<TConfig$1, {}, {}, {}, {}, {}, RequestThisContext>;
456
+ //#endregion
457
+ //#region src/api/route.d.ts
458
+ type AnyFragnoRouteConfig = FragnoRouteConfig<HTTPMethod, string, any, any, any, any, any>;
459
+ type AnyFragmentBuilder = {
460
+ readonly definition: FragmentDefinition<any, any, any, any, any, any, any>;
461
+ };
462
+ interface RouteFactoryContext<TConfig$1, TDeps$1, TServices$1> {
463
+ config: TConfig$1;
464
+ deps: TDeps$1;
465
+ services: TServices$1;
466
+ }
467
+ type RouteFactory<TConfig$1, TDeps$1, TServices$1, TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string, RequestThisContext>[]> = (context: RouteFactoryContext<TConfig$1, TDeps$1, TServices$1>) => TRoutes$1;
468
+ type AnyRouteOrFactory = AnyFragnoRouteConfig | RouteFactory<any, any, any, any>;
469
+ type FlattenRouteFactories<T extends readonly AnyRouteOrFactory[]> = T extends readonly [infer First, ...infer Rest extends readonly AnyRouteOrFactory[]] ? First extends RouteFactory<any, any, any, infer TRoutes> ? [...TRoutes, ...FlattenRouteFactories<Rest>] : [First, ...FlattenRouteFactories<Rest>] : [];
470
+ declare function resolveRouteFactories<TConfig$1, TDeps$1, TServices$1, const TRoutesOrFactories extends readonly AnyRouteOrFactory[]>(context: RouteFactoryContext<TConfig$1, TDeps$1, TServices$1>, routesOrFactories: TRoutesOrFactories): FlattenRouteFactories<TRoutesOrFactories>;
471
+ declare function defineRoute<const TMethod extends HTTPMethod, const TPath extends string, const TOutputSchema extends StandardSchemaV1 | undefined, const TErrorCode extends string = string, const TQueryParameters extends string = string, const TThisContext$1 extends RequestThisContext = RequestThisContext>(config: FragnoRouteConfig<TMethod, TPath, undefined, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1> & {
472
+ inputSchema?: undefined;
473
+ }): FragnoRouteConfig<TMethod, TPath, undefined, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1>;
474
+ declare function defineRoute<const TMethod extends HTTPMethod, const TPath extends string, const TInputSchema extends StandardSchemaV1, const TOutputSchema extends StandardSchemaV1 | undefined, const TErrorCode extends string = string, const TQueryParameters extends string = string, const TThisContext$1 extends RequestThisContext = RequestThisContext>(config: FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1> & {
475
+ inputSchema: TInputSchema;
476
+ }): FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1>;
477
+ type GetDefinition<T> = T extends {
478
+ definition: unknown;
479
+ } ? T["definition"] : never;
480
+ type ExtractFragmentConfig<T> = GetDefinition<T> extends FragmentDefinition<infer TConfig, any, any, any, any, any> ? TConfig : never;
481
+ type ExtractFragmentDeps<T> = GetDefinition<T> extends FragmentDefinition<any, infer TDeps, any, any, infer TUsedServices, any> ? TDeps & TUsedServices : never;
482
+ type OmitThisParameter<T> = T extends ((this: infer _This, ...args: infer A) => infer R) ? (...args: A) => R : T;
483
+ type BoundServicesLocal<T> = { [K in keyof T]: T[K] extends ((...args: never[]) => unknown) ? OmitThisParameter<T[K]> : T[K] extends Record<string, unknown> ? BoundServicesLocal<T[K]> : T[K] };
484
+ type ExtractFragmentServices<T> = T extends {
485
+ $types: {
486
+ services: infer S;
487
+ providedServices: infer P;
488
+ };
489
+ } ? BoundServicesLocal<S & P> : GetDefinition<T> extends FragmentDefinition<any, any, infer TServices, any, any, infer TProvidedServices> ? TServices & TProvidedServices : never;
490
+ type ExtractThisContext<T> = GetDefinition<T> extends FragmentDefinition<any, any, any, any, any, any, infer TThisContext> ? TThisContext : RequestThisContext;
491
+ declare function defineRoutes<const TFragmentBuilder extends AnyFragmentBuilder>(fragmentBuilder: TFragmentBuilder): {
492
+ create: <const TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string, ExtractThisContext<TFragmentBuilder>>[]>(fn: (context: RouteFactoryContext<ExtractFragmentConfig<TFragmentBuilder>, ExtractFragmentDeps<TFragmentBuilder>, ExtractFragmentServices<TFragmentBuilder>> & {
493
+ defineRoute: <const TMethod extends HTTPMethod, const TPath extends string, const TInputSchema extends StandardSchemaV1 | undefined, const TOutputSchema extends StandardSchemaV1 | undefined, const TErrorCode extends string = string, const TQueryParameters extends string = string>(config: FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, ExtractThisContext<TFragmentBuilder>>) => FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, ExtractThisContext<TFragmentBuilder>>;
494
+ }) => TRoutes$1) => RouteFactory<ExtractFragmentConfig<TFragmentBuilder>, ExtractFragmentDeps<TFragmentBuilder>, ExtractFragmentServices<TFragmentBuilder>, TRoutes$1>;
495
+ };
496
+ declare function defineRoutes<const TFragmentBuilder extends AnyFragmentBuilder>(): {
497
+ create: <const TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string, ExtractThisContext<TFragmentBuilder>>[]>(fn: (context: RouteFactoryContext<ExtractFragmentConfig<TFragmentBuilder>, ExtractFragmentDeps<TFragmentBuilder>, ExtractFragmentServices<TFragmentBuilder>> & {
498
+ defineRoute: <const TMethod extends HTTPMethod, const TPath extends string, const TInputSchema extends StandardSchemaV1 | undefined, const TOutputSchema extends StandardSchemaV1 | undefined, const TErrorCode extends string = string, const TQueryParameters extends string = string>(config: FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, ExtractThisContext<TFragmentBuilder>>) => FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, ExtractThisContext<TFragmentBuilder>>;
499
+ }) => TRoutes$1) => RouteFactory<ExtractFragmentConfig<TFragmentBuilder>, ExtractFragmentDeps<TFragmentBuilder>, ExtractFragmentServices<TFragmentBuilder>, TRoutes$1>;
500
+ };
501
+ declare function defineRoutes<TConfig$1 = {}, TDeps$1 = {}, TServices$1 = {}>(): {
502
+ create: <const TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string, RequestThisContext>[]>(fn: (context: RouteFactoryContext<TConfig$1, TDeps$1, TServices$1> & {
503
+ defineRoute: typeof defineRoute;
504
+ }) => TRoutes$1) => RouteFactory<TConfig$1, TDeps$1, TServices$1, TRoutes$1>;
505
+ };
506
+ //#endregion
507
+ //#region src/client/client-error.d.ts
508
+ type FragnoErrorOptions = {
509
+ cause?: Error | unknown;
510
+ };
511
+ /**
512
+ * Base error class for all Fragno client errors.
513
+ */
514
+ declare abstract class FragnoClientError<TCode extends string = string> extends Error {
515
+ #private;
516
+ constructor(message: string, code: TCode, options?: FragnoErrorOptions);
517
+ get code(): TCode | (string & {});
518
+ }
519
+ declare class FragnoClientFetchError extends FragnoClientError<"NO_BODY" | "NETWORK_ERROR" | "ABORT_ERROR"> {
520
+ constructor(message: string, code: "NO_BODY" | "NETWORK_ERROR" | "ABORT_ERROR", options?: FragnoErrorOptions);
521
+ static fromUnknownFetchError(error: unknown): FragnoClientFetchError;
522
+ }
523
+ /**
524
+ * Error thrown when a network request fails (e.g., no internet connection, DNS failure).
525
+ */
526
+ declare class FragnoClientFetchNetworkError extends FragnoClientFetchError {
527
+ constructor(message?: string, options?: FragnoErrorOptions);
528
+ }
529
+ /**
530
+ * Error thrown when a request is aborted (e.g., user cancels request, timeout).
531
+ */
532
+ declare class FragnoClientFetchAbortError extends FragnoClientFetchError {
533
+ constructor(message?: string, options?: FragnoErrorOptions);
534
+ }
535
+ /**
536
+ * Error thrown when the API result is unexpected, e.g. no json is returned.
537
+ */
538
+ declare class FragnoClientUnknownApiError extends FragnoClientError<"UNKNOWN_API_ERROR"> {
539
+ #private;
540
+ constructor(message: string | undefined, status: StatusCode, options?: FragnoErrorOptions);
541
+ get status(): StatusCode;
542
+ }
543
+ declare class FragnoClientApiError<TErrorCode extends string = string> extends FragnoClientError<TErrorCode> {
544
+ #private;
545
+ constructor({
546
+ message,
547
+ code
548
+ }: {
549
+ message: string;
550
+ code: TErrorCode;
551
+ }, status: StatusCode, options?: FragnoErrorOptions);
552
+ get status(): StatusCode;
553
+ /**
554
+ * The error code returned by the API.
555
+ *
556
+ * The type is `TErrorCode` (the set of known error codes for this route), but may also be a string
557
+ * for forward compatibility with future error codes.
558
+ */
559
+ get code(): TErrorCode | (string & {});
560
+ static fromResponse<TErrorCode extends string = string>(response: Response): Promise<FragnoClientApiError<TErrorCode> | FragnoClientUnknownApiError>;
561
+ }
562
+ //#endregion
563
+ //#region src/client/client.d.ts
564
+ /**
565
+ * Symbols used to identify hook types
566
+ */
567
+ declare const GET_HOOK_SYMBOL: unique symbol;
568
+ declare const MUTATOR_HOOK_SYMBOL: unique symbol;
569
+ declare const STORE_SYMBOL: unique symbol;
570
+ /**
571
+ * Extract only GET routes from a library config's routes array
572
+ */
573
+ type ExtractGetRoutes<T extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[]> = { [K in keyof T]: T[K] extends FragnoRouteConfig<infer Method, infer Path, infer Input, infer Output, infer ErrorCode, infer QueryParams> ? Method extends "GET" ? FragnoRouteConfig<Method, Path, Input, Output, ErrorCode, QueryParams> : never : never }[number][];
574
+ /**
575
+ * Extract the path from a route configuration for a given method
576
+ */
577
+ type ExtractRoutePath<T extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[], TExpectedMethod extends HTTPMethod = HTTPMethod> = { [K in keyof T]: T[K] extends FragnoRouteConfig<infer Method, infer Path, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string> ? Method extends TExpectedMethod ? Path : never : never }[number];
578
+ type ExtractGetRoutePaths<T extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[]> = ExtractRoutePath<T, "GET">;
579
+ type ExtractNonGetRoutePaths<T extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[]> = ExtractRoutePath<T, NonGetHTTPMethod>;
580
+ /**
581
+ * Extract the route configuration type(s) for a given path from a routes array.
582
+ * Optionally narrow by HTTP method via the third type parameter.
583
+ *
584
+ * Defaults to extracting all methods for the matching path, producing a union
585
+ * if multiple methods exist for the same path.
586
+ */
587
+ type ExtractRouteByPath<TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[], TPath extends string, TMethod extends HTTPMethod = HTTPMethod> = { [K in keyof TRoutes$1]: TRoutes$1[K] extends FragnoRouteConfig<infer M, TPath, infer Input, infer Output, infer ErrorCode, infer QueryParams> ? M extends TMethod ? FragnoRouteConfig<M, TPath, Input, Output, ErrorCode, QueryParams> : never : never }[number];
588
+ /**
589
+ * Extract the output schema type for a specific route path from a routes array
590
+ */
591
+ type ExtractOutputSchemaForPath<TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined>[], TPath extends string> = { [K in keyof TRoutes$1]: TRoutes$1[K] extends FragnoRouteConfig<infer Method, TPath, StandardSchemaV1 | undefined, infer Output> ? Method extends "GET" ? Output : never : never }[number];
592
+ /**
593
+ * Check if a path exists as a GET route in the routes array
594
+ */
595
+ type IsValidGetRoutePath<TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[], TPath extends string> = TPath extends ExtractGetRoutePaths<TRoutes$1> ? true : false;
596
+ /**
597
+ * Utility type to ensure only valid GET route paths can be used
598
+ */
599
+ type ValidateGetRoutePath<TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[], TPath extends string> = TPath extends ExtractGetRoutePaths<TRoutes$1> ? TPath : `Error: Path '${TPath}' is not a valid GET route. Available GET routes: ${ExtractGetRoutePaths<TRoutes$1>}`;
600
+ /**
601
+ * Helper type to check if a routes array has any GET routes
602
+ */
603
+ type HasGetRoutes<T extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[]> = ExtractGetRoutePaths<T> extends never ? false : true;
604
+ type ObjectContainingStoreField<T extends object> = T extends Store ? T : { [K in keyof T]: T[K] extends Store ? { [P in K]: T[P] } & Partial<Omit<T, K>> : never }[keyof T] extends never ? never : T;
605
+ type FragnoStoreData<T extends object> = {
606
+ obj: T;
607
+ [STORE_SYMBOL]: true;
608
+ };
609
+ type FragnoClientHookData<TMethod extends HTTPMethod, TPath extends string, TOutputSchema extends StandardSchemaV1, TErrorCode extends string, TQueryParameters extends string> = {
610
+ route: FragnoRouteConfig<TMethod, TPath, StandardSchemaV1 | undefined, TOutputSchema, TErrorCode, TQueryParameters>;
611
+ query(args?: {
612
+ path?: MaybeExtractPathParamsOrWiden<TPath, string>;
613
+ query?: Record<TQueryParameters, string | undefined>;
614
+ }): Promise<StandardSchemaV1.InferOutput<TOutputSchema>>;
615
+ store(args?: {
616
+ path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;
617
+ query?: Record<TQueryParameters, string | undefined | ReadableAtom<string | undefined>>;
618
+ }): FetcherStore<StandardSchemaV1.InferOutput<TOutputSchema>, FragnoClientError<TErrorCode>>;
619
+ [GET_HOOK_SYMBOL]: true;
620
+ } & {
621
+ readonly _outputSchema?: TOutputSchema;
622
+ };
623
+ type FragnoClientMutatorData<TMethod extends NonGetHTTPMethod, TPath extends string, TInputSchema extends StandardSchemaV1 | undefined, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string, TQueryParameters extends string> = {
624
+ route: FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters>;
625
+ mutateQuery(args?: {
626
+ body?: InferOr<TInputSchema, undefined>;
627
+ path?: MaybeExtractPathParamsOrWiden<TPath, string>;
628
+ query?: Record<TQueryParameters, string | undefined>;
629
+ }): Promise<InferOr<TOutputSchema, undefined>>;
630
+ mutatorStore: MutatorStore<{
631
+ body?: InferOr<TInputSchema, undefined>;
632
+ path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;
633
+ query?: Record<TQueryParameters, string | undefined | ReadableAtom<string | undefined>>;
634
+ }, InferOr<TOutputSchema, undefined>, FragnoClientError<TErrorCode>>;
635
+ [MUTATOR_HOOK_SYMBOL]: true;
636
+ } & {
637
+ readonly _inputSchema?: TInputSchema;
638
+ readonly _outputSchema?: TOutputSchema;
639
+ };
640
+ declare function buildUrl<TPath extends string>(config: {
641
+ baseUrl?: string;
642
+ mountRoute: string;
643
+ path: TPath;
644
+ }, params: {
645
+ pathParams?: Record<string, string | ReadableAtom<string>>;
646
+ queryParams?: Record<string, string | undefined | ReadableAtom<string | undefined>>;
647
+ }): string;
648
+ /**
649
+ * This method returns an array, which can be passed directly to nanostores.
650
+ *
651
+ * The returned array is always: path, pathParams (In order they appear in the path), queryParams (In alphabetical order)
652
+ * Missing pathParams are replaced with "<missing>".
653
+ * Atoms with undefined values are wrapped in computed atoms that map undefined to "" to avoid nanoquery treating the key as incomplete.
654
+ * @param path
655
+ * @param params
656
+ * @returns
657
+ */
658
+ declare function getCacheKey<TMethod extends HTTPMethod, TPath extends string>(method: TMethod, path: TPath, params?: {
659
+ pathParams?: Record<string, string | ReadableAtom<string>>;
660
+ queryParams?: Record<string, string | undefined | ReadableAtom<string | undefined>>;
661
+ }): (string | ReadableAtom<string>)[];
662
+ declare function isGetHook<TPath extends string, TOutputSchema extends StandardSchemaV1, TErrorCode extends string, TQueryParameters extends string>(hook: unknown): hook is FragnoClientHookData<"GET", TPath, TOutputSchema, TErrorCode, TQueryParameters>;
663
+ declare function isMutatorHook<TMethod extends NonGetHTTPMethod, TPath extends string, TInputSchema extends StandardSchemaV1 | undefined, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string, TQueryParameters extends string>(hook: unknown): hook is FragnoClientMutatorData<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters>;
664
+ declare function isStore<TStore extends Store>(obj: unknown): obj is FragnoStoreData<TStore>;
665
+ type OnErrorRetryFn = (opts: {
666
+ error: unknown;
667
+ key: string;
668
+ retryCount: number;
669
+ }) => number | undefined;
670
+ type CreateHookOptions = {
671
+ /**
672
+ * A function that will be called when an error occurs. Implements an exponential backoff strategy
673
+ * when left undefined. When null, retries will be disabled. The number returned (> 0) by the
674
+ * callback will determine in how many ms to retry next.
675
+ */
676
+ onErrorRetry?: OnErrorRetryFn | null;
677
+ };
678
+ type OnInvalidateFn<TPath extends string> = (invalidate: <TInnerPath extends string>(method: HTTPMethod, path: TInnerPath, params: {
679
+ pathParams?: MaybeExtractPathParamsOrWiden<TInnerPath, string>;
680
+ queryParams?: Record<string, string>;
681
+ }) => void, params: {
682
+ pathParams: MaybeExtractPathParamsOrWiden<TPath, string>;
683
+ queryParams?: Record<string, string>;
684
+ }) => void;
685
+ type CacheLine = {
686
+ data: unknown;
687
+ error: unknown;
688
+ retryCount: number;
689
+ created: number;
690
+ expires: number;
691
+ };
692
+ declare class ClientBuilder<TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[], TFragmentConfig extends FragnoFragmentSharedConfig<TRoutes$1>> {
693
+ #private;
694
+ constructor(publicConfig: FragnoPublicClientConfig, fragmentConfig: TFragmentConfig);
695
+ get cacheEntries(): Readonly<Record<string, CacheLine>>;
696
+ createStore<const T extends object>(obj: T): FragnoStoreData<T>;
697
+ /**
698
+ * Build a URL for a custom backend call using the configured baseUrl and mountRoute.
699
+ * Useful for fragment authors who need to make custom fetch calls.
700
+ */
701
+ buildUrl<TPath extends string>(path: TPath, params?: {
702
+ path?: MaybeExtractPathParamsOrWiden<TPath, string>;
703
+ query?: Record<string, string>;
704
+ }): string;
705
+ /**
706
+ * Get the configured fetcher function for custom backend calls.
707
+ * Returns fetch with merged options applied.
708
+ */
709
+ getFetcher(): {
710
+ fetcher: typeof fetch;
711
+ defaultOptions: RequestInit | undefined;
712
+ };
713
+ createHook<TPath extends ExtractGetRoutePaths<TFragmentConfig["routes"]>>(path: ValidateGetRoutePath<TFragmentConfig["routes"], TPath>, options?: CreateHookOptions): FragnoClientHookData<"GET", TPath, NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath>["outputSchema"]>, NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath>["errorCodes"]>[number], NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath>["queryParameters"]>[number]>;
714
+ createMutator<TPath extends ExtractNonGetRoutePaths<TFragmentConfig["routes"]>>(method: NonGetHTTPMethod, path: TPath, onInvalidate?: OnInvalidateFn<TPath>): FragnoClientMutatorData<NonGetHTTPMethod,
715
+ // TODO: This can be any Method, but should be related to TPath
716
+ TPath, ExtractRouteByPath<TFragmentConfig["routes"], TPath>["inputSchema"], ExtractRouteByPath<TFragmentConfig["routes"], TPath>["outputSchema"], NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath>["errorCodes"]>[number], NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath>["queryParameters"]>[number]>;
717
+ }
718
+ declare function createClientBuilder<TConfig$1, TDeps$1, TServices$1 extends Record<string, unknown>, const TRoutesOrFactories extends readonly AnyRouteOrFactory[], const TAdditionalContext extends Record<string, unknown>>(fragmentBuilder: {
719
+ definition: FragmentDefinition<TConfig$1, TDeps$1, TServices$1, TAdditionalContext>;
720
+ }, publicConfig: FragnoPublicClientConfig, routesOrFactories: TRoutesOrFactories, authorFetcherConfig?: FetcherConfig): ClientBuilder<FlattenRouteFactories<TRoutesOrFactories>, FragnoFragmentSharedConfig<FlattenRouteFactories<TRoutesOrFactories>>>;
721
+ //#endregion
722
+ //#region src/api/request-middleware.d.ts
723
+ type FragnoMiddlewareCallback<TRoutes$1 extends readonly AnyFragnoRouteConfig[], TDeps$1, TServices$1 extends Record<string, unknown>> = (inputContext: RequestMiddlewareInputContext<TRoutes$1>, outputContext: RequestMiddlewareOutputContext<TDeps$1, TServices$1>) => Promise<Response | undefined> | Response | undefined;
724
+ interface RequestMiddlewareOptions {
725
+ path: string;
726
+ method: HTTPMethod;
727
+ request: Request;
728
+ state: MutableRequestState;
729
+ }
730
+ declare class RequestMiddlewareOutputContext<const TDeps$1, const TServices$1 extends Record<string, unknown>> extends OutputContext<unknown, string> {
731
+ #private;
732
+ constructor(deps: TDeps$1, services: TServices$1);
733
+ get deps(): TDeps$1;
734
+ get services(): TServices$1;
735
+ }
736
+ declare class RequestMiddlewareInputContext<const TRoutes$1 extends readonly AnyFragnoRouteConfig[]> {
737
+ #private;
738
+ constructor(routes: TRoutes$1, options: RequestMiddlewareOptions);
739
+ get path(): string;
740
+ get method(): HTTPMethod;
741
+ get pathParams(): Record<string, string>;
742
+ get queryParams(): URLSearchParams;
743
+ get headers(): Headers;
744
+ get inputSchema(): StandardSchemaV1 | undefined;
745
+ get outputSchema(): StandardSchemaV1 | undefined;
746
+ /**
747
+ * Access to the mutable request state.
748
+ * Use this to modify query parameters, path parameters, or request body.
749
+ *
750
+ * @example
751
+ * ```typescript
752
+ * // Modify body
753
+ * requestState.setBody({ modified: true });
754
+ *
755
+ * // Query params are already accessible via queryParams getter
756
+ * // Path params are already accessible via pathParams getter
757
+ * ```
758
+ */
759
+ get requestState(): MutableRequestState;
760
+ ifMatchesRoute: <const TMethod extends HTTPMethod, const TPath extends ExtractRoutePath<TRoutes$1>, const TRoute extends ExtractRouteByPath<TRoutes$1, TPath, TMethod> = ExtractRouteByPath<TRoutes$1, TPath, TMethod>>(method: TMethod, path: TPath, handler: (...args: Parameters<TRoute["handler"]>) => Promise<Response | undefined | void> | Response | undefined | void) => Promise<Response | undefined>;
761
+ }
762
+ //#endregion
763
+ //#region src/api/fragno-response.d.ts
764
+ /**
765
+ * Discriminated union representing all possible Fragno response types
766
+ */
767
+ type FragnoResponse<T> = {
768
+ type: "empty";
769
+ status: number;
770
+ headers: Headers;
771
+ } | {
772
+ type: "error";
773
+ status: number;
774
+ headers: Headers;
775
+ error: {
776
+ message: string;
777
+ code: string;
778
+ };
779
+ } | {
780
+ type: "json";
781
+ status: number;
782
+ headers: Headers;
783
+ data: T;
784
+ } | {
785
+ type: "jsonStream";
786
+ status: number;
787
+ headers: Headers;
788
+ stream: AsyncGenerator<T extends unknown[] ? T[number] : T>;
789
+ };
790
+ //#endregion
791
+ //#region src/api/fragment-instantiation.d.ts
792
+ interface FragnoPublicConfig {
793
+ mountRoute?: string;
794
+ }
795
+ type FetcherConfig = {
796
+ type: "options";
797
+ options: RequestInit;
798
+ } | {
799
+ type: "function";
800
+ fetcher: typeof fetch;
801
+ };
802
+ interface FragnoPublicClientConfig {
803
+ mountRoute?: string;
804
+ baseUrl?: string;
805
+ fetcherConfig?: FetcherConfig;
806
+ }
807
+ type AstroHandlers = {
808
+ ALL: (req: Request) => Promise<Response>;
809
+ };
810
+ type ReactRouterHandlers = {
811
+ loader: (args: {
812
+ request: Request;
813
+ }) => Promise<Response>;
814
+ action: (args: {
815
+ request: Request;
816
+ }) => Promise<Response>;
817
+ };
818
+ type SolidStartHandlers = {
819
+ GET: (args: {
820
+ request: Request;
821
+ }) => Promise<Response>;
822
+ POST: (args: {
823
+ request: Request;
824
+ }) => Promise<Response>;
825
+ PUT: (args: {
826
+ request: Request;
827
+ }) => Promise<Response>;
828
+ DELETE: (args: {
829
+ request: Request;
830
+ }) => Promise<Response>;
831
+ PATCH: (args: {
832
+ request: Request;
833
+ }) => Promise<Response>;
834
+ HEAD: (args: {
835
+ request: Request;
836
+ }) => Promise<Response>;
837
+ OPTIONS: (args: {
838
+ request: Request;
839
+ }) => Promise<Response>;
840
+ };
841
+ type TanStackStartHandlers = SolidStartHandlers;
842
+ type StandardHandlers = {
843
+ GET: (req: Request) => Promise<Response>;
844
+ POST: (req: Request) => Promise<Response>;
845
+ PUT: (req: Request) => Promise<Response>;
846
+ DELETE: (req: Request) => Promise<Response>;
847
+ PATCH: (req: Request) => Promise<Response>;
848
+ HEAD: (req: Request) => Promise<Response>;
849
+ OPTIONS: (req: Request) => Promise<Response>;
850
+ };
851
+ type HandlersByFramework = {
852
+ astro: AstroHandlers;
853
+ "react-router": ReactRouterHandlers;
854
+ "next-js": StandardHandlers;
855
+ "svelte-kit": StandardHandlers;
856
+ "solid-start": SolidStartHandlers;
857
+ "tanstack-start": TanStackStartHandlers;
858
+ };
859
+ declare const instantiatedFragmentFakeSymbol: "$fragno-instantiated-fragment";
860
+ type FullstackFrameworks = keyof HandlersByFramework;
861
+ interface FragnoInstantiatedFragment<TRoutes$1 extends readonly AnyFragnoRouteConfig[] = [], TDeps$1 = {}, TServices$1 extends Record<string, unknown> = Record<string, unknown>, TAdditionalContext extends Record<string, unknown> = {}> {
862
+ [instantiatedFragmentFakeSymbol]: typeof instantiatedFragmentFakeSymbol;
863
+ config: FragnoFragmentSharedConfig<TRoutes$1>;
864
+ deps: TDeps$1;
865
+ services: TServices$1;
866
+ additionalContext?: TAdditionalContext;
867
+ handlersFor: <T extends FullstackFrameworks>(framework: T) => HandlersByFramework[T];
868
+ handler: (req: Request) => Promise<Response>;
869
+ mountRoute: string;
870
+ callRoute: <TMethod extends HTTPMethod, TPath extends ExtractRoutePath<TRoutes$1, TMethod>>(method: TMethod, path: TPath, inputOptions?: RouteHandlerInputOptions<TPath, ExtractRouteByPath<TRoutes$1, TPath, TMethod>["inputSchema"]>) => Promise<FragnoResponse<InferOrUnknown<NonNullable<ExtractRouteByPath<TRoutes$1, TPath, TMethod>["outputSchema"]>>>>;
871
+ callRouteRaw: <TMethod extends HTTPMethod, TPath extends ExtractRoutePath<TRoutes$1, TMethod>>(method: TMethod, path: TPath, inputOptions?: RouteHandlerInputOptions<TPath, ExtractRouteByPath<TRoutes$1, TPath, TMethod>["inputSchema"]>) => Promise<Response>;
872
+ withMiddleware: (handler: FragnoMiddlewareCallback<TRoutes$1, TDeps$1, TServices$1>) => FragnoInstantiatedFragment<TRoutes$1, TDeps$1, TServices$1, TAdditionalContext>;
873
+ }
874
+ interface FragnoFragmentSharedConfig<TRoutes$1 extends readonly FragnoRouteConfig<HTTPMethod, string, StandardSchemaV1 | undefined, StandardSchemaV1 | undefined, string, string>[]> {
875
+ name: string;
876
+ routes: TRoutes$1;
877
+ }
878
+ type AnyFragnoFragmentSharedConfig = FragnoFragmentSharedConfig<readonly AnyFragnoRouteConfig[]>;
879
+ declare function createFragment<const TConfig$1, const TDeps$1, const TServices$1 extends Record<string, unknown>, const TRoutesOrFactories extends readonly AnyRouteOrFactory[], const TAdditionalContext extends Record<string, unknown>, const TRequiredInterfaces extends Record<string, unknown>, const TProvidedInterfaces extends Record<string, unknown>, const TOptions extends FragnoPublicConfig, const TThisContext$1 extends RequestThisContext = RequestThisContext>(fragmentBuilder: {
880
+ definition: FragmentDefinition<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TRequiredInterfaces, TProvidedInterfaces, TThisContext$1>;
881
+ $requiredOptions: TOptions;
882
+ }, config: TConfig$1, routesOrFactories: TRoutesOrFactories, options: TOptions, interfaceImplementations?: TRequiredInterfaces): FragnoInstantiatedFragment<FlattenRouteFactories<TRoutesOrFactories>, TDeps$1 & TRequiredInterfaces, TServices$1 & TProvidedInterfaces & TRequiredInterfaces, TAdditionalContext>;
883
+ /**
884
+ * Builder class for fluent fragment instantiation API
885
+ */
886
+ declare class FragmentInstantiationBuilder<TConfig$1, TDeps$1, TServices$1 extends Record<string, unknown>, TRoutesOrFactories extends readonly AnyRouteOrFactory[], TAdditionalContext extends Record<string, unknown>, TRequiredInterfaces extends Record<string, unknown>, TProvidedInterfaces extends Record<string, unknown>, TOptions extends FragnoPublicConfig, TThisContext$1 extends RequestThisContext> {
887
+ #private;
888
+ constructor(fragmentBuilder: {
889
+ definition: FragmentDefinition<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TRequiredInterfaces, TProvidedInterfaces, TThisContext$1>;
890
+ $requiredOptions: TOptions;
891
+ });
892
+ /**
893
+ * Set the configuration for the fragment
894
+ */
895
+ withConfig(config: TConfig$1): this;
896
+ /**
897
+ * Set the routes for the fragment
898
+ */
899
+ withRoutes<const TNewRoutes extends readonly AnyRouteOrFactory[]>(routes: TNewRoutes): FragmentInstantiationBuilder<TConfig$1, TDeps$1, TServices$1, TNewRoutes, TAdditionalContext, TRequiredInterfaces, TProvidedInterfaces, TOptions, TThisContext$1>;
900
+ /**
901
+ * Set the options for the fragment (e.g., mountRoute, databaseAdapter)
902
+ */
903
+ withOptions(options: TOptions): this;
904
+ /**
905
+ * Provide implementations for services that this fragment uses
906
+ */
907
+ withServices(services: TRequiredInterfaces): this;
908
+ /**
909
+ * Build and return the instantiated fragment
910
+ */
911
+ build(): FragnoInstantiatedFragment<FlattenRouteFactories<TRoutesOrFactories>, TDeps$1 & TRequiredInterfaces, TServices$1 & TProvidedInterfaces & TRequiredInterfaces, TAdditionalContext>;
912
+ }
913
+ /**
914
+ * Create a fluent builder for instantiating a fragment
915
+ *
916
+ * @example
917
+ * ```ts
918
+ * const fragment = instantiateFragment(myFragmentBuilder)
919
+ * .withConfig({ apiKey: "key" })
920
+ * .withRoutes([route1, route2])
921
+ * .withOptions({ mountRoute: "/api" })
922
+ * .build();
923
+ * ```
924
+ */
925
+ declare function instantiateFragment<TConfig$1, TDeps$1, TServices$1 extends Record<string, unknown>, TAdditionalContext extends Record<string, unknown>, TRequiredInterfaces extends Record<string, unknown>, TProvidedInterfaces extends Record<string, unknown>, TOptions extends FragnoPublicConfig, TThisContext$1 extends RequestThisContext = RequestThisContext>(fragmentBuilder: {
926
+ definition: FragmentDefinition<TConfig$1, TDeps$1, TServices$1, TAdditionalContext, TRequiredInterfaces, TProvidedInterfaces, TThisContext$1>;
927
+ $requiredOptions: TOptions;
928
+ }): FragmentInstantiationBuilder<TConfig$1, TDeps$1, TServices$1, readonly [], TAdditionalContext, TRequiredInterfaces, TProvidedInterfaces, TOptions, TThisContext$1>;
929
+ //#endregion
930
+ //#region src/api/api.d.ts
931
+ type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
932
+ type NonGetHTTPMethod = Exclude<HTTPMethod, "GET">;
933
+ type PathError<T extends string, TMessage extends string> = T & [`Error: ${TMessage}`];
934
+ /**
935
+ * A valid path string that:
936
+ * - Is non-empty
937
+ * - Starts with "/"
938
+ * - Is not just "/"
939
+ * - Does not end with "/"
940
+ */
941
+ type ValidPath<T extends string = string> = T extends `/${infer Rest}` ? Rest extends "" ? PathError<T, "Path cannot be just '/'."> : T extends `${string}/` ? PathError<T, "Path cannot end with '/'."> : T : PathError<T, "Path must start with '/'.">;
942
+ /**
943
+ * Base ServiceContext interface. Can be augmented by packages like @fragno-dev/db.
944
+ */
945
+ interface RequestThisContext {}
946
+ interface FragnoRouteConfig<TMethod extends HTTPMethod, TPath extends string, TInputSchema extends StandardSchemaV1 | undefined, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string = string, TQueryParameters extends string = string, TThisContext$1 extends RequestThisContext = RequestThisContext> {
947
+ method: TMethod;
948
+ path: TPath;
949
+ inputSchema?: TInputSchema;
950
+ outputSchema?: TOutputSchema;
951
+ errorCodes?: readonly TErrorCode[];
952
+ queryParameters?: readonly TQueryParameters[];
953
+ handler(this: TThisContext$1, inputCtx: RequestInputContext<TPath, TInputSchema>, outputCtx: RequestOutputContext<TOutputSchema, TErrorCode>): Promise<Response>;
954
+ }
955
+ declare function addRoute<TMethod extends HTTPMethod, TPath extends string, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string = string, TQueryParameters extends string = string, TThisContext$1 extends RequestThisContext = RequestThisContext>(route: FragnoRouteConfig<TMethod, ValidPath<TPath>, undefined, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1> & {
956
+ inputSchema?: undefined;
957
+ }): FragnoRouteConfig<TMethod, TPath, undefined, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1>;
958
+ declare function addRoute<TMethod extends HTTPMethod, TPath extends string, TInputSchema extends StandardSchemaV1, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string = string, TQueryParameters extends string = string, TThisContext$1 extends RequestThisContext = RequestThisContext>(route: FragnoRouteConfig<TMethod, ValidPath<TPath>, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1> & {
959
+ inputSchema: TInputSchema;
960
+ }): FragnoRouteConfig<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters, TThisContext$1>;
961
+ //#endregion
962
+ export { ExtractThisContext as $, HasGetRoutes as A, FragnoClientApiError as B, ExtractNonGetRoutePaths as C, FragnoClientHookData as D, ExtractRoutePath as E, createClientBuilder as F, FragnoClientUnknownApiError as G, FragnoClientFetchAbortError as H, getCacheKey as I, AnyFragnoRouteConfig as J, FragnoErrorOptions as K, isGetHook as L, ObjectContainingStoreField as M, ValidateGetRoutePath as N, FragnoClientMutatorData as O, buildUrl as P, ExtractFragmentServices as Q, isMutatorHook as R, ExtractGetRoutes as S, ExtractRouteByPath as T, FragnoClientFetchError as U, FragnoClientError as V, FragnoClientFetchNetworkError as W, ExtractFragmentConfig as X, AnyRouteOrFactory as Y, ExtractFragmentDeps as Z, FragnoResponse as _, ExtractPathParamsOrWiden as _t, ValidPath as a, resolveRouteFactories as at, CreateHookOptions as b, QueryParamsHint as bt, FetcherConfig as c, RouteHandler as ct, FragnoInstantiatedFragment as d, FragnoApiError as dt, FlattenRouteFactories as et, FragnoPublicClientConfig as f, FragnoApiValidationError as ft, instantiatedFragmentFakeSymbol as g, RequestInputContext as gt, instantiateFragment as h, InferOrUnknown as ht, RequestThisContext as i, defineRoutes as it, IsValidGetRoutePath as j, FragnoStoreData as k, FragmentInstantiationBuilder as l, defineFragment as lt, createFragment as m, InferOr as mt, HTTPMethod as n, RouteFactoryContext as nt, addRoute as o, FragmentBuilder as ot, FragnoPublicConfig as p, RequestOutputContext as pt, AnyFragmentBuilder as q, NonGetHTTPMethod as r, defineRoute as rt, AnyFragnoFragmentSharedConfig as s, FragmentDefinition as st, FragnoRouteConfig as t, RouteFactory as tt, FragnoFragmentSharedConfig as u, RouteHandlerInputOptions as ut, CacheLine as v, HasPathParams as vt, ExtractOutputSchemaForPath as w, ExtractGetRoutePaths as x, ClientBuilder as y, MaybeExtractPathParamsOrWiden as yt, isStore as z };
963
+ //# sourceMappingURL=api-BFrUCIsF.d.ts.map