stitchkit 0.18.0 → 0.19.0
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/browser/client.d.ts.map +1 -1
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/contract/errors-factory.d.ts +18 -0
- package/dist/contract/errors-factory.d.ts.map +1 -0
- package/dist/contract/factory.d.ts +36 -0
- package/dist/contract/factory.d.ts.map +1 -0
- package/dist/contract/index.d.ts +2 -0
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +6 -1
- package/dist/contract/pagination.d.ts.map +1 -1
- package/dist/index-809wc1tt.js +18 -0
- package/dist/{index-tm7dqzxc.js → index-c7nyw0yt.js} +9 -9
- package/dist/{index-dz2k8d5h.js → index-dzx781tm.js} +1 -1
- package/dist/{index-ktn76xz0.js → index-ng2v2ts4.js} +17 -1
- package/dist/index-tje0q6gp.js +44 -0
- package/dist/{index-6qv1fxqy.js → index-wpbn133x.js} +13 -50
- package/dist/{index-yzac2zbh.js → index-x62gnfsk.js} +50 -9
- package/dist/{index-akv8rk4w.js → index-xmncnw8z.js} +2 -2
- package/dist/{index-yv93m4yr.js → index-ynnh9x6h.js} +11 -29
- package/dist/index.js +82 -62
- package/dist/internal/base64url.d.ts +16 -0
- package/dist/internal/base64url.d.ts.map +1 -0
- package/dist/node.js +5 -4
- package/dist/observability/index.js +2 -2
- package/dist/react/entity-cache.d.ts +54 -0
- package/dist/react/entity-cache.d.ts.map +1 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +74 -0
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/error-hook.d.ts +56 -0
- package/dist/server/error-hook.d.ts.map +1 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +32 -7
- package/dist/server/middleware/auth.d.ts.map +1 -1
- package/dist/server/middleware/cors.d.ts +13 -0
- package/dist/server/middleware/cors.d.ts.map +1 -1
- package/dist/server/middleware/pkce.d.ts +0 -6
- package/dist/server/middleware/pkce.d.ts.map +1 -1
- package/dist/server/router.d.ts +0 -2
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/types.d.ts +0 -8
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/agent.d.ts +2 -2
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/cli-format.d.ts +2 -2
- package/dist/tools/cli-format.d.ts.map +1 -1
- package/dist/tools/cli.d.ts +2 -2
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools/execute.d.ts +7 -0
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/mcp.d.ts +3 -3
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/mount.d.ts +3 -3
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/oauth-metadata.d.ts.map +1 -1
- package/dist/tools/oauth-provider.d.ts.map +1 -1
- package/dist/tools/tool-logger.d.ts +31 -0
- package/dist/tools/tool-logger.d.ts.map +1 -0
- package/dist/tools/transports.d.ts +28 -0
- package/dist/tools/transports.d.ts.map +1 -0
- package/dist/tools.d.ts +3 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +71 -11
- package/llms-full.txt +235 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,8 +5,10 @@ import {
|
|
|
5
5
|
appError,
|
|
6
6
|
badRequest,
|
|
7
7
|
conflict,
|
|
8
|
+
createContractFactory,
|
|
8
9
|
decodeCursor,
|
|
9
10
|
defineContract,
|
|
11
|
+
defineErrors,
|
|
10
12
|
encodeCursor,
|
|
11
13
|
forbidden,
|
|
12
14
|
isStitchErrorCode,
|
|
@@ -14,30 +16,18 @@ import {
|
|
|
14
16
|
paginatedSchema,
|
|
15
17
|
rateLimited,
|
|
16
18
|
unauthorized
|
|
17
|
-
} from "./index-
|
|
19
|
+
} from "./index-x62gnfsk.js";
|
|
20
|
+
import {
|
|
21
|
+
isRecord,
|
|
22
|
+
mapObject,
|
|
23
|
+
typedEntries
|
|
24
|
+
} from "./index-809wc1tt.js";
|
|
18
25
|
|
|
19
26
|
// src/internal/http-input.ts
|
|
20
27
|
function inputIsQuery(method) {
|
|
21
28
|
return method === "GET" || method === "DELETE";
|
|
22
29
|
}
|
|
23
30
|
|
|
24
|
-
// src/internal/typed.ts
|
|
25
|
-
function typedEntries(value) {
|
|
26
|
-
return Object.entries(value);
|
|
27
|
-
}
|
|
28
|
-
function isRecord(value) {
|
|
29
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30
|
-
}
|
|
31
|
-
function mapObject(source, mapper) {
|
|
32
|
-
const result = {};
|
|
33
|
-
for (const [key, value] of typedEntries(source)) {
|
|
34
|
-
const mapped = mapper(key, value);
|
|
35
|
-
if (mapped !== undefined)
|
|
36
|
-
result[key] = mapped;
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
31
|
// src/browser/http.ts
|
|
42
32
|
import ky, { isHTTPError } from "ky";
|
|
43
33
|
|
|
@@ -244,6 +234,12 @@ function withTimeout(options, timeout) {
|
|
|
244
234
|
return options;
|
|
245
235
|
return { ...options, timeout };
|
|
246
236
|
}
|
|
237
|
+
function withOutput(endpoint, result) {
|
|
238
|
+
const schema = endpoint.output;
|
|
239
|
+
if (!schema)
|
|
240
|
+
return result;
|
|
241
|
+
return result.then((value) => value === undefined ? undefined : schema.parse(value));
|
|
242
|
+
}
|
|
247
243
|
function isParamArray(value) {
|
|
248
244
|
return Array.isArray(value) && value.every((v) => typeof v === "string" || typeof v === "number");
|
|
249
245
|
}
|
|
@@ -310,18 +306,21 @@ function createHttpMethod(endpoint, prefix, client, config) {
|
|
|
310
306
|
if (!isMultipartFile(file)) {
|
|
311
307
|
throw new Error(`Missing multipart file field: ${endpoint.multipart}`);
|
|
312
308
|
}
|
|
309
|
+
if (httpMethod === "get" || httpMethod === "delete") {
|
|
310
|
+
throw new Error(`Multipart endpoint ${endpoint.method} ${endpoint.path} must be POST / PUT / PATCH`);
|
|
311
|
+
}
|
|
313
312
|
const formData = new FormData;
|
|
314
313
|
appendMultipartFile(formData, endpoint.multipart, file);
|
|
315
314
|
appendFormFields(formData, firstArg, new Set([...prefixKeys, endpoint.multipart]));
|
|
316
|
-
return client
|
|
315
|
+
return withOutput(endpoint, client[httpMethod](url, formData, withTimeout(undefined, endpoint.timeout)));
|
|
317
316
|
}
|
|
318
317
|
if (isGet) {
|
|
319
318
|
const params = collectQueryParams(firstArg, prefixKeys, endpoint);
|
|
320
|
-
return client.get(url, withTimeout(params ? { params } : undefined, endpoint.timeout));
|
|
319
|
+
return withOutput(endpoint, client.get(url, withTimeout(params ? { params } : undefined, endpoint.timeout)));
|
|
321
320
|
}
|
|
322
321
|
if (httpMethod === "delete") {
|
|
323
322
|
const params = collectQueryParams(firstArg, prefixKeys, endpoint);
|
|
324
|
-
return client.delete(url, withTimeout(params ? { params } : undefined, endpoint.timeout));
|
|
323
|
+
return withOutput(endpoint, client.delete(url, withTimeout(params ? { params } : undefined, endpoint.timeout)));
|
|
325
324
|
}
|
|
326
325
|
const payload = {};
|
|
327
326
|
for (const [key, value] of Object.entries(firstArg)) {
|
|
@@ -329,7 +328,7 @@ function createHttpMethod(endpoint, prefix, client, config) {
|
|
|
329
328
|
payload[key] = value;
|
|
330
329
|
}
|
|
331
330
|
}
|
|
332
|
-
return client[httpMethod](url, Object.keys(payload).length > 0 ? payload : undefined, withTimeout(undefined, endpoint.timeout));
|
|
331
|
+
return withOutput(endpoint, client[httpMethod](url, Object.keys(payload).length > 0 ? payload : undefined, withTimeout(undefined, endpoint.timeout)));
|
|
333
332
|
};
|
|
334
333
|
}
|
|
335
334
|
function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
@@ -346,6 +345,7 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
346
345
|
Accept: "application/json",
|
|
347
346
|
...typeof config.headers === "function" ? config.headers() : config.headers
|
|
348
347
|
};
|
|
348
|
+
const signal = endpoint.timeout !== undefined ? AbortSignal.timeout(endpoint.timeout) : undefined;
|
|
349
349
|
const isQuery = inputIsQuery(endpoint.method);
|
|
350
350
|
const hasBody = !isQuery && !endpoint.multipart && endpoint.input && args;
|
|
351
351
|
if (isQuery && args) {
|
|
@@ -378,7 +378,8 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
378
378
|
method: endpoint.method,
|
|
379
379
|
headers,
|
|
380
380
|
credentials: config.credentials,
|
|
381
|
-
body: formData
|
|
381
|
+
body: formData,
|
|
382
|
+
signal
|
|
382
383
|
});
|
|
383
384
|
if (!res2.ok) {
|
|
384
385
|
await throwForErrorResponse(res2, config, null);
|
|
@@ -392,6 +393,7 @@ function createFetchMethod(endpoint, prefix, config, contractConfig) {
|
|
|
392
393
|
method: endpoint.method,
|
|
393
394
|
headers,
|
|
394
395
|
credentials: config.credentials,
|
|
396
|
+
signal,
|
|
395
397
|
...hasBody && {
|
|
396
398
|
body: JSON.stringify(stripParams(hasBody, endpoint.path, prefixKeys))
|
|
397
399
|
}
|
|
@@ -461,9 +463,6 @@ function stripParams(args, path, extra) {
|
|
|
461
463
|
}
|
|
462
464
|
return result;
|
|
463
465
|
}
|
|
464
|
-
// src/browser/socket-io.ts
|
|
465
|
-
import { io } from "socket.io-client";
|
|
466
|
-
|
|
467
466
|
// src/retained.ts
|
|
468
467
|
function createRetainedTopics() {
|
|
469
468
|
const last = {};
|
|
@@ -491,6 +490,17 @@ function createRetainedTopics() {
|
|
|
491
490
|
}
|
|
492
491
|
|
|
493
492
|
// src/browser/socket-io.ts
|
|
493
|
+
var SOCKET_IO_CLIENT = "socket.io-client";
|
|
494
|
+
var ioLoader = null;
|
|
495
|
+
function loadIo() {
|
|
496
|
+
if (!ioLoader) {
|
|
497
|
+
ioLoader = import(SOCKET_IO_CLIENT).then((mod) => mod.io, (cause) => {
|
|
498
|
+
ioLoader = null;
|
|
499
|
+
throw new Error('stitchkit: createSocketIOClient needs the "socket.io-client" peer — install it (e.g. `bun add socket.io-client`).', { cause });
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
return ioLoader;
|
|
503
|
+
}
|
|
494
504
|
function toIoAuth(auth) {
|
|
495
505
|
if (typeof auth !== "function")
|
|
496
506
|
return auth;
|
|
@@ -500,6 +510,7 @@ function toIoAuth(auth) {
|
|
|
500
510
|
}
|
|
501
511
|
function createSocketIOClient(config) {
|
|
502
512
|
let socket = null;
|
|
513
|
+
let desiredConnected = false;
|
|
503
514
|
let reconnectTimer = null;
|
|
504
515
|
const serverDisconnectDelay = config.reconnectOnServerDisconnect ?? 1000;
|
|
505
516
|
const connectionListeners = new Set;
|
|
@@ -517,50 +528,57 @@ function createSocketIOClient(config) {
|
|
|
517
528
|
reconnectTimer = null;
|
|
518
529
|
}
|
|
519
530
|
}
|
|
531
|
+
function openSocket(io) {
|
|
532
|
+
if (!desiredConnected || socket)
|
|
533
|
+
return;
|
|
534
|
+
socket = io(config.url, {
|
|
535
|
+
path: config.path ?? "/socket.io/",
|
|
536
|
+
withCredentials: config.withCredentials ?? true,
|
|
537
|
+
auth: toIoAuth(config.auth),
|
|
538
|
+
...config.query && { query: config.query },
|
|
539
|
+
...config.extraHeaders && { extraHeaders: config.extraHeaders },
|
|
540
|
+
transports: config.transports ?? ["websocket", "polling"],
|
|
541
|
+
autoConnect: false,
|
|
542
|
+
reconnection: true,
|
|
543
|
+
reconnectionAttempts: config.reconnectionAttempts ?? Infinity,
|
|
544
|
+
reconnectionDelay: config.reconnectionDelay ?? 1000,
|
|
545
|
+
reconnectionDelayMax: config.reconnectionDelayMax ?? 5000,
|
|
546
|
+
timeout: config.timeout ?? 20000
|
|
547
|
+
});
|
|
548
|
+
socket.on("connect", () => notifyConnection(true));
|
|
549
|
+
socket.on("disconnect", (reason) => {
|
|
550
|
+
notifyConnection(false, reason);
|
|
551
|
+
if (reason === "io server disconnect" && serverDisconnectDelay !== false) {
|
|
552
|
+
const current = socket;
|
|
553
|
+
clearReconnectTimer();
|
|
554
|
+
reconnectTimer = setTimeout(() => {
|
|
555
|
+
reconnectTimer = null;
|
|
556
|
+
if (socket === current && current && !current.connected)
|
|
557
|
+
current.connect();
|
|
558
|
+
}, serverDisconnectDelay);
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
if (retained) {
|
|
562
|
+
for (const name of retainNames) {
|
|
563
|
+
socket.on(name, (payload) => retained.record(name, payload));
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
for (const attach of subscriptions)
|
|
567
|
+
attach(socket);
|
|
568
|
+
socket.connect();
|
|
569
|
+
}
|
|
520
570
|
return {
|
|
521
571
|
get connected() {
|
|
522
572
|
return socket?.connected ?? false;
|
|
523
573
|
},
|
|
524
574
|
connect() {
|
|
525
|
-
if (socket)
|
|
575
|
+
if (socket || desiredConnected)
|
|
526
576
|
return;
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
withCredentials: config.withCredentials ?? true,
|
|
530
|
-
auth: toIoAuth(config.auth),
|
|
531
|
-
...config.query && { query: config.query },
|
|
532
|
-
...config.extraHeaders && { extraHeaders: config.extraHeaders },
|
|
533
|
-
transports: config.transports ?? ["websocket", "polling"],
|
|
534
|
-
autoConnect: false,
|
|
535
|
-
reconnection: true,
|
|
536
|
-
reconnectionAttempts: config.reconnectionAttempts ?? Infinity,
|
|
537
|
-
reconnectionDelay: config.reconnectionDelay ?? 1000,
|
|
538
|
-
reconnectionDelayMax: config.reconnectionDelayMax ?? 5000,
|
|
539
|
-
timeout: config.timeout ?? 20000
|
|
540
|
-
});
|
|
541
|
-
socket.on("connect", () => notifyConnection(true));
|
|
542
|
-
socket.on("disconnect", (reason) => {
|
|
543
|
-
notifyConnection(false, reason);
|
|
544
|
-
if (reason === "io server disconnect" && serverDisconnectDelay !== false) {
|
|
545
|
-
const current = socket;
|
|
546
|
-
clearReconnectTimer();
|
|
547
|
-
reconnectTimer = setTimeout(() => {
|
|
548
|
-
reconnectTimer = null;
|
|
549
|
-
if (socket === current && current && !current.connected)
|
|
550
|
-
current.connect();
|
|
551
|
-
}, serverDisconnectDelay);
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
if (retained) {
|
|
555
|
-
for (const name of retainNames) {
|
|
556
|
-
socket.on(name, (payload) => retained.record(name, payload));
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
for (const attach of subscriptions)
|
|
560
|
-
attach(socket);
|
|
561
|
-
socket.connect();
|
|
577
|
+
desiredConnected = true;
|
|
578
|
+
loadIo().then(openSocket);
|
|
562
579
|
},
|
|
563
580
|
disconnect() {
|
|
581
|
+
desiredConnected = false;
|
|
564
582
|
clearReconnectTimer();
|
|
565
583
|
if (!socket)
|
|
566
584
|
return;
|
|
@@ -648,12 +666,14 @@ export {
|
|
|
648
666
|
formatTraceparent,
|
|
649
667
|
forbidden,
|
|
650
668
|
encodeCursor,
|
|
669
|
+
defineErrors,
|
|
651
670
|
defineContract,
|
|
652
671
|
decodeCursor,
|
|
653
672
|
createTraceContext,
|
|
654
673
|
createSocketIOClient,
|
|
655
674
|
createRetainedTopics,
|
|
656
675
|
createHttpClient,
|
|
676
|
+
createContractFactory,
|
|
657
677
|
createClients,
|
|
658
678
|
createClient,
|
|
659
679
|
conflict,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* base64url over raw bytes — the one codec shared by cursor pagination, JWT
|
|
3
|
+
* segments, OAuth-token minting and PKCE. `btoa`/`atob` based (not Node
|
|
4
|
+
* `Buffer`), so it works identically in the server, the browser and the typed
|
|
5
|
+
* client. Kept byte-level: string callers compose with `TextEncoder` /
|
|
6
|
+
* `TextDecoder` themselves (pagination round-trips UTF-8; JWT/PKCE are binary).
|
|
7
|
+
*/
|
|
8
|
+
/** Encode raw bytes as an unpadded base64url string. */
|
|
9
|
+
export declare function bytesToBase64Url(bytes: Uint8Array): string;
|
|
10
|
+
/**
|
|
11
|
+
* Decode a base64url string to bytes. A character outside the alphabet, or a
|
|
12
|
+
* length that no base64 string can have (`% 4 === 1`), is malformed — reject it
|
|
13
|
+
* before `atob` rather than emit silent garbage.
|
|
14
|
+
*/
|
|
15
|
+
export declare function base64UrlToBytes(segment: string): Uint8Array<ArrayBuffer>;
|
|
16
|
+
//# sourceMappingURL=base64url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64url.d.ts","sourceRoot":"","sources":["../../src/internal/base64url.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAI1D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAOzE"}
|
package/dist/node.js
CHANGED
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
createImplement,
|
|
4
4
|
createSocketIOServer,
|
|
5
5
|
implement
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-wpbn133x.js";
|
|
7
|
+
import"./index-tje0q6gp.js";
|
|
7
8
|
import {
|
|
8
9
|
AppError,
|
|
9
10
|
appError,
|
|
@@ -13,10 +14,10 @@ import {
|
|
|
13
14
|
notFound,
|
|
14
15
|
rateLimited,
|
|
15
16
|
unauthorized
|
|
16
|
-
} from "./index-
|
|
17
|
-
import"./index-
|
|
17
|
+
} from "./index-ng2v2ts4.js";
|
|
18
|
+
import"./index-dzx781tm.js";
|
|
18
19
|
import"./index-khwedj16.js";
|
|
19
|
-
import"./index-
|
|
20
|
+
import"./index-c7nyw0yt.js";
|
|
20
21
|
// src/server/node.ts
|
|
21
22
|
import { serve } from "srvx";
|
|
22
23
|
async function serveNode(config) {
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
setRequestError,
|
|
9
9
|
setRequestUser,
|
|
10
10
|
wrapInRequestContext
|
|
11
|
-
} from "../index-
|
|
11
|
+
} from "../index-dzx781tm.js";
|
|
12
12
|
import {
|
|
13
13
|
childSpan,
|
|
14
14
|
createTraceContext,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import {
|
|
20
20
|
isRecord,
|
|
21
21
|
isUnsafeKey
|
|
22
|
-
} from "../index-
|
|
22
|
+
} from "../index-c7nyw0yt.js";
|
|
23
23
|
|
|
24
24
|
// src/observability/sanitize.ts
|
|
25
25
|
var DEFAULT_SENSITIVE_KEYS = /(password|passwd|pwd|secret|token|apikey|api[-_ ]?key|auth|authorization|bearer|session|cookie|init[-_ ]?data|credential|private[-_ ]?key)/i;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative CRUD cache handlers for `createCacheBridge` — the created /
|
|
3
|
+
* updated / deleted socket events of one entity, patched into its list and
|
|
4
|
+
* detail queries. Every project hand-rolls this same updater; this builds it
|
|
5
|
+
* from a small config.
|
|
6
|
+
*
|
|
7
|
+
* It patches stitchkit's own `Paginated<T>` list envelope (plain or a TanStack
|
|
8
|
+
* `InfiniteData` of it) and the entity's detail query. It does **not** flatten
|
|
9
|
+
* pages or expose a `useAllX` surface — flattening stays in the component (a
|
|
10
|
+
* deliberate boundary): this only keeps the cache correct.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const handlers = createEntityCacheHandlers<Widget>({
|
|
14
|
+
* getId: (w) => w.id,
|
|
15
|
+
* listKey: ['widgets'],
|
|
16
|
+
* detailKey: (id) => ['widgets', id],
|
|
17
|
+
* });
|
|
18
|
+
* createCacheBridge({ socket, queryClient, handlers: {
|
|
19
|
+
* widgetCreated: handlers.created,
|
|
20
|
+
* widgetUpdated: handlers.updated,
|
|
21
|
+
* widgetDeleted: handlers.deleted,
|
|
22
|
+
* }});
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import type { QueryKey } from '@tanstack/react-query';
|
|
26
|
+
import type { CacheBridgeHandler } from './cache-bridge';
|
|
27
|
+
/** The `deleted` event may carry the whole entity or just its id. */
|
|
28
|
+
export type DeletedPayload<T> = T | {
|
|
29
|
+
id: string;
|
|
30
|
+
};
|
|
31
|
+
/** Config for `createEntityCacheHandlers`. */
|
|
32
|
+
export interface EntityCacheConfig<T> {
|
|
33
|
+
/** Read the entity's id — the identity used to match, replace and remove. */
|
|
34
|
+
getId: (entity: T) => string;
|
|
35
|
+
/** Read the id from a `deleted` payload (entity or `{ id }`). Default `getId` / `.id`. */
|
|
36
|
+
getDeletedId?: (payload: DeletedPayload<T>) => string;
|
|
37
|
+
/** Query key (or prefix) of the list(s) to patch — matched by partial equality. */
|
|
38
|
+
listKey: QueryKey;
|
|
39
|
+
/** Build the detail query key for an id. Omit to skip detail-cache updates. */
|
|
40
|
+
detailKey?: (id: string) => QueryKey;
|
|
41
|
+
}
|
|
42
|
+
/** The three handlers to wire onto a `createCacheBridge` `handlers` map. */
|
|
43
|
+
export interface EntityCacheHandlers<T> {
|
|
44
|
+
created: CacheBridgeHandler<T>;
|
|
45
|
+
updated: CacheBridgeHandler<T>;
|
|
46
|
+
deleted: CacheBridgeHandler<DeletedPayload<T>>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build created / updated / deleted cache handlers for one entity. Each skips a
|
|
50
|
+
* stale socket echo of a change the client just made (`ctx.isFresh`), keyed on
|
|
51
|
+
* the entity's detail key when available, else the list key.
|
|
52
|
+
*/
|
|
53
|
+
export declare function createEntityCacheHandlers<T>(config: EntityCacheConfig<T>): EntityCacheHandlers<T>;
|
|
54
|
+
//# sourceMappingURL=entity-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-cache.d.ts","sourceRoot":"","sources":["../../src/react/entity-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAgB,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGpE,OAAO,KAAK,EAAsB,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAK7E,qEAAqE;AACrE,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,6EAA6E;IAC7E,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IAC7B,0FAA0F;IAC1F,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC;IACtD,mFAAmF;IACnF,OAAO,EAAE,QAAQ,CAAC;IAClB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,QAAQ,CAAC;CACtC;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;CAChD;AAyBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAC3B,mBAAmB,CAAC,CAAC,CAAC,CAuCxB"}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { type CacheBridge, type CacheBridgeConfig, type CacheBridgeContext, type CacheBridgeHandler, type CacheBridgeHandlers, type CacheBridgeSocket, createCacheBridge, } from './react/cache-bridge';
|
|
2
2
|
export { type CursorQueryConfig, createCursorQuery } from './react/cursor-query';
|
|
3
|
+
export { createEntityCacheHandlers, type DeletedPayload, type EntityCacheConfig, type EntityCacheHandlers, } from './react/entity-cache';
|
|
3
4
|
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EACL,yBAAyB,EACzB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,sBAAsB,CAAC"}
|
package/dist/react.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRecord
|
|
3
|
+
} from "./index-809wc1tt.js";
|
|
4
|
+
|
|
1
5
|
// src/react/cache-bridge.ts
|
|
2
6
|
function createCacheBridge(config) {
|
|
3
7
|
const freshWindow = config.freshWindow ?? 500;
|
|
@@ -46,7 +50,77 @@ function createCursorQuery(config) {
|
|
|
46
50
|
getNextPageParam: (lastPage) => lastPage.nextCursor
|
|
47
51
|
});
|
|
48
52
|
}
|
|
53
|
+
// src/react/entity-cache.ts
|
|
54
|
+
function patchItems(data, fn) {
|
|
55
|
+
if (!data)
|
|
56
|
+
return data;
|
|
57
|
+
if ("pages" in data) {
|
|
58
|
+
return { ...data, pages: data.pages.map((page) => ({ ...page, items: fn(page.items) })) };
|
|
59
|
+
}
|
|
60
|
+
return { ...data, items: fn(data.items) };
|
|
61
|
+
}
|
|
62
|
+
function prepend(data, entity) {
|
|
63
|
+
if (!data)
|
|
64
|
+
return data;
|
|
65
|
+
if ("pages" in data) {
|
|
66
|
+
const [first, ...rest] = data.pages;
|
|
67
|
+
if (!first)
|
|
68
|
+
return data;
|
|
69
|
+
return { ...data, pages: [{ ...first, items: [entity, ...first.items] }, ...rest] };
|
|
70
|
+
}
|
|
71
|
+
return { ...data, items: [entity, ...data.items] };
|
|
72
|
+
}
|
|
73
|
+
function createEntityCacheHandlers(config) {
|
|
74
|
+
const { getId, listKey, detailKey } = config;
|
|
75
|
+
const deletedId = config.getDeletedId ?? ((payload) => idOf(payload, getId));
|
|
76
|
+
const freshKey = (id) => detailKey ? detailKey(id) : listKey;
|
|
77
|
+
const patchList = (ctx, fn) => {
|
|
78
|
+
ctx.queryClient.setQueriesData({ queryKey: listKey }, (old) => patchItems(old, fn));
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
created(entity, ctx) {
|
|
82
|
+
const id = getId(entity);
|
|
83
|
+
if (ctx.isFresh(freshKey(id)))
|
|
84
|
+
return;
|
|
85
|
+
ctx.queryClient.setQueriesData({ queryKey: listKey }, (old) => {
|
|
86
|
+
const present = hasId(old, getId, id);
|
|
87
|
+
return present ? old : prepend(old, entity);
|
|
88
|
+
});
|
|
89
|
+
if (detailKey)
|
|
90
|
+
ctx.queryClient.setQueryData(detailKey(id), entity);
|
|
91
|
+
},
|
|
92
|
+
updated(entity, ctx) {
|
|
93
|
+
const id = getId(entity);
|
|
94
|
+
if (ctx.isFresh(freshKey(id)))
|
|
95
|
+
return;
|
|
96
|
+
patchList(ctx, (items) => items.map((item) => getId(item) === id ? entity : item));
|
|
97
|
+
if (detailKey)
|
|
98
|
+
ctx.queryClient.setQueryData(detailKey(id), entity);
|
|
99
|
+
},
|
|
100
|
+
deleted(payload, ctx) {
|
|
101
|
+
const id = deletedId(payload);
|
|
102
|
+
if (ctx.isFresh(freshKey(id)))
|
|
103
|
+
return;
|
|
104
|
+
patchList(ctx, (items) => items.filter((item) => getId(item) !== id));
|
|
105
|
+
if (detailKey)
|
|
106
|
+
ctx.queryClient.removeQueries({ queryKey: detailKey(id) });
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function hasStringId(value) {
|
|
111
|
+
return isRecord(value) && typeof value.id === "string";
|
|
112
|
+
}
|
|
113
|
+
function idOf(payload, getId) {
|
|
114
|
+
return hasStringId(payload) ? payload.id : getId(payload);
|
|
115
|
+
}
|
|
116
|
+
function hasId(data, getId, id) {
|
|
117
|
+
if (!data)
|
|
118
|
+
return false;
|
|
119
|
+
const pages = "pages" in data ? data.pages : [data];
|
|
120
|
+
return pages.some((page) => page.items.some((item) => getId(item) === id));
|
|
121
|
+
}
|
|
49
122
|
export {
|
|
123
|
+
createEntityCacheHandlers,
|
|
50
124
|
createCursorQuery,
|
|
51
125
|
createCacheBridge
|
|
52
126
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA8NxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A framework for the `onError` hook — the project supplies a code map and an
|
|
3
|
+
* envelope shape, `createErrorHook` does the normalisation.
|
|
4
|
+
*
|
|
5
|
+
* Every project writes the same `onError`: turn a thrown value into one wire
|
|
6
|
+
* shape, mapping stitchkit's own error codes to the app's public codes. The
|
|
7
|
+
* exhaustive `codeMap` (`satisfies Record<StitchErrorCode, …>`) is the point —
|
|
8
|
+
* a new `StitchErrorCode` in an upgrade breaks the map at compile time instead
|
|
9
|
+
* of leaking stitchkit's code to the wire. The envelope stays app-owned via
|
|
10
|
+
* `render`, so the core prescribes no domain shape (ADR 0002).
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const onError = createErrorHook({
|
|
14
|
+
* codeMap: {
|
|
15
|
+
* BAD_REQUEST: 'bad_request', VALIDATION_ERROR: 'bad_request',
|
|
16
|
+
* UNAUTHORIZED: 'unauthenticated', FORBIDDEN: 'forbidden',
|
|
17
|
+
* NOT_FOUND: 'not_found', METHOD_NOT_ALLOWED: 'not_found',
|
|
18
|
+
* CONFLICT: 'conflict', RATE_LIMITED: 'rate_limited',
|
|
19
|
+
* INTERNAL_SERVER_ERROR: 'internal',
|
|
20
|
+
* } satisfies Record<StitchErrorCode, string>,
|
|
21
|
+
* render: (info) => ({ ok: false, error: { code: info.code, message: info.message } }),
|
|
22
|
+
* });
|
|
23
|
+
* createServer({ services, hooks: { onError } });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { type StitchErrorCode } from '../contract';
|
|
27
|
+
import type { LifecycleHooks } from './types';
|
|
28
|
+
/** The normalised error handed to `render` — code already remapped. */
|
|
29
|
+
export interface ResolvedError {
|
|
30
|
+
/** Wire code — the app code from `codeMap` for a stitch error, else the thrown code. */
|
|
31
|
+
code: string;
|
|
32
|
+
/** HTTP status. */
|
|
33
|
+
status: number;
|
|
34
|
+
/** Safe message — the `AppError` message, or a generic string for a raw throw. */
|
|
35
|
+
message: string;
|
|
36
|
+
/** Structured details, when the thrown `AppError` carried them. */
|
|
37
|
+
details?: Record<string, unknown>;
|
|
38
|
+
/** Recovery hint, when the thrown `AppError` carried one. */
|
|
39
|
+
hint?: string;
|
|
40
|
+
}
|
|
41
|
+
/** Config for `createErrorHook`. */
|
|
42
|
+
export interface ErrorHookConfig<TWireCode extends string = string> {
|
|
43
|
+
/**
|
|
44
|
+
* Remap stitchkit's own error codes to your public wire codes. Exhaustive —
|
|
45
|
+
* `satisfies Record<StitchErrorCode, …>` makes a new framework code a compile
|
|
46
|
+
* error here. Codes you threw yourself (not stitchkit's) pass through as-is.
|
|
47
|
+
*/
|
|
48
|
+
codeMap?: Record<StitchErrorCode, TWireCode>;
|
|
49
|
+
/** Build the response body from the resolved error. */
|
|
50
|
+
render: (info: ResolvedError) => unknown;
|
|
51
|
+
/** Observe the raw thrown value before rendering — logging / metrics. */
|
|
52
|
+
onError?: (error: unknown, info: ResolvedError) => void;
|
|
53
|
+
}
|
|
54
|
+
/** Build an `onError` hook from a code map + envelope renderer. */
|
|
55
|
+
export declare function createErrorHook<TWireCode extends string = string>(config: ErrorHookConfig<TWireCode>): NonNullable<LifecycleHooks['onError']>;
|
|
56
|
+
//# sourceMappingURL=error-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-hook.d.ts","sourceRoot":"","sources":["../../src/server/error-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAA+B,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,oCAAoC;AACpC,MAAM,WAAW,eAAe,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM;IAChE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IAC7C,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC;IACzC,yEAAyE;IACzE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACzD;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,EAC/D,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAoBxC"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export { AppError, appError, badRequest, conflict, forbidden, isStitchErrorCode, notFound, rateLimited, STITCH_ERROR_STATUS, type StitchErrorCode, unauthorized, } from '../contract';
|
|
2
2
|
export { cacheHeaders, createCache } from './cache';
|
|
3
3
|
export { createHandler, createServer } from './create';
|
|
4
|
+
export { createErrorHook, type ErrorHookConfig, type ResolvedError, } from './error-hook';
|
|
4
5
|
export { createEventBus, type EventBus } from './event-bus';
|
|
5
6
|
export { type ByteRange, parseByteRange, type ServeFileOptions, serveFile, weakETag, } from './file';
|
|
6
7
|
export { createImplement, implement } from './implement';
|
|
7
8
|
export { type AuthHook, type AuthHookConfig, type AuthRule, type BearerResolverConfig, createAuthHook, createBearerResolver, extractToken, type JwtPayload, type SignJwtOptions, signJwt, verifyJwt, } from './middleware/auth';
|
|
8
9
|
export { type CookieDef, type CookieOptions, defineCookie, parseCookies, serializeCookie, } from './middleware/cookies';
|
|
9
|
-
export { type CorsConfig, corsHeaders, corsPreflightResponse, } from './middleware/cors';
|
|
10
|
+
export { type CorsConfig, corsHeaders, corsPreflightResponse, DEFAULT_CORS_ALLOW_HEADERS, } from './middleware/cors';
|
|
10
11
|
export { deriveCodeChallenge, type PkceMethod, verifyPkce } from './middleware/pkce';
|
|
11
12
|
export { parseMultipart } from './multipart';
|
|
12
13
|
export { generateOpenApiDocument, type OpenApiConfig, type OpenApiDocument, type OpenApiInfo, type OpenApiServer, openApiRoute, } from './openapi';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,KAAK,SAAS,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,SAAS,EACT,QAAQ,GACT,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,OAAO,EACP,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,KAAK,SAAS,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,SAAS,EACT,QAAQ,GACT,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,OAAO,EACP,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EACL,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,YAAY,EACjB,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,aAAa,GACd,MAAM,aAAa,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
composeWebSocketHandlers,
|
|
3
|
-
corsHeaders,
|
|
4
|
-
corsPreflightResponse,
|
|
5
3
|
createHandler,
|
|
6
4
|
createImplement,
|
|
7
5
|
createServer,
|
|
@@ -12,7 +10,7 @@ import {
|
|
|
12
10
|
socketIoLane,
|
|
13
11
|
staticRoute,
|
|
14
12
|
webSocketLane
|
|
15
|
-
} from "../index-
|
|
13
|
+
} from "../index-wpbn133x.js";
|
|
16
14
|
import {
|
|
17
15
|
createAuthHook,
|
|
18
16
|
createBearerResolver,
|
|
@@ -25,7 +23,12 @@ import {
|
|
|
25
23
|
signJwt,
|
|
26
24
|
verifyJwt,
|
|
27
25
|
verifyPkce
|
|
28
|
-
} from "../index-
|
|
26
|
+
} from "../index-ynnh9x6h.js";
|
|
27
|
+
import {
|
|
28
|
+
DEFAULT_CORS_ALLOW_HEADERS,
|
|
29
|
+
corsHeaders,
|
|
30
|
+
corsPreflightResponse
|
|
31
|
+
} from "../index-tje0q6gp.js";
|
|
29
32
|
import {
|
|
30
33
|
jsonSchemaFields,
|
|
31
34
|
toJsonSchema
|
|
@@ -42,7 +45,7 @@ import {
|
|
|
42
45
|
notFound,
|
|
43
46
|
rateLimited,
|
|
44
47
|
unauthorized
|
|
45
|
-
} from "../index-
|
|
48
|
+
} from "../index-ng2v2ts4.js";
|
|
46
49
|
import {
|
|
47
50
|
extractIp,
|
|
48
51
|
generateTraceId,
|
|
@@ -50,11 +53,11 @@ import {
|
|
|
50
53
|
getTraceId,
|
|
51
54
|
resolveSocketIp,
|
|
52
55
|
resolveTraceId
|
|
53
|
-
} from "../index-
|
|
56
|
+
} from "../index-dzx781tm.js";
|
|
54
57
|
import"../index-khwedj16.js";
|
|
55
58
|
import {
|
|
56
59
|
isRecord
|
|
57
|
-
} from "../index-
|
|
60
|
+
} from "../index-c7nyw0yt.js";
|
|
58
61
|
// src/server/swept-map.ts
|
|
59
62
|
function createSweptMap(options) {
|
|
60
63
|
const store = new Map;
|
|
@@ -112,6 +115,26 @@ function cacheHeaders(maxAge, scope = "public") {
|
|
|
112
115
|
"Cache-Control": `${scope}, max-age=${maxAge}`
|
|
113
116
|
};
|
|
114
117
|
}
|
|
118
|
+
// src/server/error-hook.ts
|
|
119
|
+
function createErrorHook(config) {
|
|
120
|
+
return (_ctx, error) => {
|
|
121
|
+
const isApp = AppError.is(error);
|
|
122
|
+
const rawCode = isApp ? error.code : "INTERNAL_SERVER_ERROR";
|
|
123
|
+
const code = config.codeMap && isStitchErrorCode(rawCode) ? config.codeMap[rawCode] : rawCode;
|
|
124
|
+
const info = {
|
|
125
|
+
code,
|
|
126
|
+
status: isApp ? error.status : 500,
|
|
127
|
+
message: isApp ? error.message : "Internal server error",
|
|
128
|
+
details: isApp ? error.details : undefined,
|
|
129
|
+
hint: isApp ? error.hint : undefined
|
|
130
|
+
};
|
|
131
|
+
config.onError?.(error, info);
|
|
132
|
+
return new Response(JSON.stringify(config.render(info)), {
|
|
133
|
+
status: info.status,
|
|
134
|
+
headers: { "content-type": "application/json" }
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
}
|
|
115
138
|
// src/server/event-bus.ts
|
|
116
139
|
function createEventBus(options = {}) {
|
|
117
140
|
const subscriptions = new Map;
|
|
@@ -633,6 +656,7 @@ export {
|
|
|
633
656
|
createImplement,
|
|
634
657
|
createHandler,
|
|
635
658
|
createEventBus,
|
|
659
|
+
createErrorHook,
|
|
636
660
|
createCache,
|
|
637
661
|
createBearerResolver,
|
|
638
662
|
createAuthHook,
|
|
@@ -644,5 +668,6 @@ export {
|
|
|
644
668
|
badRequest,
|
|
645
669
|
appError,
|
|
646
670
|
STITCH_ERROR_STATUS,
|
|
671
|
+
DEFAULT_CORS_ALLOW_HEADERS,
|
|
647
672
|
AppError
|
|
648
673
|
};
|