@emeryld/rrroutes-client 2.4.0 → 2.4.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/dist/index.cjs +928 -479
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +923 -475
- package/dist/index.mjs.map +1 -1
- package/dist/routesV3.client.d.ts +4 -0
- package/dist/routesV3.client.get.d.ts +15 -0
- package/dist/routesV3.client.infiniteGet.d.ts +15 -0
- package/dist/routesV3.client.mutation.d.ts +15 -0
- package/dist/routesV3.client.shared.d.ts +44 -0
- package/dist/routesV3.client.types.d.ts +15 -0
- package/package.json +2 -2
- package/dist/routesV3.client.index.d.ts +0 -15
package/dist/index.mjs
CHANGED
|
@@ -51,19 +51,16 @@ var defaultFetcher = async (req) => {
|
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
// src/routesV3.client.
|
|
55
|
-
import {
|
|
56
|
-
buildCacheKey,
|
|
57
|
-
compilePath,
|
|
58
|
-
lowProfileParse
|
|
59
|
-
} from "@emeryld/rrroutes-contract";
|
|
54
|
+
// src/routesV3.client.get.ts
|
|
55
|
+
import { buildCacheKey, lowProfileParse as lowProfileParse2 } from "@emeryld/rrroutes-contract";
|
|
60
56
|
import {
|
|
61
57
|
keepPreviousData,
|
|
62
|
-
useInfiniteQuery,
|
|
63
|
-
useMutation,
|
|
64
58
|
useQuery
|
|
65
59
|
} from "@tanstack/react-query";
|
|
66
60
|
import { useCallback, useRef } from "react";
|
|
61
|
+
|
|
62
|
+
// src/routesV3.client.shared.ts
|
|
63
|
+
import { compilePath, lowProfileParse } from "@emeryld/rrroutes-contract";
|
|
67
64
|
var toUpper = (m) => m.toUpperCase();
|
|
68
65
|
function toSearchString(query) {
|
|
69
66
|
if (!query) return "";
|
|
@@ -74,34 +71,900 @@ function toSearchString(query) {
|
|
|
74
71
|
params.append(k, v);
|
|
75
72
|
continue;
|
|
76
73
|
}
|
|
77
|
-
if (typeof v === "number" || typeof v === "boolean") {
|
|
78
|
-
params.append(k, String(v));
|
|
79
|
-
continue;
|
|
74
|
+
if (typeof v === "number" || typeof v === "boolean") {
|
|
75
|
+
params.append(k, String(v));
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
params.append(k, JSON.stringify(v));
|
|
79
|
+
}
|
|
80
|
+
const s = params.toString();
|
|
81
|
+
return s ? `?${s}` : "";
|
|
82
|
+
}
|
|
83
|
+
function stripKey(obj, key) {
|
|
84
|
+
if (!obj) return obj;
|
|
85
|
+
const { [key]: _omit, ...rest } = obj;
|
|
86
|
+
return rest;
|
|
87
|
+
}
|
|
88
|
+
var defaultGetNextCursor = (p) => {
|
|
89
|
+
if (!p || typeof p !== "object") return void 0;
|
|
90
|
+
const record = p;
|
|
91
|
+
if ("nextCursor" in record) {
|
|
92
|
+
return record.nextCursor;
|
|
93
|
+
}
|
|
94
|
+
if ("meta" in record) {
|
|
95
|
+
const meta = record.meta;
|
|
96
|
+
if (meta && typeof meta === "object" && "nextCursor" in meta) {
|
|
97
|
+
return meta.nextCursor;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return void 0;
|
|
101
|
+
};
|
|
102
|
+
function extractArgs(args) {
|
|
103
|
+
return args[0];
|
|
104
|
+
}
|
|
105
|
+
function toArgsTuple(args) {
|
|
106
|
+
return typeof args === "undefined" ? [] : [args];
|
|
107
|
+
}
|
|
108
|
+
function buildUrl(leaf, baseUrl, params, query) {
|
|
109
|
+
const normalizedParams = leaf.cfg.paramsSchema ? lowProfileParse(leaf.cfg.paramsSchema, params) : {};
|
|
110
|
+
const normalizedQuery = leaf.cfg.querySchema ? lowProfileParse(leaf.cfg.querySchema, query) : {};
|
|
111
|
+
const path = compilePath(
|
|
112
|
+
leaf.path,
|
|
113
|
+
normalizedParams ?? {}
|
|
114
|
+
);
|
|
115
|
+
const url = `${baseUrl ?? ""}${path}${toSearchString(normalizedQuery)}`;
|
|
116
|
+
return { url, normalizedQuery, normalizedParams };
|
|
117
|
+
}
|
|
118
|
+
function toFormData(body) {
|
|
119
|
+
const fd = new FormData();
|
|
120
|
+
for (const [k, v] of Object.entries(body ?? {})) {
|
|
121
|
+
if (v == null) continue;
|
|
122
|
+
if (Array.isArray(v))
|
|
123
|
+
v.forEach((item, i) => fd.append(`${k}[${i}]`, item));
|
|
124
|
+
else fd.append(k, v);
|
|
125
|
+
}
|
|
126
|
+
return fd;
|
|
127
|
+
}
|
|
128
|
+
function getPathParamNames(path) {
|
|
129
|
+
const names = /* @__PURE__ */ new Set();
|
|
130
|
+
const re = /:([A-Za-z0-9_]+)/g;
|
|
131
|
+
let match;
|
|
132
|
+
while ((match = re.exec(path)) !== null) {
|
|
133
|
+
names.add(match[1]);
|
|
134
|
+
}
|
|
135
|
+
return names;
|
|
136
|
+
}
|
|
137
|
+
function normalizeFlatQuery(query) {
|
|
138
|
+
if (query == null) return void 0;
|
|
139
|
+
if (typeof query !== "object" || Array.isArray(query)) {
|
|
140
|
+
throw new Error("Query must be a plain object (Record<string, string>).");
|
|
141
|
+
}
|
|
142
|
+
const result = {};
|
|
143
|
+
for (const [k, v] of Object.entries(query)) {
|
|
144
|
+
if (v == null) continue;
|
|
145
|
+
if (typeof v !== "string") {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Query param "${k}" must be a string; received type "${typeof v}".`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
result[k] = v;
|
|
151
|
+
}
|
|
152
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
153
|
+
}
|
|
154
|
+
function compileRawPath(path, params) {
|
|
155
|
+
const placeholders = getPathParamNames(path);
|
|
156
|
+
if (!params || typeof params !== "object" || Array.isArray(params)) {
|
|
157
|
+
if (placeholders.size > 0) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Missing path parameters for "${path}": ${[...placeholders].join(
|
|
160
|
+
", "
|
|
161
|
+
)}`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return path;
|
|
165
|
+
}
|
|
166
|
+
const paramObj = params;
|
|
167
|
+
const providedNames = new Set(Object.keys(paramObj));
|
|
168
|
+
for (const name of providedNames) {
|
|
169
|
+
if (!placeholders.has(name)) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Unexpected path parameter "${name}" for template "${path}".`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const value = paramObj[name];
|
|
175
|
+
if (value != null && (typeof value === "object" || Array.isArray(value))) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Path parameter "${name}" must be a primitive; received "${typeof value}".`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
for (const name of placeholders) {
|
|
182
|
+
if (!providedNames.has(name)) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Missing value for path parameter "${name}" in template "${path}".`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (placeholders.size === 0) {
|
|
189
|
+
return path;
|
|
190
|
+
}
|
|
191
|
+
return compilePath(path, paramObj);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/routesV3.client.get.ts
|
|
195
|
+
function buildGetLeaf(leaf, rqOpts, env) {
|
|
196
|
+
const leafCfg = leaf.cfg;
|
|
197
|
+
const method = toUpper(leaf.method);
|
|
198
|
+
const expectsArgs = Boolean(leafCfg.paramsSchema || leafCfg.querySchema);
|
|
199
|
+
const {
|
|
200
|
+
baseUrl,
|
|
201
|
+
validateResponses,
|
|
202
|
+
fetcher,
|
|
203
|
+
queryClient,
|
|
204
|
+
emit,
|
|
205
|
+
decorateDebugEvent,
|
|
206
|
+
isVerboseDebug,
|
|
207
|
+
leafLabel
|
|
208
|
+
} = env;
|
|
209
|
+
emit({ type: "build", leaf: leafLabel });
|
|
210
|
+
const getQueryKeys = (...tuple) => {
|
|
211
|
+
const a = extractArgs(tuple);
|
|
212
|
+
const params = a?.params;
|
|
213
|
+
const query = a?.query;
|
|
214
|
+
return buildCacheKey({
|
|
215
|
+
leaf,
|
|
216
|
+
params,
|
|
217
|
+
query
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
const invalidateExact = async (...tuple) => {
|
|
221
|
+
const queryKey = getQueryKeys(...tuple);
|
|
222
|
+
await queryClient.invalidateQueries({ queryKey, exact: true });
|
|
223
|
+
emit({ type: "invalidate", key: queryKey, exact: true });
|
|
224
|
+
};
|
|
225
|
+
const setData = (...args) => {
|
|
226
|
+
const [updater, ...rest] = args;
|
|
227
|
+
const k = getQueryKeys(...rest);
|
|
228
|
+
const next = queryClient.setQueryData(
|
|
229
|
+
k,
|
|
230
|
+
(prev) => typeof updater === "function" ? updater(prev) : updater
|
|
231
|
+
);
|
|
232
|
+
emit({ type: "setData", key: k });
|
|
233
|
+
return next;
|
|
234
|
+
};
|
|
235
|
+
const buildOnReceive = rqOpts?.onReceive ?? void 0;
|
|
236
|
+
const fetchEndpoint = async (tuple, options) => {
|
|
237
|
+
const a = extractArgs(tuple);
|
|
238
|
+
const params = a?.params;
|
|
239
|
+
const query = options?.queryOverride ?? a?.query;
|
|
240
|
+
const { url, normalizedQuery, normalizedParams } = buildUrl(
|
|
241
|
+
{ ...leaf, cfg: leafCfg },
|
|
242
|
+
baseUrl,
|
|
243
|
+
params,
|
|
244
|
+
query
|
|
245
|
+
);
|
|
246
|
+
let payload;
|
|
247
|
+
const acceptsBody = Boolean(leafCfg.bodySchema);
|
|
248
|
+
const requiresBody = options?.requireBody ?? (!acceptsBody ? false : true);
|
|
249
|
+
if (typeof options?.body !== "undefined") {
|
|
250
|
+
const normalizedBody = leafCfg.bodySchema ? lowProfileParse2(leafCfg.bodySchema, options.body) : void 0;
|
|
251
|
+
const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
|
|
252
|
+
if (isMultipart && normalizedBody && typeof normalizedBody === "object") {
|
|
253
|
+
payload = toFormData(normalizedBody);
|
|
254
|
+
} else {
|
|
255
|
+
payload = normalizedBody;
|
|
256
|
+
}
|
|
257
|
+
} else if (requiresBody && acceptsBody) {
|
|
258
|
+
throw new Error("Body is required when invoking a mutation fetch.");
|
|
259
|
+
}
|
|
260
|
+
const startedAt = Date.now();
|
|
261
|
+
const detail = isVerboseDebug ? { params: normalizedParams, query: normalizedQuery } : void 0;
|
|
262
|
+
emit(
|
|
263
|
+
decorateDebugEvent(
|
|
264
|
+
{
|
|
265
|
+
type: "fetch",
|
|
266
|
+
stage: "start",
|
|
267
|
+
method,
|
|
268
|
+
url,
|
|
269
|
+
leaf: leafLabel,
|
|
270
|
+
...payload !== void 0 ? { body: payload } : {}
|
|
271
|
+
},
|
|
272
|
+
detail
|
|
273
|
+
)
|
|
274
|
+
);
|
|
275
|
+
try {
|
|
276
|
+
const out = await fetcher(
|
|
277
|
+
payload === void 0 ? { url, method } : { url, method, body: payload }
|
|
278
|
+
);
|
|
279
|
+
emit(
|
|
280
|
+
decorateDebugEvent(
|
|
281
|
+
{
|
|
282
|
+
type: "fetch",
|
|
283
|
+
stage: "fetched",
|
|
284
|
+
method,
|
|
285
|
+
url,
|
|
286
|
+
leaf: leafLabel,
|
|
287
|
+
durationMs: Date.now() - startedAt
|
|
288
|
+
},
|
|
289
|
+
isVerboseDebug ? {
|
|
290
|
+
params: normalizedParams,
|
|
291
|
+
query: normalizedQuery,
|
|
292
|
+
output: out
|
|
293
|
+
} : void 0
|
|
294
|
+
)
|
|
295
|
+
);
|
|
296
|
+
if (validateResponses) {
|
|
297
|
+
if (!leafCfg.outputSchema) {
|
|
298
|
+
throw new Error(
|
|
299
|
+
`No output schema defined for leaf ${leafLabel}, cannot validate response.`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
out.data = lowProfileParse2(
|
|
303
|
+
leafCfg.outputSchema,
|
|
304
|
+
out.data
|
|
305
|
+
);
|
|
306
|
+
emit(
|
|
307
|
+
decorateDebugEvent(
|
|
308
|
+
{
|
|
309
|
+
type: "fetch",
|
|
310
|
+
stage: "parsed",
|
|
311
|
+
method,
|
|
312
|
+
url,
|
|
313
|
+
leaf: leafLabel,
|
|
314
|
+
durationMs: Date.now() - startedAt
|
|
315
|
+
},
|
|
316
|
+
isVerboseDebug ? {
|
|
317
|
+
params: normalizedParams,
|
|
318
|
+
query: normalizedQuery,
|
|
319
|
+
output: out
|
|
320
|
+
} : void 0
|
|
321
|
+
)
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
options?.onReceive?.(out.data);
|
|
325
|
+
return out.data;
|
|
326
|
+
} catch (error) {
|
|
327
|
+
emit(
|
|
328
|
+
decorateDebugEvent(
|
|
329
|
+
{
|
|
330
|
+
type: "fetch",
|
|
331
|
+
stage: "error",
|
|
332
|
+
method,
|
|
333
|
+
url,
|
|
334
|
+
leaf: leafLabel,
|
|
335
|
+
durationMs: Date.now() - startedAt,
|
|
336
|
+
...payload !== void 0 ? { body: payload } : {},
|
|
337
|
+
error
|
|
338
|
+
},
|
|
339
|
+
detail
|
|
340
|
+
)
|
|
341
|
+
);
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const fetchGet = (...tupleWithBody) => {
|
|
346
|
+
const acceptsBody = Boolean(leafCfg.bodySchema);
|
|
347
|
+
const tupleLength = tupleWithBody.length;
|
|
348
|
+
const maybeBodyIndex = expectsArgs ? 1 : 0;
|
|
349
|
+
const hasBodyCandidate = acceptsBody && tupleLength > maybeBodyIndex;
|
|
350
|
+
const body = hasBodyCandidate ? tupleWithBody[tupleLength - 1] : void 0;
|
|
351
|
+
const tuple = hasBodyCandidate ? tupleWithBody.slice(0, tupleLength - 1) : tupleWithBody;
|
|
352
|
+
return fetchEndpoint(tuple, {
|
|
353
|
+
body,
|
|
354
|
+
onReceive: buildOnReceive,
|
|
355
|
+
requireBody: false
|
|
356
|
+
});
|
|
357
|
+
};
|
|
358
|
+
const useEndpoint = (...useArgs) => {
|
|
359
|
+
const args = useArgs[0];
|
|
360
|
+
const tuple = toArgsTuple(args);
|
|
361
|
+
const queryKeys = getQueryKeys(...tuple);
|
|
362
|
+
emit({
|
|
363
|
+
type: "useEndpoint",
|
|
364
|
+
leaf: leafLabel,
|
|
365
|
+
variant: "get",
|
|
366
|
+
keys: queryKeys
|
|
367
|
+
});
|
|
368
|
+
const buildOptions = rqOpts ?? {};
|
|
369
|
+
const listenersRef = useRef(/* @__PURE__ */ new Set());
|
|
370
|
+
const notifyOnReceive = useCallback((data) => {
|
|
371
|
+
buildOptions?.onReceive?.(data);
|
|
372
|
+
listenersRef.current.forEach((listener) => listener(data));
|
|
373
|
+
}, []);
|
|
374
|
+
const registerOnReceive = useCallback(
|
|
375
|
+
(listener) => {
|
|
376
|
+
listenersRef.current.add(listener);
|
|
377
|
+
return () => {
|
|
378
|
+
listenersRef.current.delete(listener);
|
|
379
|
+
};
|
|
380
|
+
},
|
|
381
|
+
[]
|
|
382
|
+
);
|
|
383
|
+
const queryResult = useQuery(
|
|
384
|
+
{
|
|
385
|
+
...buildOptions,
|
|
386
|
+
queryKey: getQueryKeys(...tuple),
|
|
387
|
+
placeholderData: keepPreviousData,
|
|
388
|
+
queryFn: () => fetchEndpoint(tuple, {
|
|
389
|
+
onReceive: notifyOnReceive
|
|
390
|
+
})
|
|
391
|
+
},
|
|
392
|
+
queryClient
|
|
393
|
+
);
|
|
394
|
+
return { ...queryResult, onReceive: registerOnReceive };
|
|
395
|
+
};
|
|
396
|
+
return {
|
|
397
|
+
getQueryKeys,
|
|
398
|
+
invalidate: invalidateExact,
|
|
399
|
+
setData,
|
|
400
|
+
useEndpoint,
|
|
401
|
+
fetch: fetchGet
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// src/routesV3.client.infiniteGet.ts
|
|
406
|
+
import { buildCacheKey as buildCacheKey2, lowProfileParse as lowProfileParse3 } from "@emeryld/rrroutes-contract";
|
|
407
|
+
import {
|
|
408
|
+
keepPreviousData as keepPreviousData2,
|
|
409
|
+
useInfiniteQuery
|
|
410
|
+
} from "@tanstack/react-query";
|
|
411
|
+
import { useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
412
|
+
function mergePageOutputs(prev, next) {
|
|
413
|
+
if (prev == null) return next;
|
|
414
|
+
if (next == null) return prev;
|
|
415
|
+
if (Array.isArray(prev) && Array.isArray(next)) {
|
|
416
|
+
return [...prev, ...next];
|
|
417
|
+
}
|
|
418
|
+
if (typeof prev !== "object" || typeof next !== "object") {
|
|
419
|
+
return next;
|
|
420
|
+
}
|
|
421
|
+
const merged = { ...prev };
|
|
422
|
+
for (const key of Object.keys(next)) {
|
|
423
|
+
const pv = prev[key];
|
|
424
|
+
const nv = next[key];
|
|
425
|
+
if (Array.isArray(pv) && Array.isArray(nv)) {
|
|
426
|
+
merged[key] = [...pv, ...nv];
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (pv && typeof pv === "object" && !Array.isArray(pv) && nv && typeof nv === "object" && !Array.isArray(nv)) {
|
|
430
|
+
if (key === "meta") {
|
|
431
|
+
merged[key] = mergePageOutputs(pv, nv);
|
|
432
|
+
} else {
|
|
433
|
+
merged[key] = nv;
|
|
434
|
+
}
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
merged[key] = nv;
|
|
438
|
+
}
|
|
439
|
+
return merged;
|
|
440
|
+
}
|
|
441
|
+
function buildInfiniteGetLeaf(leaf, rqOpts, env) {
|
|
442
|
+
const leafCfg = leaf.cfg;
|
|
443
|
+
const method = toUpper(leaf.method);
|
|
444
|
+
const expectsArgs = Boolean(leafCfg.paramsSchema || leafCfg.querySchema);
|
|
445
|
+
const {
|
|
446
|
+
baseUrl,
|
|
447
|
+
validateResponses,
|
|
448
|
+
fetcher,
|
|
449
|
+
queryClient,
|
|
450
|
+
emit,
|
|
451
|
+
decorateDebugEvent,
|
|
452
|
+
isVerboseDebug,
|
|
453
|
+
leafLabel
|
|
454
|
+
} = env;
|
|
455
|
+
emit({ type: "build", leaf: leafLabel });
|
|
456
|
+
const infiniteOptions = rqOpts ?? {};
|
|
457
|
+
const {
|
|
458
|
+
cursorParam,
|
|
459
|
+
getNextPageParam,
|
|
460
|
+
initialPageParam,
|
|
461
|
+
splitPageSize,
|
|
462
|
+
splitPageSizeParam,
|
|
463
|
+
...passthroughOptions
|
|
464
|
+
} = infiniteOptions;
|
|
465
|
+
const feedCursorParam = cursorParam ?? "pagination_cursor";
|
|
466
|
+
const feedNextPageParam = getNextPageParam ?? ((lastPage) => defaultGetNextCursor(lastPage));
|
|
467
|
+
const cursorFromPage = (page) => feedNextPageParam(page);
|
|
468
|
+
const feedInitialPageParam = typeof initialPageParam === "undefined" ? void 0 : initialPageParam;
|
|
469
|
+
const feedQueryOptions = passthroughOptions;
|
|
470
|
+
const effectiveSplitPageSize = typeof splitPageSize === "number" && splitPageSize > 0 ? splitPageSize : void 0;
|
|
471
|
+
const effectiveSplitPageSizeParam = splitPageSizeParam ?? "pageSize";
|
|
472
|
+
const getQueryKeys = (...tuple) => {
|
|
473
|
+
const a = extractArgs(tuple);
|
|
474
|
+
const params = a?.params;
|
|
475
|
+
const query = a?.query;
|
|
476
|
+
const qForKey = stripKey(query, feedCursorParam);
|
|
477
|
+
return buildCacheKey2({
|
|
478
|
+
leaf,
|
|
479
|
+
params,
|
|
480
|
+
query: qForKey
|
|
481
|
+
});
|
|
482
|
+
};
|
|
483
|
+
const invalidateExact = async (...tuple) => {
|
|
484
|
+
const queryKey = getQueryKeys(...tuple);
|
|
485
|
+
await queryClient.invalidateQueries({ queryKey, exact: true });
|
|
486
|
+
emit({ type: "invalidate", key: queryKey, exact: true });
|
|
487
|
+
};
|
|
488
|
+
const setData = (...args) => {
|
|
489
|
+
const [updater, ...rest] = args;
|
|
490
|
+
const k = getQueryKeys(...rest);
|
|
491
|
+
const next = queryClient.setQueryData(
|
|
492
|
+
k,
|
|
493
|
+
(prev) => typeof updater === "function" ? updater(prev) : updater
|
|
494
|
+
);
|
|
495
|
+
emit({ type: "setData", key: k });
|
|
496
|
+
return next;
|
|
497
|
+
};
|
|
498
|
+
const buildOnReceive = rqOpts?.onReceive ?? void 0;
|
|
499
|
+
const fetchEndpoint = async (tuple, options) => {
|
|
500
|
+
const a = extractArgs(tuple);
|
|
501
|
+
const params = a?.params;
|
|
502
|
+
const query = options?.queryOverride ?? a?.query;
|
|
503
|
+
const { url, normalizedQuery, normalizedParams } = buildUrl(
|
|
504
|
+
{ ...leaf, cfg: leafCfg },
|
|
505
|
+
baseUrl,
|
|
506
|
+
params,
|
|
507
|
+
query
|
|
508
|
+
);
|
|
509
|
+
let payload;
|
|
510
|
+
const acceptsBody = Boolean(leafCfg.bodySchema);
|
|
511
|
+
const requiresBody = options?.requireBody ?? (!acceptsBody ? false : true);
|
|
512
|
+
if (typeof options?.body !== "undefined") {
|
|
513
|
+
const normalizedBody = leafCfg.bodySchema ? lowProfileParse3(leafCfg.bodySchema, options.body) : void 0;
|
|
514
|
+
const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
|
|
515
|
+
if (isMultipart && normalizedBody && typeof normalizedBody === "object") {
|
|
516
|
+
payload = toFormData(normalizedBody);
|
|
517
|
+
} else {
|
|
518
|
+
payload = normalizedBody;
|
|
519
|
+
}
|
|
520
|
+
} else if (requiresBody && acceptsBody) {
|
|
521
|
+
throw new Error("Body is required when invoking a mutation fetch.");
|
|
522
|
+
}
|
|
523
|
+
const startedAt = Date.now();
|
|
524
|
+
const detail = isVerboseDebug ? { params: normalizedParams, query: normalizedQuery } : void 0;
|
|
525
|
+
emit(
|
|
526
|
+
decorateDebugEvent(
|
|
527
|
+
{
|
|
528
|
+
type: "fetch",
|
|
529
|
+
stage: "start",
|
|
530
|
+
method,
|
|
531
|
+
url,
|
|
532
|
+
leaf: leafLabel,
|
|
533
|
+
...payload !== void 0 ? { body: payload } : {}
|
|
534
|
+
},
|
|
535
|
+
detail
|
|
536
|
+
)
|
|
537
|
+
);
|
|
538
|
+
try {
|
|
539
|
+
const out = await fetcher(
|
|
540
|
+
payload === void 0 ? { url, method } : { url, method, body: payload }
|
|
541
|
+
);
|
|
542
|
+
emit(
|
|
543
|
+
decorateDebugEvent(
|
|
544
|
+
{
|
|
545
|
+
type: "fetch",
|
|
546
|
+
stage: "fetched",
|
|
547
|
+
method,
|
|
548
|
+
url,
|
|
549
|
+
leaf: leafLabel,
|
|
550
|
+
durationMs: Date.now() - startedAt
|
|
551
|
+
},
|
|
552
|
+
isVerboseDebug ? {
|
|
553
|
+
params: normalizedParams,
|
|
554
|
+
query: normalizedQuery,
|
|
555
|
+
output: out
|
|
556
|
+
} : void 0
|
|
557
|
+
)
|
|
558
|
+
);
|
|
559
|
+
if (validateResponses) {
|
|
560
|
+
if (!leafCfg.outputSchema) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
`No output schema defined for leaf ${leafLabel}, cannot validate response.`
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
out.data = lowProfileParse3(
|
|
566
|
+
leafCfg.outputSchema,
|
|
567
|
+
out.data
|
|
568
|
+
);
|
|
569
|
+
emit(
|
|
570
|
+
decorateDebugEvent(
|
|
571
|
+
{
|
|
572
|
+
type: "fetch",
|
|
573
|
+
stage: "parsed",
|
|
574
|
+
method,
|
|
575
|
+
url,
|
|
576
|
+
leaf: leafLabel,
|
|
577
|
+
durationMs: Date.now() - startedAt
|
|
578
|
+
},
|
|
579
|
+
isVerboseDebug ? {
|
|
580
|
+
params: normalizedParams,
|
|
581
|
+
query: normalizedQuery,
|
|
582
|
+
output: out
|
|
583
|
+
} : void 0
|
|
584
|
+
)
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
options?.onReceive?.(out.data);
|
|
588
|
+
return out.data;
|
|
589
|
+
} catch (error) {
|
|
590
|
+
emit(
|
|
591
|
+
decorateDebugEvent(
|
|
592
|
+
{
|
|
593
|
+
type: "fetch",
|
|
594
|
+
stage: "error",
|
|
595
|
+
method,
|
|
596
|
+
url,
|
|
597
|
+
leaf: leafLabel,
|
|
598
|
+
durationMs: Date.now() - startedAt,
|
|
599
|
+
...payload !== void 0 ? { body: payload } : {},
|
|
600
|
+
error
|
|
601
|
+
},
|
|
602
|
+
detail
|
|
603
|
+
)
|
|
604
|
+
);
|
|
605
|
+
throw error;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
const fetchGet = (...tupleWithBody) => {
|
|
609
|
+
const acceptsBody = Boolean(leafCfg.bodySchema);
|
|
610
|
+
const tupleLength = tupleWithBody.length;
|
|
611
|
+
const maybeBodyIndex = expectsArgs ? 1 : 0;
|
|
612
|
+
const hasBodyCandidate = acceptsBody && tupleLength > maybeBodyIndex;
|
|
613
|
+
const body = hasBodyCandidate ? tupleWithBody[tupleLength - 1] : void 0;
|
|
614
|
+
const tuple = hasBodyCandidate ? tupleWithBody.slice(0, tupleLength - 1) : tupleWithBody;
|
|
615
|
+
return fetchEndpoint(tuple, {
|
|
616
|
+
body,
|
|
617
|
+
onReceive: buildOnReceive,
|
|
618
|
+
requireBody: false
|
|
619
|
+
});
|
|
620
|
+
};
|
|
621
|
+
const useEndpoint = (...useArgs) => {
|
|
622
|
+
const args = useArgs[0];
|
|
623
|
+
const tuple = toArgsTuple(args);
|
|
624
|
+
const queryKeys = getQueryKeys(...tuple);
|
|
625
|
+
emit({
|
|
626
|
+
type: "useEndpoint",
|
|
627
|
+
leaf: leafLabel,
|
|
628
|
+
variant: "infiniteGet",
|
|
629
|
+
keys: queryKeys
|
|
630
|
+
});
|
|
631
|
+
const params = args?.params;
|
|
632
|
+
const query = args?.query;
|
|
633
|
+
const buildOptions = feedQueryOptions ?? {};
|
|
634
|
+
const listenersRef = useRef2(/* @__PURE__ */ new Set());
|
|
635
|
+
const notifyOnReceive = useCallback2((data) => {
|
|
636
|
+
buildOptions?.onReceive?.(data);
|
|
637
|
+
listenersRef.current.forEach((listener) => listener(data));
|
|
638
|
+
}, []);
|
|
639
|
+
const registerOnReceive = useCallback2(
|
|
640
|
+
(listener) => {
|
|
641
|
+
listenersRef.current.add(listener);
|
|
642
|
+
return () => {
|
|
643
|
+
listenersRef.current.delete(listener);
|
|
644
|
+
};
|
|
645
|
+
},
|
|
646
|
+
[]
|
|
647
|
+
);
|
|
648
|
+
const { normalizedQuery, normalizedParams } = buildUrl(
|
|
649
|
+
{ ...leaf, cfg: leafCfg },
|
|
650
|
+
baseUrl,
|
|
651
|
+
params,
|
|
652
|
+
query
|
|
653
|
+
);
|
|
654
|
+
const queryResult = useInfiniteQuery(
|
|
655
|
+
{
|
|
656
|
+
...buildOptions,
|
|
657
|
+
placeholderData: buildOptions.placeholderData ?? keepPreviousData2,
|
|
658
|
+
initialPageParam: feedInitialPageParam,
|
|
659
|
+
getNextPageParam: (lastPage) => cursorFromPage(lastPage),
|
|
660
|
+
queryKey: queryKeys,
|
|
661
|
+
queryFn: ({ pageParam }) => {
|
|
662
|
+
if (!effectiveSplitPageSize) {
|
|
663
|
+
const pageQuery = {
|
|
664
|
+
...normalizedQuery,
|
|
665
|
+
...pageParam ? { [feedCursorParam]: pageParam } : {}
|
|
666
|
+
};
|
|
667
|
+
return fetchEndpoint(tuple, {
|
|
668
|
+
queryOverride: pageQuery,
|
|
669
|
+
onReceive: notifyOnReceive
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
const basePageSizeRaw = normalizedQuery?.[effectiveSplitPageSizeParam];
|
|
673
|
+
const basePageSize = typeof basePageSizeRaw === "number" ? basePageSizeRaw : basePageSizeRaw != null ? Number(basePageSizeRaw) : void 0;
|
|
674
|
+
if (!basePageSize || !Number.isFinite(basePageSize) || basePageSize <= effectiveSplitPageSize) {
|
|
675
|
+
const pageQuery = {
|
|
676
|
+
...normalizedQuery,
|
|
677
|
+
...pageParam ? { [feedCursorParam]: pageParam } : {}
|
|
678
|
+
};
|
|
679
|
+
return fetchEndpoint(tuple, {
|
|
680
|
+
queryOverride: pageQuery,
|
|
681
|
+
onReceive: notifyOnReceive
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
const totalTarget = basePageSize;
|
|
685
|
+
const pageParamForThisPage = pageParam;
|
|
686
|
+
const runSplitFetch = async () => {
|
|
687
|
+
let remaining = totalTarget;
|
|
688
|
+
let currentCursor = pageParam;
|
|
689
|
+
let aggregated;
|
|
690
|
+
while (remaining > 0) {
|
|
691
|
+
const thisCallSize = Math.min(remaining, effectiveSplitPageSize);
|
|
692
|
+
const splitQuery = {
|
|
693
|
+
...normalizedQuery,
|
|
694
|
+
...currentCursor ? { [feedCursorParam]: currentCursor } : {},
|
|
695
|
+
[effectiveSplitPageSizeParam]: thisCallSize
|
|
696
|
+
};
|
|
697
|
+
const page = await fetchEndpoint(tuple, {
|
|
698
|
+
queryOverride: splitQuery,
|
|
699
|
+
onReceive: notifyOnReceive
|
|
700
|
+
});
|
|
701
|
+
aggregated = aggregated ? mergePageOutputs(aggregated, page) : page;
|
|
702
|
+
remaining -= thisCallSize;
|
|
703
|
+
const nextCursor = cursorFromPage(page);
|
|
704
|
+
currentCursor = nextCursor;
|
|
705
|
+
const k = queryKeys;
|
|
706
|
+
queryClient.setQueryData(k, (prev) => {
|
|
707
|
+
if (!aggregated) return prev;
|
|
708
|
+
if (!prev) {
|
|
709
|
+
return {
|
|
710
|
+
pages: [aggregated],
|
|
711
|
+
pageParams: [pageParamForThisPage]
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
const idx = prev.pageParams.findIndex(
|
|
715
|
+
(p) => p === pageParamForThisPage || p == null && pageParamForThisPage == null
|
|
716
|
+
);
|
|
717
|
+
if (idx === -1) {
|
|
718
|
+
return {
|
|
719
|
+
pages: [...prev.pages, aggregated],
|
|
720
|
+
pageParams: [...prev.pageParams, pageParamForThisPage]
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
const newPages = [...prev.pages];
|
|
724
|
+
newPages[idx] = aggregated;
|
|
725
|
+
return { ...prev, pages: newPages };
|
|
726
|
+
});
|
|
727
|
+
if (!nextCursor) {
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return aggregated;
|
|
732
|
+
};
|
|
733
|
+
return runSplitFetch();
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
queryClient
|
|
737
|
+
);
|
|
738
|
+
return { ...queryResult, onReceive: registerOnReceive };
|
|
739
|
+
};
|
|
740
|
+
return {
|
|
741
|
+
getQueryKeys,
|
|
742
|
+
invalidate: invalidateExact,
|
|
743
|
+
setData,
|
|
744
|
+
useEndpoint,
|
|
745
|
+
fetch: fetchGet
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/routesV3.client.mutation.ts
|
|
750
|
+
import { buildCacheKey as buildCacheKey3, lowProfileParse as lowProfileParse4 } from "@emeryld/rrroutes-contract";
|
|
751
|
+
import {
|
|
752
|
+
useMutation
|
|
753
|
+
} from "@tanstack/react-query";
|
|
754
|
+
import { useCallback as useCallback3, useRef as useRef3 } from "react";
|
|
755
|
+
function buildMutationLeaf(leaf, rqOpts, env) {
|
|
756
|
+
const leafCfg = leaf.cfg;
|
|
757
|
+
const method = toUpper(leaf.method);
|
|
758
|
+
const expectsArgs = Boolean(leafCfg.paramsSchema || leafCfg.querySchema);
|
|
759
|
+
const {
|
|
760
|
+
baseUrl,
|
|
761
|
+
validateResponses,
|
|
762
|
+
fetcher,
|
|
763
|
+
queryClient,
|
|
764
|
+
emit,
|
|
765
|
+
decorateDebugEvent,
|
|
766
|
+
isVerboseDebug,
|
|
767
|
+
leafLabel
|
|
768
|
+
} = env;
|
|
769
|
+
emit({ type: "build", leaf: leafLabel });
|
|
770
|
+
const getQueryKeys = (...tuple) => {
|
|
771
|
+
const a = extractArgs(tuple);
|
|
772
|
+
const params = a?.params;
|
|
773
|
+
const query = a?.query;
|
|
774
|
+
return buildCacheKey3({
|
|
775
|
+
leaf,
|
|
776
|
+
params,
|
|
777
|
+
query
|
|
778
|
+
});
|
|
779
|
+
};
|
|
780
|
+
const invalidateExact = async (...tuple) => {
|
|
781
|
+
const queryKey = getQueryKeys(...tuple);
|
|
782
|
+
await queryClient.invalidateQueries({ queryKey, exact: true });
|
|
783
|
+
emit({ type: "invalidate", key: queryKey, exact: true });
|
|
784
|
+
};
|
|
785
|
+
const setData = (...args) => {
|
|
786
|
+
const [updater, ...rest] = args;
|
|
787
|
+
const k = getQueryKeys(...rest);
|
|
788
|
+
const next = queryClient.setQueryData(
|
|
789
|
+
k,
|
|
790
|
+
(prev) => typeof updater === "function" ? updater(prev) : updater
|
|
791
|
+
);
|
|
792
|
+
emit({ type: "setData", key: k });
|
|
793
|
+
return next;
|
|
794
|
+
};
|
|
795
|
+
const mutationBuildOptions = rqOpts ?? {};
|
|
796
|
+
const fetchEndpoint = async (tuple, options) => {
|
|
797
|
+
const a = extractArgs(tuple);
|
|
798
|
+
const params = a?.params;
|
|
799
|
+
const query = options?.queryOverride ?? a?.query;
|
|
800
|
+
const { url, normalizedQuery, normalizedParams } = buildUrl(
|
|
801
|
+
{ ...leaf, cfg: leafCfg },
|
|
802
|
+
baseUrl,
|
|
803
|
+
params,
|
|
804
|
+
query
|
|
805
|
+
);
|
|
806
|
+
let payload;
|
|
807
|
+
const acceptsBody = Boolean(leafCfg.bodySchema);
|
|
808
|
+
const requiresBody = options?.requireBody ?? (!acceptsBody ? false : true);
|
|
809
|
+
if (typeof options?.body !== "undefined") {
|
|
810
|
+
const normalizedBody = leafCfg.bodySchema ? lowProfileParse4(leafCfg.bodySchema, options.body) : void 0;
|
|
811
|
+
const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
|
|
812
|
+
if (isMultipart && normalizedBody && typeof normalizedBody === "object") {
|
|
813
|
+
payload = toFormData(normalizedBody);
|
|
814
|
+
} else {
|
|
815
|
+
payload = normalizedBody;
|
|
816
|
+
}
|
|
817
|
+
} else if (requiresBody && acceptsBody) {
|
|
818
|
+
throw new Error("Body is required when invoking a mutation fetch.");
|
|
819
|
+
}
|
|
820
|
+
const startedAt = Date.now();
|
|
821
|
+
const detail = isVerboseDebug ? { params: normalizedParams, query: normalizedQuery } : void 0;
|
|
822
|
+
emit(
|
|
823
|
+
decorateDebugEvent(
|
|
824
|
+
{
|
|
825
|
+
type: "fetch",
|
|
826
|
+
stage: "start",
|
|
827
|
+
method,
|
|
828
|
+
url,
|
|
829
|
+
leaf: leafLabel,
|
|
830
|
+
...payload !== void 0 ? { body: payload } : {}
|
|
831
|
+
},
|
|
832
|
+
detail
|
|
833
|
+
)
|
|
834
|
+
);
|
|
835
|
+
try {
|
|
836
|
+
const out = await fetcher(
|
|
837
|
+
payload === void 0 ? { url, method } : { url, method, body: payload }
|
|
838
|
+
);
|
|
839
|
+
emit(
|
|
840
|
+
decorateDebugEvent(
|
|
841
|
+
{
|
|
842
|
+
type: "fetch",
|
|
843
|
+
stage: "fetched",
|
|
844
|
+
method,
|
|
845
|
+
url,
|
|
846
|
+
leaf: leafLabel,
|
|
847
|
+
durationMs: Date.now() - startedAt
|
|
848
|
+
},
|
|
849
|
+
isVerboseDebug ? {
|
|
850
|
+
params: normalizedParams,
|
|
851
|
+
query: normalizedQuery,
|
|
852
|
+
output: out
|
|
853
|
+
} : void 0
|
|
854
|
+
)
|
|
855
|
+
);
|
|
856
|
+
if (validateResponses) {
|
|
857
|
+
if (!leafCfg.outputSchema) {
|
|
858
|
+
throw new Error(
|
|
859
|
+
`No output schema defined for leaf ${leafLabel}, cannot validate response.`
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
out.data = lowProfileParse4(
|
|
863
|
+
leafCfg.outputSchema,
|
|
864
|
+
out.data
|
|
865
|
+
);
|
|
866
|
+
emit(
|
|
867
|
+
decorateDebugEvent(
|
|
868
|
+
{
|
|
869
|
+
type: "fetch",
|
|
870
|
+
stage: "parsed",
|
|
871
|
+
method,
|
|
872
|
+
url,
|
|
873
|
+
leaf: leafLabel,
|
|
874
|
+
durationMs: Date.now() - startedAt
|
|
875
|
+
},
|
|
876
|
+
isVerboseDebug ? {
|
|
877
|
+
params: normalizedParams,
|
|
878
|
+
query: normalizedQuery,
|
|
879
|
+
output: out
|
|
880
|
+
} : void 0
|
|
881
|
+
)
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
options?.onReceive?.(out.data);
|
|
885
|
+
return out.data;
|
|
886
|
+
} catch (error) {
|
|
887
|
+
emit(
|
|
888
|
+
decorateDebugEvent(
|
|
889
|
+
{
|
|
890
|
+
type: "fetch",
|
|
891
|
+
stage: "error",
|
|
892
|
+
method,
|
|
893
|
+
url,
|
|
894
|
+
leaf: leafLabel,
|
|
895
|
+
durationMs: Date.now() - startedAt,
|
|
896
|
+
...payload !== void 0 ? { body: payload } : {},
|
|
897
|
+
error
|
|
898
|
+
},
|
|
899
|
+
detail
|
|
900
|
+
)
|
|
901
|
+
);
|
|
902
|
+
throw error;
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
const fetchMutation = async (...tupleWithBody) => {
|
|
906
|
+
if (tupleWithBody.length === 0) {
|
|
907
|
+
throw new Error("Body is required when invoking a mutation fetch.");
|
|
80
908
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
909
|
+
const bodyIndex = tupleWithBody.length - 1;
|
|
910
|
+
const tuple = tupleWithBody.slice(0, bodyIndex);
|
|
911
|
+
const body = tupleWithBody[bodyIndex];
|
|
912
|
+
const result = await fetchEndpoint(tuple, {
|
|
913
|
+
body,
|
|
914
|
+
onReceive: (data) => mutationBuildOptions?.onReceive?.(data),
|
|
915
|
+
requireBody: true
|
|
916
|
+
});
|
|
917
|
+
return result;
|
|
918
|
+
};
|
|
919
|
+
const useEndpoint = (...useArgs) => {
|
|
920
|
+
const args = useArgs[0];
|
|
921
|
+
const tuple = toArgsTuple(args);
|
|
922
|
+
const mutationKey = getQueryKeys(...tuple);
|
|
923
|
+
emit({
|
|
924
|
+
type: "useEndpoint",
|
|
925
|
+
leaf: leafLabel,
|
|
926
|
+
variant: "mutation",
|
|
927
|
+
keys: mutationKey
|
|
928
|
+
});
|
|
929
|
+
const listenersRef = useRef3(/* @__PURE__ */ new Set());
|
|
930
|
+
const notifyListeners = useCallback3((data) => {
|
|
931
|
+
listenersRef.current.forEach((listener) => listener(data));
|
|
932
|
+
}, []);
|
|
933
|
+
const registerOnReceive = useCallback3(
|
|
934
|
+
(listener) => {
|
|
935
|
+
listenersRef.current.add(listener);
|
|
936
|
+
return () => {
|
|
937
|
+
listenersRef.current.delete(listener);
|
|
938
|
+
};
|
|
939
|
+
},
|
|
940
|
+
[]
|
|
941
|
+
);
|
|
942
|
+
const mutationResult = useMutation(
|
|
943
|
+
{
|
|
944
|
+
...mutationBuildOptions ?? {},
|
|
945
|
+
mutationKey,
|
|
946
|
+
mutationFn: async (body) => {
|
|
947
|
+
const result = await fetchMutation(
|
|
948
|
+
...[...tuple, body]
|
|
949
|
+
);
|
|
950
|
+
notifyListeners(result);
|
|
951
|
+
return result;
|
|
952
|
+
}
|
|
953
|
+
},
|
|
954
|
+
queryClient
|
|
955
|
+
);
|
|
956
|
+
return { ...mutationResult, onReceive: registerOnReceive };
|
|
957
|
+
};
|
|
958
|
+
return {
|
|
959
|
+
getQueryKeys,
|
|
960
|
+
invalidate: invalidateExact,
|
|
961
|
+
setData,
|
|
962
|
+
useEndpoint,
|
|
963
|
+
fetch: fetchMutation
|
|
964
|
+
};
|
|
90
965
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const record = p;
|
|
94
|
-
if ("nextCursor" in record) {
|
|
95
|
-
return record.nextCursor;
|
|
96
|
-
}
|
|
97
|
-
if ("meta" in record) {
|
|
98
|
-
const meta = record.meta;
|
|
99
|
-
if (meta && typeof meta === "object" && "nextCursor" in meta) {
|
|
100
|
-
return meta.nextCursor;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return void 0;
|
|
104
|
-
};
|
|
966
|
+
|
|
967
|
+
// src/routesV3.client.ts
|
|
105
968
|
var defaultDebugLogger = (event) => {
|
|
106
969
|
if (typeof console === "undefined") return;
|
|
107
970
|
const fn = console.debug ?? console.log;
|
|
@@ -163,22 +1026,6 @@ function createDebugEmitter(option, environment) {
|
|
|
163
1026
|
}
|
|
164
1027
|
return disabled;
|
|
165
1028
|
}
|
|
166
|
-
function extractArgs(args) {
|
|
167
|
-
return args[0];
|
|
168
|
-
}
|
|
169
|
-
function toArgsTuple(args) {
|
|
170
|
-
return typeof args === "undefined" ? [] : [args];
|
|
171
|
-
}
|
|
172
|
-
function buildUrl(leaf, baseUrl, params, query) {
|
|
173
|
-
const normalizedParams = leaf.cfg.paramsSchema ? lowProfileParse(leaf.cfg.paramsSchema, params) : {};
|
|
174
|
-
const normalizedQuery = leaf.cfg.querySchema ? lowProfileParse(leaf.cfg.querySchema, query) : {};
|
|
175
|
-
const path = compilePath(
|
|
176
|
-
leaf.path,
|
|
177
|
-
normalizedParams ?? {}
|
|
178
|
-
);
|
|
179
|
-
const url = `${baseUrl ?? ""}${path}${toSearchString(normalizedQuery)}`;
|
|
180
|
-
return { url, normalizedQuery, normalizedParams };
|
|
181
|
-
}
|
|
182
1029
|
function createRouteClient(opts) {
|
|
183
1030
|
const queryClient = opts.queryClient;
|
|
184
1031
|
const fetcher = opts.fetcher ?? defaultFetcher;
|
|
@@ -199,365 +1046,41 @@ function createRouteClient(opts) {
|
|
|
199
1046
|
emitDebug({ type: "invalidate", key: queryKey, exact });
|
|
200
1047
|
}
|
|
201
1048
|
function buildInternal(leaf, rqOpts, meta) {
|
|
202
|
-
const isGet = leaf.method === "get";
|
|
203
|
-
const isFeed = !!leaf.cfg.feed;
|
|
204
|
-
const leafCfg = leaf.cfg;
|
|
205
|
-
const validateResponses = opts.validateResponses ?? true;
|
|
206
|
-
const method = toUpper(leaf.method);
|
|
207
|
-
const expectsArgs = Boolean(leafCfg.paramsSchema || leafCfg.querySchema);
|
|
208
1049
|
const leafLabel = `${leaf.method.toUpperCase()} ${String(leaf.path)}`;
|
|
209
1050
|
const debugName = meta?.name;
|
|
210
1051
|
const emit = (event) => emitDebug(event, debugName);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
1052
|
+
const isGet = leaf.method === "get";
|
|
1053
|
+
const isFeed = !!leaf.cfg.feed;
|
|
1054
|
+
const validateResponses = opts.validateResponses ?? true;
|
|
1055
|
+
const env = {
|
|
1056
|
+
baseUrl,
|
|
1057
|
+
validateResponses,
|
|
1058
|
+
fetcher,
|
|
1059
|
+
queryClient,
|
|
1060
|
+
emit,
|
|
1061
|
+
decorateDebugEvent,
|
|
1062
|
+
isVerboseDebug,
|
|
1063
|
+
leafLabel
|
|
1064
|
+
};
|
|
216
1065
|
if (isGet && isFeed) {
|
|
217
|
-
|
|
218
|
-
const {
|
|
219
|
-
cursorParam,
|
|
220
|
-
getNextPageParam,
|
|
221
|
-
initialPageParam,
|
|
222
|
-
...passthroughOptions
|
|
223
|
-
} = infiniteOptions;
|
|
224
|
-
feedCursorParam = cursorParam ?? "pagination_cursor";
|
|
225
|
-
feedNextPageParam = getNextPageParam ?? ((lastPage) => defaultGetNextCursor(lastPage));
|
|
226
|
-
feedInitialPageParam = typeof initialPageParam === "undefined" ? void 0 : initialPageParam;
|
|
227
|
-
feedQueryOptions = passthroughOptions;
|
|
228
|
-
}
|
|
229
|
-
const getQueryKeys = (...tuple) => {
|
|
230
|
-
const a = extractArgs(tuple);
|
|
231
|
-
const params = a?.params;
|
|
232
|
-
const query = a?.query;
|
|
233
|
-
const qForKey = isGet && isFeed ? stripKey(query, feedCursorParam) : query;
|
|
234
|
-
return buildCacheKey({
|
|
1066
|
+
return buildInfiniteGetLeaf(
|
|
235
1067
|
leaf,
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
});
|
|
239
|
-
};
|
|
240
|
-
const invalidateExact = async (...tuple) => {
|
|
241
|
-
const queryKey = getQueryKeys(...tuple);
|
|
242
|
-
await queryClient.invalidateQueries({ queryKey, exact: true });
|
|
243
|
-
emit({ type: "invalidate", key: queryKey, exact: true });
|
|
244
|
-
};
|
|
245
|
-
const setData = (...args) => {
|
|
246
|
-
const [updater, ...rest] = args;
|
|
247
|
-
const k = getQueryKeys(...rest);
|
|
248
|
-
let next;
|
|
249
|
-
if (isGet && isFeed) {
|
|
250
|
-
next = queryClient.setQueryData(
|
|
251
|
-
k,
|
|
252
|
-
(prev) => typeof updater === "function" ? updater(prev) : updater
|
|
253
|
-
);
|
|
254
|
-
} else {
|
|
255
|
-
next = queryClient.setQueryData(
|
|
256
|
-
k,
|
|
257
|
-
(prev) => typeof updater === "function" ? updater(prev) : updater
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
emit({ type: "setData", key: k });
|
|
261
|
-
return next;
|
|
262
|
-
};
|
|
263
|
-
const buildOnReceive = rqOpts?.onReceive;
|
|
264
|
-
const fetchEndpoint = async (tuple, options) => {
|
|
265
|
-
const a = extractArgs(tuple);
|
|
266
|
-
const params = a?.params;
|
|
267
|
-
const query = options?.queryOverride ?? a?.query;
|
|
268
|
-
const { url, normalizedQuery, normalizedParams } = buildUrl(
|
|
269
|
-
{ ...leaf, cfg: leafCfg },
|
|
270
|
-
baseUrl,
|
|
271
|
-
params,
|
|
272
|
-
query
|
|
273
|
-
);
|
|
274
|
-
let payload;
|
|
275
|
-
const acceptsBody = Boolean(leafCfg.bodySchema);
|
|
276
|
-
const requiresBody = options?.requireBody ?? (!isGet && acceptsBody);
|
|
277
|
-
if (typeof options?.body !== "undefined") {
|
|
278
|
-
const normalizedBody = leafCfg.bodySchema ? lowProfileParse(leafCfg.bodySchema, options.body) : void 0;
|
|
279
|
-
const isMultipart = Array.isArray(leafCfg.bodyFiles) && leafCfg.bodyFiles.length > 0;
|
|
280
|
-
if (isMultipart && normalizedBody && typeof normalizedBody === "object") {
|
|
281
|
-
payload = toFormData(normalizedBody);
|
|
282
|
-
} else {
|
|
283
|
-
payload = normalizedBody;
|
|
284
|
-
}
|
|
285
|
-
} else if (requiresBody) {
|
|
286
|
-
throw new Error("Body is required when invoking a mutation fetch.");
|
|
287
|
-
}
|
|
288
|
-
const startedAt = Date.now();
|
|
289
|
-
const detail = isVerboseDebug ? { params: normalizedParams, query: normalizedQuery } : void 0;
|
|
290
|
-
emit(
|
|
291
|
-
decorateDebugEvent(
|
|
292
|
-
{
|
|
293
|
-
type: "fetch",
|
|
294
|
-
stage: "start",
|
|
295
|
-
method,
|
|
296
|
-
url,
|
|
297
|
-
leaf: leafLabel,
|
|
298
|
-
...payload !== void 0 ? { body: payload } : {}
|
|
299
|
-
},
|
|
300
|
-
detail
|
|
301
|
-
)
|
|
1068
|
+
rqOpts,
|
|
1069
|
+
env
|
|
302
1070
|
);
|
|
303
|
-
try {
|
|
304
|
-
const out = await fetcher(
|
|
305
|
-
payload === void 0 ? { url, method } : { url, method, body: payload }
|
|
306
|
-
);
|
|
307
|
-
emit(
|
|
308
|
-
decorateDebugEvent(
|
|
309
|
-
{
|
|
310
|
-
type: "fetch",
|
|
311
|
-
stage: "fetched",
|
|
312
|
-
method,
|
|
313
|
-
url,
|
|
314
|
-
leaf: leafLabel,
|
|
315
|
-
durationMs: Date.now() - startedAt
|
|
316
|
-
},
|
|
317
|
-
isVerboseDebug ? {
|
|
318
|
-
params: normalizedParams,
|
|
319
|
-
query: normalizedQuery,
|
|
320
|
-
output: out
|
|
321
|
-
} : void 0
|
|
322
|
-
)
|
|
323
|
-
);
|
|
324
|
-
if (validateResponses) {
|
|
325
|
-
if (!leafCfg.outputSchema) {
|
|
326
|
-
throw new Error(
|
|
327
|
-
`No output schema defined for leaf ${leafLabel}, cannot validate response.`
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
out.data = lowProfileParse(
|
|
331
|
-
leafCfg.outputSchema,
|
|
332
|
-
out.data
|
|
333
|
-
);
|
|
334
|
-
emit(
|
|
335
|
-
decorateDebugEvent(
|
|
336
|
-
{
|
|
337
|
-
type: "fetch",
|
|
338
|
-
stage: "parsed",
|
|
339
|
-
method,
|
|
340
|
-
url,
|
|
341
|
-
leaf: leafLabel,
|
|
342
|
-
durationMs: Date.now() - startedAt
|
|
343
|
-
},
|
|
344
|
-
isVerboseDebug ? {
|
|
345
|
-
params: normalizedParams,
|
|
346
|
-
query: normalizedQuery,
|
|
347
|
-
output: out
|
|
348
|
-
} : void 0
|
|
349
|
-
)
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
options?.onReceive?.(out.data);
|
|
353
|
-
return out.data;
|
|
354
|
-
} catch (error) {
|
|
355
|
-
emit(
|
|
356
|
-
decorateDebugEvent(
|
|
357
|
-
{
|
|
358
|
-
type: "fetch",
|
|
359
|
-
stage: "error",
|
|
360
|
-
method,
|
|
361
|
-
url,
|
|
362
|
-
leaf: leafLabel,
|
|
363
|
-
durationMs: Date.now() - startedAt,
|
|
364
|
-
...payload !== void 0 ? { body: payload } : {},
|
|
365
|
-
error
|
|
366
|
-
},
|
|
367
|
-
detail
|
|
368
|
-
)
|
|
369
|
-
);
|
|
370
|
-
throw error;
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
const fetchGet = (...tupleWithBody) => {
|
|
374
|
-
const acceptsBody = Boolean(leafCfg.bodySchema);
|
|
375
|
-
const tupleLength = tupleWithBody.length;
|
|
376
|
-
const maybeBodyIndex = expectsArgs ? 1 : 0;
|
|
377
|
-
const hasBodyCandidate = acceptsBody && tupleLength > maybeBodyIndex;
|
|
378
|
-
const body = hasBodyCandidate ? tupleWithBody[tupleLength - 1] : void 0;
|
|
379
|
-
const tuple = hasBodyCandidate ? tupleWithBody.slice(0, tupleLength - 1) : tupleWithBody;
|
|
380
|
-
return fetchEndpoint(tuple, {
|
|
381
|
-
body,
|
|
382
|
-
onReceive: buildOnReceive,
|
|
383
|
-
requireBody: false
|
|
384
|
-
});
|
|
385
|
-
};
|
|
386
|
-
if (isGet && isFeed) {
|
|
387
|
-
const useEndpoint2 = (...useArgs) => {
|
|
388
|
-
const args = useArgs[0];
|
|
389
|
-
const tuple = toArgsTuple(args);
|
|
390
|
-
const queryKeys = getQueryKeys(...tuple);
|
|
391
|
-
emit({
|
|
392
|
-
type: "useEndpoint",
|
|
393
|
-
leaf: leafLabel,
|
|
394
|
-
variant: "infiniteGet",
|
|
395
|
-
keys: queryKeys
|
|
396
|
-
});
|
|
397
|
-
const params = args?.params;
|
|
398
|
-
const query = args?.query;
|
|
399
|
-
const buildOptions = feedQueryOptions ?? {};
|
|
400
|
-
const listenersRef = useRef(/* @__PURE__ */ new Set());
|
|
401
|
-
const notifyOnReceive = useCallback((data) => {
|
|
402
|
-
buildOptions?.onReceive?.(data);
|
|
403
|
-
listenersRef.current.forEach((listener) => listener(data));
|
|
404
|
-
}, []);
|
|
405
|
-
const registerOnReceive = useCallback(
|
|
406
|
-
(listener) => {
|
|
407
|
-
listenersRef.current.add(listener);
|
|
408
|
-
return () => {
|
|
409
|
-
listenersRef.current.delete(listener);
|
|
410
|
-
};
|
|
411
|
-
},
|
|
412
|
-
[]
|
|
413
|
-
);
|
|
414
|
-
const { normalizedQuery, normalizedParams } = buildUrl(
|
|
415
|
-
{ ...leaf, cfg: leafCfg },
|
|
416
|
-
baseUrl,
|
|
417
|
-
params,
|
|
418
|
-
query
|
|
419
|
-
);
|
|
420
|
-
const queryResult = useInfiniteQuery(
|
|
421
|
-
{
|
|
422
|
-
...buildOptions,
|
|
423
|
-
placeholderData: buildOptions.placeholderData ?? keepPreviousData,
|
|
424
|
-
initialPageParam: feedInitialPageParam,
|
|
425
|
-
getNextPageParam: (lastPage) => (feedNextPageParam ?? defaultGetNextCursor)(lastPage),
|
|
426
|
-
queryKey: queryKeys,
|
|
427
|
-
queryFn: ({ pageParam }) => {
|
|
428
|
-
const pageQuery = {
|
|
429
|
-
...normalizedQuery,
|
|
430
|
-
...pageParam ? { [feedCursorParam]: pageParam } : {}
|
|
431
|
-
};
|
|
432
|
-
return fetchEndpoint(tuple, {
|
|
433
|
-
queryOverride: pageQuery,
|
|
434
|
-
onReceive: notifyOnReceive
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
// NOTE: TData is InfiniteData<T>, so we don't need a select here.
|
|
438
|
-
},
|
|
439
|
-
queryClient
|
|
440
|
-
);
|
|
441
|
-
return { ...queryResult, onReceive: registerOnReceive };
|
|
442
|
-
};
|
|
443
|
-
return {
|
|
444
|
-
getQueryKeys,
|
|
445
|
-
invalidate: invalidateExact,
|
|
446
|
-
setData,
|
|
447
|
-
useEndpoint: useEndpoint2,
|
|
448
|
-
fetch: fetchGet
|
|
449
|
-
};
|
|
450
1071
|
}
|
|
451
1072
|
if (isGet) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
emit({
|
|
457
|
-
type: "useEndpoint",
|
|
458
|
-
leaf: leafLabel,
|
|
459
|
-
variant: "get",
|
|
460
|
-
keys: queryKeys
|
|
461
|
-
});
|
|
462
|
-
const params = args?.params;
|
|
463
|
-
const query = args?.query;
|
|
464
|
-
const buildOptions = rqOpts ?? {};
|
|
465
|
-
const listenersRef = useRef(/* @__PURE__ */ new Set());
|
|
466
|
-
const notifyOnReceive = useCallback((data) => {
|
|
467
|
-
buildOptions?.onReceive?.(data);
|
|
468
|
-
listenersRef.current.forEach((listener) => listener(data));
|
|
469
|
-
}, []);
|
|
470
|
-
const registerOnReceive = useCallback(
|
|
471
|
-
(listener) => {
|
|
472
|
-
listenersRef.current.add(listener);
|
|
473
|
-
return () => {
|
|
474
|
-
listenersRef.current.delete(listener);
|
|
475
|
-
};
|
|
476
|
-
},
|
|
477
|
-
[]
|
|
478
|
-
);
|
|
479
|
-
const queryResult = useQuery(
|
|
480
|
-
{
|
|
481
|
-
...buildOptions,
|
|
482
|
-
queryKey: getQueryKeys(...tuple),
|
|
483
|
-
placeholderData: keepPreviousData,
|
|
484
|
-
queryFn: () => fetchEndpoint(tuple, {
|
|
485
|
-
onReceive: notifyOnReceive
|
|
486
|
-
})
|
|
487
|
-
},
|
|
488
|
-
queryClient
|
|
489
|
-
);
|
|
490
|
-
return { ...queryResult, onReceive: registerOnReceive };
|
|
491
|
-
};
|
|
492
|
-
return {
|
|
493
|
-
getQueryKeys,
|
|
494
|
-
invalidate: invalidateExact,
|
|
495
|
-
setData,
|
|
496
|
-
useEndpoint: useEndpoint2,
|
|
497
|
-
fetch: fetchGet
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
const mutationBuildOptions = rqOpts ?? {};
|
|
501
|
-
const fetchMutation = async (...tupleWithBody) => {
|
|
502
|
-
if (tupleWithBody.length === 0) {
|
|
503
|
-
throw new Error("Body is required when invoking a mutation fetch.");
|
|
504
|
-
}
|
|
505
|
-
const bodyIndex = tupleWithBody.length - 1;
|
|
506
|
-
const tuple = tupleWithBody.slice(0, bodyIndex);
|
|
507
|
-
const body = tupleWithBody[bodyIndex];
|
|
508
|
-
const result = await fetchEndpoint(tuple, {
|
|
509
|
-
body,
|
|
510
|
-
onReceive: (data) => mutationBuildOptions?.onReceive?.(data),
|
|
511
|
-
requireBody: true
|
|
512
|
-
});
|
|
513
|
-
return result;
|
|
514
|
-
};
|
|
515
|
-
const useEndpoint = (...useArgs) => {
|
|
516
|
-
const args = useArgs[0];
|
|
517
|
-
const tuple = toArgsTuple(args);
|
|
518
|
-
const mutationKey = getQueryKeys(...tuple);
|
|
519
|
-
emit({
|
|
520
|
-
type: "useEndpoint",
|
|
521
|
-
leaf: leafLabel,
|
|
522
|
-
variant: "mutation",
|
|
523
|
-
keys: mutationKey
|
|
524
|
-
});
|
|
525
|
-
const listenersRef = useRef(/* @__PURE__ */ new Set());
|
|
526
|
-
const notifyListeners = useCallback((data) => {
|
|
527
|
-
listenersRef.current.forEach((listener) => listener(data));
|
|
528
|
-
}, []);
|
|
529
|
-
const registerOnReceive = useCallback(
|
|
530
|
-
(listener) => {
|
|
531
|
-
listenersRef.current.add(listener);
|
|
532
|
-
return () => {
|
|
533
|
-
listenersRef.current.delete(listener);
|
|
534
|
-
};
|
|
535
|
-
},
|
|
536
|
-
[]
|
|
537
|
-
);
|
|
538
|
-
const mutationResult = useMutation(
|
|
539
|
-
{
|
|
540
|
-
...mutationBuildOptions,
|
|
541
|
-
mutationKey,
|
|
542
|
-
mutationFn: async (body) => {
|
|
543
|
-
const result = await fetchMutation(
|
|
544
|
-
...[...tuple, body]
|
|
545
|
-
);
|
|
546
|
-
notifyListeners(result);
|
|
547
|
-
return result;
|
|
548
|
-
}
|
|
549
|
-
},
|
|
550
|
-
queryClient
|
|
1073
|
+
return buildGetLeaf(
|
|
1074
|
+
leaf,
|
|
1075
|
+
rqOpts,
|
|
1076
|
+
env
|
|
551
1077
|
);
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
useEndpoint,
|
|
559
|
-
fetch: fetchMutation
|
|
560
|
-
};
|
|
1078
|
+
}
|
|
1079
|
+
return buildMutationLeaf(
|
|
1080
|
+
leaf,
|
|
1081
|
+
rqOpts,
|
|
1082
|
+
env
|
|
1083
|
+
);
|
|
561
1084
|
}
|
|
562
1085
|
const fetchRaw = async (input) => {
|
|
563
1086
|
const { path, method, query, body, params } = input;
|
|
@@ -641,81 +1164,6 @@ function buildRouter(routeClient, routes) {
|
|
|
641
1164
|
meta
|
|
642
1165
|
));
|
|
643
1166
|
}
|
|
644
|
-
function toFormData(body) {
|
|
645
|
-
const fd = new FormData();
|
|
646
|
-
for (const [k, v] of Object.entries(body ?? {})) {
|
|
647
|
-
if (v == null) continue;
|
|
648
|
-
if (Array.isArray(v))
|
|
649
|
-
v.forEach((item, i) => fd.append(`${k}[${i}]`, item));
|
|
650
|
-
else fd.append(k, v);
|
|
651
|
-
}
|
|
652
|
-
return fd;
|
|
653
|
-
}
|
|
654
|
-
function getPathParamNames(path) {
|
|
655
|
-
const names = /* @__PURE__ */ new Set();
|
|
656
|
-
const re = /:([A-Za-z0-9_]+)/g;
|
|
657
|
-
let match;
|
|
658
|
-
while ((match = re.exec(path)) !== null) {
|
|
659
|
-
names.add(match[1]);
|
|
660
|
-
}
|
|
661
|
-
return names;
|
|
662
|
-
}
|
|
663
|
-
function normalizeFlatQuery(query) {
|
|
664
|
-
if (query == null) return void 0;
|
|
665
|
-
if (typeof query !== "object" || Array.isArray(query)) {
|
|
666
|
-
throw new Error("Query must be a plain object (Record<string, string>).");
|
|
667
|
-
}
|
|
668
|
-
const result = {};
|
|
669
|
-
for (const [k, v] of Object.entries(query)) {
|
|
670
|
-
if (v == null) continue;
|
|
671
|
-
if (typeof v !== "string") {
|
|
672
|
-
throw new Error(
|
|
673
|
-
`Query param "${k}" must be a string; received type "${typeof v}".`
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
result[k] = v;
|
|
677
|
-
}
|
|
678
|
-
return Object.keys(result).length > 0 ? result : void 0;
|
|
679
|
-
}
|
|
680
|
-
function compileRawPath(path, params) {
|
|
681
|
-
const placeholders = getPathParamNames(path);
|
|
682
|
-
if (!params || typeof params !== "object" || Array.isArray(params)) {
|
|
683
|
-
if (placeholders.size > 0) {
|
|
684
|
-
throw new Error(
|
|
685
|
-
`Missing path parameters for "${path}": ${[...placeholders].join(
|
|
686
|
-
", "
|
|
687
|
-
)}`
|
|
688
|
-
);
|
|
689
|
-
}
|
|
690
|
-
return path;
|
|
691
|
-
}
|
|
692
|
-
const paramObj = params;
|
|
693
|
-
const providedNames = new Set(Object.keys(paramObj));
|
|
694
|
-
for (const name of providedNames) {
|
|
695
|
-
if (!placeholders.has(name)) {
|
|
696
|
-
throw new Error(
|
|
697
|
-
`Unexpected path parameter "${name}" for template "${path}".`
|
|
698
|
-
);
|
|
699
|
-
}
|
|
700
|
-
const value = paramObj[name];
|
|
701
|
-
if (value != null && (typeof value === "object" || Array.isArray(value))) {
|
|
702
|
-
throw new Error(
|
|
703
|
-
`Path parameter "${name}" must be a primitive; received "${typeof value}".`
|
|
704
|
-
);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
for (const name of placeholders) {
|
|
708
|
-
if (!providedNames.has(name)) {
|
|
709
|
-
throw new Error(
|
|
710
|
-
`Missing value for path parameter "${name}" in template "${path}".`
|
|
711
|
-
);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
if (placeholders.size === 0) {
|
|
715
|
-
return path;
|
|
716
|
-
}
|
|
717
|
-
return compilePath(path, paramObj);
|
|
718
|
-
}
|
|
719
1167
|
|
|
720
1168
|
// src/sockets/socket.client.sys.ts
|
|
721
1169
|
import { z } from "zod";
|