@fragno-dev/core 0.1.11 → 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 +87 -69
- package/CHANGELOG.md +79 -0
- package/dist/api/api.d.ts +21 -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 +32 -40
- package/dist/api/fragment-definition-builder.d.ts.map +1 -1
- package/dist/api/fragment-definition-builder.js +15 -21
- package/dist/api/fragment-definition-builder.js.map +1 -1
- package/dist/api/fragment-instantiator.d.ts +51 -30
- package/dist/api/fragment-instantiator.d.ts.map +1 -1
- package/dist/api/fragment-instantiator.js +201 -52
- 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 +57 -1
- package/dist/api/request-input-context.d.ts.map +1 -1
- package/dist/api/request-input-context.js +67 -0
- package/dist/api/request-input-context.js.map +1 -1
- package/dist/api/request-middleware.d.ts +2 -2
- 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 +8 -8
- 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 +90 -50
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +128 -16
- 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 +10 -4
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +24 -1
- 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/internal/trace-context.d.ts +23 -0
- package/dist/internal/trace-context.d.ts.map +1 -0
- package/dist/internal/trace-context.js +14 -0
- package/dist/internal/trace-context.js.map +1 -0
- package/dist/mod-client.d.ts +7 -20
- package/dist/mod-client.d.ts.map +1 -1
- package/dist/mod-client.js +25 -13
- package/dist/mod-client.js.map +1 -1
- package/dist/mod.d.ts +8 -6
- package/dist/mod.js +3 -1
- package/dist/runtime.d.ts +15 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +33 -0
- package/dist/runtime.js.map +1 -0
- 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 +42 -52
- package/src/api/api.test.ts +3 -1
- package/src/api/api.ts +28 -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 +56 -112
- package/src/api/fragment-instantiator.test.ts +311 -166
- package/src/api/fragment-instantiator.ts +470 -131
- package/src/api/fragment-services.test.ts +1 -0
- package/src/api/internal/path-runtime.test.ts +8 -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 +156 -2
- package/src/api/request-input-context.ts +87 -1
- package/src/api/request-middleware.test.ts +43 -2
- package/src/api/request-middleware.ts +4 -3
- 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 +9 -3
- 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 +244 -10
- package/src/client/client.ts +473 -148
- 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 +397 -8
- package/src/client/vue.ts +74 -4
- package/src/id.ts +1 -0
- package/src/internal/cuid.test.ts +164 -0
- package/src/internal/cuid.ts +133 -0
- package/src/internal/trace-context.ts +35 -0
- package/src/mod-client.ts +55 -9
- package/src/mod.ts +9 -3
- package/src/runtime.ts +48 -0
- package/src/test/test.test.ts +4 -2
- package/src/test/test.ts +14 -7
- 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 +2 -0
- package/vitest.config.ts +2 -1
package/src/client/client.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
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,
|
|
7
9
|
NonGetHTTPMethod,
|
|
8
10
|
RequestThisContext,
|
|
11
|
+
RouteContentType,
|
|
9
12
|
} from "../api/api";
|
|
13
|
+
import type { FragmentDefinition } from "../api/fragment-definition-builder";
|
|
10
14
|
import {
|
|
11
15
|
buildPath,
|
|
12
16
|
extractPathParams,
|
|
@@ -17,28 +21,28 @@ import {
|
|
|
17
21
|
import { getMountRoute } from "../api/internal/route";
|
|
18
22
|
import { RequestInputContext } from "../api/request-input-context";
|
|
19
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";
|
|
20
30
|
import type {
|
|
21
31
|
FetcherConfig,
|
|
22
32
|
FragnoFragmentSharedConfig,
|
|
23
33
|
FragnoPublicClientConfig,
|
|
24
34
|
FragnoPublicConfig,
|
|
25
35
|
} from "../api/shared-types";
|
|
26
|
-
import { FragnoClientApiError, FragnoClientError, FragnoClientFetchError } from "./client-error";
|
|
27
|
-
import type { InferOr } from "../util/types-util";
|
|
28
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";
|
|
29
42
|
import {
|
|
30
43
|
handleNdjsonStreamingFirstItem,
|
|
31
44
|
type NdjsonStreamingStore,
|
|
32
45
|
} from "./internal/ndjson-streaming";
|
|
33
|
-
import { addStore, getInitialData, SSR_ENABLED } from "../util/ssr";
|
|
34
|
-
import { unwrapObject } from "../util/nanostores";
|
|
35
|
-
import type { FragmentDefinition } from "../api/fragment-definition-builder";
|
|
36
|
-
import {
|
|
37
|
-
type AnyRouteOrFactory,
|
|
38
|
-
type FlattenRouteFactories,
|
|
39
|
-
resolveRouteFactories,
|
|
40
|
-
} from "../api/route";
|
|
41
|
-
import { mergeFetcherConfigs } from "./internal/fetcher-merge";
|
|
42
46
|
|
|
43
47
|
/**
|
|
44
48
|
* Symbols used to identify hook types
|
|
@@ -48,58 +52,294 @@ const MUTATOR_HOOK_SYMBOL = Symbol("fragno-mutator-hook");
|
|
|
48
52
|
const STORE_SYMBOL = Symbol("fragno-store");
|
|
49
53
|
|
|
50
54
|
/**
|
|
51
|
-
*
|
|
55
|
+
* Check if a value contains files that should be sent as FormData.
|
|
52
56
|
* @internal
|
|
53
57
|
*/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
function containsFiles(value: unknown): boolean {
|
|
59
|
+
if (value instanceof File || value instanceof Blob) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (value instanceof FormData) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (typeof value === "object" && value !== null) {
|
|
68
|
+
return Object.values(value).some(
|
|
69
|
+
(v) => v instanceof File || v instanceof Blob || v instanceof FormData,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Convert an object containing files to FormData.
|
|
78
|
+
* Handles nested File/Blob values by appending them directly.
|
|
79
|
+
* Other values are JSON-stringified.
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
function toFormData(value: object): FormData {
|
|
83
|
+
const formData = new FormData();
|
|
84
|
+
|
|
85
|
+
for (const [key, val] of Object.entries(value)) {
|
|
86
|
+
if (val instanceof File) {
|
|
87
|
+
formData.append(key, val, val.name);
|
|
88
|
+
} else if (val instanceof Blob) {
|
|
89
|
+
formData.append(key, val);
|
|
90
|
+
} else if (val !== undefined && val !== null) {
|
|
91
|
+
// For non-file values, stringify if needed
|
|
92
|
+
formData.append(key, typeof val === "string" ? val : JSON.stringify(val));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return formData;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Prepare request body and headers for sending.
|
|
101
|
+
* Handles FormData (file uploads) vs JSON data.
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
function prepareRequestBody(
|
|
105
|
+
body: unknown,
|
|
106
|
+
contentType?: RouteContentType,
|
|
107
|
+
): { body: BodyInit | undefined; headers?: HeadersInit } {
|
|
108
|
+
if (body === undefined) {
|
|
109
|
+
return { body: undefined };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (contentType === "application/octet-stream") {
|
|
113
|
+
if (
|
|
114
|
+
body instanceof ReadableStream ||
|
|
115
|
+
body instanceof Blob ||
|
|
116
|
+
body instanceof File ||
|
|
117
|
+
body instanceof ArrayBuffer ||
|
|
118
|
+
body instanceof Uint8Array
|
|
119
|
+
) {
|
|
120
|
+
return { body: body as BodyInit, headers: { "Content-Type": "application/octet-stream" } };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
throw new Error(
|
|
124
|
+
"Octet-stream routes only accept Blob, File, ArrayBuffer, Uint8Array, or ReadableStream bodies.",
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// If already FormData, send as-is (browser sets Content-Type with boundary)
|
|
129
|
+
if (body instanceof FormData) {
|
|
130
|
+
return { body };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// If body is directly a File or Blob, wrap it in FormData
|
|
134
|
+
if (body instanceof File) {
|
|
135
|
+
const formData = new FormData();
|
|
136
|
+
formData.append("file", body, body.name);
|
|
137
|
+
return { body: formData };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (body instanceof Blob) {
|
|
141
|
+
const formData = new FormData();
|
|
142
|
+
formData.append("file", body);
|
|
143
|
+
return { body: formData };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// If object contains files, convert to FormData
|
|
147
|
+
if (typeof body === "object" && body !== null && containsFiles(body)) {
|
|
148
|
+
return { body: toFormData(body) };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Otherwise, JSON-stringify
|
|
152
|
+
return {
|
|
153
|
+
body: JSON.stringify(body),
|
|
154
|
+
headers: { "Content-Type": "application/json" },
|
|
155
|
+
};
|
|
156
|
+
}
|
|
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
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Merge request headers from multiple sources.
|
|
185
|
+
* Returns undefined if there are no headers to merge.
|
|
186
|
+
* @internal
|
|
187
|
+
*/
|
|
188
|
+
function mergeRequestHeaders(
|
|
189
|
+
...headerSources: (HeadersInit | undefined)[]
|
|
190
|
+
): Record<string, string> | undefined {
|
|
191
|
+
const result: Record<string, string> = {};
|
|
192
|
+
let hasHeaders = false;
|
|
193
|
+
|
|
194
|
+
for (const source of headerSources) {
|
|
195
|
+
if (!source) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (source instanceof Headers) {
|
|
200
|
+
for (const [key, value] of source.entries()) {
|
|
201
|
+
result[key] = value;
|
|
202
|
+
hasHeaders = true;
|
|
203
|
+
}
|
|
204
|
+
} else if (Array.isArray(source)) {
|
|
205
|
+
for (const [key, value] of source) {
|
|
206
|
+
result[key] = value;
|
|
207
|
+
hasHeaders = true;
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
for (const [key, value] of Object.entries(source)) {
|
|
211
|
+
result[key] = value;
|
|
212
|
+
hasHeaders = true;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return hasHeaders ? result : undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @internal
|
|
222
|
+
*/
|
|
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[]> = {
|
|
64
296
|
[K in keyof T]: T[K] extends FragnoRouteConfig<
|
|
65
|
-
infer
|
|
66
|
-
infer
|
|
67
|
-
infer
|
|
68
|
-
infer
|
|
69
|
-
infer
|
|
70
|
-
infer
|
|
297
|
+
infer TMethod,
|
|
298
|
+
infer TPath,
|
|
299
|
+
infer TInputSchema,
|
|
300
|
+
infer TOutputSchema,
|
|
301
|
+
infer TErrorCode,
|
|
302
|
+
infer TQueryParameters,
|
|
303
|
+
infer TThisContext
|
|
71
304
|
>
|
|
72
|
-
?
|
|
73
|
-
? FragnoRouteConfig<
|
|
305
|
+
? TMethod extends "GET"
|
|
306
|
+
? FragnoRouteConfig<
|
|
307
|
+
TMethod,
|
|
308
|
+
TPath,
|
|
309
|
+
TInputSchema,
|
|
310
|
+
TOutputSchema,
|
|
311
|
+
TErrorCode,
|
|
312
|
+
TQueryParameters,
|
|
313
|
+
TThisContext
|
|
314
|
+
>
|
|
74
315
|
: never
|
|
75
316
|
: never;
|
|
76
317
|
}[number][];
|
|
77
318
|
|
|
78
319
|
/**
|
|
79
|
-
* Extract
|
|
320
|
+
* Extract only GET routes from a library config's routes array
|
|
80
321
|
* @internal
|
|
81
322
|
*/
|
|
82
|
-
export type
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
string
|
|
90
|
-
>[],
|
|
323
|
+
export type ExtractGetRoutes<T extends readonly AnyFragnoRouteConfig[]> = ExtractGetRoutesExact<T>;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @internal
|
|
327
|
+
*/
|
|
328
|
+
type ExtractRoutePathExact<
|
|
329
|
+
T extends readonly AnyFragnoRouteConfig[],
|
|
91
330
|
TExpectedMethod extends HTTPMethod = HTTPMethod,
|
|
92
331
|
> = {
|
|
93
332
|
[K in keyof T]: T[K] extends FragnoRouteConfig<
|
|
94
|
-
infer
|
|
95
|
-
infer
|
|
333
|
+
infer TMethod,
|
|
334
|
+
infer TPath,
|
|
96
335
|
StandardSchemaV1 | undefined,
|
|
97
336
|
StandardSchemaV1 | undefined,
|
|
98
337
|
string,
|
|
99
|
-
string
|
|
338
|
+
string,
|
|
339
|
+
RequestThisContext
|
|
100
340
|
>
|
|
101
|
-
?
|
|
102
|
-
?
|
|
341
|
+
? TMethod extends TExpectedMethod
|
|
342
|
+
? TPath
|
|
103
343
|
: never
|
|
104
344
|
: never;
|
|
105
345
|
}[number];
|
|
@@ -107,103 +347,154 @@ export type ExtractRoutePath<
|
|
|
107
347
|
/**
|
|
108
348
|
* @internal
|
|
109
349
|
*/
|
|
110
|
-
|
|
111
|
-
T extends readonly
|
|
112
|
-
|
|
113
|
-
|
|
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,
|
|
114
357
|
StandardSchemaV1 | undefined,
|
|
115
358
|
StandardSchemaV1 | undefined,
|
|
116
359
|
string,
|
|
117
|
-
string
|
|
118
|
-
|
|
119
|
-
>
|
|
360
|
+
string,
|
|
361
|
+
RequestThisContext
|
|
362
|
+
>
|
|
363
|
+
? TPath
|
|
364
|
+
: never;
|
|
365
|
+
}[number];
|
|
120
366
|
|
|
121
367
|
/**
|
|
122
368
|
* @internal
|
|
123
369
|
*/
|
|
124
|
-
|
|
125
|
-
T extends
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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;
|
|
134
388
|
|
|
135
389
|
/**
|
|
136
|
-
* Extract the route configuration
|
|
137
|
-
* Optionally narrow by HTTP method via the third type parameter.
|
|
138
|
-
*
|
|
139
|
-
* Defaults to extracting all methods for the matching path, producing a union
|
|
140
|
-
* if multiple methods exist for the same path.
|
|
390
|
+
* Extract the path from a route configuration for a given method
|
|
141
391
|
* @internal
|
|
142
392
|
*/
|
|
143
|
-
export type
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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[],
|
|
152
423
|
TPath extends string,
|
|
153
424
|
TMethod extends HTTPMethod = HTTPMethod,
|
|
154
425
|
> = {
|
|
155
426
|
[K in keyof TRoutes]: TRoutes[K] extends FragnoRouteConfig<
|
|
156
|
-
infer
|
|
427
|
+
infer TRouteMethod,
|
|
157
428
|
TPath,
|
|
158
|
-
infer
|
|
159
|
-
infer
|
|
160
|
-
infer
|
|
161
|
-
infer
|
|
429
|
+
infer TInputSchema,
|
|
430
|
+
infer TOutputSchema,
|
|
431
|
+
infer TErrorCode,
|
|
432
|
+
infer TQueryParameters,
|
|
433
|
+
infer TThisContext
|
|
162
434
|
>
|
|
163
|
-
?
|
|
164
|
-
? FragnoRouteConfig<
|
|
435
|
+
? TRouteMethod extends TMethod
|
|
436
|
+
? FragnoRouteConfig<
|
|
437
|
+
TRouteMethod,
|
|
438
|
+
TPath,
|
|
439
|
+
TInputSchema,
|
|
440
|
+
TOutputSchema,
|
|
441
|
+
TErrorCode,
|
|
442
|
+
TQueryParameters,
|
|
443
|
+
TThisContext
|
|
444
|
+
>
|
|
165
445
|
: never
|
|
166
446
|
: never;
|
|
167
447
|
}[number];
|
|
168
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
|
+
|
|
169
478
|
/**
|
|
170
479
|
* Extract the output schema type for a specific route path from a routes array
|
|
171
480
|
* @internal
|
|
172
481
|
*/
|
|
173
482
|
export type ExtractOutputSchemaForPath<
|
|
174
|
-
TRoutes extends readonly
|
|
175
|
-
HTTPMethod,
|
|
176
|
-
string,
|
|
177
|
-
StandardSchemaV1 | undefined,
|
|
178
|
-
StandardSchemaV1 | undefined
|
|
179
|
-
>[],
|
|
483
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
180
484
|
TPath extends string,
|
|
181
|
-
> =
|
|
182
|
-
|
|
183
|
-
infer
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
infer Output
|
|
187
|
-
>
|
|
188
|
-
? Method extends "GET"
|
|
189
|
-
? Output
|
|
190
|
-
: never
|
|
485
|
+
> =
|
|
486
|
+
ExtractRouteByPath<TRoutes, TPath, "GET"> extends {
|
|
487
|
+
outputSchema?: infer TOutputSchema;
|
|
488
|
+
}
|
|
489
|
+
? TOutputSchema
|
|
191
490
|
: never;
|
|
192
|
-
}[number];
|
|
193
491
|
|
|
194
492
|
/**
|
|
195
493
|
* Check if a path exists as a GET route in the routes array
|
|
196
494
|
* @internal
|
|
197
495
|
*/
|
|
198
496
|
export type IsValidGetRoutePath<
|
|
199
|
-
TRoutes extends readonly
|
|
200
|
-
HTTPMethod,
|
|
201
|
-
string,
|
|
202
|
-
StandardSchemaV1 | undefined,
|
|
203
|
-
StandardSchemaV1 | undefined,
|
|
204
|
-
string,
|
|
205
|
-
string
|
|
206
|
-
>[],
|
|
497
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
207
498
|
TPath extends string,
|
|
208
499
|
> = TPath extends ExtractGetRoutePaths<TRoutes> ? true : false;
|
|
209
500
|
|
|
@@ -212,14 +503,7 @@ export type IsValidGetRoutePath<
|
|
|
212
503
|
* @internal
|
|
213
504
|
*/
|
|
214
505
|
export type ValidateGetRoutePath<
|
|
215
|
-
TRoutes extends readonly
|
|
216
|
-
HTTPMethod,
|
|
217
|
-
string,
|
|
218
|
-
StandardSchemaV1 | undefined,
|
|
219
|
-
StandardSchemaV1 | undefined,
|
|
220
|
-
string,
|
|
221
|
-
string
|
|
222
|
-
>[],
|
|
506
|
+
TRoutes extends readonly AnyFragnoRouteConfig[],
|
|
223
507
|
TPath extends string,
|
|
224
508
|
> =
|
|
225
509
|
TPath extends ExtractGetRoutePaths<TRoutes>
|
|
@@ -230,16 +514,8 @@ export type ValidateGetRoutePath<
|
|
|
230
514
|
* Helper type to check if a routes array has any GET routes
|
|
231
515
|
* @internal
|
|
232
516
|
*/
|
|
233
|
-
export type HasGetRoutes<
|
|
234
|
-
T extends
|
|
235
|
-
HTTPMethod,
|
|
236
|
-
string,
|
|
237
|
-
StandardSchemaV1 | undefined,
|
|
238
|
-
StandardSchemaV1 | undefined,
|
|
239
|
-
string,
|
|
240
|
-
string
|
|
241
|
-
>[],
|
|
242
|
-
> = ExtractGetRoutePaths<T> extends never ? false : true;
|
|
517
|
+
export type HasGetRoutes<T extends readonly AnyFragnoRouteConfig[]> =
|
|
518
|
+
ExtractGetRoutePaths<T> extends never ? false : true;
|
|
243
519
|
|
|
244
520
|
/**
|
|
245
521
|
* @internal
|
|
@@ -255,11 +531,20 @@ export type ObjectContainingStoreField<T extends object> = T extends Store
|
|
|
255
531
|
/**
|
|
256
532
|
* @internal
|
|
257
533
|
*/
|
|
258
|
-
export type
|
|
534
|
+
export type FragnoStoreObjectData<T extends object> = {
|
|
259
535
|
obj: T;
|
|
260
536
|
[STORE_SYMBOL]: true;
|
|
261
537
|
};
|
|
262
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
|
+
|
|
263
548
|
export type FragnoClientHookData<
|
|
264
549
|
TMethod extends HTTPMethod,
|
|
265
550
|
TPath extends string,
|
|
@@ -484,7 +769,9 @@ export function isMutatorHook<
|
|
|
484
769
|
/**
|
|
485
770
|
* @internal
|
|
486
771
|
*/
|
|
487
|
-
export function isStore<TStore extends
|
|
772
|
+
export function isStore<TStore extends object, TArgs extends unknown[] = []>(
|
|
773
|
+
obj: unknown,
|
|
774
|
+
): obj is FragnoStoreData<TStore, TArgs> {
|
|
488
775
|
return (
|
|
489
776
|
typeof obj === "object" && obj !== null && STORE_SYMBOL in obj && obj[STORE_SYMBOL] === true
|
|
490
777
|
);
|
|
@@ -569,8 +856,18 @@ export class ClientBuilder<
|
|
|
569
856
|
return Object.fromEntries(this.#cache.entries());
|
|
570
857
|
}
|
|
571
858
|
|
|
572
|
-
createStore<const T extends object>(
|
|
573
|
-
|
|
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 };
|
|
574
871
|
}
|
|
575
872
|
|
|
576
873
|
/**
|
|
@@ -585,7 +882,10 @@ export class ClientBuilder<
|
|
|
585
882
|
},
|
|
586
883
|
): string {
|
|
587
884
|
const baseUrl = this.#publicConfig.baseUrl ?? "";
|
|
588
|
-
const mountRoute = getMountRoute(
|
|
885
|
+
const mountRoute = getMountRoute({
|
|
886
|
+
name: this.#fragmentConfig.name,
|
|
887
|
+
mountRoute: this.#publicConfig.mountRoute,
|
|
888
|
+
});
|
|
589
889
|
|
|
590
890
|
return buildUrl(
|
|
591
891
|
{ baseUrl, mountRoute, path },
|
|
@@ -611,7 +911,7 @@ export class ClientBuilder<
|
|
|
611
911
|
if (this.#fetcherConfig?.type === "function") {
|
|
612
912
|
return this.#fetcherConfig.fetcher;
|
|
613
913
|
}
|
|
614
|
-
return fetch;
|
|
914
|
+
return globalThis.fetch.bind(globalThis);
|
|
615
915
|
}
|
|
616
916
|
|
|
617
917
|
#getFetcherOptions(): RequestInit | undefined {
|
|
@@ -627,9 +927,11 @@ export class ClientBuilder<
|
|
|
627
927
|
): FragnoClientHookData<
|
|
628
928
|
"GET",
|
|
629
929
|
TPath,
|
|
630
|
-
NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath>["outputSchema"]>,
|
|
631
|
-
NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath>["errorCodes"]>[number],
|
|
632
|
-
NonNullable<
|
|
930
|
+
NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath, "GET">["outputSchema"]>,
|
|
931
|
+
NonNullable<ExtractRouteByPath<TFragmentConfig["routes"], TPath, "GET">["errorCodes"]>[number],
|
|
932
|
+
NonNullable<
|
|
933
|
+
ExtractRouteByPath<TFragmentConfig["routes"], TPath, "GET">["queryParameters"]
|
|
934
|
+
>[number]
|
|
633
935
|
> {
|
|
634
936
|
const route = this.#fragmentConfig.routes.find(
|
|
635
937
|
(
|
|
@@ -717,7 +1019,10 @@ export class ClientBuilder<
|
|
|
717
1019
|
}
|
|
718
1020
|
|
|
719
1021
|
const baseUrl = this.#publicConfig.baseUrl ?? "";
|
|
720
|
-
const mountRoute = getMountRoute(
|
|
1022
|
+
const mountRoute = getMountRoute({
|
|
1023
|
+
name: this.#fragmentConfig.name,
|
|
1024
|
+
mountRoute: this.#publicConfig.mountRoute,
|
|
1025
|
+
});
|
|
721
1026
|
const fetcher = this.#getFetcher();
|
|
722
1027
|
const fetcherOptions = this.#getFetcherOptions();
|
|
723
1028
|
|
|
@@ -908,7 +1213,10 @@ export class ClientBuilder<
|
|
|
908
1213
|
const method = route.method;
|
|
909
1214
|
|
|
910
1215
|
const baseUrl = this.#publicConfig.baseUrl ?? "";
|
|
911
|
-
const mountRoute = getMountRoute(
|
|
1216
|
+
const mountRoute = getMountRoute({
|
|
1217
|
+
name: this.#fragmentConfig.name,
|
|
1218
|
+
mountRoute: this.#publicConfig.mountRoute,
|
|
1219
|
+
});
|
|
912
1220
|
const fetcher = this.#getFetcher();
|
|
913
1221
|
const fetcherOptions = this.#getFetcherOptions();
|
|
914
1222
|
|
|
@@ -944,11 +1252,27 @@ export class ClientBuilder<
|
|
|
944
1252
|
|
|
945
1253
|
let response: Response;
|
|
946
1254
|
try {
|
|
947
|
-
const
|
|
1255
|
+
const { body: preparedBody, headers: bodyHeaders } = prepareRequestBody(
|
|
1256
|
+
body,
|
|
1257
|
+
route.contentType,
|
|
1258
|
+
);
|
|
1259
|
+
|
|
1260
|
+
// Merge headers: fetcherOptions headers + body-specific headers (e.g., Content-Type for JSON)
|
|
1261
|
+
// For FormData, bodyHeaders is undefined and browser sets Content-Type with boundary automatically
|
|
1262
|
+
const mergedHeaders = mergeRequestHeaders(
|
|
1263
|
+
fetcherOptions?.headers as HeadersInit | undefined,
|
|
1264
|
+
bodyHeaders,
|
|
1265
|
+
);
|
|
1266
|
+
|
|
1267
|
+
const requestOptions: RequestInit & { duplex?: "half" } = {
|
|
948
1268
|
...fetcherOptions,
|
|
949
1269
|
method,
|
|
950
|
-
body:
|
|
1270
|
+
body: preparedBody,
|
|
1271
|
+
...(mergedHeaders ? { headers: mergedHeaders } : {}),
|
|
951
1272
|
};
|
|
1273
|
+
if (preparedBody instanceof ReadableStream) {
|
|
1274
|
+
requestOptions.duplex = "half";
|
|
1275
|
+
}
|
|
952
1276
|
response = await fetcher(url, requestOptions);
|
|
953
1277
|
} catch (error) {
|
|
954
1278
|
throw FragnoClientFetchError.fromUnknownFetchError(error);
|
|
@@ -980,9 +1304,7 @@ export class ClientBuilder<
|
|
|
980
1304
|
query?: Record<string, string>;
|
|
981
1305
|
};
|
|
982
1306
|
|
|
983
|
-
|
|
984
|
-
throw new Error("Body is required.");
|
|
985
|
-
}
|
|
1307
|
+
await assertBodyProvided(body, route.inputSchema, "Body is required.");
|
|
986
1308
|
|
|
987
1309
|
const response = await executeMutateQuery({ body, path, query });
|
|
988
1310
|
|
|
@@ -1051,9 +1373,7 @@ export class ClientBuilder<
|
|
|
1051
1373
|
query?: Record<string, string>;
|
|
1052
1374
|
};
|
|
1053
1375
|
|
|
1054
|
-
|
|
1055
|
-
throw new Error("Body is required for mutateQuery");
|
|
1056
|
-
}
|
|
1376
|
+
await assertBodyProvided(body, route.inputSchema, "Body is required for mutateQuery");
|
|
1057
1377
|
|
|
1058
1378
|
const response = await executeMutateQuery({ body, path, query });
|
|
1059
1379
|
|
|
@@ -1130,6 +1450,7 @@ export function createClientBuilder<
|
|
|
1130
1450
|
THandlerThisContext extends RequestThisContext,
|
|
1131
1451
|
TRequestStorage,
|
|
1132
1452
|
const TRoutesOrFactories extends readonly AnyRouteOrFactory[],
|
|
1453
|
+
TInternalRoutes extends readonly AnyRouteOrFactory[] = readonly [],
|
|
1133
1454
|
>(
|
|
1134
1455
|
definition: FragmentDefinition<
|
|
1135
1456
|
TConfig,
|
|
@@ -1141,7 +1462,8 @@ export function createClientBuilder<
|
|
|
1141
1462
|
TPrivateServices,
|
|
1142
1463
|
TServiceThisContext,
|
|
1143
1464
|
THandlerThisContext,
|
|
1144
|
-
TRequestStorage
|
|
1465
|
+
TRequestStorage,
|
|
1466
|
+
TInternalRoutes
|
|
1145
1467
|
>,
|
|
1146
1468
|
publicConfig: FragnoPublicClientConfig,
|
|
1147
1469
|
routesOrFactories: TRoutesOrFactories,
|
|
@@ -1166,7 +1488,10 @@ export function createClientBuilder<
|
|
|
1166
1488
|
routes,
|
|
1167
1489
|
};
|
|
1168
1490
|
|
|
1169
|
-
const mountRoute =
|
|
1491
|
+
const mountRoute = getMountRoute({
|
|
1492
|
+
name: definition.name,
|
|
1493
|
+
mountRoute: publicConfig.mountRoute,
|
|
1494
|
+
});
|
|
1170
1495
|
const mergedFetcherConfig = mergeFetcherConfigs(authorFetcherConfig, publicConfig.fetcherConfig);
|
|
1171
1496
|
const fullPublicConfig = {
|
|
1172
1497
|
...publicConfig,
|