stitchkit 0.90.7 → 0.91.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/CHANGELOG.md +107 -0
- package/dist/agent-runtime-coding-tools.js +4 -4
- package/dist/agent-runtime-harness.js +6 -6
- package/dist/agent-runtime-sandbox.js +4 -4
- package/dist/agent-runtime.js +18 -17
- package/dist/application-grammy.js +1 -1
- package/dist/application.js +3 -3
- package/dist/cli.js +7 -7
- package/dist/contract/errors-factory.d.ts +12 -0
- package/dist/contract/errors-factory.d.ts.map +1 -1
- package/dist/contract/errors.d.ts +35 -1
- 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 +4 -2
- package/dist/{index-nrqg8tks.js → index-0a349c33.js} +3 -3
- package/dist/index-0j3vcp5m.js +28 -0
- package/dist/{index-vy2nxwg8.js → index-137jjs4v.js} +2 -2
- package/dist/{index-2hryh65w.js → index-13cjtmrw.js} +54 -13
- package/dist/{index-7gqx71yd.js → index-13e1k7v9.js} +9 -3
- package/dist/{index-1bnkzq95.js → index-1qvdwnp2.js} +10 -3
- package/dist/{index-scs3f1eg.js → index-2vtcmrj9.js} +8 -2
- package/dist/{index-xbppf54a.js → index-6kyksz9y.js} +12 -7
- package/dist/{index-aj9geeez.js → index-709nh7z7.js} +37 -17
- package/dist/{index-zkcqhxx8.js → index-a11g2kry.js} +1 -1
- package/dist/{index-1txvygak.js → index-b971qjes.js} +1 -1
- package/dist/{index-tgh3ksfh.js → index-bh70rk41.js} +3 -3
- package/dist/{index-bva395we.js → index-bv7mytab.js} +2 -2
- package/dist/{index-s208wab5.js → index-bx6yq2m4.js} +23 -495
- package/dist/{index-83fafqw8.js → index-f4p4b8f6.js} +10 -11
- package/dist/index-kw9t5ayn.js +507 -0
- package/dist/{index-8pjqv3zh.js → index-mqhjmadk.js} +43 -21
- package/dist/{index-3yqgj323.js → index-qjeyx5t2.js} +2 -2
- package/dist/{index-gte38nbm.js → index-qmy6zq75.js} +1 -1
- package/dist/{index-zsdgd1tz.js → index-qrbdq8jk.js} +1 -1
- package/dist/{index-fqg5mfk7.js → index-ya611vx3.js} +4 -4
- package/dist/{index-640tz39q.js → index-zsqy3xfn.js} +5 -5
- package/dist/index.js +8 -6
- package/dist/internal/canonical-json.d.ts +20 -0
- package/dist/internal/canonical-json.d.ts.map +1 -0
- package/dist/internal/errors.d.ts +13 -4
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/node.js +6 -6
- package/dist/observability/bounded-logger.d.ts +2 -0
- package/dist/observability/bounded-logger.d.ts.map +1 -1
- package/dist/observability/index.js +7 -4
- package/dist/observability/sanitize.d.ts +15 -0
- package/dist/observability/sanitize.d.ts.map +1 -1
- package/dist/primitives.js +2 -2
- package/dist/realtime/rejected-frame.d.ts +6 -0
- package/dist/realtime/rejected-frame.d.ts.map +1 -1
- package/dist/remote.js +5 -5
- package/dist/server/implement.d.ts +33 -7
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +8 -8
- package/dist/testing/surface-manifest.d.ts +2 -1
- package/dist/testing/surface-manifest.d.ts.map +1 -1
- package/dist/testing.js +11 -27
- package/dist/tool-invoker.js +6 -6
- package/dist/tools/agent.d.ts +12 -0
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/cli-format.d.ts +1 -1
- package/dist/tools/connections/index.js +1 -1
- package/dist/tools/durability-context.d.ts +1 -1
- package/dist/tools/durability-context.d.ts.map +1 -1
- package/dist/tools/durability-port.d.ts +55 -0
- package/dist/tools/durability-port.d.ts.map +1 -0
- package/dist/tools/execute.d.ts +59 -1
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/mcp-catalog.d.ts +68 -0
- package/dist/tools/mcp-catalog.d.ts.map +1 -0
- package/dist/tools/mcp.d.ts +3 -0
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/mount.d.ts +2 -2
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/native-mcp.d.ts +3 -0
- package/dist/tools/native-mcp.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts +1 -1
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools.d.ts +5 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +99 -20
- package/dist/tracking.js +2 -2
- package/llms-full.txt +258 -8
- package/package.json +2 -2
- package/dist/index-7rkhw9ec.js +0 -34
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AppError
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-2vtcmrj9.js";
|
|
4
4
|
import {
|
|
5
5
|
isRecord
|
|
6
6
|
} from "./index-77fekveh.js";
|
|
@@ -10,21 +10,62 @@ import { z } from "zod";
|
|
|
10
10
|
function issuePath(path) {
|
|
11
11
|
return path.length > 0 ? path.map(String).join(".") : "(root)";
|
|
12
12
|
}
|
|
13
|
+
var MAX_UNION_DEPTH = 3;
|
|
14
|
+
var MAX_DESCRIBED_BRANCHES = 5;
|
|
15
|
+
function unionBranches(issue) {
|
|
16
|
+
const errors = Reflect.get(issue, "errors");
|
|
17
|
+
if (!Array.isArray(errors) || errors.length === 0)
|
|
18
|
+
return;
|
|
19
|
+
if (!errors.every((branch) => Array.isArray(branch)))
|
|
20
|
+
return;
|
|
21
|
+
return errors;
|
|
22
|
+
}
|
|
23
|
+
function unionSummary(branches, prefix) {
|
|
24
|
+
const described = branches.slice(0, MAX_DESCRIBED_BRANCHES).map((issues, index) => {
|
|
25
|
+
const first = issues[0];
|
|
26
|
+
if (!first)
|
|
27
|
+
return `branch ${index + 1} reported no reason`;
|
|
28
|
+
return `branch ${index + 1} at ${issuePath([...prefix, ...first.path])}: ${first.message}`;
|
|
29
|
+
});
|
|
30
|
+
const rest = branches.length - described.length;
|
|
31
|
+
const suffix = rest > 0 ? `; ...and ${rest} more branches` : "";
|
|
32
|
+
return `No union branch matched — ${described.join("; ")}${suffix}`;
|
|
33
|
+
}
|
|
34
|
+
function collectIssues(issues, prefix, branch, depth, into) {
|
|
35
|
+
for (const issue of issues) {
|
|
36
|
+
const path = [...prefix, ...issue.path];
|
|
37
|
+
const branches = depth < MAX_UNION_DEPTH ? unionBranches(issue) : undefined;
|
|
38
|
+
into.push({
|
|
39
|
+
path: issuePath(path),
|
|
40
|
+
code: issue.code,
|
|
41
|
+
message: branches ? unionSummary(branches, path) : issue.message,
|
|
42
|
+
...branch !== undefined && { branch }
|
|
43
|
+
});
|
|
44
|
+
if (!branches)
|
|
45
|
+
continue;
|
|
46
|
+
branches.forEach((branchIssues, index) => {
|
|
47
|
+
collectIssues(branchIssues, path, index + 1, depth + 1, into);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function zodIssues(error) {
|
|
52
|
+
const issues = [];
|
|
53
|
+
collectIssues(error.issues, [], undefined, 0, issues);
|
|
54
|
+
return issues;
|
|
55
|
+
}
|
|
56
|
+
var MAX_FORMATTED_ISSUES = 5;
|
|
13
57
|
function formatZodError(error) {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
58
|
+
const all = zodIssues(error);
|
|
59
|
+
const shown = all.slice(0, MAX_FORMATTED_ISSUES);
|
|
60
|
+
const lines = shown.map((issue) => {
|
|
61
|
+
const where = issue.branch === undefined ? issue.path : `${issue.path} (branch ${issue.branch})`;
|
|
62
|
+
return `${where}: ${issue.message}`;
|
|
63
|
+
});
|
|
64
|
+
const suffix = all.length > shown.length ? `
|
|
65
|
+
...and ${all.length - shown.length} more issues` : "";
|
|
18
66
|
return lines.join(`
|
|
19
67
|
`) + suffix;
|
|
20
68
|
}
|
|
21
|
-
function zodIssues(error) {
|
|
22
|
-
return error.issues.map((issue) => ({
|
|
23
|
-
path: issuePath(issue.path),
|
|
24
|
-
code: issue.code,
|
|
25
|
-
message: issue.message
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
69
|
var MAX_DETAIL_ISSUES = 20;
|
|
29
70
|
function errorCode(err) {
|
|
30
71
|
if (AppError.is(err))
|
|
@@ -109,4 +150,4 @@ function validateDeclaredOutput(schema, data, onStripped) {
|
|
|
109
150
|
return validateHandlerOutput(schema, data, onStripped);
|
|
110
151
|
}
|
|
111
152
|
|
|
112
|
-
export {
|
|
153
|
+
export { zodIssues, formatZodError, errorCode, recordedErrorMessage, normalizeError, validateDeclaredOutput };
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./index-2qzskm8h.js";
|
|
5
5
|
import {
|
|
6
6
|
zodIssues
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-13cjtmrw.js";
|
|
8
8
|
import {
|
|
9
9
|
AppError
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-2vtcmrj9.js";
|
|
11
11
|
|
|
12
12
|
// src/realtime/rejected-frame.ts
|
|
13
13
|
var REALTIME_REJECTION_KEY = "@stitchkit/realtime-rejected";
|
|
@@ -43,7 +43,13 @@ function parseIssues(value) {
|
|
|
43
43
|
const code = Reflect.get(entry, "code");
|
|
44
44
|
const message = Reflect.get(entry, "message");
|
|
45
45
|
if (typeof path === "string" && typeof code === "string" && typeof message === "string") {
|
|
46
|
-
|
|
46
|
+
const branch = Reflect.get(entry, "branch");
|
|
47
|
+
issues.push({
|
|
48
|
+
path,
|
|
49
|
+
code,
|
|
50
|
+
message,
|
|
51
|
+
...typeof branch === "number" && Number.isInteger(branch) && branch > 0 && { branch }
|
|
52
|
+
});
|
|
47
53
|
}
|
|
48
54
|
}
|
|
49
55
|
return issues.length > 0 ? issues : undefined;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
executeToolMethod
|
|
3
|
-
|
|
2
|
+
executeToolMethod,
|
|
3
|
+
toolErrorFromResult
|
|
4
|
+
} from "./index-mqhjmadk.js";
|
|
4
5
|
import {
|
|
5
6
|
assertToolExtensionCompatible,
|
|
6
7
|
mergeSchemas,
|
|
7
8
|
projectToolSurface,
|
|
8
9
|
rebuildObject
|
|
9
10
|
} from "./index-fenaekmk.js";
|
|
11
|
+
import {
|
|
12
|
+
isRetryableStatus
|
|
13
|
+
} from "./index-2vtcmrj9.js";
|
|
10
14
|
|
|
11
15
|
// src/tools/mount.ts
|
|
12
16
|
import { z } from "zod";
|
|
@@ -54,7 +58,10 @@ function createToolRunner(config) {
|
|
|
54
58
|
};
|
|
55
59
|
}
|
|
56
60
|
function formatToolError(result, toolName, errorHint) {
|
|
57
|
-
const err = {
|
|
61
|
+
const err = {
|
|
62
|
+
error: result.code,
|
|
63
|
+
retryable: result.retryable ?? isRetryableStatus(toolErrorFromResult(result).status)
|
|
64
|
+
};
|
|
58
65
|
if (result.details)
|
|
59
66
|
err.details = result.details;
|
|
60
67
|
const hints = [];
|
|
@@ -7,13 +7,15 @@ class AppError extends Error {
|
|
|
7
7
|
details;
|
|
8
8
|
hint;
|
|
9
9
|
traceId;
|
|
10
|
-
|
|
10
|
+
retryable;
|
|
11
|
+
constructor(code, message, status = 500, details, hint, traceId, retryable) {
|
|
11
12
|
super(message ?? code);
|
|
12
13
|
this.code = code;
|
|
13
14
|
this.status = status;
|
|
14
15
|
this.details = details;
|
|
15
16
|
this.hint = hint;
|
|
16
17
|
this.traceId = traceId;
|
|
18
|
+
this.retryable = retryable;
|
|
17
19
|
this.name = "AppError";
|
|
18
20
|
Object.defineProperty(this, APP_ERROR_BRAND, { value: true });
|
|
19
21
|
}
|
|
@@ -68,6 +70,7 @@ var STITCH_ERROR_STATUS = {
|
|
|
68
70
|
REALTIME_CONTRACT_VIOLATION: 500,
|
|
69
71
|
APPLICATION_NOT_ACCEPTING: 503,
|
|
70
72
|
GRAMMY_WEBHOOK_NOT_ACCEPTING: 503,
|
|
73
|
+
NOT_IMPLEMENTED: 501,
|
|
71
74
|
WAIT_TIMEOUT: 408,
|
|
72
75
|
WAIT_FAILED: 409,
|
|
73
76
|
DOWNLOAD_NOT_FOUND: 404,
|
|
@@ -82,6 +85,9 @@ var STITCH_ERROR_STATUS = {
|
|
|
82
85
|
SPILL_REFERENCE_UNKNOWN: 404,
|
|
83
86
|
INTERNAL_SERVER_ERROR: 500
|
|
84
87
|
};
|
|
88
|
+
function isRetryableStatus(status) {
|
|
89
|
+
return status === 408 || status === 429 || status === 502 || status === 503 || status === 504;
|
|
90
|
+
}
|
|
85
91
|
function isStitchErrorCode(code) {
|
|
86
92
|
return Object.hasOwn(STITCH_ERROR_STATUS, code);
|
|
87
93
|
}
|
|
@@ -89,4 +95,4 @@ function appError(code, message, details) {
|
|
|
89
95
|
throw new AppError(code, message, isStitchErrorCode(code) ? STITCH_ERROR_STATUS[code] : 500, details);
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
export { AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError };
|
|
98
|
+
export { AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isRetryableStatus, isStitchErrorCode, appError };
|
|
@@ -81,7 +81,12 @@ function redact(value, options = {}) {
|
|
|
81
81
|
return matchesPath(matcher, path, patternIndex + 1, pathIndex + 1);
|
|
82
82
|
};
|
|
83
83
|
const isSensitivePath = (path) => pathMatchers.some((matcher) => matchesPath(matcher, path));
|
|
84
|
-
const
|
|
84
|
+
const stringBoundFor = (key) => {
|
|
85
|
+
const byKey = key === undefined ? undefined : options.maxStringLengthByKey?.[key];
|
|
86
|
+
return byKey ?? maxStringLength;
|
|
87
|
+
};
|
|
88
|
+
const safeString = (input, key) => {
|
|
89
|
+
const bound = stringBoundFor(key);
|
|
85
90
|
let output = input;
|
|
86
91
|
for (const pattern of options.sensitiveUrlPatterns ?? []) {
|
|
87
92
|
try {
|
|
@@ -89,9 +94,9 @@ function redact(value, options = {}) {
|
|
|
89
94
|
output = output.replace(global, MASK);
|
|
90
95
|
} catch {}
|
|
91
96
|
}
|
|
92
|
-
if (output.length <=
|
|
97
|
+
if (output.length <= bound)
|
|
93
98
|
return output;
|
|
94
|
-
return `${output.slice(0, Math.max(0,
|
|
99
|
+
return `${output.slice(0, Math.max(0, bound))}…[truncated]`;
|
|
95
100
|
};
|
|
96
101
|
const ancestors = new Set;
|
|
97
102
|
const maxNodes = options.maxNodes ?? DEFAULT_MAX_NODES;
|
|
@@ -105,7 +110,7 @@ function redact(value, options = {}) {
|
|
|
105
110
|
if (input === null || input === undefined)
|
|
106
111
|
return null;
|
|
107
112
|
if (typeof input === "string")
|
|
108
|
-
return safeString(input);
|
|
113
|
+
return safeString(input, path[path.length - 1]);
|
|
109
114
|
if (typeof input === "number" || typeof input === "boolean") {
|
|
110
115
|
return input;
|
|
111
116
|
}
|
|
@@ -164,9 +169,9 @@ function redact(value, options = {}) {
|
|
|
164
169
|
const cause = property("cause");
|
|
165
170
|
return {
|
|
166
171
|
_type: "error",
|
|
167
|
-
name: safeString(String(property("name"))),
|
|
168
|
-
message: safeString(String(property("message"))),
|
|
169
|
-
...stack !== undefined && { stack: safeString(String(stack)) },
|
|
172
|
+
name: safeString(String(property("name")), "name"),
|
|
173
|
+
message: safeString(String(property("message")), "message"),
|
|
174
|
+
...stack !== undefined && { stack: safeString(String(stack), "stack") },
|
|
170
175
|
...cause !== undefined && { cause: walk(cause, depth + 1, [...path, "cause"]) }
|
|
171
176
|
};
|
|
172
177
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mergeMeta,
|
|
3
3
|
resolveRouteParamsSchema
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-0a349c33.js";
|
|
5
|
+
import {
|
|
6
|
+
AppError
|
|
7
|
+
} from "./index-2vtcmrj9.js";
|
|
5
8
|
import {
|
|
6
9
|
isUnsafeKey
|
|
7
10
|
} from "./index-kzfs85xp.js";
|
|
@@ -70,14 +73,24 @@ function contractOnlyService(contract) {
|
|
|
70
73
|
return bindContract(contract, handlers);
|
|
71
74
|
}
|
|
72
75
|
var HTTP_ONLY = Object.freeze(["HTTP"]);
|
|
73
|
-
function
|
|
76
|
+
function stubHandler(label) {
|
|
77
|
+
return () => {
|
|
78
|
+
throw new AppError("NOT_IMPLEMENTED", `[stitchkit] ${label} is declared by its contract and has no handler`, 501);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function bindContract(contract, handlers, options) {
|
|
74
82
|
const methods = {};
|
|
75
83
|
const groupScope = contract.meta.scope ?? "public";
|
|
76
84
|
for (const [key, endpoint] of typedEntries(contract.endpoints)) {
|
|
77
|
-
const
|
|
85
|
+
const label = `${contract.meta.prefix}.${String(key)}`;
|
|
86
|
+
let typedHandler = handlers[String(key)];
|
|
78
87
|
const isStreaming = endpoint.multipart?.delivery === "stream";
|
|
79
88
|
if (!isStreaming && typeof typedHandler !== "function") {
|
|
80
|
-
|
|
89
|
+
if (options?.onMissingHandler !== "stub") {
|
|
90
|
+
throw new Error(`[stitchkit] implement: missing handler for "${label}"`);
|
|
91
|
+
}
|
|
92
|
+
console.warn(`[stitchkit] implement: "${label}" has no handler and is mounted as a 501 stub`);
|
|
93
|
+
typedHandler = stubHandler(label);
|
|
81
94
|
}
|
|
82
95
|
if (isStreaming && !isStreamingImplementation(typedHandler)) {
|
|
83
96
|
throw new Error(`[stitchkit] implement: streaming multipart endpoint "${contract.meta.prefix}.${String(key)}" must use defineMultipartStream()`);
|
|
@@ -125,14 +138,14 @@ function bindContract(contract, handlers) {
|
|
|
125
138
|
methods
|
|
126
139
|
};
|
|
127
140
|
}
|
|
128
|
-
function implement(contract, handlers) {
|
|
129
|
-
return bindContract(contract, handlers);
|
|
141
|
+
function implement(contract, handlers, options) {
|
|
142
|
+
return bindContract(contract, handlers, options);
|
|
130
143
|
}
|
|
131
144
|
function createImplement() {
|
|
132
|
-
return (contract, handlers) => implement(contract, handlers);
|
|
145
|
+
return (contract, handlers, options) => implement(contract, handlers, options);
|
|
133
146
|
}
|
|
134
147
|
function createScopedImplement() {
|
|
135
|
-
const implementScoped = (contract, handlers) => bindContract(contract, handlers);
|
|
148
|
+
const implementScoped = (contract, handlers, options) => bindContract(contract, handlers, options);
|
|
136
149
|
const stream = (scope, endpoint, config) => {
|
|
137
150
|
if (endpoint.scope !== undefined && endpoint.scope !== scope) {
|
|
138
151
|
throw new Error(`[stitchkit] createScopedImplement.stream: endpoint declares scope "${endpoint.scope}" but "${String(scope)}" was given`);
|
|
@@ -143,18 +156,21 @@ function createScopedImplement() {
|
|
|
143
156
|
return Object.assign(implementScoped, { stream, declare });
|
|
144
157
|
}
|
|
145
158
|
function createScopedImplementRegistry() {
|
|
146
|
-
return (contracts, handlers) => transportResult(bindRegistry(contracts, handlers));
|
|
159
|
+
return (contracts, handlers, options) => transportResult(bindRegistry(contracts, handlers, options));
|
|
147
160
|
}
|
|
148
161
|
function isImplementationContract(value) {
|
|
149
162
|
return isRecord(value) && isRecord(value.meta) && typeof value.meta.prefix === "string" && isRecord(value.endpoints);
|
|
150
163
|
}
|
|
151
|
-
function bindRegistry(contracts, handlers) {
|
|
164
|
+
function bindRegistry(contracts, handlers, options) {
|
|
152
165
|
const contractKeys = Object.keys(contracts);
|
|
153
166
|
const handlerKeys = Object.keys(handlers);
|
|
154
167
|
const missing = contractKeys.filter((key) => !Object.hasOwn(handlers, key));
|
|
155
168
|
const extra = handlerKeys.filter((key) => !Object.hasOwn(contracts, key));
|
|
156
169
|
if (missing.length > 0 || extra.length > 0) {
|
|
157
|
-
|
|
170
|
+
if (options?.onMissingHandler !== "stub") {
|
|
171
|
+
throw new Error(`[stitchkit] implementRegistry: registry mismatch (missing: ${missing.join(", ") || "none"}; extra: ${extra.join(", ") || "none"})`);
|
|
172
|
+
}
|
|
173
|
+
console.warn(`[stitchkit] implementRegistry: registry mismatch (missing: ${missing.join(", ") || "none"}; extra: ${extra.join(", ") || "none"}) — missing contracts are mounted as 501 stubs and extra handlers are ignored`);
|
|
158
174
|
}
|
|
159
175
|
const prefixes = new Map;
|
|
160
176
|
const services = [];
|
|
@@ -171,7 +187,7 @@ function bindRegistry(contracts, handlers) {
|
|
|
171
187
|
throw new Error(`[stitchkit] implementRegistry: duplicate contract prefix "${contract.meta.prefix}" in scope "${groupScope}" at "${previousKey}" and "${key}"`);
|
|
172
188
|
}
|
|
173
189
|
prefixes.set(identity, key);
|
|
174
|
-
const entryHandlers = handlers[key];
|
|
190
|
+
const entryHandlers = handlers[key] === undefined && options?.onMissingHandler === "stub" ? {} : handlers[key];
|
|
175
191
|
if (!isRecord(entryHandlers)) {
|
|
176
192
|
throw new TypeError(`[stitchkit] implementRegistry: handlers for "${key}" must be an object`);
|
|
177
193
|
}
|
|
@@ -180,20 +196,24 @@ function bindRegistry(contracts, handlers) {
|
|
|
180
196
|
const missingEndpoints = endpointKeys.filter((endpointKey) => !Object.hasOwn(entryHandlers, endpointKey));
|
|
181
197
|
const extraEndpoints = handlerEntryKeys.filter((endpointKey) => !Object.hasOwn(contract.endpoints, endpointKey));
|
|
182
198
|
if (missingEndpoints.length > 0 || extraEndpoints.length > 0) {
|
|
183
|
-
|
|
199
|
+
const detail = `handlers for "${key}" mismatch (missing: ${missingEndpoints.join(", ") || "none"}; extra: ${extraEndpoints.join(", ") || "none"})`;
|
|
200
|
+
if (options?.onMissingHandler !== "stub") {
|
|
201
|
+
throw new Error(`[stitchkit] implementRegistry: ${detail}`);
|
|
202
|
+
}
|
|
203
|
+
console.warn(`[stitchkit] implementRegistry: ${detail} — missing endpoints are mounted as 501 stubs and extra handlers are ignored`);
|
|
184
204
|
}
|
|
185
|
-
const service = bindContract(contract, entryHandlers);
|
|
205
|
+
const service = bindContract(contract, entryHandlers, options);
|
|
186
206
|
services.push(service);
|
|
187
207
|
byKey[key] = service;
|
|
188
208
|
}
|
|
189
209
|
Object.defineProperty(services, "byKey", { value: byKey, enumerable: false });
|
|
190
210
|
return transportResult(services);
|
|
191
211
|
}
|
|
192
|
-
function implementRegistry(contracts, handlers) {
|
|
193
|
-
return transportResult(bindRegistry(contracts, handlers));
|
|
212
|
+
function implementRegistry(contracts, handlers, options) {
|
|
213
|
+
return transportResult(bindRegistry(contracts, handlers, options));
|
|
194
214
|
}
|
|
195
215
|
function createImplementRegistry() {
|
|
196
|
-
return (contracts, handlers) => transportResult(bindRegistry(contracts, handlers));
|
|
216
|
+
return (contracts, handlers, options) => transportResult(bindRegistry(contracts, handlers, options));
|
|
197
217
|
}
|
|
198
218
|
|
|
199
219
|
// src/server/middleware/cors.ts
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
collectTools,
|
|
3
3
|
createToolRunner
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-1qvdwnp2.js";
|
|
5
5
|
import {
|
|
6
6
|
toolErrorFromResult
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-mqhjmadk.js";
|
|
8
8
|
import {
|
|
9
9
|
assertUniqueToolName
|
|
10
10
|
} from "./index-fenaekmk.js";
|
|
11
11
|
import {
|
|
12
12
|
AppError
|
|
13
|
-
} from "./index-
|
|
13
|
+
} from "./index-2vtcmrj9.js";
|
|
14
14
|
|
|
15
15
|
// src/tools/invoker.ts
|
|
16
16
|
function createToolInvoker(services, config) {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
contextContributionDelta,
|
|
6
6
|
mergeContextContribution,
|
|
7
7
|
prepareContextContribution
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-709nh7z7.js";
|
|
9
9
|
import {
|
|
10
10
|
base64UrlToBytes,
|
|
11
11
|
bytesToBase64Url
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
forbidden,
|
|
15
15
|
unauthorized
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-2vtcmrj9.js";
|
|
17
17
|
import {
|
|
18
18
|
isUnsafeKey,
|
|
19
19
|
safeJsonParse
|