@fragno-dev/core 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +72 -62
- package/CHANGELOG.md +28 -0
- package/dist/api/api.d.ts +3 -2
- package/dist/api/api.d.ts.map +1 -1
- package/dist/api/api.js +2 -1
- package/dist/api/api.js.map +1 -1
- package/dist/api/bind-services.d.ts +0 -1
- package/dist/api/bind-services.d.ts.map +1 -1
- package/dist/api/bind-services.js.map +1 -1
- package/dist/api/error.d.ts.map +1 -1
- package/dist/api/error.js.map +1 -1
- package/dist/api/fragment-definition-builder.d.ts +26 -44
- package/dist/api/fragment-definition-builder.d.ts.map +1 -1
- package/dist/api/fragment-definition-builder.js +15 -22
- package/dist/api/fragment-definition-builder.js.map +1 -1
- package/dist/api/fragment-instantiator.d.ts +51 -37
- package/dist/api/fragment-instantiator.d.ts.map +1 -1
- package/dist/api/fragment-instantiator.js +74 -69
- package/dist/api/fragment-instantiator.js.map +1 -1
- package/dist/api/request-context-storage.d.ts +4 -0
- package/dist/api/request-context-storage.d.ts.map +1 -1
- package/dist/api/request-context-storage.js +6 -0
- package/dist/api/request-context-storage.js.map +1 -1
- package/dist/api/request-input-context.d.ts.map +1 -1
- package/dist/api/request-input-context.js.map +1 -1
- package/dist/api/request-middleware.d.ts +1 -1
- package/dist/api/request-middleware.d.ts.map +1 -1
- package/dist/api/request-middleware.js.map +1 -1
- package/dist/api/request-output-context.d.ts +1 -1
- package/dist/api/request-output-context.d.ts.map +1 -1
- package/dist/api/request-output-context.js.map +1 -1
- package/dist/api/route-caller.d.ts +30 -0
- package/dist/api/route-caller.d.ts.map +1 -0
- package/dist/api/route-caller.js +63 -0
- package/dist/api/route-caller.js.map +1 -0
- package/dist/api/route-handler-input-options.d.ts.map +1 -1
- package/dist/api/route.d.ts +1 -1
- package/dist/api/route.d.ts.map +1 -1
- package/dist/api/route.js.map +1 -1
- package/dist/api/shared-types.d.ts.map +1 -1
- package/dist/client/client-error.d.ts.map +1 -1
- package/dist/client/client-error.js.map +1 -1
- package/dist/client/client.d.ts +91 -52
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +25 -9
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.svelte.d.ts +6 -5
- package/dist/client/client.svelte.d.ts.map +1 -1
- package/dist/client/client.svelte.js +10 -2
- package/dist/client/client.svelte.js.map +1 -1
- package/dist/client/internal/ndjson-streaming.js.map +1 -1
- package/dist/client/react.d.ts +5 -4
- package/dist/client/react.d.ts.map +1 -1
- package/dist/client/react.js +104 -12
- package/dist/client/react.js.map +1 -1
- package/dist/client/solid.d.ts +7 -5
- package/dist/client/solid.d.ts.map +1 -1
- package/dist/client/solid.js +23 -9
- package/dist/client/solid.js.map +1 -1
- package/dist/client/vanilla.d.ts +16 -4
- package/dist/client/vanilla.d.ts.map +1 -1
- package/dist/client/vanilla.js +21 -1
- package/dist/client/vanilla.js.map +1 -1
- package/dist/client/vue.d.ts +7 -5
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +18 -10
- package/dist/client/vue.js.map +1 -1
- package/dist/id.d.ts +2 -0
- package/dist/id.js +3 -0
- package/dist/internal/cuid.d.ts +16 -0
- package/dist/internal/cuid.d.ts.map +1 -0
- package/dist/internal/cuid.js +82 -0
- package/dist/internal/cuid.js.map +1 -0
- package/dist/mod-client.d.ts +5 -4
- package/dist/mod-client.d.ts.map +1 -1
- package/dist/mod-client.js +7 -5
- package/dist/mod-client.js.map +1 -1
- package/dist/mod.d.ts +6 -5
- package/dist/mod.js +2 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/test/test.d.ts +6 -6
- package/dist/test/test.d.ts.map +1 -1
- package/dist/test/test.js.map +1 -1
- package/dist/util/ssr.js.map +1 -1
- package/package.json +24 -40
- package/src/api/api.test.ts +3 -1
- package/src/api/api.ts +6 -0
- package/src/api/bind-services.ts +0 -5
- package/src/api/error.ts +1 -0
- package/src/api/fragment-definition-builder.extend.test.ts +2 -1
- package/src/api/fragment-definition-builder.test.ts +2 -1
- package/src/api/fragment-definition-builder.ts +49 -124
- package/src/api/fragment-instantiator.test.ts +92 -233
- package/src/api/fragment-instantiator.ts +228 -196
- package/src/api/fragment-services.test.ts +1 -0
- package/src/api/internal/path-runtime.test.ts +1 -0
- package/src/api/internal/path-type.test.ts +3 -1
- package/src/api/internal/route.test.ts +1 -0
- package/src/api/request-context-storage.ts +7 -0
- package/src/api/request-input-context.test.ts +4 -2
- package/src/api/request-input-context.ts +2 -1
- package/src/api/request-middleware.test.ts +9 -14
- package/src/api/request-middleware.ts +3 -2
- package/src/api/request-output-context.test.ts +3 -1
- package/src/api/request-output-context.ts +2 -1
- package/src/api/route-caller.test.ts +195 -0
- package/src/api/route-caller.ts +167 -0
- package/src/api/route-handler-input-options.ts +2 -1
- package/src/api/route.test.ts +4 -2
- package/src/api/route.ts +2 -1
- package/src/api/shared-types.ts +2 -1
- package/src/client/client-builder.test.ts +4 -2
- package/src/client/client-error.test.ts +2 -1
- package/src/client/client-error.ts +1 -1
- package/src/client/client-types.test.ts +19 -5
- package/src/client/client.ssr.test.ts +6 -4
- package/src/client/client.svelte.test.ts +18 -9
- package/src/client/client.svelte.ts +38 -13
- package/src/client/client.test.ts +49 -10
- package/src/client/client.ts +291 -141
- package/src/client/internal/ndjson-streaming.test.ts +6 -3
- package/src/client/internal/ndjson-streaming.ts +1 -0
- package/src/client/react.test.ts +176 -6
- package/src/client/react.ts +226 -31
- package/src/client/solid.test.ts +29 -5
- package/src/client/solid.ts +60 -22
- package/src/client/vanilla.test.ts +148 -6
- package/src/client/vanilla.ts +63 -9
- package/src/client/vue.test.ts +223 -84
- package/src/client/vue.ts +57 -30
- package/src/id.ts +1 -0
- package/src/internal/cuid.test.ts +164 -0
- package/src/internal/cuid.ts +133 -0
- package/src/mod-client.ts +4 -2
- package/src/mod.ts +3 -2
- package/src/runtime.ts +1 -1
- package/src/test/test.test.ts +4 -2
- package/src/test/test.ts +7 -9
- package/src/util/async.test.ts +1 -0
- package/src/util/content-type.test.ts +1 -0
- package/src/util/nanostores.test.ts +3 -1
- package/src/util/ssr.ts +1 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +1 -0
- package/vitest.config.ts +2 -1
package/src/client/client.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { computed, task, type ReadableAtom, type Store } from "nanostores";
|
|
2
|
+
|
|
1
3
|
import { nanoquery, type FetcherStore, type MutatorStore } from "@nanostores/query";
|
|
2
4
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
-
|
|
5
|
+
|
|
4
6
|
import type {
|
|
5
7
|
FragnoRouteConfig,
|
|
6
8
|
HTTPMethod,
|
|
@@ -8,6 +10,7 @@ import type {
|
|
|
8
10
|
RequestThisContext,
|
|
9
11
|
RouteContentType,
|
|
10
12
|
} from "../api/api";
|
|
13
|
+
import type { FragmentDefinition } from "../api/fragment-definition-builder";
|
|
11
14
|
import {
|
|
12
15
|
buildPath,
|
|
13
16
|
extractPathParams,
|
|
@@ -18,29 +21,28 @@ import {
|
|
|
18
21
|
import { getMountRoute } from "../api/internal/route";
|
|
19
22
|
import { RequestInputContext } from "../api/request-input-context";
|
|
20
23
|
import { RequestOutputContext } from "../api/request-output-context";
|
|
24
|
+
import {
|
|
25
|
+
type AnyFragnoRouteConfig,
|
|
26
|
+
type AnyRouteOrFactory,
|
|
27
|
+
type FlattenRouteFactories,
|
|
28
|
+
resolveRouteFactories,
|
|
29
|
+
} from "../api/route";
|
|
21
30
|
import type {
|
|
22
31
|
FetcherConfig,
|
|
23
32
|
FragnoFragmentSharedConfig,
|
|
24
33
|
FragnoPublicClientConfig,
|
|
25
34
|
FragnoPublicConfig,
|
|
26
35
|
} from "../api/shared-types";
|
|
27
|
-
import { FragnoClientApiError, FragnoClientError, FragnoClientFetchError } from "./client-error";
|
|
28
|
-
import type { InferOr } from "../util/types-util";
|
|
29
36
|
import { parseContentType } from "../util/content-type";
|
|
37
|
+
import { unwrapObject } from "../util/nanostores";
|
|
38
|
+
import { addStore, getInitialData, SSR_ENABLED } from "../util/ssr";
|
|
39
|
+
import type { InferOr } from "../util/types-util";
|
|
40
|
+
import { FragnoClientApiError, FragnoClientError, FragnoClientFetchError } from "./client-error";
|
|
41
|
+
import { mergeFetcherConfigs } from "./internal/fetcher-merge";
|
|
30
42
|
import {
|
|
31
43
|
handleNdjsonStreamingFirstItem,
|
|
32
44
|
type NdjsonStreamingStore,
|
|
33
45
|
} from "./internal/ndjson-streaming";
|
|
34
|
-
import { addStore, getInitialData, SSR_ENABLED } from "../util/ssr";
|
|
35
|
-
import { unwrapObject } from "../util/nanostores";
|
|
36
|
-
import type { FragmentDefinition } from "../api/fragment-definition-builder";
|
|
37
|
-
import type { AnyFragnoInstantiatedFragment } from "../api/fragment-instantiator";
|
|
38
|
-
import {
|
|
39
|
-
type AnyRouteOrFactory,
|
|
40
|
-
type FlattenRouteFactories,
|
|
41
|
-
resolveRouteFactories,
|
|
42
|
-
} from "../api/route";
|
|
43
|
-
import { mergeFetcherConfigs } from "./internal/fetcher-merge";
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* Symbols used to identify hook types
|
|
@@ -153,6 +155,31 @@ function prepareRequestBody(
|
|
|
153
155
|
};
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
async function schemaAllowsUndefined(schema: StandardSchemaV1): Promise<boolean> {
|
|
159
|
+
try {
|
|
160
|
+
const result = await schema["~standard"].validate(undefined);
|
|
161
|
+
return !result.issues;
|
|
162
|
+
} catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function assertBodyProvided(
|
|
168
|
+
body: unknown,
|
|
169
|
+
inputSchema: StandardSchemaV1 | undefined,
|
|
170
|
+
errorMessage: string,
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
if (typeof body !== "undefined" || inputSchema === undefined) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (await schemaAllowsUndefined(inputSchema)) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
throw new Error(errorMessage);
|
|
181
|
+
}
|
|
182
|
+
|
|
156
183
|
/**
|
|
157
184
|
* Merge request headers from multiple sources.
|
|
158
185
|
* Returns undefined if there are no headers to merge.
|
|
@@ -191,58 +218,128 @@ function mergeRequestHeaders(
|
|
|
191
218
|
}
|
|
192
219
|
|
|
193
220
|
/**
|
|
194
|
-
* Extract only GET routes from a library config's routes array
|
|
195
221
|
* @internal
|
|
196
222
|
*/
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
>
|
|
223
|
+
type FilterRouteByMethod<TRoute, TExpectedMethod extends HTTPMethod> =
|
|
224
|
+
TRoute extends FragnoRouteConfig<
|
|
225
|
+
infer TMethod,
|
|
226
|
+
infer TPath,
|
|
227
|
+
infer TInputSchema,
|
|
228
|
+
infer TOutputSchema,
|
|
229
|
+
infer TErrorCode,
|
|
230
|
+
infer TQueryParameters,
|
|
231
|
+
infer TThisContext
|
|
232
|
+
>
|
|
233
|
+
? [Extract<TMethod, TExpectedMethod>] extends [never]
|
|
234
|
+
? [Extract<TExpectedMethod, TMethod>] extends [never]
|
|
235
|
+
? never
|
|
236
|
+
: FragnoRouteConfig<
|
|
237
|
+
TMethod,
|
|
238
|
+
TPath,
|
|
239
|
+
TInputSchema,
|
|
240
|
+
TOutputSchema,
|
|
241
|
+
TErrorCode,
|
|
242
|
+
TQueryParameters,
|
|
243
|
+
TThisContext
|
|
244
|
+
>
|
|
245
|
+
: FragnoRouteConfig<
|
|
246
|
+
TMethod,
|
|
247
|
+
TPath,
|
|
248
|
+
TInputSchema,
|
|
249
|
+
TOutputSchema,
|
|
250
|
+
TErrorCode,
|
|
251
|
+
TQueryParameters,
|
|
252
|
+
TThisContext
|
|
253
|
+
>
|
|
254
|
+
: never;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @internal
|
|
258
|
+
*/
|
|
259
|
+
type FilterRouteByPath<TRoute, TPath extends string> =
|
|
260
|
+
TRoute extends FragnoRouteConfig<
|
|
261
|
+
infer TMethod,
|
|
262
|
+
infer TRoutePath,
|
|
263
|
+
infer TInputSchema,
|
|
264
|
+
infer TOutputSchema,
|
|
265
|
+
infer TErrorCode,
|
|
266
|
+
infer TQueryParameters,
|
|
267
|
+
infer TThisContext
|
|
268
|
+
>
|
|
269
|
+
? [Extract<TRoutePath, TPath>] extends [never]
|
|
270
|
+
? [Extract<TPath, TRoutePath>] extends [never]
|
|
271
|
+
? never
|
|
272
|
+
: FragnoRouteConfig<
|
|
273
|
+
TMethod,
|
|
274
|
+
TRoutePath,
|
|
275
|
+
TInputSchema,
|
|
276
|
+
TOutputSchema,
|
|
277
|
+
TErrorCode,
|
|
278
|
+
TQueryParameters,
|
|
279
|
+
TThisContext
|
|
280
|
+
>
|
|
281
|
+
: FragnoRouteConfig<
|
|
282
|
+
TMethod,
|
|
283
|
+
TRoutePath,
|
|
284
|
+
TInputSchema,
|
|
285
|
+
TOutputSchema,
|
|
286
|
+
TErrorCode,
|
|
287
|
+
TQueryParameters,
|
|
288
|
+
TThisContext
|
|
289
|
+
>
|
|
290
|
+
: never;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @internal
|
|
294
|
+
*/
|
|
295
|
+
type ExtractGetRoutesExact<T extends readonly AnyFragnoRouteConfig[]> = {
|
|
207
296
|
[K in keyof T]: T[K] extends FragnoRouteConfig<
|
|
208
|
-
infer
|
|
209
|
-
infer
|
|
210
|
-
infer
|
|
211
|
-
infer
|
|
212
|
-
infer
|
|
213
|
-
infer
|
|
297
|
+
infer TMethod,
|
|
298
|
+
infer TPath,
|
|
299
|
+
infer TInputSchema,
|
|
300
|
+
infer TOutputSchema,
|
|
301
|
+
infer TErrorCode,
|
|
302
|
+
infer TQueryParameters,
|
|
303
|
+
infer TThisContext
|
|
214
304
|
>
|
|
215
|
-
?
|
|
216
|
-
? FragnoRouteConfig<
|
|
305
|
+
? TMethod extends "GET"
|
|
306
|
+
? FragnoRouteConfig<
|
|
307
|
+
TMethod,
|
|
308
|
+
TPath,
|
|
309
|
+
TInputSchema,
|
|
310
|
+
TOutputSchema,
|
|
311
|
+
TErrorCode,
|
|
312
|
+
TQueryParameters,
|
|
313
|
+
TThisContext
|
|
314
|
+
>
|
|
217
315
|
: never
|
|
218
316
|
: never;
|
|
219
317
|
}[number][];
|
|
220
318
|
|
|
221
319
|
/**
|
|
222
|
-
* Extract
|
|
320
|
+
* Extract only GET routes from a library config's routes array
|
|
223
321
|
* @internal
|
|
224
322
|
*/
|
|
225
|
-
export type
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
string
|
|
233
|
-
>[],
|
|
323
|
+
export type ExtractGetRoutes<T extends readonly AnyFragnoRouteConfig[]> = ExtractGetRoutesExact<T>;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @internal
|
|
327
|
+
*/
|
|
328
|
+
type ExtractRoutePathExact<
|
|
329
|
+
T extends readonly AnyFragnoRouteConfig[],
|
|
234
330
|
TExpectedMethod extends HTTPMethod = HTTPMethod,
|
|
235
331
|
> = {
|
|
236
332
|
[K in keyof T]: T[K] extends FragnoRouteConfig<
|
|
237
|
-
infer
|
|
238
|
-
infer
|
|
333
|
+
infer TMethod,
|
|
334
|
+
infer TPath,
|
|
239
335
|
StandardSchemaV1 | undefined,
|
|
240
336
|
StandardSchemaV1 | undefined,
|
|
241
337
|
string,
|
|
242
|
-
string
|
|
338
|
+
string,
|
|
339
|
+
RequestThisContext
|
|
243
340
|
>
|
|
244
|
-
?
|
|
245
|
-
?
|
|
341
|
+
? TMethod extends TExpectedMethod
|
|
342
|
+
? TPath
|
|
246
343
|
: never
|
|
247
344
|
: never;
|
|
248
345
|
}[number];
|
|
@@ -250,103 +347,154 @@ export type ExtractRoutePath<
|
|
|
250
347
|
/**
|
|
251
348
|
* @internal
|
|
252
349
|
*/
|
|
253
|
-
|
|
254
|
-
T extends readonly
|
|
255
|
-
|
|
256
|
-
|
|
350
|
+
type ExtractRoutePathLoose<
|
|
351
|
+
T extends readonly AnyFragnoRouteConfig[],
|
|
352
|
+
TExpectedMethod extends HTTPMethod = HTTPMethod,
|
|
353
|
+
> = {
|
|
354
|
+
[K in keyof T]: FilterRouteByMethod<T[K], TExpectedMethod> extends FragnoRouteConfig<
|
|
355
|
+
infer _TMethod,
|
|
356
|
+
infer TPath,
|
|
257
357
|
StandardSchemaV1 | undefined,
|
|
258
358
|
StandardSchemaV1 | undefined,
|
|
259
359
|
string,
|
|
260
|
-
string
|
|
261
|
-
|
|
262
|
-
>
|
|
360
|
+
string,
|
|
361
|
+
RequestThisContext
|
|
362
|
+
>
|
|
363
|
+
? TPath
|
|
364
|
+
: never;
|
|
365
|
+
}[number];
|
|
263
366
|
|
|
264
367
|
/**
|
|
265
368
|
* @internal
|
|
266
369
|
*/
|
|
267
|
-
|
|
268
|
-
T extends
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
370
|
+
type HasWidenedRouteShape<T extends readonly AnyFragnoRouteConfig[]> =
|
|
371
|
+
T[number] extends infer TRoute
|
|
372
|
+
? TRoute extends FragnoRouteConfig<
|
|
373
|
+
infer TMethod,
|
|
374
|
+
infer TPath,
|
|
375
|
+
StandardSchemaV1 | undefined,
|
|
376
|
+
StandardSchemaV1 | undefined,
|
|
377
|
+
string,
|
|
378
|
+
string,
|
|
379
|
+
RequestThisContext
|
|
380
|
+
>
|
|
381
|
+
? string extends TPath
|
|
382
|
+
? true
|
|
383
|
+
: HTTPMethod extends TMethod
|
|
384
|
+
? true
|
|
385
|
+
: false
|
|
386
|
+
: false
|
|
387
|
+
: false;
|
|
277
388
|
|
|
278
389
|
/**
|
|
279
|
-
* Extract the route configuration
|
|
280
|
-
* Optionally narrow by HTTP method via the third type parameter.
|
|
281
|
-
*
|
|
282
|
-
* Defaults to extracting all methods for the matching path, producing a union
|
|
283
|
-
* if multiple methods exist for the same path.
|
|
390
|
+
* Extract the path from a route configuration for a given method
|
|
284
391
|
* @internal
|
|
285
392
|
*/
|
|
286
|
-
export type
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
393
|
+
export type ExtractRoutePath<
|
|
394
|
+
T extends readonly AnyFragnoRouteConfig[],
|
|
395
|
+
TExpectedMethod extends HTTPMethod = HTTPMethod,
|
|
396
|
+
> = [ExtractRoutePathExact<T, TExpectedMethod>] extends [never]
|
|
397
|
+
? HasWidenedRouteShape<T> extends true
|
|
398
|
+
? ExtractRoutePathLoose<T, TExpectedMethod> & string
|
|
399
|
+
: never
|
|
400
|
+
: ExtractRoutePathExact<T, TExpectedMethod>;
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* @internal
|
|
404
|
+
*/
|
|
405
|
+
export type ExtractGetRoutePaths<T extends readonly AnyFragnoRouteConfig[]> = ExtractRoutePath<
|
|
406
|
+
T,
|
|
407
|
+
"GET"
|
|
408
|
+
>;
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @internal
|
|
412
|
+
*/
|
|
413
|
+
export type ExtractNonGetRoutePaths<T extends readonly AnyFragnoRouteConfig[]> = ExtractRoutePath<
|
|
414
|
+
T,
|
|
415
|
+
NonGetHTTPMethod
|
|
416
|
+
>;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* @internal
|
|
420
|
+
*/
|
|
421
|
+
type ExtractRouteByPathExact<
|
|
422
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
295
423
|
TPath extends string,
|
|
296
424
|
TMethod extends HTTPMethod = HTTPMethod,
|
|
297
425
|
> = {
|
|
298
426
|
[K in keyof TRoutes]: TRoutes[K] extends FragnoRouteConfig<
|
|
299
|
-
infer
|
|
427
|
+
infer TRouteMethod,
|
|
300
428
|
TPath,
|
|
301
|
-
infer
|
|
302
|
-
infer
|
|
303
|
-
infer
|
|
304
|
-
infer
|
|
429
|
+
infer TInputSchema,
|
|
430
|
+
infer TOutputSchema,
|
|
431
|
+
infer TErrorCode,
|
|
432
|
+
infer TQueryParameters,
|
|
433
|
+
infer TThisContext
|
|
305
434
|
>
|
|
306
|
-
?
|
|
307
|
-
? FragnoRouteConfig<
|
|
435
|
+
? TRouteMethod extends TMethod
|
|
436
|
+
? FragnoRouteConfig<
|
|
437
|
+
TRouteMethod,
|
|
438
|
+
TPath,
|
|
439
|
+
TInputSchema,
|
|
440
|
+
TOutputSchema,
|
|
441
|
+
TErrorCode,
|
|
442
|
+
TQueryParameters,
|
|
443
|
+
TThisContext
|
|
444
|
+
>
|
|
308
445
|
: never
|
|
309
446
|
: never;
|
|
310
447
|
}[number];
|
|
311
448
|
|
|
449
|
+
/**
|
|
450
|
+
* @internal
|
|
451
|
+
*/
|
|
452
|
+
type ExtractRouteByPathLoose<
|
|
453
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
454
|
+
TPath extends string,
|
|
455
|
+
TMethod extends HTTPMethod = HTTPMethod,
|
|
456
|
+
> = {
|
|
457
|
+
[K in keyof TRoutes]: FilterRouteByPath<FilterRouteByMethod<TRoutes[K], TMethod>, TPath>;
|
|
458
|
+
}[number];
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Extract the route configuration type(s) for a given path from a routes array.
|
|
462
|
+
* Optionally narrow by HTTP method via the third type parameter.
|
|
463
|
+
*
|
|
464
|
+
* Defaults to extracting all methods for the matching path, producing a union
|
|
465
|
+
* if multiple methods exist for the same path.
|
|
466
|
+
* @internal
|
|
467
|
+
*/
|
|
468
|
+
export type ExtractRouteByPath<
|
|
469
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
470
|
+
TPath extends string,
|
|
471
|
+
TMethod extends HTTPMethod = HTTPMethod,
|
|
472
|
+
> = [ExtractRouteByPathExact<TRoutes, TPath, TMethod>] extends [never]
|
|
473
|
+
? HasWidenedRouteShape<TRoutes> extends true
|
|
474
|
+
? ExtractRouteByPathLoose<TRoutes, TPath, TMethod>
|
|
475
|
+
: never
|
|
476
|
+
: ExtractRouteByPathExact<TRoutes, TPath, TMethod>;
|
|
477
|
+
|
|
312
478
|
/**
|
|
313
479
|
* Extract the output schema type for a specific route path from a routes array
|
|
314
480
|
* @internal
|
|
315
481
|
*/
|
|
316
482
|
export type ExtractOutputSchemaForPath<
|
|
317
|
-
TRoutes extends readonly
|
|
318
|
-
HTTPMethod,
|
|
319
|
-
string,
|
|
320
|
-
StandardSchemaV1 | undefined,
|
|
321
|
-
StandardSchemaV1 | undefined
|
|
322
|
-
>[],
|
|
483
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
323
484
|
TPath extends string,
|
|
324
|
-
> =
|
|
325
|
-
|
|
326
|
-
infer
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
infer Output
|
|
330
|
-
>
|
|
331
|
-
? Method extends "GET"
|
|
332
|
-
? Output
|
|
333
|
-
: never
|
|
485
|
+
> =
|
|
486
|
+
ExtractRouteByPath<TRoutes, TPath, "GET"> extends {
|
|
487
|
+
outputSchema?: infer TOutputSchema;
|
|
488
|
+
}
|
|
489
|
+
? TOutputSchema
|
|
334
490
|
: never;
|
|
335
|
-
}[number];
|
|
336
491
|
|
|
337
492
|
/**
|
|
338
493
|
* Check if a path exists as a GET route in the routes array
|
|
339
494
|
* @internal
|
|
340
495
|
*/
|
|
341
496
|
export type IsValidGetRoutePath<
|
|
342
|
-
TRoutes extends readonly
|
|
343
|
-
HTTPMethod,
|
|
344
|
-
string,
|
|
345
|
-
StandardSchemaV1 | undefined,
|
|
346
|
-
StandardSchemaV1 | undefined,
|
|
347
|
-
string,
|
|
348
|
-
string
|
|
349
|
-
>[],
|
|
497
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
350
498
|
TPath extends string,
|
|
351
499
|
> = TPath extends ExtractGetRoutePaths<TRoutes> ? true : false;
|
|
352
500
|
|
|
@@ -355,14 +503,7 @@ export type IsValidGetRoutePath<
|
|
|
355
503
|
* @internal
|
|
356
504
|
*/
|
|
357
505
|
export type ValidateGetRoutePath<
|
|
358
|
-
TRoutes extends readonly
|
|
359
|
-
HTTPMethod,
|
|
360
|
-
string,
|
|
361
|
-
StandardSchemaV1 | undefined,
|
|
362
|
-
StandardSchemaV1 | undefined,
|
|
363
|
-
string,
|
|
364
|
-
string
|
|
365
|
-
>[],
|
|
506
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
366
507
|
TPath extends string,
|
|
367
508
|
> =
|
|
368
509
|
TPath extends ExtractGetRoutePaths<TRoutes>
|
|
@@ -373,16 +514,8 @@ export type ValidateGetRoutePath<
|
|
|
373
514
|
* Helper type to check if a routes array has any GET routes
|
|
374
515
|
* @internal
|
|
375
516
|
*/
|
|
376
|
-
export type HasGetRoutes<
|
|
377
|
-
T extends
|
|
378
|
-
HTTPMethod,
|
|
379
|
-
string,
|
|
380
|
-
StandardSchemaV1 | undefined,
|
|
381
|
-
StandardSchemaV1 | undefined,
|
|
382
|
-
string,
|
|
383
|
-
string
|
|
384
|
-
>[],
|
|
385
|
-
> = ExtractGetRoutePaths<T> extends never ? false : true;
|
|
517
|
+
export type HasGetRoutes<T extends readonly AnyFragnoRouteConfig[]> =
|
|
518
|
+
ExtractGetRoutePaths<T> extends never ? false : true;
|
|
386
519
|
|
|
387
520
|
/**
|
|
388
521
|
* @internal
|
|
@@ -398,11 +531,20 @@ export type ObjectContainingStoreField<T extends object> = T extends Store
|
|
|
398
531
|
/**
|
|
399
532
|
* @internal
|
|
400
533
|
*/
|
|
401
|
-
export type
|
|
534
|
+
export type FragnoStoreObjectData<T extends object> = {
|
|
402
535
|
obj: T;
|
|
403
536
|
[STORE_SYMBOL]: true;
|
|
404
537
|
};
|
|
405
538
|
|
|
539
|
+
export type FragnoStoreFactoryData<T extends object, TArgs extends unknown[] = []> = {
|
|
540
|
+
factory: (...args: TArgs) => T;
|
|
541
|
+
[STORE_SYMBOL]: true;
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
export type FragnoStoreData<T extends object, TArgs extends unknown[] = []> =
|
|
545
|
+
| FragnoStoreObjectData<T>
|
|
546
|
+
| FragnoStoreFactoryData<T, TArgs>;
|
|
547
|
+
|
|
406
548
|
export type FragnoClientHookData<
|
|
407
549
|
TMethod extends HTTPMethod,
|
|
408
550
|
TPath extends string,
|
|
@@ -627,7 +769,9 @@ export function isMutatorHook<
|
|
|
627
769
|
/**
|
|
628
770
|
* @internal
|
|
629
771
|
*/
|
|
630
|
-
export function isStore<TStore extends
|
|
772
|
+
export function isStore<TStore extends object, TArgs extends unknown[] = []>(
|
|
773
|
+
obj: unknown,
|
|
774
|
+
): obj is FragnoStoreData<TStore, TArgs> {
|
|
631
775
|
return (
|
|
632
776
|
typeof obj === "object" && obj !== null && STORE_SYMBOL in obj && obj[STORE_SYMBOL] === true
|
|
633
777
|
);
|
|
@@ -712,8 +856,18 @@ export class ClientBuilder<
|
|
|
712
856
|
return Object.fromEntries(this.#cache.entries());
|
|
713
857
|
}
|
|
714
858
|
|
|
715
|
-
createStore<const T extends object>(
|
|
716
|
-
|
|
859
|
+
createStore<const TArgs extends unknown[], const T extends object>(
|
|
860
|
+
factory: (...args: TArgs) => T,
|
|
861
|
+
): FragnoStoreFactoryData<T, TArgs>;
|
|
862
|
+
createStore<const T extends object>(obj: T): FragnoStoreObjectData<T>;
|
|
863
|
+
createStore<const TArgs extends unknown[], const T extends object>(
|
|
864
|
+
input: T | ((...args: TArgs) => T),
|
|
865
|
+
): FragnoStoreData<T, TArgs> {
|
|
866
|
+
if (typeof input === "function") {
|
|
867
|
+
return { factory: input as (...args: TArgs) => T, [STORE_SYMBOL]: true };
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
return { obj: input, [STORE_SYMBOL]: true };
|
|
717
871
|
}
|
|
718
872
|
|
|
719
873
|
/**
|
|
@@ -757,7 +911,7 @@ export class ClientBuilder<
|
|
|
757
911
|
if (this.#fetcherConfig?.type === "function") {
|
|
758
912
|
return this.#fetcherConfig.fetcher;
|
|
759
913
|
}
|
|
760
|
-
return fetch;
|
|
914
|
+
return globalThis.fetch.bind(globalThis);
|
|
761
915
|
}
|
|
762
916
|
|
|
763
917
|
#getFetcherOptions(): RequestInit | undefined {
|
|
@@ -1150,9 +1304,7 @@ export class ClientBuilder<
|
|
|
1150
1304
|
query?: Record<string, string>;
|
|
1151
1305
|
};
|
|
1152
1306
|
|
|
1153
|
-
|
|
1154
|
-
throw new Error("Body is required.");
|
|
1155
|
-
}
|
|
1307
|
+
await assertBodyProvided(body, route.inputSchema, "Body is required.");
|
|
1156
1308
|
|
|
1157
1309
|
const response = await executeMutateQuery({ body, path, query });
|
|
1158
1310
|
|
|
@@ -1221,9 +1373,7 @@ export class ClientBuilder<
|
|
|
1221
1373
|
query?: Record<string, string>;
|
|
1222
1374
|
};
|
|
1223
1375
|
|
|
1224
|
-
|
|
1225
|
-
throw new Error("Body is required for mutateQuery");
|
|
1226
|
-
}
|
|
1376
|
+
await assertBodyProvided(body, route.inputSchema, "Body is required for mutateQuery");
|
|
1227
1377
|
|
|
1228
1378
|
const response = await executeMutateQuery({ body, path, query });
|
|
1229
1379
|
|
|
@@ -1300,7 +1450,7 @@ export function createClientBuilder<
|
|
|
1300
1450
|
THandlerThisContext extends RequestThisContext,
|
|
1301
1451
|
TRequestStorage,
|
|
1302
1452
|
const TRoutesOrFactories extends readonly AnyRouteOrFactory[],
|
|
1303
|
-
|
|
1453
|
+
TInternalRoutes extends readonly AnyRouteOrFactory[] = readonly [],
|
|
1304
1454
|
>(
|
|
1305
1455
|
definition: FragmentDefinition<
|
|
1306
1456
|
TConfig,
|
|
@@ -1313,7 +1463,7 @@ export function createClientBuilder<
|
|
|
1313
1463
|
TServiceThisContext,
|
|
1314
1464
|
THandlerThisContext,
|
|
1315
1465
|
TRequestStorage,
|
|
1316
|
-
|
|
1466
|
+
TInternalRoutes
|
|
1317
1467
|
>,
|
|
1318
1468
|
publicConfig: FragnoPublicClientConfig,
|
|
1319
1469
|
routesOrFactories: TRoutesOrFactories,
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { describe, test, expect, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { FragnoClientError, FragnoClientFetchAbortError } from "../client-error";
|
|
4
|
-
import { nanoquery } from "@nanostores/query";
|
|
2
|
+
|
|
5
3
|
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import { nanoquery } from "@nanostores/query";
|
|
6
6
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
|
+
|
|
7
8
|
import { createAsyncIteratorFromCallback } from "../../util/async";
|
|
9
|
+
import { FragnoClientError, FragnoClientFetchAbortError } from "../client-error";
|
|
10
|
+
import { handleNdjsonStreamingFirstItem, type NdjsonStreamingStore } from "./ndjson-streaming";
|
|
8
11
|
|
|
9
12
|
describe("handleNdjsonStreaming", () => {
|
|
10
13
|
test("should return first item and continue streaming updates", async () => {
|