stitchkit 0.54.0 → 0.56.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/README.md +4 -1
- package/dist/browser/socket-io.d.ts +25 -7
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/cli.js +14 -9
- package/dist/contract/errors.d.ts +7 -0
- package/dist/contract/errors.d.ts.map +1 -1
- package/dist/contract/file-ref.d.ts +13 -0
- package/dist/contract/file-ref.d.ts.map +1 -0
- package/dist/contract/index.d.ts +1 -0
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +21 -17
- package/dist/files/boundary.d.ts +55 -0
- package/dist/files/boundary.d.ts.map +1 -0
- package/dist/files.d.ts +3 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +16 -0
- package/dist/index-1bx83sw4.js +4 -0
- package/dist/{index-pfqjb5xy.js → index-28cqssm3.js} +30 -5
- package/dist/index-557by2db.js +34 -0
- package/dist/index-5r13htq1.js +283 -0
- package/dist/index-6k1937bx.js +20 -0
- package/dist/index-6y759j86.js +1031 -0
- package/dist/{index-bmnhqtya.js → index-7eq9va6e.js} +1 -4
- package/dist/index-bfcpjw20.js +363 -0
- package/dist/{index-yxpe3phd.js → index-cby4ar3v.js} +1 -18
- package/dist/{index-7vb44hy8.js → index-escqg10p.js} +193 -751
- package/dist/{index-173tvqcp.js → index-j3dem06f.js} +9 -114
- package/dist/{index-gvha32jh.js → index-jcc611vh.js} +2 -2
- package/dist/{index-z7761jk2.js → index-n4nfa7gh.js} +16 -22
- package/dist/{index-e1es808r.js → index-qh4xevf5.js} +1 -1
- package/dist/index-sbdmyz75.js +18 -0
- package/dist/{index-b15rtha1.js → index-sm2tjx06.js} +98 -3
- package/dist/{index-yez419px.js → index-xy8fmh6w.js} +99 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +188 -40
- package/dist/node.js +31 -27
- package/dist/observability/index.js +28 -25
- package/dist/react.js +2 -2
- package/dist/realtime/contract.d.ts +9 -0
- package/dist/realtime/contract.d.ts.map +1 -1
- package/dist/realtime/index.d.ts +2 -1
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/request.d.ts +21 -0
- package/dist/realtime/request.d.ts.map +1 -0
- package/dist/realtime/socket.d.ts +3 -0
- package/dist/realtime/socket.d.ts.map +1 -1
- package/dist/remote.d.ts +9 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +79 -0
- package/dist/server/context-contribution.d.ts +18 -0
- package/dist/server/context-contribution.d.ts.map +1 -0
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +136 -88
- package/dist/server/lifecycle.d.ts +4 -0
- package/dist/server/lifecycle.d.ts.map +1 -0
- package/dist/server/middleware/auth.d.ts +64 -9
- package/dist/server/middleware/auth.d.ts.map +1 -1
- package/dist/server/types.d.ts +1 -1
- package/dist/server/types.d.ts.map +1 -1
- package/dist/testing/surface-conformance.d.ts +180 -0
- package/dist/testing/surface-conformance.d.ts.map +1 -0
- package/dist/testing/surface-manifest.d.ts +255 -0
- package/dist/testing/surface-manifest.d.ts.map +1 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +714 -3
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/async-operation.d.ts +360 -0
- package/dist/tools/async-operation.d.ts.map +1 -0
- package/dist/tools/cli-args.d.ts +1 -1
- package/dist/tools/cli-args.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-wait.d.ts +11 -2
- package/dist/tools/cli-wait.d.ts.map +1 -1
- package/dist/tools/cli.d.ts +2 -0
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools/define-download-tool.d.ts +6 -5
- package/dist/tools/define-download-tool.d.ts.map +1 -1
- package/dist/tools/define-upload-tool.d.ts +3 -1
- package/dist/tools/define-upload-tool.d.ts.map +1 -1
- package/dist/tools/define-wait-tool.d.ts +1 -1
- package/dist/tools/define-wait-tool.d.ts.map +1 -1
- package/dist/tools/download-core.d.ts +5 -10
- package/dist/tools/download-core.d.ts.map +1 -1
- package/dist/tools/internal/surface-projector.d.ts +101 -0
- package/dist/tools/internal/surface-projector.d.ts.map +1 -0
- package/dist/tools/lifecycle.d.ts +4 -0
- package/dist/tools/lifecycle.d.ts.map +1 -0
- package/dist/tools/managed-file-error.d.ts +6 -0
- package/dist/tools/managed-file-error.d.ts.map +1 -0
- package/dist/tools/mcp-prepare.d.ts +3 -21
- package/dist/tools/mcp-prepare.d.ts.map +1 -1
- package/dist/tools/mcp-round-policy.d.ts +9 -0
- package/dist/tools/mcp-round-policy.d.ts.map +1 -0
- package/dist/tools/mcp-round.d.ts +0 -4
- package/dist/tools/mcp-round.d.ts.map +1 -1
- package/dist/tools/mount-download.d.ts +5 -4
- package/dist/tools/mount-download.d.ts.map +1 -1
- package/dist/tools/mount-upload.d.ts +4 -2
- package/dist/tools/mount-upload.d.ts.map +1 -1
- package/dist/tools/mount.d.ts +5 -9
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools/surface.d.ts +7 -0
- package/dist/tools/surface.d.ts.map +1 -1
- package/dist/tools/upload-core.d.ts +3 -2
- package/dist/tools/upload-core.d.ts.map +1 -1
- package/dist/tools/view-file.d.ts +4 -3
- package/dist/tools/view-file.d.ts.map +1 -1
- package/dist/tools/wait-core.d.ts +6 -1
- package/dist/tools/wait-core.d.ts.map +1 -1
- package/dist/tools.d.ts +3 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +705 -599
- package/llms-full.txt +727 -34
- package/package.json +10 -2
|
@@ -1,119 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AppError,
|
|
3
|
+
isUnsafeKey
|
|
4
|
+
} from "./index-5r13htq1.js";
|
|
1
5
|
import {
|
|
2
6
|
isRecord,
|
|
3
7
|
resolveTraceContext
|
|
4
|
-
} from "./index-
|
|
5
|
-
|
|
6
|
-
// src/contract/errors.ts
|
|
7
|
-
var APP_ERROR_BRAND = Symbol.for("stitchkit.AppError");
|
|
8
|
-
|
|
9
|
-
class AppError extends Error {
|
|
10
|
-
code;
|
|
11
|
-
status;
|
|
12
|
-
details;
|
|
13
|
-
hint;
|
|
14
|
-
traceId;
|
|
15
|
-
constructor(code, message, status = 500, details, hint, traceId) {
|
|
16
|
-
super(message ?? code);
|
|
17
|
-
this.code = code;
|
|
18
|
-
this.status = status;
|
|
19
|
-
this.details = details;
|
|
20
|
-
this.hint = hint;
|
|
21
|
-
this.traceId = traceId;
|
|
22
|
-
this.name = "AppError";
|
|
23
|
-
Object.defineProperty(this, APP_ERROR_BRAND, { value: true });
|
|
24
|
-
}
|
|
25
|
-
static is(err) {
|
|
26
|
-
return typeof err === "object" && err !== null && APP_ERROR_BRAND in err;
|
|
27
|
-
}
|
|
28
|
-
toJSON() {
|
|
29
|
-
return {
|
|
30
|
-
error: {
|
|
31
|
-
code: this.code,
|
|
32
|
-
message: this.message,
|
|
33
|
-
...this.details && { details: this.details },
|
|
34
|
-
...this.hint && { hint: this.hint }
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
function notFound(message = "Not found") {
|
|
40
|
-
throw new AppError("NOT_FOUND", message, 404);
|
|
41
|
-
}
|
|
42
|
-
function badRequest(message, details) {
|
|
43
|
-
throw new AppError("BAD_REQUEST", message, 400, details);
|
|
44
|
-
}
|
|
45
|
-
function unauthorized(message = "Unauthorized") {
|
|
46
|
-
throw new AppError("UNAUTHORIZED", message, 401);
|
|
47
|
-
}
|
|
48
|
-
function forbidden(message = "Forbidden") {
|
|
49
|
-
throw new AppError("FORBIDDEN", message, 403);
|
|
50
|
-
}
|
|
51
|
-
function conflict(message = "Conflict", details) {
|
|
52
|
-
throw new AppError("CONFLICT", message, 409, details);
|
|
53
|
-
}
|
|
54
|
-
function rateLimited(message = "Too many requests") {
|
|
55
|
-
throw new AppError("RATE_LIMITED", message, 429);
|
|
56
|
-
}
|
|
57
|
-
var STITCH_ERROR_STATUS = {
|
|
58
|
-
BAD_REQUEST: 400,
|
|
59
|
-
UNAUTHORIZED: 401,
|
|
60
|
-
FORBIDDEN: 403,
|
|
61
|
-
NOT_FOUND: 404,
|
|
62
|
-
METHOD_NOT_ALLOWED: 405,
|
|
63
|
-
CONFLICT: 409,
|
|
64
|
-
RATE_LIMITED: 429,
|
|
65
|
-
VALIDATION_ERROR: 400,
|
|
66
|
-
REALTIME_CONTRACT_VIOLATION: 500,
|
|
67
|
-
INTERNAL_SERVER_ERROR: 500
|
|
68
|
-
};
|
|
69
|
-
function isStitchErrorCode(code) {
|
|
70
|
-
return Object.hasOwn(STITCH_ERROR_STATUS, code);
|
|
71
|
-
}
|
|
72
|
-
function appError(code, message, details) {
|
|
73
|
-
throw new AppError(code, message, isStitchErrorCode(code) ? STITCH_ERROR_STATUS[code] : 500, details);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/contract/define.ts
|
|
77
|
-
import { z } from "zod";
|
|
78
|
-
|
|
79
|
-
// src/internal/safe-json.ts
|
|
80
|
-
function isUnsafeKey(key) {
|
|
81
|
-
return key === "__proto__";
|
|
82
|
-
}
|
|
83
|
-
function safeJsonParse(text) {
|
|
84
|
-
return JSON.parse(text, (key, value) => isUnsafeKey(key) ? undefined : value);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/contract/define.ts
|
|
88
|
-
function mergeMeta(contractMeta, endpointMeta) {
|
|
89
|
-
if (!contractMeta)
|
|
90
|
-
return endpointMeta;
|
|
91
|
-
if (!endpointMeta)
|
|
92
|
-
return { ...contractMeta };
|
|
93
|
-
return { ...contractMeta, ...endpointMeta };
|
|
94
|
-
}
|
|
95
|
-
// src/contract/errors-factory.ts
|
|
96
|
-
import { z as z2 } from "zod";
|
|
97
|
-
// src/contract/pagination.ts
|
|
98
|
-
import { z as z3 } from "zod";
|
|
8
|
+
} from "./index-7eq9va6e.js";
|
|
99
9
|
|
|
100
|
-
// src/internal/base64url.ts
|
|
101
|
-
function bytesToBase64Url(bytes) {
|
|
102
|
-
let binary = "";
|
|
103
|
-
for (const byte of bytes)
|
|
104
|
-
binary += String.fromCharCode(byte);
|
|
105
|
-
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
106
|
-
}
|
|
107
|
-
function base64UrlToBytes(segment) {
|
|
108
|
-
if (!/^[A-Za-z0-9_-]*$/.test(segment) || segment.length % 4 === 1) {
|
|
109
|
-
throw new Error("invalid base64url segment");
|
|
110
|
-
}
|
|
111
|
-
const b64 = segment.replace(/-/g, "+").replace(/_/g, "/");
|
|
112
|
-
const padded = b64.padEnd(Math.ceil(b64.length / 4) * 4, "=");
|
|
113
|
-
return Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
|
|
114
|
-
}
|
|
115
10
|
// src/internal/errors.ts
|
|
116
|
-
import { z
|
|
11
|
+
import { z } from "zod";
|
|
117
12
|
function issuePath(path) {
|
|
118
13
|
return path.length > 0 ? path.map(String).join(".") : "(root)";
|
|
119
14
|
}
|
|
@@ -136,7 +31,7 @@ var MAX_DETAIL_ISSUES = 20;
|
|
|
136
31
|
function errorCode(err) {
|
|
137
32
|
if (AppError.is(err))
|
|
138
33
|
return err.code;
|
|
139
|
-
if (err instanceof
|
|
34
|
+
if (err instanceof z.ZodError)
|
|
140
35
|
return "VALIDATION_ERROR";
|
|
141
36
|
return;
|
|
142
37
|
}
|
|
@@ -156,7 +51,7 @@ function normalizeError(err) {
|
|
|
156
51
|
}
|
|
157
52
|
return err;
|
|
158
53
|
}
|
|
159
|
-
if (err instanceof
|
|
54
|
+
if (err instanceof z.ZodError) {
|
|
160
55
|
return new AppError("VALIDATION_ERROR", formatZodError(err), 400, {
|
|
161
56
|
issues: zodIssues(err).slice(0, MAX_DETAIL_ISSUES)
|
|
162
57
|
});
|
|
@@ -322,4 +217,4 @@ function wrapInRequestContext(handler, options = {}) {
|
|
|
322
217
|
};
|
|
323
218
|
}
|
|
324
219
|
|
|
325
|
-
export {
|
|
220
|
+
export { formatZodError, zodIssues, errorCode, recordedErrorMessage, normalizeError, validateDeclaredOutput, generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
|
|
@@ -1,39 +1,44 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_PROCESS_SIGNALS,
|
|
3
|
+
RUNTIME_CONTEXT_RESERVED_KEYS,
|
|
3
4
|
assertCorsConfig,
|
|
4
5
|
corsHeaders,
|
|
5
6
|
corsPreflightResponse,
|
|
6
7
|
defaultSignalSource,
|
|
7
8
|
guardSignalCallback,
|
|
8
9
|
reportSignalError
|
|
9
|
-
} from "./index-
|
|
10
|
+
} from "./index-sm2tjx06.js";
|
|
10
11
|
import {
|
|
11
|
-
AppError,
|
|
12
|
-
badRequest,
|
|
13
12
|
errorCode,
|
|
14
13
|
extractIp,
|
|
15
14
|
getClientInfo,
|
|
16
15
|
getRequestContext,
|
|
17
|
-
isUnsafeKey,
|
|
18
16
|
normalizeError,
|
|
19
17
|
parseQueryParams,
|
|
20
18
|
recordedErrorMessage,
|
|
21
19
|
resolveSocketIp,
|
|
22
20
|
resolveTraceId,
|
|
23
21
|
runWithRequestContext,
|
|
24
|
-
safeJsonParse,
|
|
25
22
|
setRequestEndpoint,
|
|
26
23
|
setRequestError,
|
|
27
24
|
validateDeclaredOutput,
|
|
28
25
|
zodIssues
|
|
29
|
-
} from "./index-
|
|
26
|
+
} from "./index-j3dem06f.js";
|
|
27
|
+
import {
|
|
28
|
+
AppError,
|
|
29
|
+
badRequest,
|
|
30
|
+
isUnsafeKey,
|
|
31
|
+
safeJsonParse
|
|
32
|
+
} from "./index-5r13htq1.js";
|
|
30
33
|
import {
|
|
31
|
-
__require,
|
|
32
34
|
isRecord,
|
|
33
35
|
parseTrailingWildcard,
|
|
34
36
|
resolveTraceContext,
|
|
35
37
|
transportResult
|
|
36
|
-
} from "./index-
|
|
38
|
+
} from "./index-7eq9va6e.js";
|
|
39
|
+
import {
|
|
40
|
+
__require
|
|
41
|
+
} from "./index-1bx83sw4.js";
|
|
37
42
|
|
|
38
43
|
// src/server/multipart.ts
|
|
39
44
|
var DEFAULT_MAX_REQUEST_BYTES = 25 * 1024 * 1024;
|
|
@@ -500,19 +505,6 @@ async function readRequestText(req, maxBytes) {
|
|
|
500
505
|
}
|
|
501
506
|
|
|
502
507
|
// src/server/context.ts
|
|
503
|
-
var RESERVED_KEYS = new Set([
|
|
504
|
-
"params",
|
|
505
|
-
"input",
|
|
506
|
-
"source",
|
|
507
|
-
"req",
|
|
508
|
-
"url",
|
|
509
|
-
"headers",
|
|
510
|
-
"rawBody",
|
|
511
|
-
"traceId",
|
|
512
|
-
"spanId",
|
|
513
|
-
"ipAddress",
|
|
514
|
-
"userAgent"
|
|
515
|
-
]);
|
|
516
508
|
function parseJsonBody(req, text) {
|
|
517
509
|
if (text.trim() === "")
|
|
518
510
|
return {};
|
|
@@ -528,7 +520,7 @@ function parseJsonBody(req, text) {
|
|
|
528
520
|
function buildBaseContext(req, url, pathParams, traceId, clientIp) {
|
|
529
521
|
const safePathParams = {};
|
|
530
522
|
for (const [k, v] of Object.entries(pathParams)) {
|
|
531
|
-
if (!
|
|
523
|
+
if (!RUNTIME_CONTEXT_RESERVED_KEYS.has(k) && !isUnsafeKey(k))
|
|
532
524
|
safePathParams[k] = v;
|
|
533
525
|
}
|
|
534
526
|
return {
|
|
@@ -538,6 +530,7 @@ function buildBaseContext(req, url, pathParams, traceId, clientIp) {
|
|
|
538
530
|
req,
|
|
539
531
|
url,
|
|
540
532
|
headers: req.headers,
|
|
533
|
+
signal: req.signal,
|
|
541
534
|
...safePathParams,
|
|
542
535
|
traceId,
|
|
543
536
|
...getClientInfo(req, clientIp)
|
|
@@ -585,6 +578,7 @@ function buildErrorContext(req, url, traceId, clientIp) {
|
|
|
585
578
|
req,
|
|
586
579
|
url,
|
|
587
580
|
headers: req.headers,
|
|
581
|
+
signal: req.signal,
|
|
588
582
|
traceId,
|
|
589
583
|
...getClientInfo(req, clientIp)
|
|
590
584
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/internal/within-dir.ts
|
|
2
|
+
import { realpath } from "node:fs/promises";
|
|
3
|
+
import { sep } from "node:path";
|
|
4
|
+
function isWithinDir(root, target) {
|
|
5
|
+
const base = root.endsWith(sep) ? root.slice(0, -sep.length) : root;
|
|
6
|
+
return target === root || target === base || target.startsWith(base + sep);
|
|
7
|
+
}
|
|
8
|
+
async function realPathWithinDir(root, target) {
|
|
9
|
+
const [realRoot, realTarget] = await Promise.all([
|
|
10
|
+
realpath(root).catch(() => null),
|
|
11
|
+
realpath(target).catch(() => null)
|
|
12
|
+
]);
|
|
13
|
+
if (realRoot === null || realTarget === null)
|
|
14
|
+
return null;
|
|
15
|
+
return isWithinDir(realRoot, realTarget) ? realTarget : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { isWithinDir, realPathWithinDir };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
isUnsafeKey,
|
|
2
3
|
mergeMeta
|
|
3
|
-
} from "./index-
|
|
4
|
+
} from "./index-5r13htq1.js";
|
|
4
5
|
import {
|
|
5
6
|
callRuntimeHandler,
|
|
6
7
|
isRecord,
|
|
7
8
|
transportResult,
|
|
8
9
|
typedEntries
|
|
9
|
-
} from "./index-
|
|
10
|
+
} from "./index-7eq9va6e.js";
|
|
10
11
|
|
|
11
12
|
// src/server/middleware/cors.ts
|
|
12
13
|
var DEFAULT_CORS_ALLOW_HEADERS = "Content-Type, Authorization, X-Trace-Id, traceparent, tracestate";
|
|
@@ -246,6 +247,100 @@ function createImplementRegistry() {
|
|
|
246
247
|
return (contracts, handlers) => transportResult(bindRegistry(contracts, handlers));
|
|
247
248
|
}
|
|
248
249
|
|
|
250
|
+
// src/server/context-contribution.ts
|
|
251
|
+
var RUNTIME_CONTEXT_RESERVED_KEYS = new Set([
|
|
252
|
+
"params",
|
|
253
|
+
"input",
|
|
254
|
+
"files",
|
|
255
|
+
"rawBody",
|
|
256
|
+
"source",
|
|
257
|
+
"req",
|
|
258
|
+
"url",
|
|
259
|
+
"headers",
|
|
260
|
+
"traceId",
|
|
261
|
+
"spanId",
|
|
262
|
+
"ipAddress",
|
|
263
|
+
"userAgent",
|
|
264
|
+
"signal",
|
|
265
|
+
"mcp"
|
|
266
|
+
]);
|
|
267
|
+
function contributionError(scope, reason) {
|
|
268
|
+
return new TypeError(`[stitchkit] auth: invalid context contribution for scope ${JSON.stringify(scope)}: ${reason}`);
|
|
269
|
+
}
|
|
270
|
+
function descriptorsEqual(left, right) {
|
|
271
|
+
if (!left || !right)
|
|
272
|
+
return left === right;
|
|
273
|
+
if (left.enumerable !== right.enumerable || left.configurable !== right.configurable || left.writable !== right.writable) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
if ("value" in left || "value" in right) {
|
|
277
|
+
return "value" in left && "value" in right && Object.is(left.value, right.value);
|
|
278
|
+
}
|
|
279
|
+
return left.get === right.get && left.set === right.set;
|
|
280
|
+
}
|
|
281
|
+
function contextContributionDelta(original, shadow, scope) {
|
|
282
|
+
if (Object.getPrototypeOf(shadow) !== Object.getPrototypeOf(original)) {
|
|
283
|
+
throw contributionError(scope, "context prototype changes are not supported");
|
|
284
|
+
}
|
|
285
|
+
const originalKeys = Reflect.ownKeys(original);
|
|
286
|
+
const shadowKeys = Reflect.ownKeys(shadow);
|
|
287
|
+
const shadowKeySet = new Set(shadowKeys);
|
|
288
|
+
for (const key of originalKeys) {
|
|
289
|
+
if (!shadowKeySet.has(key)) {
|
|
290
|
+
const printable = typeof key === "string" ? JSON.stringify(key) : "a symbol key";
|
|
291
|
+
throw contributionError(scope, `context key ${printable} may not be deleted`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const contribution = Object.create(null);
|
|
295
|
+
for (const key of shadowKeys) {
|
|
296
|
+
const originalDescriptor = Object.getOwnPropertyDescriptor(original, key);
|
|
297
|
+
const shadowDescriptor = Object.getOwnPropertyDescriptor(shadow, key);
|
|
298
|
+
if (!shadowDescriptor || descriptorsEqual(originalDescriptor, shadowDescriptor))
|
|
299
|
+
continue;
|
|
300
|
+
Object.defineProperty(contribution, key, shadowDescriptor);
|
|
301
|
+
}
|
|
302
|
+
return contribution;
|
|
303
|
+
}
|
|
304
|
+
function prepareContextContribution(value, scope) {
|
|
305
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
306
|
+
throw contributionError(scope, "expected a plain record");
|
|
307
|
+
}
|
|
308
|
+
let prototype;
|
|
309
|
+
let descriptors;
|
|
310
|
+
let keys;
|
|
311
|
+
try {
|
|
312
|
+
prototype = Object.getPrototypeOf(value);
|
|
313
|
+
descriptors = Object.getOwnPropertyDescriptors(value);
|
|
314
|
+
keys = Reflect.ownKeys(value);
|
|
315
|
+
} catch {
|
|
316
|
+
throw contributionError(scope, "record inspection failed");
|
|
317
|
+
}
|
|
318
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
319
|
+
throw contributionError(scope, "expected Object.prototype or null prototype");
|
|
320
|
+
}
|
|
321
|
+
const prepared = Object.create(null);
|
|
322
|
+
for (const key of keys) {
|
|
323
|
+
if (typeof key !== "string") {
|
|
324
|
+
throw contributionError(scope, "symbol keys are not supported");
|
|
325
|
+
}
|
|
326
|
+
if (isUnsafeKey(key)) {
|
|
327
|
+
throw contributionError(scope, `unsafe key ${JSON.stringify(key)}`);
|
|
328
|
+
}
|
|
329
|
+
if (RUNTIME_CONTEXT_RESERVED_KEYS.has(key)) {
|
|
330
|
+
throw contributionError(scope, `reserved key ${JSON.stringify(key)}`);
|
|
331
|
+
}
|
|
332
|
+
const descriptor = descriptors[key];
|
|
333
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) {
|
|
334
|
+
throw contributionError(scope, `key ${JSON.stringify(key)} must be enumerable data`);
|
|
335
|
+
}
|
|
336
|
+
prepared[key] = descriptor.value;
|
|
337
|
+
}
|
|
338
|
+
return prepared;
|
|
339
|
+
}
|
|
340
|
+
function mergeContextContribution(ctx, value, scope) {
|
|
341
|
+
Object.assign(ctx, prepareContextContribution(value, scope));
|
|
342
|
+
}
|
|
343
|
+
|
|
249
344
|
// src/server/process-signal-common.ts
|
|
250
345
|
var DEFAULT_PROCESS_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
251
346
|
var defaultSignalSource = {
|
|
@@ -275,4 +370,4 @@ function guardSignalCallback(run, phase, onError) {
|
|
|
275
370
|
}
|
|
276
371
|
}
|
|
277
372
|
|
|
278
|
-
export { DEFAULT_CORS_ALLOW_HEADERS, DEFAULT_CORS_EXPOSE_HEADERS, assertCorsConfig, corsHeaders, corsPreflightResponse, defineMultipartStream, createMultipartStream, contractOnlyService, implement, createImplement, createScopedImplement, createScopedImplementRegistry, implementRegistry, createImplementRegistry, DEFAULT_PROCESS_SIGNALS, defaultSignalSource, reportSignalError, guardSignalCallback };
|
|
373
|
+
export { RUNTIME_CONTEXT_RESERVED_KEYS, contextContributionDelta, prepareContextContribution, mergeContextContribution, DEFAULT_CORS_ALLOW_HEADERS, DEFAULT_CORS_EXPOSE_HEADERS, assertCorsConfig, corsHeaders, corsPreflightResponse, defineMultipartStream, createMultipartStream, contractOnlyService, implement, createImplement, createScopedImplement, createScopedImplementRegistry, implementRegistry, createImplementRegistry, DEFAULT_PROCESS_SIGNALS, defaultSignalSource, reportSignalError, guardSignalCallback };
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
contextContributionDelta,
|
|
3
|
+
mergeContextContribution,
|
|
4
|
+
prepareContextContribution
|
|
5
|
+
} from "./index-sm2tjx06.js";
|
|
1
6
|
import {
|
|
2
7
|
base64UrlToBytes,
|
|
3
8
|
bytesToBase64Url,
|
|
@@ -5,10 +10,10 @@ import {
|
|
|
5
10
|
isUnsafeKey,
|
|
6
11
|
safeJsonParse,
|
|
7
12
|
unauthorized
|
|
8
|
-
} from "./index-
|
|
13
|
+
} from "./index-5r13htq1.js";
|
|
9
14
|
import {
|
|
10
15
|
isRecord
|
|
11
|
-
} from "./index-
|
|
16
|
+
} from "./index-7eq9va6e.js";
|
|
12
17
|
|
|
13
18
|
// src/server/middleware/cookies.ts
|
|
14
19
|
function parseCookies(header) {
|
|
@@ -151,7 +156,22 @@ function extractToken(req, cookieName) {
|
|
|
151
156
|
return null;
|
|
152
157
|
}
|
|
153
158
|
function isThenable(value) {
|
|
154
|
-
|
|
159
|
+
try {
|
|
160
|
+
return "then" in value && typeof value.then === "function";
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
var scopedAuthHookBrand = Symbol("stitchkit.scoped-auth-hook");
|
|
166
|
+
var authOwnershipPlans = new WeakMap;
|
|
167
|
+
function createShadowContext(ctx) {
|
|
168
|
+
const shadow = {
|
|
169
|
+
params: ctx.params,
|
|
170
|
+
input: ctx.input,
|
|
171
|
+
source: ctx.source
|
|
172
|
+
};
|
|
173
|
+
Object.defineProperties(shadow, Object.getOwnPropertyDescriptors(ctx));
|
|
174
|
+
return shadow;
|
|
155
175
|
}
|
|
156
176
|
function createAuthHook(config) {
|
|
157
177
|
const onAnonymous = config.onAnonymous ?? (() => unauthorized());
|
|
@@ -169,10 +189,10 @@ function createAuthHook(config) {
|
|
|
169
189
|
const rule = typeof entry === "object" ? entry.rule : entry;
|
|
170
190
|
if (typeof entry === "object" && entry.inject && identity !== null) {
|
|
171
191
|
const fields = entry.inject(identity, ctx);
|
|
172
|
-
if (isThenable(fields)) {
|
|
192
|
+
if (typeof fields === "object" && fields !== null && isThenable(fields)) {
|
|
173
193
|
throw new Error(`[stitchkit] auth: the inject of scope "${scope}" must be synchronous — an async inject merges a Promise, not fields`);
|
|
174
194
|
}
|
|
175
|
-
|
|
195
|
+
mergeContextContribution(ctx, fields, scope);
|
|
176
196
|
}
|
|
177
197
|
if (rule === "public")
|
|
178
198
|
return;
|
|
@@ -182,11 +202,83 @@ function createAuthHook(config) {
|
|
|
182
202
|
}
|
|
183
203
|
if (rule === "authenticated")
|
|
184
204
|
return;
|
|
185
|
-
|
|
205
|
+
const result = await rule(identity, ctx);
|
|
206
|
+
if (result === false) {
|
|
186
207
|
onForbidden();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (result === true)
|
|
211
|
+
return;
|
|
212
|
+
mergeContextContribution(ctx, result, scope);
|
|
187
213
|
}
|
|
214
|
+
auth[scopedAuthHookBrand] = () => {
|
|
215
|
+
return;
|
|
216
|
+
};
|
|
217
|
+
authOwnershipPlans.set(auth, {
|
|
218
|
+
defaultScope: config.defaultScope,
|
|
219
|
+
hook: auth,
|
|
220
|
+
scopes: new Set(Object.keys(config.rules))
|
|
221
|
+
});
|
|
188
222
|
return auth;
|
|
189
223
|
}
|
|
224
|
+
function composeAuthHooks(config) {
|
|
225
|
+
const plans = [];
|
|
226
|
+
for (const hook of config.hooks) {
|
|
227
|
+
const plan = authOwnershipPlans.get(hook);
|
|
228
|
+
if (!plan) {
|
|
229
|
+
throw new TypeError("[stitchkit] auth: composeAuthHooks accepts only hooks created by createAuthHook or composeAuthHooks");
|
|
230
|
+
}
|
|
231
|
+
if (plan.defaultScope !== undefined && plan.defaultScope !== config.defaultScope) {
|
|
232
|
+
throw new TypeError(`[stitchkit] auth: child default scope ${JSON.stringify(plan.defaultScope)} must match the composite default scope`);
|
|
233
|
+
}
|
|
234
|
+
plans.push(plan);
|
|
235
|
+
}
|
|
236
|
+
const defaultScope = config.defaultScope;
|
|
237
|
+
if (defaultScope !== undefined && !plans.some((plan) => plan.scopes.has(defaultScope))) {
|
|
238
|
+
throw new TypeError(`[stitchkit] auth: composite default scope ${JSON.stringify(defaultScope)} has no owner`);
|
|
239
|
+
}
|
|
240
|
+
const ownedScopes = new Set;
|
|
241
|
+
for (const plan of plans) {
|
|
242
|
+
for (const scope of plan.scopes)
|
|
243
|
+
ownedScopes.add(scope);
|
|
244
|
+
}
|
|
245
|
+
async function composed(ctx, endpoint) {
|
|
246
|
+
const scope = endpoint.scope ?? config.defaultScope;
|
|
247
|
+
if (!scope)
|
|
248
|
+
return;
|
|
249
|
+
const owners = plans.filter((plan) => plan.scopes.has(scope));
|
|
250
|
+
if (owners.length === 0) {
|
|
251
|
+
throw new Error(`[stitchkit] auth: no rule for scope "${scope}"`);
|
|
252
|
+
}
|
|
253
|
+
const scopedEndpoint = { ...endpoint, scope };
|
|
254
|
+
const contribution = Object.create(null);
|
|
255
|
+
const contributionOwners = new Set;
|
|
256
|
+
for (const owner of owners) {
|
|
257
|
+
ctx.signal?.throwIfAborted();
|
|
258
|
+
const shadow = createShadowContext(ctx);
|
|
259
|
+
await owner.hook(shadow, scopedEndpoint);
|
|
260
|
+
const ownerContribution = prepareContextContribution(contextContributionDelta(ctx, shadow, scope), scope);
|
|
261
|
+
for (const key of Object.keys(ownerContribution)) {
|
|
262
|
+
if (contributionOwners.has(key)) {
|
|
263
|
+
throw new TypeError(`[stitchkit] auth: multiple owners contributed context key ${JSON.stringify(key)} for scope ${JSON.stringify(scope)}`);
|
|
264
|
+
}
|
|
265
|
+
contributionOwners.add(key);
|
|
266
|
+
}
|
|
267
|
+
Object.assign(contribution, ownerContribution);
|
|
268
|
+
}
|
|
269
|
+
ctx.signal?.throwIfAborted();
|
|
270
|
+
mergeContextContribution(ctx, contribution, scope);
|
|
271
|
+
}
|
|
272
|
+
composed[scopedAuthHookBrand] = () => {
|
|
273
|
+
return;
|
|
274
|
+
};
|
|
275
|
+
authOwnershipPlans.set(composed, {
|
|
276
|
+
defaultScope: config.defaultScope,
|
|
277
|
+
hook: composed,
|
|
278
|
+
scopes: ownedScopes
|
|
279
|
+
});
|
|
280
|
+
return composed;
|
|
281
|
+
}
|
|
190
282
|
function createBearerResolver(config) {
|
|
191
283
|
return async (req) => {
|
|
192
284
|
const token = extractToken(req);
|
|
@@ -208,4 +300,4 @@ async function verifyPkce(verifier, challenge) {
|
|
|
208
300
|
return derived === challenge;
|
|
209
301
|
}
|
|
210
302
|
|
|
211
|
-
export { parseCookies, serializeCookie, defineCookie, verifyJwt, signJwt, extractToken, createAuthHook, createBearerResolver, deriveCodeChallenge, verifyPkce };
|
|
303
|
+
export { parseCookies, serializeCookie, defineCookie, verifyJwt, signJwt, extractToken, createAuthHook, composeAuthHooks, createBearerResolver, deriveCodeChallenge, verifyPkce };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { type ClientConfig, type ClientContract, type ClientFetch, type ClientRegistryValue, type ContractClientConfig, contractEndpointMatchers, createClient, createClients, createScopedClients, createScopedUrlBuilders, createUrlBuilder, createUrlBuilders, type PathPrefixArgs, type RegistryScope, type ScopeClientConfigs, type ScopedClientRegistry, type ScopedUrlBuilderRegistry, type UrlBuilderConfig, } from './browser/client';
|
|
2
2
|
export { ApiError, type ApiEvent, type ApiEventListener, type ConfiguredHttpClient, createHttpClient, type HeaderProvider, type HttpClient, type HttpClientConfig, type RequestOptions, type UnauthorizedMatcher, } from './browser/http';
|
|
3
|
-
export type { RealtimeClient, RealtimeClientOptions, SocketEventMap, SocketIOClient, SocketIOClientConfig, } from './browser/socket-io';
|
|
4
|
-
export { createRealtimeClient, createSocketIOClient } from './browser/socket-io';
|
|
3
|
+
export type { BindRealtimeClientOptions, BoundRealtimeClient, RealtimeClient, RealtimeClientOptions, RealtimeClientTransport, SocketEventMap, SocketIOClient, SocketIOClientConfig, } from './browser/socket-io';
|
|
4
|
+
export { bindRealtimeClient, createRealtimeClient, createSocketIOClient, } from './browser/socket-io';
|
|
5
5
|
export { type ParseSSEOptions, parseSSE } from './browser/stream';
|
|
6
6
|
export * from './contract';
|
|
7
7
|
export type { StitchLogger } from './logger';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,wBAAwB,EACxB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,wBAAwB,EACxB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAClE,cAAc,YAAY,CAAC;AAC3B,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC"}
|