stitchkit 0.45.0 → 0.47.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 +5 -4
- package/dist/browser/cancellation.d.ts +14 -0
- package/dist/browser/cancellation.d.ts.map +1 -0
- package/dist/browser/client-multipart.d.ts +3 -1
- package/dist/browser/client-multipart.d.ts.map +1 -1
- package/dist/browser/client.d.ts +1 -0
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/http.d.ts +1 -0
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/browser/socket-io.d.ts +3 -1
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/cli.js +3 -4
- package/dist/contract/define.d.ts +59 -15
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/errors.d.ts +1 -0
- package/dist/contract/errors.d.ts.map +1 -1
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +2 -2
- package/dist/{index-w0mec79h.js → index-44xysy8r.js} +697 -301
- package/dist/{index-r6czv7yt.js → index-45dz4m51.js} +50 -3
- package/dist/index-8ekq6res.js +181 -0
- package/dist/{index-yh0p5ddn.js → index-ee621cmy.js} +39 -19
- package/dist/{index-mvjyq9h9.js → index-kp8xamqp.js} +309 -144
- package/dist/{index-36f1xkdb.js → index-nrytvb30.js} +5 -4
- package/dist/{index-6jypn22c.js → index-r1qp4rve.js} +9 -1
- package/dist/{index-s4qsmgwe.js → index-tss6bk5c.js} +4 -1
- package/dist/index-yxpe3phd.js +63 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +315 -134
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/secure-fetch.d.ts +23 -3
- package/dist/internal/secure-fetch.d.ts.map +1 -1
- package/dist/internal/typed.d.ts +7 -0
- package/dist/internal/typed.d.ts.map +1 -1
- package/dist/internal/within-dir.d.ts +6 -0
- package/dist/internal/within-dir.d.ts.map +1 -1
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/node.js +3 -4
- package/dist/observability/audit.d.ts +22 -3
- package/dist/observability/audit.d.ts.map +1 -1
- package/dist/observability/event.d.ts +7 -0
- package/dist/observability/event.d.ts.map +1 -1
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +130 -134
- package/dist/observability/sanitize.d.ts +8 -1
- package/dist/observability/sanitize.d.ts.map +1 -1
- package/dist/observability/trace.d.ts +3 -1
- package/dist/observability/trace.d.ts.map +1 -1
- package/dist/react/cache-bridge.d.ts +4 -0
- package/dist/react/cache-bridge.d.ts.map +1 -1
- package/dist/react.js +46 -5
- package/dist/realtime/contract.d.ts +4 -1
- package/dist/realtime/contract.d.ts.map +1 -1
- package/dist/realtime/rejection.d.ts +10 -0
- package/dist/realtime/rejection.d.ts.map +1 -0
- package/dist/realtime/socket.d.ts +14 -1
- package/dist/realtime/socket.d.ts.map +1 -1
- package/dist/server/cache.d.ts +5 -1
- package/dist/server/cache.d.ts.map +1 -1
- package/dist/server/context.d.ts +8 -5
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/error-hook.d.ts +1 -0
- package/dist/server/error-hook.d.ts.map +1 -1
- package/dist/server/file.d.ts +6 -0
- package/dist/server/file.d.ts.map +1 -1
- package/dist/server/implement.d.ts +33 -2
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.d.ts +5 -6
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +133 -14
- package/dist/server/middleware/auth.d.ts +7 -4
- package/dist/server/middleware/auth.d.ts.map +1 -1
- package/dist/server/middleware/cors.d.ts.map +1 -1
- package/dist/server/multipart.d.ts +13 -18
- package/dist/server/multipart.d.ts.map +1 -1
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/realtime.d.ts +2 -0
- package/dist/server/realtime.d.ts.map +1 -1
- package/dist/server/router.d.ts +0 -8
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/stream.d.ts.map +1 -1
- package/dist/server/types.d.ts +50 -22
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/cli-args.d.ts +11 -3
- package/dist/tools/cli-args.d.ts.map +1 -1
- package/dist/tools/cli.d.ts +5 -0
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools/coerce.d.ts.map +1 -1
- package/dist/tools/json-schema.d.ts.map +1 -1
- package/dist/tools/mcp-handler.d.ts +4 -3
- package/dist/tools/mcp-handler.d.ts.map +1 -1
- package/dist/tools/mcp-prepare.d.ts +95 -0
- package/dist/tools/mcp-prepare.d.ts.map +1 -0
- package/dist/tools/mcp-round.d.ts +4 -0
- package/dist/tools/mcp-round.d.ts.map +1 -1
- package/dist/tools/mcp-stdio.d.ts +2 -1
- package/dist/tools/mcp-stdio.d.ts.map +1 -1
- package/dist/tools/mcp.d.ts +2 -78
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/mount-download.d.ts +5 -0
- package/dist/tools/mount-download.d.ts.map +1 -1
- package/dist/tools/native-mcp.d.ts +1 -1
- package/dist/tools/native-mcp.d.ts.map +1 -1
- package/dist/tools/oauth-provider.d.ts +20 -1
- package/dist/tools/oauth-provider.d.ts.map +1 -1
- package/dist/tools/tool-logger.d.ts +1 -1
- package/dist/tools/tool-logger.d.ts.map +1 -1
- package/dist/tools/view-file.d.ts +9 -0
- package/dist/tools/view-file.d.ts.map +1 -1
- package/dist/tools.d.ts +2 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +505 -278
- package/llms-full.txt +473 -85
- package/llms.txt +1 -1
- package/package.json +2 -2
- package/dist/index-frfyw9fa.js +0 -33
- package/dist/index-x3fcszf8.js +0 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mapObjectTypeBoundary
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-tss6bk5c.js";
|
|
4
4
|
|
|
5
5
|
// src/contract/define.ts
|
|
6
6
|
import { z } from "zod";
|
|
@@ -47,6 +47,11 @@ function parseTrailingWildcard(path) {
|
|
|
47
47
|
return wildcard;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// src/internal/safe-json.ts
|
|
51
|
+
function isUnsafeKey(key) {
|
|
52
|
+
return key === "__proto__";
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
// src/contract/define.ts
|
|
51
56
|
var ALL_TRANSPORTS = ["HTTP", "MCP", "AGENT", "CLI"];
|
|
52
57
|
function defineContract(meta, endpoints) {
|
|
@@ -68,6 +73,8 @@ function defineContract(meta, endpoints) {
|
|
|
68
73
|
if (ep.maxJsonBodyBytes !== undefined && (!Number.isSafeInteger(ep.maxJsonBodyBytes) || ep.maxJsonBodyBytes <= 0)) {
|
|
69
74
|
throw new Error(`Contract "${meta.prefix}": endpoint "${key}" maxJsonBodyBytes must be a positive safe integer, received ${ep.maxJsonBodyBytes}`);
|
|
70
75
|
}
|
|
76
|
+
if (ep.multipart)
|
|
77
|
+
assertMultipartEndpoint(meta.prefix, key, ep);
|
|
71
78
|
if (ep.rawResponse)
|
|
72
79
|
assertRawEndpoint(meta.prefix, key, ep);
|
|
73
80
|
if (ep.method === "HEAD")
|
|
@@ -96,6 +103,45 @@ function defineContract(meta, endpoints) {
|
|
|
96
103
|
}
|
|
97
104
|
return { meta, endpoints };
|
|
98
105
|
}
|
|
106
|
+
function assertPositiveLimit(where, name, value) {
|
|
107
|
+
if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0)) {
|
|
108
|
+
throw new Error(`${where} ${name} must be a positive safe integer, received ${value}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function assertMultipartEndpoint(prefix, key, ep) {
|
|
112
|
+
const where = `Contract "${prefix}": multipart endpoint "${key}"`;
|
|
113
|
+
if (ep.method !== "POST" && ep.method !== "PUT" && ep.method !== "PATCH") {
|
|
114
|
+
throw new Error(`${where} must use POST, PUT or PATCH`);
|
|
115
|
+
}
|
|
116
|
+
const multipart = ep.multipart;
|
|
117
|
+
if (!multipart || typeof multipart !== "object") {
|
|
118
|
+
throw new Error(`${where} must declare a multipart descriptor`);
|
|
119
|
+
}
|
|
120
|
+
assertPositiveLimit(where, "maxRequestBytes", multipart.maxRequestBytes);
|
|
121
|
+
assertPositiveLimit(where, "maxFieldBytes", multipart.maxFieldBytes);
|
|
122
|
+
const entries = Object.entries(multipart.files);
|
|
123
|
+
if (entries.length === 0)
|
|
124
|
+
throw new Error(`${where} must declare at least one file field`);
|
|
125
|
+
for (const [field, policy] of entries) {
|
|
126
|
+
if (!field || isUnsafeKey(field))
|
|
127
|
+
throw new Error(`${where} has an invalid file field name`);
|
|
128
|
+
assertPositiveLimit(`${where} field "${field}"`, "maxBytes", policy.maxBytes);
|
|
129
|
+
assertPositiveLimit(`${where} field "${field}"`, "maxFiles", policy.maxFiles);
|
|
130
|
+
if (policy.multiple !== true && policy.maxFiles !== undefined) {
|
|
131
|
+
throw new Error(`${where} field "${field}" may set maxFiles only with multiple: true`);
|
|
132
|
+
}
|
|
133
|
+
if (policy.contentTypes) {
|
|
134
|
+
if (policy.contentTypes.length === 0) {
|
|
135
|
+
throw new Error(`${where} field "${field}" contentTypes cannot be empty`);
|
|
136
|
+
}
|
|
137
|
+
for (const contentType of policy.contentTypes) {
|
|
138
|
+
if (!/^[a-z0-9!#$&^_.+-]+\/(?:[a-z0-9!#$&^_.+-]+|\*)$/i.test(contentType)) {
|
|
139
|
+
throw new Error(`${where} field "${field}" has invalid content type policy "${contentType}"`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
99
145
|
function assertRawEndpoint(prefix, key, ep) {
|
|
100
146
|
const where = `Contract "${prefix}": raw endpoint "${key}"`;
|
|
101
147
|
if (ep.output)
|
|
@@ -228,10 +274,11 @@ var STITCH_ERROR_STATUS = {
|
|
|
228
274
|
CONFLICT: 409,
|
|
229
275
|
RATE_LIMITED: 429,
|
|
230
276
|
VALIDATION_ERROR: 400,
|
|
277
|
+
REALTIME_CONTRACT_VIOLATION: 500,
|
|
231
278
|
INTERNAL_SERVER_ERROR: 500
|
|
232
279
|
};
|
|
233
280
|
function isStitchErrorCode(code) {
|
|
234
|
-
return code
|
|
281
|
+
return Object.hasOwn(STITCH_ERROR_STATUS, code);
|
|
235
282
|
}
|
|
236
283
|
function appError(code, message, details) {
|
|
237
284
|
throw new AppError(code, message, isStitchErrorCode(code) ? STITCH_ERROR_STATUS[code] : 500, details);
|
|
@@ -342,4 +389,4 @@ function decodeCursor(cursor, schema) {
|
|
|
342
389
|
return null;
|
|
343
390
|
}
|
|
344
391
|
}
|
|
345
|
-
export { parseTrailingWildcard,
|
|
392
|
+
export { parseTrailingWildcard, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, ALL_TRANSPORTS, defineContract, defineErrors, createContractFactory, paginatedSchema, encodeCursor, decodeCursor };
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRecord,
|
|
3
|
+
isUnsafeKey
|
|
4
|
+
} from "./index-ee621cmy.js";
|
|
5
|
+
|
|
6
|
+
// src/observability/sanitize.ts
|
|
7
|
+
var SENSITIVE_WORDS = new Set([
|
|
8
|
+
"password",
|
|
9
|
+
"passwords",
|
|
10
|
+
"passwd",
|
|
11
|
+
"pwd",
|
|
12
|
+
"secret",
|
|
13
|
+
"secrets",
|
|
14
|
+
"token",
|
|
15
|
+
"tokens",
|
|
16
|
+
"apikey",
|
|
17
|
+
"auth",
|
|
18
|
+
"authorization",
|
|
19
|
+
"bearer",
|
|
20
|
+
"cookie",
|
|
21
|
+
"cookies",
|
|
22
|
+
"credential",
|
|
23
|
+
"credentials"
|
|
24
|
+
]);
|
|
25
|
+
var SENSITIVE_WORD_PAIRS = new Set([
|
|
26
|
+
"apikey",
|
|
27
|
+
"privatekey",
|
|
28
|
+
"initdata",
|
|
29
|
+
"sessionid",
|
|
30
|
+
"sessionkey"
|
|
31
|
+
]);
|
|
32
|
+
var SENSITIVE_EXACT = new Set(["session"]);
|
|
33
|
+
function splitKeyWords(key) {
|
|
34
|
+
return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter((word) => word.length > 0);
|
|
35
|
+
}
|
|
36
|
+
function isSensitiveKeyDefault(key) {
|
|
37
|
+
const words = splitKeyWords(key);
|
|
38
|
+
if (words.length === 1 && SENSITIVE_EXACT.has(words[0] ?? ""))
|
|
39
|
+
return true;
|
|
40
|
+
for (let index = 0;index < words.length; index += 1) {
|
|
41
|
+
const word = words[index] ?? "";
|
|
42
|
+
if (SENSITIVE_WORDS.has(word))
|
|
43
|
+
return true;
|
|
44
|
+
const next = words[index + 1];
|
|
45
|
+
if (next !== undefined && SENSITIVE_WORD_PAIRS.has(word + next))
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
var DEFAULT_MAX_BYTES = 16000;
|
|
51
|
+
var DEFAULT_MAX_DEPTH = 20;
|
|
52
|
+
var MASK = "[redacted]";
|
|
53
|
+
function redact(value, options = {}) {
|
|
54
|
+
const custom = options.sensitiveKeys;
|
|
55
|
+
const isSensitive = custom === undefined ? isSensitiveKeyDefault : (key) => {
|
|
56
|
+
custom.lastIndex = 0;
|
|
57
|
+
return custom.test(key);
|
|
58
|
+
};
|
|
59
|
+
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
60
|
+
const ancestors = new Set;
|
|
61
|
+
const walk = (input, depth) => {
|
|
62
|
+
if (depth > maxDepth)
|
|
63
|
+
return "[max depth]";
|
|
64
|
+
if (input === null || input === undefined)
|
|
65
|
+
return null;
|
|
66
|
+
if (typeof input === "string" || typeof input === "number" || typeof input === "boolean") {
|
|
67
|
+
return input;
|
|
68
|
+
}
|
|
69
|
+
if (input instanceof Uint8Array || input instanceof ArrayBuffer) {
|
|
70
|
+
return { _type: "binary", size: input.byteLength };
|
|
71
|
+
}
|
|
72
|
+
if (input instanceof Blob) {
|
|
73
|
+
return { _type: "blob", size: input.size, mime: input.type };
|
|
74
|
+
}
|
|
75
|
+
if (typeof FormData !== "undefined" && input instanceof FormData) {
|
|
76
|
+
return { _type: "formdata", keys: [...input.keys()] };
|
|
77
|
+
}
|
|
78
|
+
if (input instanceof Map) {
|
|
79
|
+
if (ancestors.has(input))
|
|
80
|
+
return "[circular]";
|
|
81
|
+
ancestors.add(input);
|
|
82
|
+
const result = [...input.entries()].map(([key, value2]) => [
|
|
83
|
+
walk(key, depth + 1),
|
|
84
|
+
walk(value2, depth + 1)
|
|
85
|
+
]);
|
|
86
|
+
ancestors.delete(input);
|
|
87
|
+
return { _type: "map", entries: result };
|
|
88
|
+
}
|
|
89
|
+
if (input instanceof Set) {
|
|
90
|
+
if (ancestors.has(input))
|
|
91
|
+
return "[circular]";
|
|
92
|
+
ancestors.add(input);
|
|
93
|
+
const values = [...input].map((item) => walk(item, depth + 1));
|
|
94
|
+
ancestors.delete(input);
|
|
95
|
+
return { _type: "set", values };
|
|
96
|
+
}
|
|
97
|
+
if (input instanceof Error) {
|
|
98
|
+
return {
|
|
99
|
+
_type: "error",
|
|
100
|
+
name: input.name,
|
|
101
|
+
message: input.message,
|
|
102
|
+
...input.stack !== undefined && { stack: input.stack }
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(input)) {
|
|
106
|
+
if (ancestors.has(input))
|
|
107
|
+
return "[circular]";
|
|
108
|
+
ancestors.add(input);
|
|
109
|
+
const result = input.map((item) => walk(item, depth + 1));
|
|
110
|
+
ancestors.delete(input);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
if (isRecord(input)) {
|
|
114
|
+
if (ancestors.has(input))
|
|
115
|
+
return "[circular]";
|
|
116
|
+
ancestors.add(input);
|
|
117
|
+
const out = {};
|
|
118
|
+
for (const key of Object.keys(input)) {
|
|
119
|
+
if (isUnsafeKey(key))
|
|
120
|
+
continue;
|
|
121
|
+
if (isSensitive(key)) {
|
|
122
|
+
out[key] = MASK;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
out[key] = walk(Reflect.get(input, key), depth + 1);
|
|
127
|
+
} catch {
|
|
128
|
+
out[key] = "[unreadable]";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
ancestors.delete(input);
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
return String(input);
|
|
135
|
+
};
|
|
136
|
+
return walk(value, 0);
|
|
137
|
+
}
|
|
138
|
+
function truncatePreview(value, maxBytes = DEFAULT_MAX_BYTES) {
|
|
139
|
+
const json = JSON.stringify(value);
|
|
140
|
+
const bytes = new TextEncoder().encode(json);
|
|
141
|
+
if (bytes.byteLength <= maxBytes)
|
|
142
|
+
return value;
|
|
143
|
+
let end = Math.max(0, maxBytes);
|
|
144
|
+
while (end > 0 && ((bytes[end] ?? 0) & 192) === 128)
|
|
145
|
+
end -= 1;
|
|
146
|
+
const preview = new TextDecoder().decode(bytes.subarray(0, end));
|
|
147
|
+
return {
|
|
148
|
+
_truncated: true,
|
|
149
|
+
_originalBytes: bytes.byteLength,
|
|
150
|
+
preview: `${preview}…`
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function sanitizePayload(value, options = {}) {
|
|
154
|
+
if (value === undefined || value === null)
|
|
155
|
+
return null;
|
|
156
|
+
try {
|
|
157
|
+
return truncatePreview(redact(value, options), options.maxBytes ?? DEFAULT_MAX_BYTES);
|
|
158
|
+
} catch {
|
|
159
|
+
return "[unserializable]";
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function measureSize(value) {
|
|
163
|
+
if (value === undefined || value === null) {
|
|
164
|
+
return { resultSize: null, responseBytes: 0 };
|
|
165
|
+
}
|
|
166
|
+
let responseBytes = 0;
|
|
167
|
+
try {
|
|
168
|
+
responseBytes = new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
169
|
+
} catch {
|
|
170
|
+
return { resultSize: null, responseBytes: 0, unserializable: true };
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(value)) {
|
|
173
|
+
return { resultSize: value.length, responseBytes };
|
|
174
|
+
}
|
|
175
|
+
if (isRecord(value) && Array.isArray(value.items) && "nextCursor" in value) {
|
|
176
|
+
return { resultSize: value.items.length, responseBytes };
|
|
177
|
+
}
|
|
178
|
+
return { resultSize: null, responseBytes };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { redact, truncatePreview, sanitizePayload, measureSize };
|
|
@@ -59,10 +59,11 @@ var STITCH_ERROR_STATUS = {
|
|
|
59
59
|
CONFLICT: 409,
|
|
60
60
|
RATE_LIMITED: 429,
|
|
61
61
|
VALIDATION_ERROR: 400,
|
|
62
|
+
REALTIME_CONTRACT_VIOLATION: 500,
|
|
62
63
|
INTERNAL_SERVER_ERROR: 500
|
|
63
64
|
};
|
|
64
65
|
function isStitchErrorCode(code) {
|
|
65
|
-
return code
|
|
66
|
+
return Object.hasOwn(STITCH_ERROR_STATUS, code);
|
|
66
67
|
}
|
|
67
68
|
function appError(code, message, details) {
|
|
68
69
|
throw new AppError(code, message, isStitchErrorCode(code) ? STITCH_ERROR_STATUS[code] : 500, details);
|
|
@@ -113,6 +114,14 @@ function parseTrailingWildcard(path) {
|
|
|
113
114
|
return wildcard;
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
// src/internal/safe-json.ts
|
|
118
|
+
function isUnsafeKey(key) {
|
|
119
|
+
return key === "__proto__";
|
|
120
|
+
}
|
|
121
|
+
function safeJsonParse(text) {
|
|
122
|
+
return JSON.parse(text, (key, value) => isUnsafeKey(key) ? undefined : value);
|
|
123
|
+
}
|
|
124
|
+
|
|
116
125
|
// src/contract/define.ts
|
|
117
126
|
function mergeMeta(contractMeta, endpointMeta) {
|
|
118
127
|
if (!contractMeta)
|
|
@@ -131,6 +140,12 @@ function typedEntries(value) {
|
|
|
131
140
|
function isRecord(value) {
|
|
132
141
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
133
142
|
}
|
|
143
|
+
function callRuntimeHandler(handler, context) {
|
|
144
|
+
if (typeof handler !== "function") {
|
|
145
|
+
throw new TypeError("Runtime handler must be a function");
|
|
146
|
+
}
|
|
147
|
+
return Reflect.apply(handler, undefined, [context]);
|
|
148
|
+
}
|
|
134
149
|
// src/contract/pagination.ts
|
|
135
150
|
import { z as z3 } from "zod";
|
|
136
151
|
|
|
@@ -178,7 +193,7 @@ function errorCode(err) {
|
|
|
178
193
|
return;
|
|
179
194
|
}
|
|
180
195
|
function recordedErrorMessage(code, envelopeMessage, thrown) {
|
|
181
|
-
if (code === "INTERNAL_SERVER_ERROR" && thrown !== undefined) {
|
|
196
|
+
if ((code === "INTERNAL_SERVER_ERROR" || code === "REALTIME_CONTRACT_VIOLATION") && thrown !== undefined) {
|
|
182
197
|
if (thrown instanceof Error)
|
|
183
198
|
return thrown.message;
|
|
184
199
|
if (typeof thrown === "string")
|
|
@@ -187,8 +202,12 @@ function recordedErrorMessage(code, envelopeMessage, thrown) {
|
|
|
187
202
|
return envelopeMessage;
|
|
188
203
|
}
|
|
189
204
|
function normalizeError(err) {
|
|
190
|
-
if (AppError.is(err))
|
|
205
|
+
if (AppError.is(err)) {
|
|
206
|
+
if (err.code === "REALTIME_CONTRACT_VIOLATION") {
|
|
207
|
+
return new AppError("REALTIME_CONTRACT_VIOLATION", "Realtime contract violation", 500);
|
|
208
|
+
}
|
|
191
209
|
return err;
|
|
210
|
+
}
|
|
192
211
|
if (err instanceof z4.ZodError) {
|
|
193
212
|
return new AppError("VALIDATION_ERROR", formatZodError(err), 400, {
|
|
194
213
|
issues: zodIssues(err).slice(0, MAX_DETAIL_ISSUES)
|
|
@@ -249,14 +268,6 @@ function validateDeclaredOutput(schema, data, onStripped) {
|
|
|
249
268
|
return validateHandlerOutput(schema, data, onStripped);
|
|
250
269
|
}
|
|
251
270
|
|
|
252
|
-
// src/internal/safe-json.ts
|
|
253
|
-
function isUnsafeKey(key) {
|
|
254
|
-
return key === "__proto__";
|
|
255
|
-
}
|
|
256
|
-
function safeJsonParse(text) {
|
|
257
|
-
return JSON.parse(text, (key, value) => isUnsafeKey(key) ? undefined : value);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
271
|
// src/server/request.ts
|
|
261
272
|
function generateTraceId() {
|
|
262
273
|
return `${Date.now().toString(36)}-${crypto.randomUUID().slice(0, 8)}`;
|
|
@@ -310,7 +321,7 @@ function parseQueryParams(url) {
|
|
|
310
321
|
}
|
|
311
322
|
|
|
312
323
|
// src/observability/trace.ts
|
|
313
|
-
var TRACEPARENT_RE = /^
|
|
324
|
+
var TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(.*)$/i;
|
|
314
325
|
function randomHex(bytes) {
|
|
315
326
|
const arr = new Uint8Array(bytes);
|
|
316
327
|
crypto.getRandomValues(arr);
|
|
@@ -326,16 +337,24 @@ function parseTraceparent(header) {
|
|
|
326
337
|
if (!header)
|
|
327
338
|
return null;
|
|
328
339
|
const match = TRACEPARENT_RE.exec(header.trim());
|
|
329
|
-
if (!match?.[1] || !match[2])
|
|
340
|
+
if (!match?.[1] || !match[2] || !match[3] || !match[4] || match[5] === undefined)
|
|
330
341
|
return null;
|
|
331
|
-
const
|
|
332
|
-
|
|
342
|
+
const version = match[1].toLowerCase();
|
|
343
|
+
if (version === "ff")
|
|
344
|
+
return null;
|
|
345
|
+
const suffix = match[5];
|
|
346
|
+
if (version === "00" ? suffix !== "" : suffix !== "" && !/^(?:-[0-9a-f]{2,})+$/i.test(suffix)) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
const traceId = match[2].toLowerCase();
|
|
350
|
+
const parentSpanId = match[3].toLowerCase();
|
|
351
|
+
const traceFlags = match[4].toLowerCase();
|
|
333
352
|
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
|
|
334
353
|
return null;
|
|
335
|
-
return { traceId, spanId: randomHex(8), parentSpanId };
|
|
354
|
+
return { traceId, spanId: randomHex(8), parentSpanId, traceFlags };
|
|
336
355
|
}
|
|
337
356
|
function formatTraceparent(ctx) {
|
|
338
|
-
return `00-${ctx.traceId}-${ctx.spanId}
|
|
357
|
+
return `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags ?? "01"}`;
|
|
339
358
|
}
|
|
340
359
|
function resolveTraceContext(req) {
|
|
341
360
|
return parseTraceparent(req.headers.get("traceparent")) ?? createTraceContext();
|
|
@@ -346,7 +365,8 @@ function childSpan(parent) {
|
|
|
346
365
|
spanId: randomHex(8),
|
|
347
366
|
parentSpanId: parent.spanId,
|
|
348
367
|
...parent.tracestate !== undefined && { tracestate: parent.tracestate },
|
|
349
|
-
...parent.baggage !== undefined && { baggage: parent.baggage }
|
|
368
|
+
...parent.baggage !== undefined && { baggage: parent.baggage },
|
|
369
|
+
...parent.traceFlags !== undefined && { traceFlags: parent.traceFlags }
|
|
350
370
|
};
|
|
351
371
|
}
|
|
352
372
|
var encoder = new TextEncoder;
|
|
@@ -434,4 +454,4 @@ function wrapInRequestContext(handler, options = {}) {
|
|
|
434
454
|
};
|
|
435
455
|
}
|
|
436
456
|
|
|
437
|
-
export { __require, parseTrailingWildcard, mergeMeta, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, typedEntries, isRecord, bytesToBase64Url, base64UrlToBytes, formatZodError, zodIssues, errorCode, recordedErrorMessage, normalizeError, validateDeclaredOutput,
|
|
457
|
+
export { __require, parseTrailingWildcard, isUnsafeKey, safeJsonParse, mergeMeta, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, typedEntries, isRecord, callRuntimeHandler, bytesToBase64Url, base64UrlToBytes, formatZodError, zodIssues, errorCode, recordedErrorMessage, normalizeError, validateDeclaredOutput, generateTraceId, resolveTraceId, resolveSocketIp, extractIp, getClientInfo, parseQueryParams, createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, resolvePropagationContext, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestEndpoint, setRequestDimensions, setRequestError, wrapInRequestContext };
|