stitchkit 0.114.0 → 0.114.2
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 +37 -0
- package/README.md +1 -1
- package/dist/browser/client-url.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/coding-tools.js +1 -1
- package/dist/entrypoints/agent-runtime/harness.js +4 -4
- package/dist/entrypoints/agent-runtime/realtime.js +2 -2
- package/dist/entrypoints/agent-runtime/sandbox.js +3 -3
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +3 -3
- package/dist/entrypoints/agent-runtime/sqlite/node.js +3 -3
- package/dist/entrypoints/agent-runtime/testing.js +4 -4
- package/dist/entrypoints/agent-runtime.js +12 -12
- package/dist/entrypoints/application/directory-inbox.js +3 -3
- package/dist/entrypoints/application.js +4 -4
- package/dist/entrypoints/cli/publish.js +1 -1
- package/dist/entrypoints/cli.js +4 -4
- package/dist/entrypoints/contract.js +2 -2
- package/dist/entrypoints/http.js +2 -2
- package/dist/entrypoints/index.js +5 -5
- package/dist/entrypoints/node.js +3 -3
- package/dist/entrypoints/observability.js +3 -3
- package/dist/entrypoints/react/keyboard/testing.d.ts +2 -0
- package/dist/entrypoints/react/keyboard/testing.d.ts.map +1 -0
- package/dist/entrypoints/react/keyboard/testing.js +127 -0
- package/dist/entrypoints/react/keyboard.d.ts +4 -2
- package/dist/entrypoints/react/keyboard.d.ts.map +1 -1
- package/dist/entrypoints/react/keyboard.js +83 -319
- package/dist/entrypoints/react.js +15 -3
- package/dist/entrypoints/realtime.js +1 -1
- package/dist/entrypoints/remote.js +1 -1
- package/dist/entrypoints/server.js +18 -18
- package/dist/entrypoints/telegram/grammy.d.ts +2 -0
- package/dist/entrypoints/telegram/grammy.d.ts.map +1 -0
- package/dist/entrypoints/telegram/grammy.js +50 -0
- package/dist/entrypoints/telegram/screens.js +1 -1
- package/dist/entrypoints/telegram.js +16 -10
- package/dist/entrypoints/testing.js +3 -3
- package/dist/entrypoints/tools/connections.js +10 -10
- package/dist/entrypoints/tools.js +19 -19
- package/dist/entrypoints/tracking.js +1 -1
- package/dist/{index-hs35ss3p.js → index-61hve0ez.js} +4 -25
- package/dist/index-6j725ez5.js +25 -0
- package/dist/{index-1csp1hwm.js → index-6p3frkv5.js} +1 -1
- package/dist/{index-erv5shjq.js → index-912sza5h.js} +1 -1
- package/dist/{index-fy4av0hq.js → index-9bwcthxw.js} +1 -1
- package/dist/{index-523tq7y4.js → index-a3462dqf.js} +1 -1
- package/dist/{index-506kd458.js → index-aw6zahv1.js} +1 -1
- package/dist/{index-tpwbct8j.js → index-dc9ere5p.js} +1 -1
- package/dist/{index-cxpcdswt.js → index-mgb7r8b8.js} +123 -63
- package/dist/{index-7fc0c2np.js → index-n3v695sb.js} +1 -1
- package/dist/index-p02zgk8x.js +351 -0
- package/dist/{index-vtann8bz.js → index-p0rf7sq9.js} +8 -8
- package/dist/{index-aykhzcnf.js → index-qj1sy4ep.js} +1 -1
- package/dist/{index-k7z3j3hr.js → index-tnxsq7cw.js} +4 -4
- package/dist/{index-c5at3ykd.js → index-tsngj2b5.js} +22 -10
- package/dist/internal/pinned-http.d.ts +27 -0
- package/dist/internal/pinned-http.d.ts.map +1 -0
- package/dist/internal/secure-fetch.d.ts +26 -6
- package/dist/internal/secure-fetch.d.ts.map +1 -1
- package/dist/react/entity-cache.d.ts +24 -2
- package/dist/react/entity-cache.d.ts.map +1 -1
- package/dist/react/keyboard/hooks.d.ts +41 -10
- package/dist/react/keyboard/hooks.d.ts.map +1 -1
- package/dist/react/keyboard/layers.d.ts +27 -8
- package/dist/react/keyboard/layers.d.ts.map +1 -1
- package/dist/react/keyboard/modality.d.ts +21 -0
- package/dist/react/keyboard/modality.d.ts.map +1 -0
- package/dist/react/keyboard/refs.d.ts +13 -0
- package/dist/react/keyboard/refs.d.ts.map +1 -0
- package/dist/react/keyboard/testing.d.ts +80 -0
- package/dist/react/keyboard/testing.d.ts.map +1 -0
- package/dist/react/keyboard/zone.d.ts +60 -10
- package/dist/react/keyboard/zone.d.ts.map +1 -1
- package/dist/telegram/budget-transformer.d.ts +35 -0
- package/dist/telegram/budget-transformer.d.ts.map +1 -0
- package/dist/telegram/outbound-budget.d.ts +4 -2
- package/dist/telegram/outbound-budget.d.ts.map +1 -1
- package/llms/react-keyboard-testing.txt +24 -0
- package/llms/react-keyboard.txt +264 -4
- package/llms/react.txt +1 -1
- package/llms/server.3.txt +31 -0
- package/llms/stitchkit.2.txt +118 -0
- package/llms/stitchkit.txt +4 -118
- package/llms/telegram-grammy.txt +22 -0
- package/llms/telegram.txt +19 -7
- package/llms-full.txt +345 -12
- package/llms.txt +7 -5
- package/package.json +9 -1
- package/dist/{index-616xh7f2.js → index-4qnzda76.js} +0 -0
- package/dist/{index-fsw1ybf3.js → index-d9hq291n.js} +3 -3
- package/dist/{index-bjcjqj46.js → index-m8a44e64.js} +3 -3
- package/dist/{index-5efrpfmj.js → index-qndsr7f0.js} +3 -3
- package/dist/{index-zktz242w.js → index-s47ac8zt.js} +3 -3
- package/dist/{index-56yx8dxp.js → index-tvtacc9a.js} +3 -3
- /package/dist/{index-v1tswj0z.js → index-txg1npmg.js} +0 -0
|
@@ -7,15 +7,20 @@ import {
|
|
|
7
7
|
attemptExclusiveLock
|
|
8
8
|
} from "../index-5v5a9k2n.js";
|
|
9
9
|
import {
|
|
10
|
-
TelegramNotDispatchedError2,
|
|
11
|
-
isTelegramNotDispatchedError,
|
|
12
10
|
TELEGRAM_SEND_FAILURE_REASONS2,
|
|
13
11
|
classifyTelegramSendFailure2
|
|
14
|
-
} from "../index-
|
|
12
|
+
} from "../index-61hve0ez.js";
|
|
13
|
+
import {
|
|
14
|
+
TelegramNotDispatchedError2,
|
|
15
|
+
isTelegramNotDispatchedError
|
|
16
|
+
} from "../index-6j725ez5.js";
|
|
15
17
|
import {
|
|
16
18
|
TELEGRAM_TEXT_LIMIT2,
|
|
17
19
|
truncateTelegramHtml2
|
|
18
20
|
} from "../index-nmaqxdx7.js";
|
|
21
|
+
import {
|
|
22
|
+
BOT_TOKEN_SECRET
|
|
23
|
+
} from "../index-sznqf8fx.js";
|
|
19
24
|
import {
|
|
20
25
|
writeFileAtomic2
|
|
21
26
|
} from "../index-07dcf2yn.js";
|
|
@@ -26,15 +31,12 @@ import {
|
|
|
26
31
|
MAX_TIMER_MS,
|
|
27
32
|
sleep
|
|
28
33
|
} from "../index-eemvahkc.js";
|
|
29
|
-
import {
|
|
30
|
-
assertPositiveSafeInteger
|
|
31
|
-
} from "../index-0s4xebbg.js";
|
|
32
|
-
import {
|
|
33
|
-
BOT_TOKEN_SECRET
|
|
34
|
-
} from "../index-sznqf8fx.js";
|
|
35
34
|
import {
|
|
36
35
|
untilAborted
|
|
37
36
|
} from "../index-a5qr2rj6.js";
|
|
37
|
+
import {
|
|
38
|
+
assertPositiveSafeInteger
|
|
39
|
+
} from "../index-0s4xebbg.js";
|
|
38
40
|
import {
|
|
39
41
|
argumentsDigest
|
|
40
42
|
} from "../index-r7a7r7ha.js";
|
|
@@ -1087,12 +1089,16 @@ function createBudget(rate, fallback, now, sleepFor) {
|
|
|
1087
1089
|
await acquire(cost, signal);
|
|
1088
1090
|
if (signal?.aborted)
|
|
1089
1091
|
throw signal.reason;
|
|
1092
|
+
let result;
|
|
1090
1093
|
try {
|
|
1091
|
-
|
|
1094
|
+
result = await send();
|
|
1092
1095
|
} catch (error) {
|
|
1093
1096
|
pauseAfter(error);
|
|
1094
1097
|
throw error;
|
|
1095
1098
|
}
|
|
1099
|
+
if (isRecord(result) && result.ok === false)
|
|
1100
|
+
pauseAfter(result);
|
|
1101
|
+
return result;
|
|
1096
1102
|
};
|
|
1097
1103
|
const budget = {
|
|
1098
1104
|
run,
|
|
@@ -6,7 +6,7 @@ import"../index-p6apg0jg.js";
|
|
|
6
6
|
import"../index-q0th8q0z.js";
|
|
7
7
|
import {
|
|
8
8
|
createApplication2
|
|
9
|
-
} from "../index-
|
|
9
|
+
} from "../index-txg1npmg.js";
|
|
10
10
|
import"../index-w5s3xftz.js";
|
|
11
11
|
import {
|
|
12
12
|
RealtimeRequestTimeoutError2,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "../index-4s0fep5q.js";
|
|
16
16
|
import {
|
|
17
17
|
TOOL_TRANSPORTS2
|
|
18
|
-
} from "../index-
|
|
18
|
+
} from "../index-d9hq291n.js";
|
|
19
19
|
import {
|
|
20
20
|
RealtimeRejectDirectionSchema,
|
|
21
21
|
RealtimeRejectPhaseSchema,
|
|
@@ -35,7 +35,7 @@ import"../index-k42ckyzx.js";
|
|
|
35
35
|
import {
|
|
36
36
|
createClient2,
|
|
37
37
|
createClients2
|
|
38
|
-
} from "../index-
|
|
38
|
+
} from "../index-tsngj2b5.js";
|
|
39
39
|
import {
|
|
40
40
|
assertPositiveSafeInteger
|
|
41
41
|
} from "../index-0s4xebbg.js";
|
|
@@ -11,28 +11,28 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
withSignalDeadline
|
|
13
13
|
} from "../../index-9tqbxv5p.js";
|
|
14
|
+
import {
|
|
15
|
+
defineRuntimeTool2
|
|
16
|
+
} from "../../index-ega3yz4c.js";
|
|
17
|
+
import {
|
|
18
|
+
TOOL_ERROR_PROJECTION
|
|
19
|
+
} from "../../index-98hv3sba.js";
|
|
14
20
|
import {
|
|
15
21
|
raceAbort
|
|
16
22
|
} from "../../index-b0kddvzw.js";
|
|
17
23
|
import {
|
|
18
24
|
readBoundedChunks,
|
|
19
25
|
concatChunks
|
|
20
|
-
} from "../../index-
|
|
26
|
+
} from "../../index-qndsr7f0.js";
|
|
21
27
|
import {
|
|
22
28
|
MAX_TIMER_MS
|
|
23
29
|
} from "../../index-eemvahkc.js";
|
|
24
|
-
import {
|
|
25
|
-
assertPositiveSafeInteger
|
|
26
|
-
} from "../../index-0s4xebbg.js";
|
|
27
|
-
import {
|
|
28
|
-
defineRuntimeTool2
|
|
29
|
-
} from "../../index-ega3yz4c.js";
|
|
30
|
-
import {
|
|
31
|
-
TOOL_ERROR_PROJECTION
|
|
32
|
-
} from "../../index-98hv3sba.js";
|
|
33
30
|
import {
|
|
34
31
|
safeJsonParse
|
|
35
32
|
} from "../../index-zsarb5xp.js";
|
|
33
|
+
import {
|
|
34
|
+
assertPositiveSafeInteger
|
|
35
|
+
} from "../../index-0s4xebbg.js";
|
|
36
36
|
import {
|
|
37
37
|
AppError2,
|
|
38
38
|
STITCH_ERROR_STATUS2,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
createLocalStepDurability2,
|
|
6
6
|
AgentToolError2,
|
|
7
7
|
isAgentToolError2
|
|
8
|
-
} from "../index-
|
|
8
|
+
} from "../index-tvtacc9a.js";
|
|
9
9
|
import {
|
|
10
10
|
normalizeError2
|
|
11
11
|
} from "../index-k42ckyzx.js";
|
|
@@ -33,13 +33,13 @@ import {
|
|
|
33
33
|
mountAgent2,
|
|
34
34
|
describeToolCatalog2,
|
|
35
35
|
buildToolManifest2
|
|
36
|
-
} from "../index-
|
|
36
|
+
} from "../index-6p3frkv5.js";
|
|
37
37
|
import"../index-m38ej7e5.js";
|
|
38
38
|
import {
|
|
39
39
|
ALL_TRANSPORTS2,
|
|
40
40
|
TOOL_TRANSPORTS2,
|
|
41
41
|
defineContract2
|
|
42
|
-
} from "../index-
|
|
42
|
+
} from "../index-d9hq291n.js";
|
|
43
43
|
import {
|
|
44
44
|
PROTECTED_RESOURCE_PATH2,
|
|
45
45
|
protectedResourceMetadataUrl2,
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
WaitTimeoutError,
|
|
75
75
|
runWaitOperation,
|
|
76
76
|
createCli2
|
|
77
|
-
} from "../index-
|
|
77
|
+
} from "../index-tnxsq7cw.js";
|
|
78
78
|
import {
|
|
79
79
|
ManagedFilePathSchema2,
|
|
80
80
|
ManagedFileRefSchema2
|
|
@@ -87,9 +87,22 @@ import {
|
|
|
87
87
|
contractOnlyService,
|
|
88
88
|
mediaTypeEssence
|
|
89
89
|
} from "../index-cqmqyjax.js";
|
|
90
|
+
import {
|
|
91
|
+
DEFAULT_CORS_ALLOW_HEADERS2
|
|
92
|
+
} from "../index-yk4g8805.js";
|
|
90
93
|
import {
|
|
91
94
|
createToolInvoker2
|
|
92
95
|
} from "../index-vwhrnp67.js";
|
|
96
|
+
import {
|
|
97
|
+
collectToolSurface
|
|
98
|
+
} from "../index-86nbfysb.js";
|
|
99
|
+
import {
|
|
100
|
+
getTraceId2
|
|
101
|
+
} from "../index-r6v4mc67.js";
|
|
102
|
+
import {
|
|
103
|
+
defineRuntimeTool2,
|
|
104
|
+
createRuntimeToolFactory2
|
|
105
|
+
} from "../index-ega3yz4c.js";
|
|
93
106
|
import {
|
|
94
107
|
ManagedFileError2
|
|
95
108
|
} from "../index-2f9r0jgr.js";
|
|
@@ -97,28 +110,15 @@ import {
|
|
|
97
110
|
fetchGuarded,
|
|
98
111
|
fetchPinnedDocument,
|
|
99
112
|
readCapped
|
|
100
|
-
} from "../index-
|
|
113
|
+
} from "../index-mgb7r8b8.js";
|
|
101
114
|
import"../index-1bx1xv1k.js";
|
|
102
115
|
import {
|
|
103
116
|
readBoundedChunks,
|
|
104
117
|
concatChunks
|
|
105
|
-
} from "../index-
|
|
118
|
+
} from "../index-qndsr7f0.js";
|
|
106
119
|
import {
|
|
107
120
|
assertPositiveSafeInteger
|
|
108
121
|
} from "../index-0s4xebbg.js";
|
|
109
|
-
import {
|
|
110
|
-
DEFAULT_CORS_ALLOW_HEADERS2
|
|
111
|
-
} from "../index-yk4g8805.js";
|
|
112
|
-
import {
|
|
113
|
-
collectToolSurface
|
|
114
|
-
} from "../index-86nbfysb.js";
|
|
115
|
-
import {
|
|
116
|
-
getTraceId2
|
|
117
|
-
} from "../index-r6v4mc67.js";
|
|
118
|
-
import {
|
|
119
|
-
defineRuntimeTool2,
|
|
120
|
-
createRuntimeToolFactory2
|
|
121
|
-
} from "../index-ega3yz4c.js";
|
|
122
122
|
import {
|
|
123
123
|
formatZodError2
|
|
124
124
|
} from "../index-1eeqpadm.js";
|
|
@@ -1,31 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isTelegramNotDispatched
|
|
3
|
+
} from "./index-6j725ez5.js";
|
|
1
4
|
import {
|
|
2
5
|
isRecord
|
|
3
6
|
} from "./index-9jfdm5tg.js";
|
|
4
7
|
|
|
5
|
-
// src/telegram/not-dispatched.ts
|
|
6
|
-
class TelegramNotDispatchedError2 extends Error {
|
|
7
|
-
stage;
|
|
8
|
-
name = "TelegramNotDispatchedError";
|
|
9
|
-
code = "TELEGRAM_NOT_DISPATCHED";
|
|
10
|
-
constructor(stage, message, options) {
|
|
11
|
-
super(message, options);
|
|
12
|
-
this.stage = stage;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
function isTelegramNotDispatchedError(error) {
|
|
16
|
-
return error instanceof TelegramNotDispatchedError2 || error instanceof Error && error.name === "TelegramNotDispatchedError" && Reflect.get(error, "code") === "TELEGRAM_NOT_DISPATCHED";
|
|
17
|
-
}
|
|
18
|
-
function isTelegramNotDispatched(error, depth = 0) {
|
|
19
|
-
if (error instanceof TelegramNotDispatchedError2)
|
|
20
|
-
return true;
|
|
21
|
-
if (typeof error !== "object" || error === null || depth > 4)
|
|
22
|
-
return false;
|
|
23
|
-
if (Reflect.get(error, "code") === "TELEGRAM_NOT_DISPATCHED")
|
|
24
|
-
return true;
|
|
25
|
-
const nested = Reflect.get(error, "cause") ?? Reflect.get(error, "error");
|
|
26
|
-
return nested !== error && isTelegramNotDispatched(nested, depth + 1);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
8
|
// src/telegram/send-failure.ts
|
|
30
9
|
var BY_DESCRIPTION = [
|
|
31
10
|
[/bot was blocked by the user|bot was kicked/i, "blocked-by-user"],
|
|
@@ -176,4 +155,4 @@ function classifyTelegramEditRefusal(error) {
|
|
|
176
155
|
return "other";
|
|
177
156
|
}
|
|
178
157
|
|
|
179
|
-
export {
|
|
158
|
+
export { TELEGRAM_SEND_FAILURE_REASONS2, classifyTelegramSendFailure2, classifyTelegramEditRefusal };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/telegram/not-dispatched.ts
|
|
2
|
+
class TelegramNotDispatchedError2 extends Error {
|
|
3
|
+
stage;
|
|
4
|
+
name = "TelegramNotDispatchedError";
|
|
5
|
+
code = "TELEGRAM_NOT_DISPATCHED";
|
|
6
|
+
constructor(stage, message, options) {
|
|
7
|
+
super(message, options);
|
|
8
|
+
this.stage = stage;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function isTelegramNotDispatchedError(error) {
|
|
12
|
+
return error instanceof TelegramNotDispatchedError2 || error instanceof Error && error.name === "TelegramNotDispatchedError" && Reflect.get(error, "code") === "TELEGRAM_NOT_DISPATCHED";
|
|
13
|
+
}
|
|
14
|
+
function isTelegramNotDispatched(error, depth = 0) {
|
|
15
|
+
if (error instanceof TelegramNotDispatchedError2)
|
|
16
|
+
return true;
|
|
17
|
+
if (typeof error !== "object" || error === null || depth > 4)
|
|
18
|
+
return false;
|
|
19
|
+
if (Reflect.get(error, "code") === "TELEGRAM_NOT_DISPATCHED")
|
|
20
|
+
return true;
|
|
21
|
+
const nested = Reflect.get(error, "cause") ?? Reflect.get(error, "error");
|
|
22
|
+
return nested !== error && isTelegramNotDispatched(nested, depth + 1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { TelegramNotDispatchedError2, isTelegramNotDispatchedError, isTelegramNotDispatched };
|
|
@@ -3,13 +3,92 @@ import {
|
|
|
3
3
|
} from "./index-b0kddvzw.js";
|
|
4
4
|
import {
|
|
5
5
|
readBoundedChunks
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-qndsr7f0.js";
|
|
7
7
|
|
|
8
8
|
// src/internal/secure-fetch.ts
|
|
9
9
|
import { lookup } from "node:dns/promises";
|
|
10
|
+
import { isIP } from "node:net";
|
|
11
|
+
|
|
12
|
+
// src/internal/pinned-http.ts
|
|
10
13
|
import { request as httpRequest } from "node:http";
|
|
11
14
|
import { request as httpsRequest } from "node:https";
|
|
12
|
-
|
|
15
|
+
async function requestPinned(url, resolved, signal, headers = {}) {
|
|
16
|
+
const transport = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
17
|
+
const incoming = await new Promise((resolve, reject) => {
|
|
18
|
+
let answered = false;
|
|
19
|
+
const request = transport({
|
|
20
|
+
protocol: url.protocol,
|
|
21
|
+
hostname: resolved.address,
|
|
22
|
+
family: resolved.family,
|
|
23
|
+
port: url.port || undefined,
|
|
24
|
+
path: `${url.pathname}${url.search}`,
|
|
25
|
+
method: "GET",
|
|
26
|
+
signal,
|
|
27
|
+
...url.protocol === "https:" ? { servername: url.hostname } : {},
|
|
28
|
+
headers: { host: url.host, accept: "*/*", ...headers }
|
|
29
|
+
}, (response) => {
|
|
30
|
+
answered = true;
|
|
31
|
+
resolve(response);
|
|
32
|
+
});
|
|
33
|
+
request.once("error", (error) => {
|
|
34
|
+
if (answered)
|
|
35
|
+
return;
|
|
36
|
+
reject(signal?.aborted && signal.reason !== undefined ? signal.reason : error);
|
|
37
|
+
});
|
|
38
|
+
request.end();
|
|
39
|
+
});
|
|
40
|
+
return pinnedResponse(incoming);
|
|
41
|
+
}
|
|
42
|
+
function pinnedResponse(incoming) {
|
|
43
|
+
const status = incoming.statusCode ?? 0;
|
|
44
|
+
const headers = new Headers;
|
|
45
|
+
for (const [name, value] of Object.entries(incoming.headers)) {
|
|
46
|
+
if (Array.isArray(value)) {
|
|
47
|
+
for (const item of value)
|
|
48
|
+
headers.append(name, item);
|
|
49
|
+
} else if (value !== undefined) {
|
|
50
|
+
headers.set(name, value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (status === 204 || status === 205 || status === 304) {
|
|
54
|
+
incoming.resume();
|
|
55
|
+
return new Response(null, { status, statusText: incoming.statusMessage, headers });
|
|
56
|
+
}
|
|
57
|
+
let done = false;
|
|
58
|
+
const body = new ReadableStream({
|
|
59
|
+
start(controller) {
|
|
60
|
+
incoming.on("data", (chunk) => {
|
|
61
|
+
if (done)
|
|
62
|
+
return;
|
|
63
|
+
controller.enqueue(chunk);
|
|
64
|
+
if ((controller.desiredSize ?? 1) <= 0)
|
|
65
|
+
incoming.pause();
|
|
66
|
+
});
|
|
67
|
+
incoming.once("end", () => {
|
|
68
|
+
if (done)
|
|
69
|
+
return;
|
|
70
|
+
done = true;
|
|
71
|
+
controller.close();
|
|
72
|
+
});
|
|
73
|
+
incoming.once("error", (error) => {
|
|
74
|
+
if (done)
|
|
75
|
+
return;
|
|
76
|
+
done = true;
|
|
77
|
+
controller.error(error);
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
pull() {
|
|
81
|
+
incoming.resume();
|
|
82
|
+
},
|
|
83
|
+
cancel() {
|
|
84
|
+
done = true;
|
|
85
|
+
incoming.destroy();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return new Response(body, { status, statusText: incoming.statusMessage, headers });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/internal/secure-fetch.ts
|
|
13
92
|
var NUMERIC_HOST = /^(0x[0-9a-f]+|[0-9.]+)$/i;
|
|
14
93
|
var MAX_REDIRECTS = 5;
|
|
15
94
|
function assertHttpUrl(url) {
|
|
@@ -102,9 +181,10 @@ function isPrivateIp(ip) {
|
|
|
102
181
|
}
|
|
103
182
|
return false;
|
|
104
183
|
}
|
|
105
|
-
async
|
|
106
|
-
await
|
|
107
|
-
|
|
184
|
+
var defaultLookup = async (host) => {
|
|
185
|
+
const records = await lookup(host, { all: true });
|
|
186
|
+
return Array.isArray(records) ? records : [records];
|
|
187
|
+
};
|
|
108
188
|
async function fetchGuarded(start, allowPrivate, options = {}) {
|
|
109
189
|
const timeoutMs = options.timeoutMs ?? 15000;
|
|
110
190
|
const bodyTimeoutMs = options.bodyTimeoutMs ?? 120000;
|
|
@@ -120,15 +200,16 @@ async function fetchGuarded(start, allowPrivate, options = {}) {
|
|
|
120
200
|
controller.abort(new Error(`fetch did not produce response headers within ${timeoutMs}ms`));
|
|
121
201
|
}, timeoutMs);
|
|
122
202
|
headerTimer.unref?.();
|
|
203
|
+
const transport = options.transport ?? requestPinned;
|
|
123
204
|
let settled = false;
|
|
124
205
|
try {
|
|
125
206
|
let url = start;
|
|
126
207
|
for (let hop = 0;hop <= MAX_REDIRECTS; hop++) {
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const res = await
|
|
208
|
+
if (url.username || url.password) {
|
|
209
|
+
throw new Error("refusing to fetch a URL that carries credentials");
|
|
210
|
+
}
|
|
211
|
+
const resolved = await resolveAddress(url, allowPrivate, signal, options.dns);
|
|
212
|
+
const res = await transport(url, resolved, signal);
|
|
132
213
|
const location = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
|
|
133
214
|
if (location === null) {
|
|
134
215
|
settled = true;
|
|
@@ -148,11 +229,27 @@ async function fetchGuarded(start, allowPrivate, options = {}) {
|
|
|
148
229
|
clearTimeout(headerTimer);
|
|
149
230
|
}
|
|
150
231
|
}
|
|
232
|
+
async function resolveAddress(url, allowPrivate, signal, dns) {
|
|
233
|
+
if (!allowPrivate)
|
|
234
|
+
return resolvePublicAddress(url, signal, dns);
|
|
235
|
+
assertHttpUrl(url);
|
|
236
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
237
|
+
if (!host)
|
|
238
|
+
throw new Error("refusing to fetch a URL with no host");
|
|
239
|
+
const ipFamily = isIP(host);
|
|
240
|
+
if (ipFamily)
|
|
241
|
+
return { address: host, family: ipFamily === 6 ? 6 : 4 };
|
|
242
|
+
const records = await (dns ?? defaultLookup)(host, { all: true });
|
|
243
|
+
const record = records[0];
|
|
244
|
+
if (!record)
|
|
245
|
+
throw new Error("host resolved to no addresses");
|
|
246
|
+
return { address: record.address, family: record.family === 6 ? 6 : 4 };
|
|
247
|
+
}
|
|
151
248
|
|
|
152
249
|
class PrivateAddressRefusal extends Error {
|
|
153
250
|
name = "PrivateAddressRefusal";
|
|
154
251
|
}
|
|
155
|
-
async function resolvePublicAddress(url, signal) {
|
|
252
|
+
async function resolvePublicAddress(url, signal, dns) {
|
|
156
253
|
assertHttpUrl(url);
|
|
157
254
|
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
158
255
|
if (!host)
|
|
@@ -169,7 +266,7 @@ async function resolvePublicAddress(url, signal) {
|
|
|
169
266
|
if (host === "localhost" || host.endsWith(".local") || host.endsWith(".internal")) {
|
|
170
267
|
throw new PrivateAddressRefusal("refusing to fetch an internal host");
|
|
171
268
|
}
|
|
172
|
-
const pending =
|
|
269
|
+
const pending = (dns ?? defaultLookup)(host, { all: true });
|
|
173
270
|
const records = signal ? await raceAbort(pending, signal) : await pending;
|
|
174
271
|
for (const record of records) {
|
|
175
272
|
if (isPrivateIp(record.address)) {
|
|
@@ -202,61 +299,24 @@ async function fetchPinnedDocument(start, options) {
|
|
|
202
299
|
throw new Error("document URL cannot contain credentials");
|
|
203
300
|
}
|
|
204
301
|
const resolved = await resolvePublicAddress(url, signal);
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
protocol: url.protocol,
|
|
209
|
-
hostname: resolved.address,
|
|
210
|
-
family: resolved.family,
|
|
211
|
-
port: url.port || undefined,
|
|
212
|
-
path: `${url.pathname}${url.search}`,
|
|
213
|
-
method: "GET",
|
|
214
|
-
signal,
|
|
215
|
-
servername: url.hostname,
|
|
216
|
-
headers: {
|
|
217
|
-
host: url.host,
|
|
218
|
-
accept: "application/json",
|
|
219
|
-
...options.headers
|
|
220
|
-
}
|
|
221
|
-
}, (incoming) => {
|
|
222
|
-
const headers = new Headers;
|
|
223
|
-
for (const [name, value] of Object.entries(incoming.headers)) {
|
|
224
|
-
if (Array.isArray(value)) {
|
|
225
|
-
for (const item of value)
|
|
226
|
-
headers.append(name, item);
|
|
227
|
-
} else if (value !== undefined) {
|
|
228
|
-
headers.set(name, value);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const chunks = [];
|
|
232
|
-
let total = 0;
|
|
233
|
-
incoming.on("data", (chunk) => {
|
|
234
|
-
total += chunk.byteLength;
|
|
235
|
-
if (total > options.maxBytes) {
|
|
236
|
-
incoming.destroy(new Error("response body exceeds configured byte limit"));
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
chunks.push(chunk);
|
|
240
|
-
});
|
|
241
|
-
incoming.once("error", reject);
|
|
242
|
-
incoming.once("end", () => {
|
|
243
|
-
const body = new Uint8Array(total);
|
|
244
|
-
let offset = 0;
|
|
245
|
-
for (const chunk of chunks) {
|
|
246
|
-
body.set(chunk, offset);
|
|
247
|
-
offset += chunk.byteLength;
|
|
248
|
-
}
|
|
249
|
-
resolve({ status: incoming.statusCode ?? 0, headers, body, url });
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
request.once("error", reject);
|
|
253
|
-
request.end();
|
|
302
|
+
const response = await requestPinned(url, resolved, signal, {
|
|
303
|
+
accept: "application/json",
|
|
304
|
+
...options.headers
|
|
254
305
|
});
|
|
306
|
+
const body = await readCapped(response, options.maxBytes);
|
|
307
|
+
if (body === null)
|
|
308
|
+
throw new Error("response body exceeds configured byte limit");
|
|
309
|
+
const document = {
|
|
310
|
+
status: response.status,
|
|
311
|
+
headers: response.headers,
|
|
312
|
+
body: new Uint8Array(body),
|
|
313
|
+
url
|
|
314
|
+
};
|
|
255
315
|
if (response.status < 300 || response.status >= 400)
|
|
256
|
-
return
|
|
316
|
+
return document;
|
|
257
317
|
const location = response.headers.get("location");
|
|
258
318
|
if (!location)
|
|
259
|
-
return
|
|
319
|
+
return document;
|
|
260
320
|
url = new URL(location, url);
|
|
261
321
|
}
|
|
262
322
|
throw new Error("too many redirects");
|