stitchkit 0.118.0 → 0.119.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 +78 -0
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/contract/client-types.d.ts +6 -3
- package/dist/contract/client-types.d.ts.map +1 -1
- package/dist/contract/define-validation.d.ts.map +1 -1
- package/dist/contract/define.d.ts +18 -12
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/endpoint-capabilities.d.ts +28 -0
- package/dist/contract/endpoint-capabilities.d.ts.map +1 -0
- package/dist/contract/factory.d.ts +49 -19
- package/dist/contract/factory.d.ts.map +1 -1
- package/dist/contract/tool-view.d.ts +1 -1
- package/dist/contract/tool-view.d.ts.map +1 -1
- package/dist/contract/transports.d.ts +5 -0
- package/dist/contract/transports.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/coding-tools.js +6 -5
- package/dist/entrypoints/agent-runtime/harness.js +6 -5
- package/dist/entrypoints/agent-runtime/sandbox.js +6 -5
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +9 -8
- package/dist/entrypoints/agent-runtime/sqlite/node.js +9 -8
- package/dist/entrypoints/agent-runtime/testing.js +9 -8
- package/dist/entrypoints/agent-runtime.js +14 -13
- package/dist/entrypoints/application/diagnostic-journal.js +3 -3
- package/dist/entrypoints/application/directory-inbox.js +4 -4
- package/dist/entrypoints/application/opentelemetry.js +1 -1
- package/dist/entrypoints/application.js +5 -5
- package/dist/entrypoints/cli/publish.js +4 -4
- package/dist/entrypoints/cli.js +8 -7
- package/dist/entrypoints/contract.d.ts +1 -1
- package/dist/entrypoints/contract.d.ts.map +1 -1
- package/dist/entrypoints/contract.js +6 -4
- package/dist/entrypoints/files.js +3 -3
- package/dist/entrypoints/geo/contract.d.ts +7 -0
- package/dist/entrypoints/geo/contract.d.ts.map +1 -0
- package/dist/entrypoints/geo/contract.js +6 -0
- package/dist/entrypoints/geo.js +60 -23
- package/dist/entrypoints/http.js +2 -2
- package/dist/entrypoints/index.js +8 -6
- package/dist/entrypoints/live.js +1 -1
- package/dist/entrypoints/node.js +7 -6
- package/dist/entrypoints/primitives.js +1 -1
- package/dist/entrypoints/process/owner-loss.js +1 -1
- package/dist/entrypoints/process.js +3 -3
- package/dist/entrypoints/react.js +1 -1
- package/dist/entrypoints/remote.js +4 -3
- package/dist/entrypoints/server.d.ts +1 -1
- package/dist/entrypoints/server.d.ts.map +1 -1
- package/dist/entrypoints/server.js +42 -27
- package/dist/entrypoints/telegram.js +2 -2
- package/dist/entrypoints/testing.js +7 -6
- package/dist/entrypoints/tools/connections.js +3 -2
- package/dist/entrypoints/tools/contract.js +1 -1
- package/dist/entrypoints/tools/invoker.js +5 -4
- package/dist/entrypoints/tools/mcp.js +7 -6
- package/dist/entrypoints/tools.js +17 -15
- package/dist/entrypoints/tracking/contract.js +5 -3
- package/dist/entrypoints/tracking/performance.js +3 -3
- package/dist/entrypoints/tracking.d.ts +1 -1
- package/dist/entrypoints/tracking.d.ts.map +1 -1
- package/dist/entrypoints/tracking.js +63 -83
- package/dist/entrypoints/xlsx.js +1 -1
- package/dist/geo/index.d.ts +2 -1
- package/dist/geo/index.d.ts.map +1 -1
- package/dist/geo/record.d.ts +8 -0
- package/dist/geo/record.d.ts.map +1 -0
- package/dist/geo/resolver.d.ts +1 -3
- package/dist/geo/resolver.d.ts.map +1 -1
- package/dist/geo/schema.d.ts +44 -0
- package/dist/geo/schema.d.ts.map +1 -0
- package/dist/geo/types.d.ts +2 -13
- package/dist/geo/types.d.ts.map +1 -1
- package/dist/{index-n5sv4z0w.js → index-1k18qzqa.js} +13 -15
- package/dist/{index-tsngj2b5.js → index-2dfvv1jg.js} +206 -206
- package/dist/{index-d9hq291n.js → index-4jpykzvw.js} +70 -81
- package/dist/{index-ghtpfz4z.js → index-57gqaq8b.js} +2 -2
- package/dist/index-69t14s4a.js +39 -0
- package/dist/{index-6p3frkv5.js → index-6a69xzrx.js} +4 -4
- package/dist/{index-dky0dcmf.js → index-72r9k0av.js} +6 -2
- package/dist/{index-vv1sch8a.js → index-8vzh5wpv.js} +13 -8
- package/dist/{index-xx1j310k.js → index-8yxgcyt6.js} +171 -169
- package/dist/{index-p6apg0jg.js → index-9frf01t9.js} +16 -9
- package/dist/{index-q0th8q0z.js → index-9mjrnqxs.js} +1 -3
- package/dist/{index-ega3yz4c.js → index-aqwg2dm5.js} +1 -1
- package/dist/{index-073nw9qr.js → index-ba7are04.js} +524 -522
- package/dist/{index-095ya5hm.js → index-bbvc59gw.js} +13 -11
- package/dist/{index-txg1npmg.js → index-cyxp8rbf.js} +1 -1
- package/dist/index-d3xdyjt6.js +38 -0
- package/dist/{index-n8z3rvzw.js → index-f4njz9j0.js} +3 -5
- package/dist/{index-90p34rts.js → index-fcqj44mb.js} +3 -1
- package/dist/{index-86nbfysb.js → index-ff39f9dr.js} +3 -3
- package/dist/{index-75ns2ybj.js → index-fqd4yqwd.js} +1 -1
- package/dist/{index-nqxrm176.js → index-g444vfz2.js} +1 -1
- package/dist/{index-vwhrnp67.js → index-kz9734jc.js} +3 -3
- package/dist/{index-dr3t5n1v.js → index-nn9qvkww.js} +46 -46
- package/dist/{index-qezhmp51.js → index-nz06qw5a.js} +3 -1
- package/dist/{index-1bx1xv1k.js → index-pfvde2fz.js} +5 -2
- package/dist/{index-s80awwsw.js → index-qch1vcaa.js} +3 -1
- package/dist/{index-cycp3r3e.js → index-rxcgp4b9.js} +2 -2
- package/dist/{index-w7jq3fz9.js → index-s0qjs6ee.js} +1198 -1196
- package/dist/{index-p0rf7sq9.js → index-s20s2mad.js} +209 -209
- package/dist/{index-v6vb5qx8.js → index-s3yxw6kt.js} +1 -1
- package/dist/{index-cqmqyjax.js → index-sa99p98w.js} +1 -1
- package/dist/{index-0gxvns6s.js → index-sba3e6m4.js} +1 -0
- package/dist/{index-f24bdt13.js → index-v1swr26p.js} +3 -1
- package/dist/{index-rhzkndr5.js → index-x4p3kw1p.js} +533 -530
- package/dist/{index-hdjmdwsj.js → index-x8d9fdeg.js} +513 -507
- package/dist/{index-htxh46ej.js → index-ycqhyars.js} +2 -2
- package/dist/{index-9bwcthxw.js → index-yj6saztf.js} +31 -13
- package/dist/{index-tdpmfks8.js → index-ynrf908v.js} +1 -1
- package/dist/{index-f6m4c545.js → index-zrdcmg6j.js} +4 -6
- package/dist/process/bun-child.d.ts +3 -2
- package/dist/process/bun-child.d.ts.map +1 -1
- package/dist/server/contract-method.d.ts.map +1 -1
- package/dist/server/file.d.ts +12 -6
- package/dist/server/file.d.ts.map +1 -1
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools/operations/async-operation-canonical-types.d.ts +1 -1
- package/dist/tracking/attribution.d.ts +21 -25
- package/dist/tracking/attribution.d.ts.map +1 -1
- package/dist/tracking/client-visit.d.ts +5 -7
- package/dist/tracking/client-visit.d.ts.map +1 -1
- package/dist/tracking/client.d.ts +2 -2
- package/dist/tracking/client.d.ts.map +1 -1
- package/dist/tracking/contract.d.ts +1 -1
- package/dist/tracking/host.d.ts +0 -1
- package/dist/tracking/host.d.ts.map +1 -1
- package/dist/tracking/privacy.d.ts +6 -0
- package/dist/tracking/privacy.d.ts.map +1 -1
- package/dist/tracking/schemas.d.ts +2 -2
- package/dist/tracking/schemas.d.ts.map +1 -1
- package/llms/contract.txt +46 -24
- package/llms/geo-contract.txt +23 -0
- package/llms/geo.txt +40 -4
- package/llms/server.2.txt +19 -6
- package/llms/server.5.txt +2 -1
- package/llms/stitchkit.txt +4 -3
- package/llms/testing.txt +3 -3
- package/llms/tools.2.txt +2 -2
- package/llms/tools.3.txt +1 -1
- package/llms/tracking-contract.txt +1 -1
- package/llms/tracking.txt +27 -5
- package/llms/{upgrading-0.105.0-0.118.0.txt → upgrading-0.106.0-0.119.0.txt} +121 -410
- package/llms/upgrading-0.37.0-0.53.0.txt +969 -0
- package/llms/{upgrading-0.44.0-0.62.0.txt → upgrading-0.55.0-0.68.0.txt} +509 -528
- package/llms/{upgrading-0.63.0-0.83.0.txt → upgrading-0.69.0-0.95.0.txt} +506 -509
- package/llms/{upgrading-0.84.0-0.104.0.txt → upgrading-0.96.0-0.105.0.txt} +410 -506
- package/llms/upgrading.txt +5 -5
- package/llms-full.txt +271 -48
- package/llms.txt +11 -10
- package/package.json +23 -19
- package/llms/upgrading-0.37.0-0.44.0.txt +0 -444
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
uploadProgressRoute,
|
|
14
14
|
withUploadProgress,
|
|
15
15
|
parseApiErrorBody
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-9frf01t9.js";
|
|
17
17
|
import {
|
|
18
18
|
inputIsQuery
|
|
19
19
|
} from "./index-xhzq2qvj.js";
|
|
@@ -33,211 +33,6 @@ import {
|
|
|
33
33
|
mapObject
|
|
34
34
|
} from "./index-9jfdm5tg.js";
|
|
35
35
|
|
|
36
|
-
// src/internal/bounded-lines.ts
|
|
37
|
-
var DEFAULT_STREAM_LINE_BYTES = 1024 * 1024;
|
|
38
|
-
|
|
39
|
-
class StreamLineLimitError2 extends RangeError {
|
|
40
|
-
limitBytes;
|
|
41
|
-
lineBytes;
|
|
42
|
-
name = "StreamLineLimitError";
|
|
43
|
-
constructor(limitBytes, lineBytes) {
|
|
44
|
-
super(`Stream line exceeds the ${limitBytes} byte limit (${lineBytes} bytes so far)`);
|
|
45
|
-
this.limitBytes = limitBytes;
|
|
46
|
-
this.lineBytes = lineBytes;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
class StreamTruncatedLineError2 extends SyntaxError {
|
|
51
|
-
lineBytes;
|
|
52
|
-
name = "StreamTruncatedLineError";
|
|
53
|
-
constructor(lineBytes) {
|
|
54
|
-
super(`Stream ended with an unterminated final line (${lineBytes} bytes)`);
|
|
55
|
-
this.lineBytes = lineBytes;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function lineLimit(value) {
|
|
59
|
-
const resolved = value ?? DEFAULT_STREAM_LINE_BYTES;
|
|
60
|
-
assertPositiveSafeInteger("maxLineBytes", resolved);
|
|
61
|
-
return resolved;
|
|
62
|
-
}
|
|
63
|
-
function createLineSplitter(maxLineBytes, requireFinalNewline = false) {
|
|
64
|
-
const limit = lineLimit(maxLineBytes);
|
|
65
|
-
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
66
|
-
let parts = [];
|
|
67
|
-
let pendingBytes = 0;
|
|
68
|
-
let ended = false;
|
|
69
|
-
let failed = false;
|
|
70
|
-
const drop = () => {
|
|
71
|
-
parts = [];
|
|
72
|
-
pendingBytes = 0;
|
|
73
|
-
};
|
|
74
|
-
const retain = (bytes) => {
|
|
75
|
-
if (bytes.byteLength === 0)
|
|
76
|
-
return;
|
|
77
|
-
pendingBytes += bytes.byteLength;
|
|
78
|
-
if (pendingBytes > limit) {
|
|
79
|
-
const seen = pendingBytes;
|
|
80
|
-
drop();
|
|
81
|
-
throw new StreamLineLimitError2(limit, seen);
|
|
82
|
-
}
|
|
83
|
-
parts.push(new Uint8Array(bytes));
|
|
84
|
-
};
|
|
85
|
-
const take = () => {
|
|
86
|
-
const line = new Uint8Array(pendingBytes);
|
|
87
|
-
let at = 0;
|
|
88
|
-
for (const part of parts) {
|
|
89
|
-
line.set(part, at);
|
|
90
|
-
at += part.byteLength;
|
|
91
|
-
}
|
|
92
|
-
drop();
|
|
93
|
-
return decoder.decode(line);
|
|
94
|
-
};
|
|
95
|
-
function* lines(chunk) {
|
|
96
|
-
if (ended)
|
|
97
|
-
throw new Error("Line decoder received bytes after end()");
|
|
98
|
-
if (failed)
|
|
99
|
-
throw new Error("Line decoder stopped at an earlier error; read the source again");
|
|
100
|
-
try {
|
|
101
|
-
let start = 0;
|
|
102
|
-
for (let index = chunk.indexOf(10);index !== -1; index = chunk.indexOf(10, start)) {
|
|
103
|
-
retain(chunk.subarray(start, index));
|
|
104
|
-
yield take();
|
|
105
|
-
start = index + 1;
|
|
106
|
-
}
|
|
107
|
-
retain(chunk.subarray(start));
|
|
108
|
-
} catch (error) {
|
|
109
|
-
failed = true;
|
|
110
|
-
throw error;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
lines,
|
|
115
|
-
push: (chunk) => [...lines(chunk)],
|
|
116
|
-
end() {
|
|
117
|
-
ended = true;
|
|
118
|
-
if (pendingBytes === 0)
|
|
119
|
-
return [];
|
|
120
|
-
if (requireFinalNewline) {
|
|
121
|
-
const seen = pendingBytes;
|
|
122
|
-
drop();
|
|
123
|
-
throw new StreamTruncatedLineError2(seen);
|
|
124
|
-
}
|
|
125
|
-
return [take()];
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
function createBoundedLineDecoder(maxLineBytes, requireFinalNewline = false) {
|
|
130
|
-
const { push, end } = createLineSplitter(maxLineBytes, requireFinalNewline);
|
|
131
|
-
return { push, end };
|
|
132
|
-
}
|
|
133
|
-
async function* readBoundedUtf8Lines(source, maxLineBytes, requireFinalNewline = false, signal) {
|
|
134
|
-
const splitter = createLineSplitter(maxLineBytes, requireFinalNewline);
|
|
135
|
-
for await (const chunk of chunksOf(source, signal)) {
|
|
136
|
-
for (const line of splitter.lines(chunk)) {
|
|
137
|
-
signal?.throwIfAborted();
|
|
138
|
-
yield line;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
for (const line of splitter.end()) {
|
|
142
|
-
signal?.throwIfAborted();
|
|
143
|
-
yield line;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// src/browser/stream.ts
|
|
148
|
-
function ndjsonLine(rawLine) {
|
|
149
|
-
return (rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine).trim();
|
|
150
|
-
}
|
|
151
|
-
function parseFailure(raw, error, onParseError) {
|
|
152
|
-
const failure = error instanceof Error ? error : new Error(String(error));
|
|
153
|
-
if (!onParseError)
|
|
154
|
-
throw failure;
|
|
155
|
-
onParseError(raw, failure);
|
|
156
|
-
}
|
|
157
|
-
async function* parseNDJSON2(source, options) {
|
|
158
|
-
let reporting = false;
|
|
159
|
-
try {
|
|
160
|
-
for await (const rawLine of readBoundedUtf8Lines(source, options?.maxLineBytes ?? DEFAULT_STREAM_LINE_BYTES, options?.finalLine === "require-newline", options?.signal)) {
|
|
161
|
-
const line = ndjsonLine(rawLine);
|
|
162
|
-
if (line === "")
|
|
163
|
-
continue;
|
|
164
|
-
let value;
|
|
165
|
-
try {
|
|
166
|
-
value = JSON.parse(line);
|
|
167
|
-
} catch (error) {
|
|
168
|
-
reporting = true;
|
|
169
|
-
parseFailure(line, error, options?.onParseError);
|
|
170
|
-
reporting = false;
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
yield value;
|
|
174
|
-
}
|
|
175
|
-
} catch (error) {
|
|
176
|
-
if (reporting || options?.signal?.aborted)
|
|
177
|
-
throw error;
|
|
178
|
-
parseFailure("", error, options?.onParseError);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
function createNDJSONDecoder2(options) {
|
|
182
|
-
const lines = createBoundedLineDecoder(options?.maxLineBytes ?? DEFAULT_STREAM_LINE_BYTES, options?.finalLine === "require-newline");
|
|
183
|
-
let failed = false;
|
|
184
|
-
const values = (rawLines) => {
|
|
185
|
-
const parsed = [];
|
|
186
|
-
for (const rawLine of rawLines) {
|
|
187
|
-
const line = ndjsonLine(rawLine);
|
|
188
|
-
if (line === "")
|
|
189
|
-
continue;
|
|
190
|
-
try {
|
|
191
|
-
parsed.push(JSON.parse(line));
|
|
192
|
-
} catch (error) {
|
|
193
|
-
parseFailure(line, error, options?.onParseError);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return parsed;
|
|
197
|
-
};
|
|
198
|
-
const guarded = (step) => {
|
|
199
|
-
if (failed)
|
|
200
|
-
throw new Error("NDJSON decoder stopped at an earlier error; read the source again");
|
|
201
|
-
try {
|
|
202
|
-
return values(step());
|
|
203
|
-
} catch (error) {
|
|
204
|
-
failed = true;
|
|
205
|
-
throw error;
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
return {
|
|
209
|
-
push: (chunk) => guarded(() => lines.push(chunk)),
|
|
210
|
-
end: () => guarded(() => lines.end())
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
async function* parseSSE2(source, options) {
|
|
214
|
-
let reporting = false;
|
|
215
|
-
try {
|
|
216
|
-
for await (const rawLine of readBoundedUtf8Lines(source, options?.maxLineBytes ?? DEFAULT_STREAM_LINE_BYTES, false, options?.signal)) {
|
|
217
|
-
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
218
|
-
if (!line.startsWith("data:"))
|
|
219
|
-
continue;
|
|
220
|
-
const data = line.slice(5).replace(/^ /, "");
|
|
221
|
-
if (data === "[DONE]")
|
|
222
|
-
return;
|
|
223
|
-
let value;
|
|
224
|
-
try {
|
|
225
|
-
value = JSON.parse(data);
|
|
226
|
-
} catch (error) {
|
|
227
|
-
reporting = true;
|
|
228
|
-
parseFailure(data, error, options?.onParseError);
|
|
229
|
-
reporting = false;
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
yield value;
|
|
233
|
-
}
|
|
234
|
-
} catch (error) {
|
|
235
|
-
if (reporting || options?.signal?.aborted)
|
|
236
|
-
throw error;
|
|
237
|
-
parseFailure("", error, options?.onParseError);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
36
|
// src/browser/client-arguments.ts
|
|
242
37
|
function endpointHasArguments(endpoint) {
|
|
243
38
|
return Boolean(endpoint.params || endpoint.input || endpoint.multipart);
|
|
@@ -464,6 +259,211 @@ function joinClientBaseUrl(baseUrl, relativeUrl) {
|
|
|
464
259
|
return `${base}${path}`;
|
|
465
260
|
}
|
|
466
261
|
|
|
262
|
+
// src/internal/bounded-lines.ts
|
|
263
|
+
var DEFAULT_STREAM_LINE_BYTES = 1024 * 1024;
|
|
264
|
+
|
|
265
|
+
class StreamLineLimitError2 extends RangeError {
|
|
266
|
+
limitBytes;
|
|
267
|
+
lineBytes;
|
|
268
|
+
name = "StreamLineLimitError";
|
|
269
|
+
constructor(limitBytes, lineBytes) {
|
|
270
|
+
super(`Stream line exceeds the ${limitBytes} byte limit (${lineBytes} bytes so far)`);
|
|
271
|
+
this.limitBytes = limitBytes;
|
|
272
|
+
this.lineBytes = lineBytes;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
class StreamTruncatedLineError2 extends SyntaxError {
|
|
277
|
+
lineBytes;
|
|
278
|
+
name = "StreamTruncatedLineError";
|
|
279
|
+
constructor(lineBytes) {
|
|
280
|
+
super(`Stream ended with an unterminated final line (${lineBytes} bytes)`);
|
|
281
|
+
this.lineBytes = lineBytes;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function lineLimit(value) {
|
|
285
|
+
const resolved = value ?? DEFAULT_STREAM_LINE_BYTES;
|
|
286
|
+
assertPositiveSafeInteger("maxLineBytes", resolved);
|
|
287
|
+
return resolved;
|
|
288
|
+
}
|
|
289
|
+
function createLineSplitter(maxLineBytes, requireFinalNewline = false) {
|
|
290
|
+
const limit = lineLimit(maxLineBytes);
|
|
291
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
292
|
+
let parts = [];
|
|
293
|
+
let pendingBytes = 0;
|
|
294
|
+
let ended = false;
|
|
295
|
+
let failed = false;
|
|
296
|
+
const drop = () => {
|
|
297
|
+
parts = [];
|
|
298
|
+
pendingBytes = 0;
|
|
299
|
+
};
|
|
300
|
+
const retain = (bytes) => {
|
|
301
|
+
if (bytes.byteLength === 0)
|
|
302
|
+
return;
|
|
303
|
+
pendingBytes += bytes.byteLength;
|
|
304
|
+
if (pendingBytes > limit) {
|
|
305
|
+
const seen = pendingBytes;
|
|
306
|
+
drop();
|
|
307
|
+
throw new StreamLineLimitError2(limit, seen);
|
|
308
|
+
}
|
|
309
|
+
parts.push(new Uint8Array(bytes));
|
|
310
|
+
};
|
|
311
|
+
const take = () => {
|
|
312
|
+
const line = new Uint8Array(pendingBytes);
|
|
313
|
+
let at = 0;
|
|
314
|
+
for (const part of parts) {
|
|
315
|
+
line.set(part, at);
|
|
316
|
+
at += part.byteLength;
|
|
317
|
+
}
|
|
318
|
+
drop();
|
|
319
|
+
return decoder.decode(line);
|
|
320
|
+
};
|
|
321
|
+
function* lines(chunk) {
|
|
322
|
+
if (ended)
|
|
323
|
+
throw new Error("Line decoder received bytes after end()");
|
|
324
|
+
if (failed)
|
|
325
|
+
throw new Error("Line decoder stopped at an earlier error; read the source again");
|
|
326
|
+
try {
|
|
327
|
+
let start = 0;
|
|
328
|
+
for (let index = chunk.indexOf(10);index !== -1; index = chunk.indexOf(10, start)) {
|
|
329
|
+
retain(chunk.subarray(start, index));
|
|
330
|
+
yield take();
|
|
331
|
+
start = index + 1;
|
|
332
|
+
}
|
|
333
|
+
retain(chunk.subarray(start));
|
|
334
|
+
} catch (error) {
|
|
335
|
+
failed = true;
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
lines,
|
|
341
|
+
push: (chunk) => [...lines(chunk)],
|
|
342
|
+
end() {
|
|
343
|
+
ended = true;
|
|
344
|
+
if (pendingBytes === 0)
|
|
345
|
+
return [];
|
|
346
|
+
if (requireFinalNewline) {
|
|
347
|
+
const seen = pendingBytes;
|
|
348
|
+
drop();
|
|
349
|
+
throw new StreamTruncatedLineError2(seen);
|
|
350
|
+
}
|
|
351
|
+
return [take()];
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function createBoundedLineDecoder(maxLineBytes, requireFinalNewline = false) {
|
|
356
|
+
const { push, end } = createLineSplitter(maxLineBytes, requireFinalNewline);
|
|
357
|
+
return { push, end };
|
|
358
|
+
}
|
|
359
|
+
async function* readBoundedUtf8Lines(source, maxLineBytes, requireFinalNewline = false, signal) {
|
|
360
|
+
const splitter = createLineSplitter(maxLineBytes, requireFinalNewline);
|
|
361
|
+
for await (const chunk of chunksOf(source, signal)) {
|
|
362
|
+
for (const line of splitter.lines(chunk)) {
|
|
363
|
+
signal?.throwIfAborted();
|
|
364
|
+
yield line;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
for (const line of splitter.end()) {
|
|
368
|
+
signal?.throwIfAborted();
|
|
369
|
+
yield line;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/browser/stream.ts
|
|
374
|
+
function ndjsonLine(rawLine) {
|
|
375
|
+
return (rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine).trim();
|
|
376
|
+
}
|
|
377
|
+
function parseFailure(raw, error, onParseError) {
|
|
378
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
379
|
+
if (!onParseError)
|
|
380
|
+
throw failure;
|
|
381
|
+
onParseError(raw, failure);
|
|
382
|
+
}
|
|
383
|
+
async function* parseNDJSON2(source, options) {
|
|
384
|
+
let reporting = false;
|
|
385
|
+
try {
|
|
386
|
+
for await (const rawLine of readBoundedUtf8Lines(source, options?.maxLineBytes ?? DEFAULT_STREAM_LINE_BYTES, options?.finalLine === "require-newline", options?.signal)) {
|
|
387
|
+
const line = ndjsonLine(rawLine);
|
|
388
|
+
if (line === "")
|
|
389
|
+
continue;
|
|
390
|
+
let value;
|
|
391
|
+
try {
|
|
392
|
+
value = JSON.parse(line);
|
|
393
|
+
} catch (error) {
|
|
394
|
+
reporting = true;
|
|
395
|
+
parseFailure(line, error, options?.onParseError);
|
|
396
|
+
reporting = false;
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
yield value;
|
|
400
|
+
}
|
|
401
|
+
} catch (error) {
|
|
402
|
+
if (reporting || options?.signal?.aborted)
|
|
403
|
+
throw error;
|
|
404
|
+
parseFailure("", error, options?.onParseError);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function createNDJSONDecoder2(options) {
|
|
408
|
+
const lines = createBoundedLineDecoder(options?.maxLineBytes ?? DEFAULT_STREAM_LINE_BYTES, options?.finalLine === "require-newline");
|
|
409
|
+
let failed = false;
|
|
410
|
+
const values = (rawLines) => {
|
|
411
|
+
const parsed = [];
|
|
412
|
+
for (const rawLine of rawLines) {
|
|
413
|
+
const line = ndjsonLine(rawLine);
|
|
414
|
+
if (line === "")
|
|
415
|
+
continue;
|
|
416
|
+
try {
|
|
417
|
+
parsed.push(JSON.parse(line));
|
|
418
|
+
} catch (error) {
|
|
419
|
+
parseFailure(line, error, options?.onParseError);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return parsed;
|
|
423
|
+
};
|
|
424
|
+
const guarded = (step) => {
|
|
425
|
+
if (failed)
|
|
426
|
+
throw new Error("NDJSON decoder stopped at an earlier error; read the source again");
|
|
427
|
+
try {
|
|
428
|
+
return values(step());
|
|
429
|
+
} catch (error) {
|
|
430
|
+
failed = true;
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
return {
|
|
435
|
+
push: (chunk) => guarded(() => lines.push(chunk)),
|
|
436
|
+
end: () => guarded(() => lines.end())
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
async function* parseSSE2(source, options) {
|
|
440
|
+
let reporting = false;
|
|
441
|
+
try {
|
|
442
|
+
for await (const rawLine of readBoundedUtf8Lines(source, options?.maxLineBytes ?? DEFAULT_STREAM_LINE_BYTES, false, options?.signal)) {
|
|
443
|
+
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
444
|
+
if (!line.startsWith("data:"))
|
|
445
|
+
continue;
|
|
446
|
+
const data = line.slice(5).replace(/^ /, "");
|
|
447
|
+
if (data === "[DONE]")
|
|
448
|
+
return;
|
|
449
|
+
let value;
|
|
450
|
+
try {
|
|
451
|
+
value = JSON.parse(data);
|
|
452
|
+
} catch (error) {
|
|
453
|
+
reporting = true;
|
|
454
|
+
parseFailure(data, error, options?.onParseError);
|
|
455
|
+
reporting = false;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
yield value;
|
|
459
|
+
}
|
|
460
|
+
} catch (error) {
|
|
461
|
+
if (reporting || options?.signal?.aborted)
|
|
462
|
+
throw error;
|
|
463
|
+
parseFailure("", error, options?.onParseError);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
467
|
// src/browser/contract-stream.ts
|
|
468
468
|
function sourceFor(response, descriptor) {
|
|
469
469
|
const options = {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveRouteParamsSchema
|
|
3
3
|
} from "./index-m38ej7e5.js";
|
|
4
|
+
import {
|
|
5
|
+
TOOL_TRANSPORTS2,
|
|
6
|
+
isHttpOnlyEndpoint,
|
|
7
|
+
assertEndpointExposure
|
|
8
|
+
} from "./index-69t14s4a.js";
|
|
4
9
|
import {
|
|
5
10
|
isUnsafeKey
|
|
6
11
|
} from "./index-zsarb5xp.js";
|
|
@@ -11,71 +16,10 @@ import {
|
|
|
11
16
|
isRecord
|
|
12
17
|
} from "./index-9jfdm5tg.js";
|
|
13
18
|
|
|
14
|
-
// src/contract/tool-view.ts
|
|
15
|
-
import { z } from "zod";
|
|
16
|
-
var DECLARED_TOOL_VIEW = Symbol.for("stitchkit.toolView");
|
|
17
|
-
function withToolView2(endpoint, view) {
|
|
18
|
-
const declared = { ...view, [DECLARED_TOOL_VIEW]: true };
|
|
19
|
-
return { ...endpoint, tool: { ...endpoint.tool, view: declared } };
|
|
20
|
-
}
|
|
21
|
-
function objectKeys(schema) {
|
|
22
|
-
return schema instanceof z.ZodObject ? new Set(Object.keys(schema.shape)) : new Set;
|
|
23
|
-
}
|
|
24
|
-
function assertToolView(prefix, key, ep) {
|
|
25
|
-
const where = `Contract "${prefix}": endpoint "${key}" tool.view`;
|
|
26
|
-
const tool = Reflect.get(ep, "tool");
|
|
27
|
-
const view = isRecord(tool) ? tool.view : undefined;
|
|
28
|
-
if (!isRecord(view))
|
|
29
|
-
throw new Error(`${where} must be an object`);
|
|
30
|
-
if (Reflect.get(view, DECLARED_TOOL_VIEW) !== true) {
|
|
31
|
-
throw new Error(`${where} must be declared with withToolView, which types its project`);
|
|
32
|
-
}
|
|
33
|
-
if (ep.rawResponse || ep.rawBody || ep.multipart || "responseMeta" in ep || "stream" in ep) {
|
|
34
|
-
throw new Error(`${where} is only for a JSON tool endpoint — this one is HTTP-only by kind`);
|
|
35
|
-
}
|
|
36
|
-
if (!ep.output) {
|
|
37
|
-
throw new Error(`${where} needs the endpoint's full output — the view is derived from it`);
|
|
38
|
-
}
|
|
39
|
-
const output = view.output;
|
|
40
|
-
const project = view.project;
|
|
41
|
-
if (output !== undefined && !(output instanceof z.ZodType)) {
|
|
42
|
-
throw new Error(`${where}.output must be a Zod schema`);
|
|
43
|
-
}
|
|
44
|
-
if (project !== undefined && typeof project !== "function") {
|
|
45
|
-
throw new Error(`${where}.project must be a function`);
|
|
46
|
-
}
|
|
47
|
-
const defaults = view.defaults;
|
|
48
|
-
if (defaults !== undefined && !isRecord(defaults)) {
|
|
49
|
-
throw new Error(`${where}.defaults must be an object`);
|
|
50
|
-
}
|
|
51
|
-
const entries = defaults === undefined ? [] : Object.entries(defaults);
|
|
52
|
-
if (output === undefined && project === undefined && entries.length === 0) {
|
|
53
|
-
throw new Error(`${where} declares no defaults, output or project — it would change nothing`);
|
|
54
|
-
}
|
|
55
|
-
if (entries.length === 0)
|
|
56
|
-
return;
|
|
57
|
-
if (!(ep.input instanceof z.ZodObject)) {
|
|
58
|
-
throw new Error(`${where}.defaults needs an object input schema to name keys of`);
|
|
59
|
-
}
|
|
60
|
-
const inputKeys = objectKeys(ep.input);
|
|
61
|
-
const paramKeys = objectKeys(ep.params);
|
|
62
|
-
for (const [name, value] of entries) {
|
|
63
|
-
if (paramKeys.has(name)) {
|
|
64
|
-
throw new Error(`${where}.defaults.${name} is a path param — a route segment has no default`);
|
|
65
|
-
}
|
|
66
|
-
if (!inputKeys.has(name)) {
|
|
67
|
-
throw new Error(`${where}.defaults.${name} is not a key of the endpoint's input`);
|
|
68
|
-
}
|
|
69
|
-
const field = ep.input.shape[name];
|
|
70
|
-
if (field === undefined || !z.safeParse(field, value).success) {
|
|
71
|
-
throw new Error(`${where}.defaults.${name} is not a valid value for that input key`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
19
|
// src/contract/define-validation.ts
|
|
77
20
|
function assertMultipartEndpoint(prefix, key, ep) {
|
|
78
21
|
const where = `Contract "${prefix}": multipart endpoint "${key}"`;
|
|
22
|
+
assertNoToolOptions(where, ep);
|
|
79
23
|
if (ep.method !== "POST" && ep.method !== "PUT" && ep.method !== "PATCH") {
|
|
80
24
|
throw new Error(`${where} must use POST, PUT or PATCH`);
|
|
81
25
|
}
|
|
@@ -113,10 +57,6 @@ function assertRawEndpoint(prefix, key, ep) {
|
|
|
113
57
|
if (ep.output)
|
|
114
58
|
throw new Error(`${where} cannot declare an output schema`);
|
|
115
59
|
assertNoToolOptions(where, ep);
|
|
116
|
-
const nonHttp = (ep.expose ?? []).filter((t) => t !== "HTTP");
|
|
117
|
-
if (nonHttp.length > 0) {
|
|
118
|
-
throw new Error(`${where} is HTTP-only — remove ${nonHttp.join(", ")} from expose`);
|
|
119
|
-
}
|
|
120
60
|
}
|
|
121
61
|
function assertStreamingResponseEndpoint(prefix, key, ep) {
|
|
122
62
|
const where = `Contract "${prefix}": streaming endpoint "${key}"`;
|
|
@@ -153,10 +93,6 @@ function assertStreamingResponseEndpoint(prefix, key, ep) {
|
|
|
153
93
|
if (ep.multipart)
|
|
154
94
|
throw new Error(`${where} cannot be multipart`);
|
|
155
95
|
assertNoToolOptions(where, ep);
|
|
156
|
-
const nonHttp = (ep.expose ?? []).filter((transport) => transport !== "HTTP");
|
|
157
|
-
if (nonHttp.length > 0) {
|
|
158
|
-
throw new Error(`${where} is HTTP-only — remove ${nonHttp.join(", ")} from expose`);
|
|
159
|
-
}
|
|
160
96
|
}
|
|
161
97
|
var UNGROUPED_TOOL_OPTIONS = {
|
|
162
98
|
toolName: "tool.name",
|
|
@@ -214,10 +150,6 @@ function assertRawBodyEndpoint(prefix, key, ep) {
|
|
|
214
150
|
throw new Error(`${where} must use POST, PUT or PATCH`);
|
|
215
151
|
}
|
|
216
152
|
assertNoToolOptions(where, ep);
|
|
217
|
-
const nonHttp = (ep.expose ?? []).filter((transport) => transport !== "HTTP");
|
|
218
|
-
if (nonHttp.length > 0) {
|
|
219
|
-
throw new Error(`${where} is HTTP-only — remove ${nonHttp.join(", ")} from expose`);
|
|
220
|
-
}
|
|
221
153
|
}
|
|
222
154
|
function assertSafelistedBodyEndpoint(prefix, key, ep) {
|
|
223
155
|
const where = `Contract "${prefix}": safelistedBody endpoint "${key}"`;
|
|
@@ -245,15 +177,71 @@ function assertResponseMetaEndpoint(prefix, key, ep) {
|
|
|
245
177
|
if (ep.rawResponse)
|
|
246
178
|
throw new Error(`${where} cannot also be a rawResponse endpoint`);
|
|
247
179
|
assertNoToolOptions(where, ep);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/contract/tool-view.ts
|
|
183
|
+
import { z } from "zod";
|
|
184
|
+
var DECLARED_TOOL_VIEW = Symbol.for("stitchkit.toolView");
|
|
185
|
+
function withToolView2(endpoint, view) {
|
|
186
|
+
const declared = { ...view, [DECLARED_TOOL_VIEW]: true };
|
|
187
|
+
return { ...endpoint, tool: { ...endpoint.tool, view: declared } };
|
|
188
|
+
}
|
|
189
|
+
function objectKeys(schema) {
|
|
190
|
+
return schema instanceof z.ZodObject ? new Set(Object.keys(schema.shape)) : new Set;
|
|
191
|
+
}
|
|
192
|
+
function assertToolView(prefix, key, ep) {
|
|
193
|
+
const where = `Contract "${prefix}": endpoint "${key}" tool.view`;
|
|
194
|
+
const tool = Reflect.get(ep, "tool");
|
|
195
|
+
const view = isRecord(tool) ? tool.view : undefined;
|
|
196
|
+
if (!isRecord(view))
|
|
197
|
+
throw new Error(`${where} must be an object`);
|
|
198
|
+
if (Reflect.get(view, DECLARED_TOOL_VIEW) !== true) {
|
|
199
|
+
throw new Error(`${where} must be declared with withToolView, which types its project`);
|
|
200
|
+
}
|
|
201
|
+
if (isHttpOnlyEndpoint(ep)) {
|
|
202
|
+
throw new Error(`${where} is only for a JSON tool endpoint — this one is HTTP-only by kind`);
|
|
203
|
+
}
|
|
204
|
+
if (!ep.output) {
|
|
205
|
+
throw new Error(`${where} needs the endpoint's full output — the view is derived from it`);
|
|
206
|
+
}
|
|
207
|
+
const output = view.output;
|
|
208
|
+
const project = view.project;
|
|
209
|
+
if (output !== undefined && !(output instanceof z.ZodType)) {
|
|
210
|
+
throw new Error(`${where}.output must be a Zod schema`);
|
|
211
|
+
}
|
|
212
|
+
if (project !== undefined && typeof project !== "function") {
|
|
213
|
+
throw new Error(`${where}.project must be a function`);
|
|
214
|
+
}
|
|
215
|
+
const defaults = view.defaults;
|
|
216
|
+
if (defaults !== undefined && !isRecord(defaults)) {
|
|
217
|
+
throw new Error(`${where}.defaults must be an object`);
|
|
218
|
+
}
|
|
219
|
+
const entries = defaults === undefined ? [] : Object.entries(defaults);
|
|
220
|
+
if (output === undefined && project === undefined && entries.length === 0) {
|
|
221
|
+
throw new Error(`${where} declares no defaults, output or project — it would change nothing`);
|
|
222
|
+
}
|
|
223
|
+
if (entries.length === 0)
|
|
224
|
+
return;
|
|
225
|
+
if (!(ep.input instanceof z.ZodObject)) {
|
|
226
|
+
throw new Error(`${where}.defaults needs an object input schema to name keys of`);
|
|
227
|
+
}
|
|
228
|
+
const inputKeys = objectKeys(ep.input);
|
|
229
|
+
const paramKeys = objectKeys(ep.params);
|
|
230
|
+
for (const [name, value] of entries) {
|
|
231
|
+
if (paramKeys.has(name)) {
|
|
232
|
+
throw new Error(`${where}.defaults.${name} is a path param — a route segment has no default`);
|
|
233
|
+
}
|
|
234
|
+
if (!inputKeys.has(name)) {
|
|
235
|
+
throw new Error(`${where}.defaults.${name} is not a key of the endpoint's input`);
|
|
236
|
+
}
|
|
237
|
+
const field = ep.input.shape[name];
|
|
238
|
+
if (field === undefined || !z.safeParse(field, value).success) {
|
|
239
|
+
throw new Error(`${where}.defaults.${name} is not a valid value for that input key`);
|
|
240
|
+
}
|
|
251
241
|
}
|
|
252
242
|
}
|
|
253
243
|
|
|
254
244
|
// src/contract/define.ts
|
|
255
|
-
var ALL_TRANSPORTS2 = ["HTTP", "MCP", "AGENT", "CLI"];
|
|
256
|
-
var TOOL_TRANSPORTS2 = ["MCP", "AGENT", "CLI"];
|
|
257
245
|
function defineContract2(meta, endpoints) {
|
|
258
246
|
const materializedEndpoints = {};
|
|
259
247
|
for (const [key, endpoint] of Object.entries(endpoints)) {
|
|
@@ -262,6 +250,7 @@ function defineContract2(meta, endpoints) {
|
|
|
262
250
|
}
|
|
263
251
|
const toolTransports = new Map;
|
|
264
252
|
for (const [key, ep] of Object.entries(materializedEndpoints)) {
|
|
253
|
+
assertEndpointExposure(meta.prefix, key, ep);
|
|
265
254
|
if (ep.desc.trim() === "") {
|
|
266
255
|
throw new Error(`Contract "${meta.prefix}": endpoint "${key}" has an empty desc`);
|
|
267
256
|
}
|
|
@@ -289,7 +278,7 @@ function defineContract2(meta, endpoints) {
|
|
|
289
278
|
}
|
|
290
279
|
const transports = new Set(ep.expose ? ep.expose.filter((t) => t !== "HTTP") : ["MCP", "AGENT"]);
|
|
291
280
|
if (transports.size === 0) {
|
|
292
|
-
throw new Error(`Contract "${meta.prefix}": endpoint "${key}" sets tool options but is not exposed on any tool transport (${TOOL_TRANSPORTS2.join(" / ")}) — a
|
|
281
|
+
throw new Error(`Contract "${meta.prefix}": endpoint "${key}" sets tool options but is not exposed on any tool transport (${TOOL_TRANSPORTS2.join(" / ")}) — add a tool transport to expose or the factory default`);
|
|
293
282
|
}
|
|
294
283
|
if (tool.view !== undefined)
|
|
295
284
|
assertToolView(meta.prefix, key, ep);
|
|
@@ -310,4 +299,4 @@ function defineContract2(meta, endpoints) {
|
|
|
310
299
|
return { meta, endpoints: materializedEndpoints };
|
|
311
300
|
}
|
|
312
301
|
|
|
313
|
-
export { withToolView2,
|
|
302
|
+
export { withToolView2, defineContract2 };
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
AgentSeedReceiptSchema2,
|
|
9
9
|
AgentHistoryMutationSchema2,
|
|
10
10
|
isActiveRunState
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-8yxgcyt6.js";
|
|
12
12
|
import {
|
|
13
13
|
AgentRecordIdSchema2,
|
|
14
14
|
AgentMessageSchema2
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
replaceMessage,
|
|
18
18
|
ArchiveSpillSchema,
|
|
19
19
|
createAgentRuntimeStore2
|
|
20
|
-
} from "./index-
|
|
20
|
+
} from "./index-rxcgp4b9.js";
|
|
21
21
|
|
|
22
22
|
// src/agent-runtime/store-memory.ts
|
|
23
23
|
import { z as z2 } from "zod";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// src/contract/endpoint-capabilities.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
// src/contract/transports.ts
|
|
5
|
+
var ALL_TRANSPORTS2 = ["HTTP", "MCP", "AGENT", "CLI"];
|
|
6
|
+
var TOOL_TRANSPORTS2 = ["MCP", "AGENT", "CLI"];
|
|
7
|
+
|
|
8
|
+
// src/contract/endpoint-capabilities.ts
|
|
9
|
+
var HTTP_ONLY_FEATURES = [
|
|
10
|
+
"rawResponse",
|
|
11
|
+
"rawBody",
|
|
12
|
+
"responseMeta",
|
|
13
|
+
"multipart",
|
|
14
|
+
"stream"
|
|
15
|
+
];
|
|
16
|
+
var HTTP_ONLY_EXPOSURE = Object.freeze(["HTTP"]);
|
|
17
|
+
var ExposureSchema = z.array(z.enum(ALL_TRANSPORTS2)).refine((transports) => new Set(transports).size === transports.length, {
|
|
18
|
+
message: "Each transport appears at most once"
|
|
19
|
+
}).readonly();
|
|
20
|
+
function isHttpOnlyEndpoint(endpoint) {
|
|
21
|
+
return endpoint.method === "HEAD" || HTTP_ONLY_FEATURES.some((feature) => Boolean(endpoint[feature]));
|
|
22
|
+
}
|
|
23
|
+
function assertEndpointExposure(prefix, key, endpoint) {
|
|
24
|
+
if (endpoint.expose === undefined)
|
|
25
|
+
return;
|
|
26
|
+
const exposure = ExposureSchema.safeParse(endpoint.expose);
|
|
27
|
+
const where = `Contract "${prefix}": endpoint "${key}"`;
|
|
28
|
+
if (!exposure.success) {
|
|
29
|
+
throw new Error(`${where} expose must be an array of distinct transports: ${ALL_TRANSPORTS2.join(" / ")}`);
|
|
30
|
+
}
|
|
31
|
+
if (isHttpOnlyEndpoint(endpoint)) {
|
|
32
|
+
const unsupported = exposure.data.filter((transport) => transport !== "HTTP");
|
|
33
|
+
if (unsupported.length > 0) {
|
|
34
|
+
throw new Error(`${where} is HTTP-only — remove ${unsupported.join(", ")} from expose`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { ALL_TRANSPORTS2, TOOL_TRANSPORTS2, HTTP_ONLY_EXPOSURE, ExposureSchema, isHttpOnlyEndpoint, assertEndpointExposure };
|