brass-runtime 1.16.0 → 1.16.1
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 +17 -0
- package/README.md +283 -18
- package/dist/agent/cli/main.cjs +38 -38
- package/dist/agent/cli/main.js +6 -6
- package/dist/agent/cli/main.mjs +6 -6
- package/dist/agent/index.cjs +7 -7
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +6 -6
- package/dist/agent/index.mjs +6 -6
- package/dist/chunk-2HQTDLHF.mjs +683 -0
- package/dist/chunk-36I3M4UC.mjs +370 -0
- package/dist/{chunk-QY5FKYEQ.js → chunk-3AYM6WPJ.js} +570 -51
- package/dist/chunk-3LOYJFRR.cjs +300 -0
- package/dist/chunk-3Y2RIUMM.js +300 -0
- package/dist/{chunk-N6VHMOWB.cjs → chunk-4ROBZFL6.cjs} +128 -128
- package/dist/{chunk-NC5SDRYE.js → chunk-52OB2ROS.js} +4 -4
- package/dist/{chunk-JX3LZQJH.cjs → chunk-52PPNNI4.cjs} +82 -20
- package/dist/{chunk-5YOQOXEQ.cjs → chunk-5EC274J5.cjs} +676 -293
- package/dist/chunk-5QC7LRZ3.js +229 -0
- package/dist/{chunk-7TL2LHQJ.js → chunk-5VRJNBLZ.mjs} +524 -141
- package/dist/chunk-62AZW6UT.cjs +313 -0
- package/dist/chunk-6IXXWIUM.js +683 -0
- package/dist/chunk-74ZTY6CP.js +2871 -0
- package/dist/chunk-76YMRMH2.cjs +777 -0
- package/dist/chunk-7CMJS3QE.mjs +2871 -0
- package/dist/{chunk-2WC63LJK.mjs → chunk-7JIJOVCT.js} +20 -10
- package/dist/{chunk-FM4W4QPL.js → chunk-A2OM6NEH.mjs} +5 -4
- package/dist/chunk-AGR5B2BC.cjs +683 -0
- package/dist/chunk-AVNQLJ5V.js +777 -0
- package/dist/chunk-B33ICAKP.js +313 -0
- package/dist/{chunk-J3H54ZRV.mjs → chunk-B5JD23U7.mjs} +1 -1
- package/dist/chunk-BABBZK4Y.js +2024 -0
- package/dist/{chunk-U5KWK3PX.mjs → chunk-C3MDXTRZ.js} +11 -0
- package/dist/{chunk-F5EUMJL7.mjs → chunk-CIZFIMK5.js} +55 -5
- package/dist/{chunk-SPUEME2B.cjs → chunk-CZIVE6NT.cjs} +12 -1
- package/dist/{chunk-TDVMADDN.js → chunk-DNFJLJMW.mjs} +11 -0
- package/dist/chunk-DNFO2EIZ.mjs +777 -0
- package/dist/{chunk-XDZOO4L5.js → chunk-EJ6BPYVR.mjs} +79 -17
- package/dist/{chunk-JNFRRJYH.cjs → chunk-ENKODRU3.cjs} +242 -192
- package/dist/chunk-EOC4UHBS.mjs +229 -0
- package/dist/{chunk-7LVI2GIN.js → chunk-FH2X7BVP.js} +507 -72
- package/dist/{chunk-OOGJ73B6.js → chunk-FHQGHPMO.mjs} +20 -10
- package/dist/{chunk-WQ5QNU5R.cjs → chunk-GLE2WY7Z.cjs} +652 -217
- package/dist/{chunk-G6IQOE4P.mjs → chunk-GYM3LLGS.mjs} +507 -72
- package/dist/chunk-HLWLMW2F.mjs +2024 -0
- package/dist/{chunk-TVN5I4U6.cjs → chunk-JF5WGYJJ.cjs} +25 -24
- package/dist/{chunk-CY33PGEX.mjs → chunk-KH4SYAOS.mjs} +570 -51
- package/dist/chunk-KN32XNTH.mjs +313 -0
- package/dist/chunk-KQLYONSE.cjs +2871 -0
- package/dist/{chunk-7HUOJA4W.cjs → chunk-KZJQ723N.cjs} +90 -80
- package/dist/{chunk-CCKHV5BT.mjs → chunk-L2SYFEBS.js} +5 -4
- package/dist/{chunk-IJT6RRQ5.cjs → chunk-L6VB5N7Q.cjs} +20 -9
- package/dist/{chunk-ZGLD4TVZ.mjs → chunk-MBEJI5HF.mjs} +4 -4
- package/dist/{chunk-PRWCB3QL.mjs → chunk-MIIYDLGM.js} +524 -141
- package/dist/{chunk-H55LI6WY.js → chunk-MOO4L7F4.mjs} +15 -4
- package/dist/{chunk-7XOPAB5Q.js → chunk-MT3OWDPC.mjs} +55 -5
- package/dist/chunk-MVGUEJ5Z.cjs +370 -0
- package/dist/chunk-PD4EJTQC.cjs +229 -0
- package/dist/chunk-PWC3RBQE.mjs +300 -0
- package/dist/{chunk-MWXMNYJS.cjs → chunk-Q2I37RP3.cjs} +643 -124
- package/dist/{chunk-VFIUZG7J.mjs → chunk-RKGKFN2A.js} +79 -17
- package/dist/{chunk-NYL4D7SK.cjs → chunk-SA6HUJVI.cjs} +5 -5
- package/dist/{chunk-K2T3DV26.mjs → chunk-TRM4JUZQ.js} +15 -4
- package/dist/chunk-UB4B6OFY.js +370 -0
- package/dist/{chunk-G3XGCZDQ.js → chunk-UCUBNWM2.js} +1 -1
- package/dist/chunk-VN44DYYT.cjs +2024 -0
- package/dist/{client-CtFmoDvM.d.ts → client-CZHU674n.d.ts} +211 -36
- package/dist/core/index.cjs +135 -9
- package/dist/core/index.d.ts +238 -33
- package/dist/core/index.js +155 -29
- package/dist/core/index.mjs +155 -29
- package/dist/{effect-CGNl5Rqp.d.ts → effect-DIUHZ9IN.d.ts} +89 -1
- package/dist/effectRunner-CFLC32IK.cjs +8 -0
- package/dist/{effectRunner-A4CHJXJI.js → effectRunner-L4S7IPT3.js} +2 -2
- package/dist/{effectRunner-OPUF6QRN.mjs → effectRunner-NNGG75QA.mjs} +2 -2
- package/dist/http/index.cjs +324 -2986
- package/dist/http/index.d.ts +54 -68
- package/dist/http/index.js +238 -2900
- package/dist/http/index.mjs +238 -2900
- package/dist/http/testing.cjs +14 -12
- package/dist/http/testing.d.ts +5 -4
- package/dist/http/testing.js +10 -8
- package/dist/http/testing.mjs +10 -8
- package/dist/index.cjs +423 -255
- package/dist/index.d.ts +87 -69
- package/dist/index.js +301 -133
- package/dist/index.mjs +301 -133
- package/dist/observability/index.cjs +16 -531
- package/dist/observability/index.d.ts +81 -8
- package/dist/observability/index.js +23 -538
- package/dist/observability/index.mjs +23 -538
- package/dist/perf/cli.cjs +401 -0
- package/dist/perf/cli.d.ts +1 -0
- package/dist/perf/cli.js +401 -0
- package/dist/perf/cli.mjs +401 -0
- package/dist/perf/index.cjs +141 -0
- package/dist/perf/index.d.ts +483 -0
- package/dist/perf/index.js +141 -0
- package/dist/perf/index.mjs +141 -0
- package/dist/schedule-CK3Ml_7p.d.ts +259 -0
- package/dist/schema/index.cjs +6 -2
- package/dist/schema/index.d.ts +3 -1
- package/dist/schema/index.js +5 -1
- package/dist/schema/index.mjs +5 -1
- package/dist/{server-C8hDXA74.d.ts → server-GJPg8ZSG.d.ts} +4 -3
- package/dist/{stream-dvSs0QS5.d.ts → stream-B4oK9JFP.d.ts} +1 -1
- package/dist/{tracer-B5tRH9H7.d.ts → tracer-Hwt1cl7h.d.ts} +13 -54
- package/dist/{tracing-Dt9S_6V8.d.ts → tracing-DqbTKGcf.d.ts} +1 -1
- package/docs/ARCHITECTURE.md +292 -0
- package/docs/README.md +63 -0
- package/docs/adr/0001-ai-context-pack.md +32 -0
- package/docs/agent-apply-mode.md +104 -0
- package/docs/agent-approvals.md +110 -0
- package/docs/agent-batch.md +185 -0
- package/docs/agent-boundaries.md +112 -0
- package/docs/agent-chat-sessions.md +160 -0
- package/docs/agent-ci.md +17 -0
- package/docs/agent-cli.md +405 -0
- package/docs/agent-config.md +480 -0
- package/docs/agent-context-discovery.md +159 -0
- package/docs/agent-copilot-like-dx.md +126 -0
- package/docs/agent-declarative-optimized-planning.md +138 -0
- package/docs/agent-dx.md +224 -0
- package/docs/agent-env-files.md +126 -0
- package/docs/agent-follow-up-context.md +43 -0
- package/docs/agent-global-usage.md +180 -0
- package/docs/agent-init.md +109 -0
- package/docs/agent-install-and-configure.md +516 -0
- package/docs/agent-language-workspace-ux.md +99 -0
- package/docs/agent-llm-adapters.md +123 -0
- package/docs/agent-local-install.md +190 -0
- package/docs/agent-local-tests.md +51 -0
- package/docs/agent-observability.md +155 -0
- package/docs/agent-patch-quality-loop.md +162 -0
- package/docs/agent-presets.md +22 -0
- package/docs/agent-project-commands.md +237 -0
- package/docs/agent-project-intelligence.md +156 -0
- package/docs/agent-redaction.md +18 -0
- package/docs/agent-release-readiness.md +76 -0
- package/docs/agent-rollback-safety.md +162 -0
- package/docs/agent-rollback.md +23 -0
- package/docs/agent-run-artifacts.md +16 -0
- package/docs/agent-vscode-auto-discovery.md +137 -0
- package/docs/agent-vscode-batch-runner.md +100 -0
- package/docs/agent-vscode-chat-layout.md +90 -0
- package/docs/agent-vscode-clean-install.md +147 -0
- package/docs/agent-vscode-code-actions.md +70 -0
- package/docs/agent-vscode-diff-preview.md +45 -0
- package/docs/agent-vscode-inline-assist.md +56 -0
- package/docs/agent-vscode-install.md +186 -0
- package/docs/agent-vscode-model-setup.md +97 -0
- package/docs/agent-vscode-patch-preview.md +92 -0
- package/docs/agent-vscode-problems.md +79 -0
- package/docs/agent-vscode-project-dashboard.md +106 -0
- package/docs/agent-vscode-run-history.md +92 -0
- package/docs/agent-vscode-ux.md +73 -0
- package/docs/ai/INVARIANTS.md +84 -0
- package/docs/ai/PROJECT_MAP.md +338 -0
- package/docs/ai/PUBLIC_API.md +336 -0
- package/docs/ai/VALIDATION_MATRIX.md +67 -0
- package/docs/api-polish.md +37 -0
- package/docs/cancellation.md +162 -0
- package/docs/coverage.md +46 -0
- package/docs/getting-started.md +159 -0
- package/docs/guides/README.md +40 -0
- package/docs/guides/circuit-breaker.md +89 -0
- package/docs/guides/error-handling.md +91 -0
- package/docs/guides/getting-started.md +107 -0
- package/docs/guides/layers.md +189 -0
- package/docs/guides/metrics.md +101 -0
- package/docs/guides/resource-management.md +141 -0
- package/docs/guides/retry.md +215 -0
- package/docs/guides/semaphore.md +66 -0
- package/docs/guides/streams.md +117 -0
- package/docs/guides/supervisors.md +98 -0
- package/docs/guides/testing.md +162 -0
- package/docs/guides/tracing.md +71 -0
- package/docs/http-recipes.md +399 -0
- package/docs/http.md +749 -0
- package/docs/modules.md +285 -0
- package/docs/observability-collector-smoke.md +31 -0
- package/docs/observability-framework-examples.md +98 -0
- package/docs/observability.md +542 -0
- package/docs/otel-collector-smoke.yaml +27 -0
- package/docs/performance-profiler.md +199 -0
- package/docs/production-readiness.md +73 -0
- package/docs/recipes/README.md +12 -0
- package/docs/recipes/http-server.md +45 -0
- package/docs/recipes/layers.md +44 -0
- package/docs/recipes/performance.md +47 -0
- package/docs/recipes/runtime.md +41 -0
- package/docs/recipes/testing.md +41 -0
- package/docs/release.md +53 -0
- package/docs/wasm-bounded-queues.md +44 -0
- package/docs/wasm-engine-observability-benchmarks.md +85 -0
- package/docs/wasm-fiber-engine.md +117 -0
- package/docs/wasm-scheduler-state-machine.md +122 -0
- package/docs/wasm-stream-chunks.md +54 -0
- package/package.json +22 -2
- package/dist/chunk-45F7OKGT.cjs +0 -104
- package/dist/chunk-7V4KY4RL.mjs +0 -104
- package/dist/chunk-DJQ7OMMB.cjs +0 -144
- package/dist/chunk-GOV47PPB.mjs +0 -552
- package/dist/chunk-JF4XXPZ5.cjs +0 -552
- package/dist/chunk-KCPT2D6G.js +0 -552
- package/dist/chunk-NOYZIMUJ.mjs +0 -144
- package/dist/chunk-PNVFW245.js +0 -144
- package/dist/chunk-ROJC3NBJ.js +0 -104
- package/dist/effectRunner-3ZHAD3LE.cjs +0 -8
- package/dist/schedule-Fque9Abz.d.ts +0 -70
|
@@ -1,24 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerHttpEffect
|
|
3
|
+
} from "./chunk-MOO4L7F4.mjs";
|
|
1
4
|
import {
|
|
2
5
|
streamFromReadableStream
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FHQGHPMO.mjs";
|
|
4
7
|
import {
|
|
8
|
+
makeScheduleDriver,
|
|
5
9
|
sleep
|
|
6
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2HQTDLHF.mjs";
|
|
11
|
+
import {
|
|
12
|
+
getHttpRequestPolicy,
|
|
13
|
+
isExternalAbortError,
|
|
14
|
+
isHttpError,
|
|
15
|
+
isRetryableHttpError,
|
|
16
|
+
toHttpError,
|
|
17
|
+
withHttpRequestPolicy
|
|
18
|
+
} from "./chunk-PWC3RBQE.mjs";
|
|
7
19
|
import {
|
|
8
20
|
fromPromiseAbortable,
|
|
9
21
|
resolveWasmModule
|
|
10
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-GYM3LLGS.mjs";
|
|
11
23
|
import {
|
|
24
|
+
Cause,
|
|
12
25
|
asyncEffect,
|
|
13
26
|
asyncFail,
|
|
14
27
|
asyncFlatMap,
|
|
15
28
|
asyncFold,
|
|
16
29
|
asyncSucceed
|
|
17
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-36I3M4UC.mjs";
|
|
18
31
|
import {
|
|
19
32
|
Schema,
|
|
20
33
|
parseConfig
|
|
21
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-DNFJLJMW.mjs";
|
|
22
35
|
|
|
23
36
|
// src/http/retry/wasmRetryPlanner.ts
|
|
24
37
|
var WasmRetryPlannerBridge = class {
|
|
@@ -65,7 +78,7 @@ function makeWasmRetryPlanner() {
|
|
|
65
78
|
// src/http/retry/retry.ts
|
|
66
79
|
var defaultRetryableMethods = ["GET", "HEAD", "OPTIONS"];
|
|
67
80
|
var defaultRetryOnStatus = (s) => s === 408 || s === 429 || s === 500 || s === 502 || s === 503 || s === 504;
|
|
68
|
-
var defaultRetryOnError = (e) => e
|
|
81
|
+
var defaultRetryOnError = (e) => isRetryableHttpError(e, { retryOnStatus: defaultRetryOnStatus });
|
|
69
82
|
var clamp = (n, min, max) => Math.max(min, Math.min(max, n));
|
|
70
83
|
var backoffDelayMs = (attempt, base, cap) => {
|
|
71
84
|
const b = Math.max(0, base);
|
|
@@ -92,7 +105,7 @@ var normalizeRetryBudget = (ms) => {
|
|
|
92
105
|
return Math.max(0, Math.floor(ms));
|
|
93
106
|
};
|
|
94
107
|
var resolveEffectivePolicy = (req, basePolicy) => {
|
|
95
|
-
const override = req.retry;
|
|
108
|
+
const override = getHttpRequestPolicy(req).retry;
|
|
96
109
|
if (override === false) return null;
|
|
97
110
|
if (override === void 0) return basePolicy;
|
|
98
111
|
return {
|
|
@@ -118,17 +131,16 @@ var withRetry = (p) => (next) => {
|
|
|
118
131
|
const retryEngine = resolveRetryEngine(p);
|
|
119
132
|
const wasmPlanner = retryEngine === "wasm" ? makeWasmRetryPlanner() : void 0;
|
|
120
133
|
const isMethodRetryable = (req) => retryOnMethods.includes(req.method);
|
|
121
|
-
const nextDelay = (ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable,
|
|
134
|
+
const nextDelay = (ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable, scheduleDriver, input) => {
|
|
122
135
|
if (!retryable) return void 0;
|
|
123
136
|
const remainingBudget = epMaxElapsedMs === void 0 ? Number.POSITIVE_INFINITY : epMaxElapsedMs - (performance.now() - startedAt);
|
|
124
137
|
if (remainingBudget <= 0) return void 0;
|
|
125
|
-
if (
|
|
126
|
-
const
|
|
138
|
+
if (scheduleDriver) {
|
|
139
|
+
const decision = scheduleDriver.next(input);
|
|
127
140
|
if (!decision.continue) return void 0;
|
|
128
141
|
const rawDelay2 = input.retryAfterMs === void 0 ? decision.delayMs : Math.min(input.retryAfterMs, ep.maxDelayMs);
|
|
129
142
|
return {
|
|
130
|
-
delayMs: Math.max(0, Math.min(rawDelay2, remainingBudget))
|
|
131
|
-
scheduleState: nextScheduleState
|
|
143
|
+
delayMs: Math.max(0, Math.min(rawDelay2, remainingBudget))
|
|
132
144
|
};
|
|
133
145
|
}
|
|
134
146
|
if (wasmPlanner && retryId !== void 0) {
|
|
@@ -137,10 +149,10 @@ var withRetry = (p) => (next) => {
|
|
|
137
149
|
retryable,
|
|
138
150
|
retryAfterMs: input.retryAfterMs
|
|
139
151
|
});
|
|
140
|
-
return delay === void 0 ? void 0 : { delayMs: delay
|
|
152
|
+
return delay === void 0 ? void 0 : { delayMs: delay };
|
|
141
153
|
}
|
|
142
154
|
const rawDelay = input.retryAfterMs === void 0 ? backoffDelayMs(attempt, ep.baseDelayMs, ep.maxDelayMs) : Math.min(input.retryAfterMs, ep.maxDelayMs);
|
|
143
|
-
return { delayMs: Math.max(0, Math.min(rawDelay, remainingBudget))
|
|
155
|
+
return { delayMs: Math.max(0, Math.min(rawDelay, remainingBudget)) };
|
|
144
156
|
};
|
|
145
157
|
const sleepWithCleanup = (ms, onCancel) => {
|
|
146
158
|
return asyncEffect((_env, cb) => {
|
|
@@ -152,13 +164,9 @@ var withRetry = (p) => (next) => {
|
|
|
152
164
|
};
|
|
153
165
|
});
|
|
154
166
|
};
|
|
155
|
-
const loop = (req, attempt, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop,
|
|
167
|
+
const loop = (req, attempt, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver) => {
|
|
156
168
|
if (!isMethodRetryable(req)) return next(req);
|
|
157
|
-
const effectiveReq = attempt > 0 ? (()
|
|
158
|
-
const boostedReq = { ...req };
|
|
159
|
-
boostedReq.priority = Math.max(0, originalPriority - 1);
|
|
160
|
-
return boostedReq;
|
|
161
|
-
})() : req;
|
|
169
|
+
const effectiveReq = attempt > 0 ? withHttpRequestPolicy(req, { priority: Math.max(0, originalPriority - 1) }) : req;
|
|
162
170
|
const remainingBudget = () => epMaxElapsedMs === void 0 ? Number.POSITIVE_INFINITY : epMaxElapsedMs - (performance.now() - startedAt);
|
|
163
171
|
return asyncFold(
|
|
164
172
|
next(effectiveReq),
|
|
@@ -168,7 +176,7 @@ var withRetry = (p) => (next) => {
|
|
|
168
176
|
return asyncFail(e);
|
|
169
177
|
}
|
|
170
178
|
const retryable = attempt < ep.maxRetries && epRetryOnError(e) && remainingBudget() > 0;
|
|
171
|
-
const retryDecision = nextDelay(ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable,
|
|
179
|
+
const retryDecision = nextDelay(ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable, scheduleDriver, {
|
|
172
180
|
attempt,
|
|
173
181
|
elapsedMs: performance.now() - startedAt,
|
|
174
182
|
request: req,
|
|
@@ -189,12 +197,12 @@ var withRetry = (p) => (next) => {
|
|
|
189
197
|
timestamp: Date.now()
|
|
190
198
|
});
|
|
191
199
|
}
|
|
192
|
-
return asyncFlatMap(sleepWithCleanup(retryDecision.delayMs, () => safeDrop(retryId)), () => loop(req, attempt + 1, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop,
|
|
200
|
+
return asyncFlatMap(sleepWithCleanup(retryDecision.delayMs, () => safeDrop(retryId)), () => loop(req, attempt + 1, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver));
|
|
193
201
|
},
|
|
194
202
|
(w) => {
|
|
195
203
|
const retryable = attempt < ep.maxRetries && epRetryOnStatus(w.status) && remainingBudget() > 0;
|
|
196
204
|
const ra = ep.respectRetryAfter === false ? void 0 : retryAfterMs(w.headers);
|
|
197
|
-
const retryDecision = nextDelay(ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable,
|
|
205
|
+
const retryDecision = nextDelay(ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable, scheduleDriver, {
|
|
198
206
|
attempt,
|
|
199
207
|
elapsedMs: performance.now() - startedAt,
|
|
200
208
|
request: req,
|
|
@@ -216,7 +224,7 @@ var withRetry = (p) => (next) => {
|
|
|
216
224
|
timestamp: Date.now()
|
|
217
225
|
});
|
|
218
226
|
}
|
|
219
|
-
return asyncFlatMap(sleepWithCleanup(retryDecision.delayMs, () => safeDrop(retryId)), () => loop(req, attempt + 1, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop,
|
|
227
|
+
return asyncFlatMap(sleepWithCleanup(retryDecision.delayMs, () => safeDrop(retryId)), () => loop(req, attempt + 1, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver));
|
|
220
228
|
}
|
|
221
229
|
);
|
|
222
230
|
};
|
|
@@ -227,7 +235,7 @@ var withRetry = (p) => (next) => {
|
|
|
227
235
|
const epRetryOnStatus = effectivePolicy.retryOnStatus ?? defaultRetryOnStatus;
|
|
228
236
|
const epRetryOnError = effectivePolicy.retryOnError ?? defaultRetryOnError;
|
|
229
237
|
const epMaxElapsedMs = normalizeRetryBudget(effectivePolicy.maxElapsedMs);
|
|
230
|
-
const originalPriority = req.priority ?? 5;
|
|
238
|
+
const originalPriority = getHttpRequestPolicy(req).priority ?? 5;
|
|
231
239
|
const startedAt = performance.now();
|
|
232
240
|
const retryId = wasmPlanner?.start({
|
|
233
241
|
nowMs: startedAt,
|
|
@@ -243,8 +251,12 @@ var withRetry = (p) => (next) => {
|
|
|
243
251
|
wasmPlanner?.drop(id);
|
|
244
252
|
}
|
|
245
253
|
};
|
|
246
|
-
const
|
|
247
|
-
|
|
254
|
+
const scheduleDriver = effectivePolicy.schedule ? makeScheduleDriver(effectivePolicy.schedule, {
|
|
255
|
+
name: effectivePolicy.schedule.name ?? "http.retry",
|
|
256
|
+
startedAtMs: startedAt,
|
|
257
|
+
onDecision: effectivePolicy.onScheduleDecision
|
|
258
|
+
}) : void 0;
|
|
259
|
+
return loop(req, 0, startedAt, retryId, effectivePolicy, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver);
|
|
248
260
|
};
|
|
249
261
|
};
|
|
250
262
|
|
|
@@ -257,23 +269,23 @@ var WasmHttpPermitPoolBridge = class {
|
|
|
257
269
|
constructor(Ctor, options) {
|
|
258
270
|
this.pool = new Ctor(options.concurrency, options.maxQueue, toU64(options.queueTimeoutMs));
|
|
259
271
|
}
|
|
260
|
-
acquire(key, subjectId,
|
|
272
|
+
acquire(key, subjectId, nowMs2 = Date.now()) {
|
|
261
273
|
const keyId = this.internKey(key);
|
|
262
|
-
const decision = this.pool.acquire(subjectId, keyId, toU64(
|
|
274
|
+
const decision = this.pool.acquire(subjectId, keyId, toU64(nowMs2));
|
|
263
275
|
const permitId = this.pool.last_permit_id();
|
|
264
276
|
if (decision === DECISION_RUN_NOW) return { kind: "run", keyId, permitId };
|
|
265
277
|
if (decision === DECISION_QUEUED) return { kind: "queued", keyId, permitId };
|
|
266
278
|
return { kind: "rejected", keyId, permitId };
|
|
267
279
|
}
|
|
268
|
-
release(keyId,
|
|
269
|
-
const ptr = this.pool.release(keyId, toU64(
|
|
280
|
+
release(keyId, nowMs2 = Date.now()) {
|
|
281
|
+
const ptr = this.pool.release(keyId, toU64(nowMs2));
|
|
270
282
|
return this.readEvents(ptr, this.pool.permit_events_len());
|
|
271
283
|
}
|
|
272
284
|
cancel(permitId) {
|
|
273
285
|
this.pool.cancel(permitId);
|
|
274
286
|
}
|
|
275
|
-
advanceTime(
|
|
276
|
-
const ptr = this.pool.advance_time(toU64(
|
|
287
|
+
advanceTime(nowMs2 = Date.now()) {
|
|
288
|
+
const ptr = this.pool.advance_time(toU64(nowMs2));
|
|
277
289
|
return this.readEvents(ptr, this.pool.permit_events_len());
|
|
278
290
|
}
|
|
279
291
|
nextDeadlineMs() {
|
|
@@ -356,7 +368,7 @@ function resolveHttpPoolEngine(config) {
|
|
|
356
368
|
return "ts";
|
|
357
369
|
}
|
|
358
370
|
function resolveHttpPoolKey(resolver, req, url) {
|
|
359
|
-
const custom = req.poolKey?.trim();
|
|
371
|
+
const custom = getHttpRequestPolicy(req).poolKey?.trim();
|
|
360
372
|
if (custom) return custom.slice(0, 160);
|
|
361
373
|
const r = resolver ?? "origin";
|
|
362
374
|
if (typeof r === "function") return r(req, url).trim().slice(0, 160) || "global";
|
|
@@ -1904,6 +1916,351 @@ var mergeHeaders = (extra) => (req) => Lens.over(Request.headers, (h) => ({ ...h
|
|
|
1904
1916
|
var mergeHeadersUnder = (under) => (req) => Lens.over(Request.headers, (h) => ({ ...under, ...h }))(req);
|
|
1905
1917
|
var setHeaderIfMissing = (k, v) => (req) => Lens.over(Request.headers, (h) => h[k] ? h : { ...h, [k]: v })(req);
|
|
1906
1918
|
|
|
1919
|
+
// src/http/transport.ts
|
|
1920
|
+
var isTaggedHttpError = (error) => {
|
|
1921
|
+
return isHttpError(error);
|
|
1922
|
+
};
|
|
1923
|
+
var isAbortError = (error) => isExternalAbortError(error);
|
|
1924
|
+
var normalizeHttpError = (error, options) => toHttpError(error, options);
|
|
1925
|
+
var headersOf = (response) => {
|
|
1926
|
+
const headers = {};
|
|
1927
|
+
response.headers.forEach((value, key) => {
|
|
1928
|
+
headers[key] = value;
|
|
1929
|
+
});
|
|
1930
|
+
return headers;
|
|
1931
|
+
};
|
|
1932
|
+
function normalizeHttpHeaders(headers) {
|
|
1933
|
+
if (!headers) return {};
|
|
1934
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
1935
|
+
const out = {};
|
|
1936
|
+
headers.forEach((value, key) => {
|
|
1937
|
+
out[key] = value;
|
|
1938
|
+
});
|
|
1939
|
+
return out;
|
|
1940
|
+
}
|
|
1941
|
+
if (Array.isArray(headers)) {
|
|
1942
|
+
return headers.reduce((acc, item) => {
|
|
1943
|
+
if (!Array.isArray(item) || item.length < 2) return acc;
|
|
1944
|
+
const [key, value] = item;
|
|
1945
|
+
if (key !== void 0 && value !== void 0 && value !== null) {
|
|
1946
|
+
acc[String(key)] = Array.isArray(value) ? value.map(String).join(", ") : String(value);
|
|
1947
|
+
}
|
|
1948
|
+
return acc;
|
|
1949
|
+
}, {});
|
|
1950
|
+
}
|
|
1951
|
+
if (typeof headers.toJSON === "function") {
|
|
1952
|
+
return normalizeHttpHeaders(headers.toJSON());
|
|
1953
|
+
}
|
|
1954
|
+
if (typeof headers === "object") {
|
|
1955
|
+
return Object.entries(headers).reduce((acc, [key, value]) => {
|
|
1956
|
+
if (value !== void 0 && value !== null) {
|
|
1957
|
+
acc[key] = Array.isArray(value) ? value.map(String).join(", ") : String(value);
|
|
1958
|
+
}
|
|
1959
|
+
return acc;
|
|
1960
|
+
}, {});
|
|
1961
|
+
}
|
|
1962
|
+
return {};
|
|
1963
|
+
}
|
|
1964
|
+
var abortErrorForSignal = (signal) => {
|
|
1965
|
+
const reason = signal.reason;
|
|
1966
|
+
if (isTaggedHttpError(reason) && reason._tag === "Timeout") return reason;
|
|
1967
|
+
return { _tag: "Abort" };
|
|
1968
|
+
};
|
|
1969
|
+
var linkAbortSignals = (...signals) => {
|
|
1970
|
+
const activeSignals = signals.filter((signal) => signal !== void 0);
|
|
1971
|
+
if (activeSignals.length === 0) {
|
|
1972
|
+
const controller2 = new AbortController();
|
|
1973
|
+
return { signal: controller2.signal, cleanup: () => void 0 };
|
|
1974
|
+
}
|
|
1975
|
+
const controller = new AbortController();
|
|
1976
|
+
const listeners = [];
|
|
1977
|
+
const abortFrom = (signal) => {
|
|
1978
|
+
try {
|
|
1979
|
+
controller.abort(signal.reason);
|
|
1980
|
+
} catch {
|
|
1981
|
+
controller.abort();
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1984
|
+
for (const signal of activeSignals) {
|
|
1985
|
+
if (signal.aborted) {
|
|
1986
|
+
abortFrom(signal);
|
|
1987
|
+
break;
|
|
1988
|
+
}
|
|
1989
|
+
const abort = () => abortFrom(signal);
|
|
1990
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
1991
|
+
listeners.push({ signal, abort });
|
|
1992
|
+
}
|
|
1993
|
+
return {
|
|
1994
|
+
signal: controller.signal,
|
|
1995
|
+
cleanup: () => {
|
|
1996
|
+
for (const listener of listeners) {
|
|
1997
|
+
listener.signal.removeEventListener("abort", listener.abort);
|
|
1998
|
+
}
|
|
1999
|
+
listeners.length = 0;
|
|
2000
|
+
}
|
|
2001
|
+
};
|
|
2002
|
+
};
|
|
2003
|
+
var nowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
2004
|
+
var hasMethod = (value, name) => typeof value === "object" && value !== null && typeof value[name] === "function";
|
|
2005
|
+
var defaultPromiseBody = (response, mode) => {
|
|
2006
|
+
if (mode === "json" && hasMethod(response, "json")) return response.json();
|
|
2007
|
+
if (mode === "text" && hasMethod(response, "text")) return response.text();
|
|
2008
|
+
if (typeof response === "object" && response !== null) {
|
|
2009
|
+
const record = response;
|
|
2010
|
+
if ("data" in record) return record.data;
|
|
2011
|
+
if ("bodyText" in record) return record.bodyText;
|
|
2012
|
+
if ("body" in record) return record.body;
|
|
2013
|
+
}
|
|
2014
|
+
return response;
|
|
2015
|
+
};
|
|
2016
|
+
var encodePromiseBody = (body, mode) => {
|
|
2017
|
+
if (mode === "text") return body === void 0 || body === null ? "" : String(body);
|
|
2018
|
+
const encoded = JSON.stringify(body);
|
|
2019
|
+
return encoded === void 0 ? "" : encoded;
|
|
2020
|
+
};
|
|
2021
|
+
var finiteNumber = (value) => {
|
|
2022
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
2023
|
+
return Number.isFinite(n) ? n : void 0;
|
|
2024
|
+
};
|
|
2025
|
+
var isPlainRecord = (value) => Object.prototype.toString.call(value) === "[object Object]";
|
|
2026
|
+
var injectSignal = (config, signal) => isPlainRecord(config) ? { ...config, signal } : config;
|
|
2027
|
+
var inferPromiseResponseInfo = (response) => {
|
|
2028
|
+
if (typeof response !== "object" || response === null) {
|
|
2029
|
+
return { status: 200, statusText: "", headers: {} };
|
|
2030
|
+
}
|
|
2031
|
+
const record = response;
|
|
2032
|
+
return {
|
|
2033
|
+
status: finiteNumber(record.status) ?? finiteNumber(record.statusCode) ?? 200,
|
|
2034
|
+
statusText: typeof record.statusText === "string" ? record.statusText : typeof record.statusMessage === "string" ? record.statusMessage : "",
|
|
2035
|
+
headers: record.headers,
|
|
2036
|
+
ms: finiteNumber(record.ms)
|
|
2037
|
+
};
|
|
2038
|
+
};
|
|
2039
|
+
var toPromiseTransportResponse = (bodyText, info) => ({
|
|
2040
|
+
status: info.status ?? 200,
|
|
2041
|
+
statusText: info.statusText ?? "",
|
|
2042
|
+
headers: normalizeHttpHeaders(info.headers),
|
|
2043
|
+
bodyText,
|
|
2044
|
+
...info.ms !== void 0 ? { ms: info.ms } : {},
|
|
2045
|
+
...info.transportMeta !== void 0 ? { transportMeta: info.transportMeta } : {}
|
|
2046
|
+
});
|
|
2047
|
+
function makePromiseHttpTransport(config) {
|
|
2048
|
+
return (context) => asyncEffect((_env, cb) => {
|
|
2049
|
+
let done = false;
|
|
2050
|
+
const finish = (exit) => {
|
|
2051
|
+
if (done) return;
|
|
2052
|
+
done = true;
|
|
2053
|
+
context.signal.removeEventListener("abort", abort);
|
|
2054
|
+
cb(exit);
|
|
2055
|
+
};
|
|
2056
|
+
const fail = (error) => finish({ _tag: "Failure", cause: Cause.fail(error) });
|
|
2057
|
+
const abort = () => fail(abortErrorForSignal(context.signal));
|
|
2058
|
+
if (context.signal.aborted) {
|
|
2059
|
+
abort();
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
context.signal.addEventListener("abort", abort, { once: true });
|
|
2063
|
+
const run = async () => {
|
|
2064
|
+
const startedAt = nowMs();
|
|
2065
|
+
try {
|
|
2066
|
+
const raw = await config.request(context);
|
|
2067
|
+
const durationMs = Math.round(nowMs() - startedAt);
|
|
2068
|
+
const mapped = await config.response(raw, context, { startedAt, durationMs });
|
|
2069
|
+
finish({
|
|
2070
|
+
_tag: "Success",
|
|
2071
|
+
value: {
|
|
2072
|
+
...mapped,
|
|
2073
|
+
ms: mapped.ms ?? durationMs
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
} catch (error) {
|
|
2077
|
+
if (context.signal.aborted) {
|
|
2078
|
+
fail(abortErrorForSignal(context.signal));
|
|
2079
|
+
return;
|
|
2080
|
+
}
|
|
2081
|
+
fail(config.error?.(error, context) ?? normalizeHttpError(error, { signal: context.signal }));
|
|
2082
|
+
}
|
|
2083
|
+
};
|
|
2084
|
+
void run();
|
|
2085
|
+
return () => {
|
|
2086
|
+
if (done) return;
|
|
2087
|
+
done = true;
|
|
2088
|
+
context.signal.removeEventListener("abort", abort);
|
|
2089
|
+
};
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
function makePromiseHttpTransportBodyBuilder(config) {
|
|
2093
|
+
const makeBodyTransport = (mode, body, responseMapper, currentConfig = config) => makePromiseHttpTransport({
|
|
2094
|
+
...currentConfig,
|
|
2095
|
+
response: async (raw, context, timing) => {
|
|
2096
|
+
const selected = await (body ?? ((value) => defaultPromiseBody(value, mode)))(raw, context, timing);
|
|
2097
|
+
const inferred = inferPromiseResponseInfo(raw);
|
|
2098
|
+
const mapped = responseMapper ? await responseMapper(raw, context, timing) : {};
|
|
2099
|
+
return toPromiseTransportResponse(encodePromiseBody(selected, mode), {
|
|
2100
|
+
...inferred,
|
|
2101
|
+
...mapped,
|
|
2102
|
+
headers: mapped.headers ?? inferred.headers
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
});
|
|
2106
|
+
const makeFluentResponseBuilder = (mode, body, currentConfig = config) => {
|
|
2107
|
+
return {
|
|
2108
|
+
response: (responseMapper) => makeBodyTransport(mode, body, responseMapper, currentConfig),
|
|
2109
|
+
error: (error) => makeFluentResponseBuilder(mode, body, { ...currentConfig, error })
|
|
2110
|
+
};
|
|
2111
|
+
};
|
|
2112
|
+
return {
|
|
2113
|
+
response: (response) => makePromiseHttpTransport({ ...config, response }),
|
|
2114
|
+
json: (body, response) => makeBodyTransport("json", body, response),
|
|
2115
|
+
text: (body, response) => makeBodyTransport("text", body, response),
|
|
2116
|
+
fromJson: (body) => makeFluentResponseBuilder("json", body),
|
|
2117
|
+
fromText: (body) => makeFluentResponseBuilder("text", body),
|
|
2118
|
+
error: (error) => makePromiseHttpTransportBodyBuilder({ ...config, error })
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
function makePromiseHttpTransportRequestConfigBuilder(requestConfig) {
|
|
2122
|
+
return {
|
|
2123
|
+
send: (send) => makePromiseHttpTransportBodyBuilder({
|
|
2124
|
+
request: async (context) => {
|
|
2125
|
+
const config = await requestConfig({
|
|
2126
|
+
request: context.request,
|
|
2127
|
+
url: context.url
|
|
2128
|
+
});
|
|
2129
|
+
return send(injectSignal(config, context.signal));
|
|
2130
|
+
}
|
|
2131
|
+
})
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
function promiseHttpTransport() {
|
|
2135
|
+
return {
|
|
2136
|
+
request: (request) => makePromiseHttpTransportBodyBuilder({ request }),
|
|
2137
|
+
requestConfig: (requestConfig) => makePromiseHttpTransportRequestConfigBuilder(requestConfig)
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2140
|
+
var fetchUnavailableError = () => ({
|
|
2141
|
+
_tag: "FetchError",
|
|
2142
|
+
message: "global `fetch` is not available; provide MakeHttpConfig.transport/streamTransport or run in an environment with fetch support."
|
|
2143
|
+
});
|
|
2144
|
+
function makeFetchTransport() {
|
|
2145
|
+
return ({ request, url, signal }) => asyncEffect((_env, cb) => {
|
|
2146
|
+
if (typeof fetch === "undefined") {
|
|
2147
|
+
cb({ _tag: "Failure", cause: Cause.fail(fetchUnavailableError()) });
|
|
2148
|
+
return;
|
|
2149
|
+
}
|
|
2150
|
+
const localController = new AbortController();
|
|
2151
|
+
const linkedSignal = linkAbortSignals(signal, request.init?.signal, localController.signal);
|
|
2152
|
+
let done = false;
|
|
2153
|
+
const finish = (exit) => {
|
|
2154
|
+
if (done) return;
|
|
2155
|
+
done = true;
|
|
2156
|
+
linkedSignal.cleanup();
|
|
2157
|
+
cb(exit);
|
|
2158
|
+
};
|
|
2159
|
+
const run = async () => {
|
|
2160
|
+
try {
|
|
2161
|
+
if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
|
|
2162
|
+
const started = nowMs();
|
|
2163
|
+
const response = await fetch(url, {
|
|
2164
|
+
...request.init ?? {},
|
|
2165
|
+
method: request.method,
|
|
2166
|
+
headers: Request.headers.get(request),
|
|
2167
|
+
body: request.body,
|
|
2168
|
+
signal: linkedSignal.signal
|
|
2169
|
+
});
|
|
2170
|
+
const bodyText = await response.text();
|
|
2171
|
+
const latencyMs = Math.round(nowMs() - started);
|
|
2172
|
+
finish({
|
|
2173
|
+
_tag: "Success",
|
|
2174
|
+
value: {
|
|
2175
|
+
status: response.status,
|
|
2176
|
+
statusText: response.statusText,
|
|
2177
|
+
headers: headersOf(response),
|
|
2178
|
+
bodyText,
|
|
2179
|
+
ms: latencyMs
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
} catch (error) {
|
|
2183
|
+
finish({
|
|
2184
|
+
_tag: "Failure",
|
|
2185
|
+
cause: Cause.fail(normalizeHttpError(error, { signal: linkedSignal.signal }))
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
void run();
|
|
2190
|
+
return () => {
|
|
2191
|
+
if (done) return;
|
|
2192
|
+
try {
|
|
2193
|
+
localController.abort();
|
|
2194
|
+
} catch {
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2199
|
+
function makeFetchStreamTransport() {
|
|
2200
|
+
return ({ request, url, signal }) => asyncEffect((_env, cb) => {
|
|
2201
|
+
if (typeof fetch === "undefined") {
|
|
2202
|
+
cb({ _tag: "Failure", cause: Cause.fail(fetchUnavailableError()) });
|
|
2203
|
+
return;
|
|
2204
|
+
}
|
|
2205
|
+
const localController = new AbortController();
|
|
2206
|
+
const linkedSignal = linkAbortSignals(signal, request.init?.signal, localController.signal);
|
|
2207
|
+
let done = false;
|
|
2208
|
+
let cleanupTransferredToBody = false;
|
|
2209
|
+
const cleanup = () => {
|
|
2210
|
+
if (!cleanupTransferredToBody) linkedSignal.cleanup();
|
|
2211
|
+
};
|
|
2212
|
+
const finish = (exit) => {
|
|
2213
|
+
if (done) return;
|
|
2214
|
+
done = true;
|
|
2215
|
+
cleanup();
|
|
2216
|
+
cb(exit);
|
|
2217
|
+
};
|
|
2218
|
+
const run = async () => {
|
|
2219
|
+
try {
|
|
2220
|
+
if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
|
|
2221
|
+
const started = nowMs();
|
|
2222
|
+
const response = await fetch(url, {
|
|
2223
|
+
...request.init ?? {},
|
|
2224
|
+
method: request.method,
|
|
2225
|
+
headers: Request.headers.get(request),
|
|
2226
|
+
body: request.body,
|
|
2227
|
+
signal: linkedSignal.signal
|
|
2228
|
+
});
|
|
2229
|
+
const headers = headersOf(response);
|
|
2230
|
+
const latencyMs = Math.round(nowMs() - started);
|
|
2231
|
+
const body = streamFromReadableStream(response.body, normalizeHttpError, {
|
|
2232
|
+
signal: linkedSignal.signal,
|
|
2233
|
+
onRelease: linkedSignal.cleanup
|
|
2234
|
+
});
|
|
2235
|
+
cleanupTransferredToBody = response.body !== null;
|
|
2236
|
+
finish({
|
|
2237
|
+
_tag: "Success",
|
|
2238
|
+
value: {
|
|
2239
|
+
status: response.status,
|
|
2240
|
+
statusText: response.statusText,
|
|
2241
|
+
headers,
|
|
2242
|
+
body,
|
|
2243
|
+
ms: latencyMs
|
|
2244
|
+
}
|
|
2245
|
+
});
|
|
2246
|
+
} catch (error) {
|
|
2247
|
+
finish({
|
|
2248
|
+
_tag: "Failure",
|
|
2249
|
+
cause: Cause.fail(normalizeHttpError(error, { signal: linkedSignal.signal }))
|
|
2250
|
+
});
|
|
2251
|
+
}
|
|
2252
|
+
};
|
|
2253
|
+
void run();
|
|
2254
|
+
return () => {
|
|
2255
|
+
if (done) return;
|
|
2256
|
+
try {
|
|
2257
|
+
localController.abort();
|
|
2258
|
+
} catch {
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
});
|
|
2262
|
+
}
|
|
2263
|
+
|
|
1907
2264
|
// src/http/configValidation.ts
|
|
1908
2265
|
var fn = Schema.custom((value) => typeof value === "function", "function");
|
|
1909
2266
|
var object = Schema.custom(
|
|
@@ -2015,6 +2372,31 @@ var retryConfig = Schema.union([
|
|
|
2015
2372
|
onRetry: fn.optional()
|
|
2016
2373
|
}, { unknownKeys: "passthrough" })
|
|
2017
2374
|
]);
|
|
2375
|
+
var requestRetryOverrideConfig = Schema.union([
|
|
2376
|
+
Schema.literal(false),
|
|
2377
|
+
Schema.object({
|
|
2378
|
+
maxRetries: Schema.number({ min: 0, int: true }).optional(),
|
|
2379
|
+
baseDelayMs: Schema.number({ min: 0, int: true }).optional(),
|
|
2380
|
+
maxDelayMs: Schema.number({ min: 0, int: true }).optional(),
|
|
2381
|
+
schedule: object.optional(),
|
|
2382
|
+
retryOnStatus: fn.optional()
|
|
2383
|
+
}, { unknownKeys: "passthrough" })
|
|
2384
|
+
]);
|
|
2385
|
+
var requestPolicyConfig = Schema.object({
|
|
2386
|
+
preset: Schema.string({ minLength: 1 }).optional(),
|
|
2387
|
+
lane: Schema.string({ minLength: 1 }).optional(),
|
|
2388
|
+
dedupKey: Schema.string({ minLength: 1 }).optional(),
|
|
2389
|
+
priority: Schema.number({ min: 0, max: 9, int: true }).optional(),
|
|
2390
|
+
retry: requestRetryOverrideConfig.optional(),
|
|
2391
|
+
poolKey: Schema.string({ minLength: 1 }).optional()
|
|
2392
|
+
}, { unknownKeys: "passthrough" });
|
|
2393
|
+
var policyPresetsConfig = Schema.record(Schema.union([requestPolicyConfig, fn]));
|
|
2394
|
+
var compressionConfig = Schema.union([
|
|
2395
|
+
Schema.literal(false),
|
|
2396
|
+
Schema.object({
|
|
2397
|
+
encodings: Schema.array(Schema.enum(["gzip", "br", "deflate"])).optional()
|
|
2398
|
+
}, { unknownKeys: "passthrough" })
|
|
2399
|
+
]);
|
|
2018
2400
|
var prewarmConfig = Schema.union([
|
|
2019
2401
|
Schema.literal(false),
|
|
2020
2402
|
Schema.object({
|
|
@@ -2041,6 +2423,8 @@ var wireConfig = Schema.object({
|
|
|
2041
2423
|
baseUrl: Schema.string().optional(),
|
|
2042
2424
|
headers: Schema.record(Schema.string()).optional(),
|
|
2043
2425
|
timeoutMs: Schema.number({ min: 1, int: true }).optional(),
|
|
2426
|
+
transport: fn.optional(),
|
|
2427
|
+
streamTransport: fn.optional(),
|
|
2044
2428
|
pool: poolConfig.optional(),
|
|
2045
2429
|
adaptiveLimiter: adaptiveLimiterConfig.optional()
|
|
2046
2430
|
}, { unknownKeys: "passthrough" });
|
|
@@ -2048,6 +2432,8 @@ var lifecycleConfig = Schema.object({
|
|
|
2048
2432
|
baseUrl: Schema.string().optional(),
|
|
2049
2433
|
headers: Schema.record(Schema.string()).optional(),
|
|
2050
2434
|
timeoutMs: Schema.number({ min: 1, int: true }).optional(),
|
|
2435
|
+
transport: fn.optional(),
|
|
2436
|
+
streamTransport: fn.optional(),
|
|
2051
2437
|
pool: poolConfig.optional(),
|
|
2052
2438
|
adaptiveLimiter: adaptiveLimiterConfig.optional(),
|
|
2053
2439
|
dedup: Schema.union([Schema.literal(false), object]).optional(),
|
|
@@ -2056,12 +2442,15 @@ var lifecycleConfig = Schema.object({
|
|
|
2056
2442
|
priority: priorityConfig.optional(),
|
|
2057
2443
|
retry: retryConfig.optional(),
|
|
2058
2444
|
prewarm: prewarmConfig.optional(),
|
|
2059
|
-
onEvent: fn.optional()
|
|
2445
|
+
onEvent: fn.optional(),
|
|
2446
|
+
policyPresets: policyPresetsConfig.optional()
|
|
2060
2447
|
}, { unknownKeys: "passthrough" });
|
|
2061
2448
|
var defaultClientConfig = Schema.object({
|
|
2062
2449
|
baseUrl: Schema.string().optional(),
|
|
2063
2450
|
headers: Schema.record(Schema.string()).optional(),
|
|
2064
2451
|
timeoutMs: Schema.number({ min: 1, int: true }).optional(),
|
|
2452
|
+
transport: fn.optional(),
|
|
2453
|
+
streamTransport: fn.optional(),
|
|
2065
2454
|
pool: poolConfig.optional(),
|
|
2066
2455
|
adaptiveLimiter: adaptiveLimiterConfig.optional(),
|
|
2067
2456
|
dedup: Schema.union([Schema.literal(false), object]).optional(),
|
|
@@ -2071,9 +2460,10 @@ var defaultClientConfig = Schema.object({
|
|
|
2071
2460
|
retry: retryConfig.optional(),
|
|
2072
2461
|
prewarm: prewarmConfig.optional(),
|
|
2073
2462
|
onEvent: fn.optional(),
|
|
2074
|
-
preset: Schema.enum(["minimal", "balanced", "default"]).optional(),
|
|
2075
|
-
compression:
|
|
2076
|
-
middleware: Schema.array(fn).optional()
|
|
2463
|
+
preset: Schema.enum(["minimal", "balanced", "default", "production"]).optional(),
|
|
2464
|
+
compression: compressionConfig.optional(),
|
|
2465
|
+
middleware: Schema.array(fn).optional(),
|
|
2466
|
+
policyPresets: policyPresetsConfig.optional()
|
|
2077
2467
|
}, { unknownKeys: "passthrough" });
|
|
2078
2468
|
function validateMakeHttpConfig(config) {
|
|
2079
2469
|
parseConfig("MakeHttpConfig", wireConfig, config);
|
|
@@ -2110,17 +2500,6 @@ var withMiddleware = (mw) => (c) => decorate(mw(c), c.stats, {
|
|
|
2110
2500
|
shutdown: c.shutdown
|
|
2111
2501
|
});
|
|
2112
2502
|
var decorateStream = (run, stats = emptyStats) => Object.assign(((req) => run(req)), { stats });
|
|
2113
|
-
var isTaggedHttpError = (e) => {
|
|
2114
|
-
if (typeof e !== "object" || e === null || !("_tag" in e)) return false;
|
|
2115
|
-
const tag = e._tag;
|
|
2116
|
-
return tag === "Abort" || tag === "BadUrl" || tag === "FetchError" || tag === "Timeout" || tag === "PoolRejected" || tag === "PoolTimeout" || tag === "PoolClosed" || tag === "BatchSplitError";
|
|
2117
|
-
};
|
|
2118
|
-
var isAbortError = (e) => typeof e === "object" && e !== null && "name" in e && e.name === "AbortError";
|
|
2119
|
-
var normalizeHttpError = (e) => {
|
|
2120
|
-
if (isTaggedHttpError(e)) return e;
|
|
2121
|
-
if (isAbortError(e)) return { _tag: "Abort" };
|
|
2122
|
-
return { _tag: "FetchError", message: String(e) };
|
|
2123
|
-
};
|
|
2124
2503
|
var normalizeHeadersInit = (h) => {
|
|
2125
2504
|
if (!h) return void 0;
|
|
2126
2505
|
if (typeof Headers !== "undefined" && h instanceof Headers) {
|
|
@@ -2212,11 +2591,6 @@ var resolveRequestUrl = (req, baseUrl) => {
|
|
|
2212
2591
|
return { _tag: "BadUrl", message: `URL inv\xE1lida: ${req.url}` };
|
|
2213
2592
|
}
|
|
2214
2593
|
};
|
|
2215
|
-
var headersOf = (res) => {
|
|
2216
|
-
const headers = {};
|
|
2217
|
-
res.headers.forEach((v, k) => headers[k] = v);
|
|
2218
|
-
return headers;
|
|
2219
|
-
};
|
|
2220
2594
|
var fetchLabel = (req, url) => `http:${req.method}:${url.origin}`;
|
|
2221
2595
|
var timeoutReason = (req, url, timeoutMs) => ({
|
|
2222
2596
|
_tag: "Timeout",
|
|
@@ -2225,33 +2599,73 @@ var timeoutReason = (req, url, timeoutMs) => ({
|
|
|
2225
2599
|
message: `HTTP ${req.method} ${url.origin} timed out after ${timeoutMs}ms`
|
|
2226
2600
|
});
|
|
2227
2601
|
var requestPriority = (req) => {
|
|
2228
|
-
const
|
|
2229
|
-
if (
|
|
2602
|
+
const fromPolicy = getHttpRequestPolicy(req).priority;
|
|
2603
|
+
if (fromPolicy !== void 0) return fromPolicy;
|
|
2230
2604
|
return req.init?.priority;
|
|
2231
2605
|
};
|
|
2232
|
-
var
|
|
2233
|
-
if (
|
|
2234
|
-
const
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2606
|
+
var exitError = (exit) => {
|
|
2607
|
+
if (exit._tag === "Success") return void 0;
|
|
2608
|
+
const failure = Cause.firstFailure(exit.cause);
|
|
2609
|
+
if (failure._tag === "Some") return failure.value;
|
|
2610
|
+
const defect = Cause.firstDefect(exit.cause);
|
|
2611
|
+
if (defect._tag === "Some") return defect.value;
|
|
2612
|
+
if (Cause.containsInterrupt(exit.cause)) return { _tag: "Abort" };
|
|
2613
|
+
return Cause.toError(exit.cause);
|
|
2614
|
+
};
|
|
2615
|
+
var runTransportEffect = (effect, env, signal) => new Promise((resolve, reject) => {
|
|
2616
|
+
let done = false;
|
|
2617
|
+
let cancel;
|
|
2618
|
+
const finish = (exit) => {
|
|
2619
|
+
if (done) return;
|
|
2620
|
+
done = true;
|
|
2621
|
+
signal.removeEventListener("abort", abort);
|
|
2622
|
+
cancel = void 0;
|
|
2623
|
+
if (exit._tag === "Success") {
|
|
2624
|
+
resolve(exit.value);
|
|
2625
|
+
return;
|
|
2240
2626
|
}
|
|
2627
|
+
reject(exitError(exit));
|
|
2241
2628
|
};
|
|
2242
|
-
const
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
signal
|
|
2250
|
-
cleanup: () => {
|
|
2251
|
-
runtimeSignal.removeEventListener("abort", abortFromRuntime);
|
|
2252
|
-
requestSignal.removeEventListener("abort", abortFromRequest);
|
|
2253
|
-
}
|
|
2629
|
+
const abort = () => {
|
|
2630
|
+
if (done) return;
|
|
2631
|
+
done = true;
|
|
2632
|
+
signal.removeEventListener("abort", abort);
|
|
2633
|
+
const currentCancel = cancel;
|
|
2634
|
+
cancel = void 0;
|
|
2635
|
+
currentCancel?.();
|
|
2636
|
+
reject(abortErrorForSignal(signal));
|
|
2254
2637
|
};
|
|
2638
|
+
if (signal.aborted) {
|
|
2639
|
+
abort();
|
|
2640
|
+
return;
|
|
2641
|
+
}
|
|
2642
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
2643
|
+
try {
|
|
2644
|
+
cancel = registerHttpEffect(effect, env, finish);
|
|
2645
|
+
} catch (error) {
|
|
2646
|
+
if (done) return;
|
|
2647
|
+
done = true;
|
|
2648
|
+
signal.removeEventListener("abort", abort);
|
|
2649
|
+
reject(error);
|
|
2650
|
+
}
|
|
2651
|
+
});
|
|
2652
|
+
var releaseSuccess = (lease, adaptiveLimiter, response) => {
|
|
2653
|
+
if (!lease) return void 0;
|
|
2654
|
+
if (adaptiveLimiter) {
|
|
2655
|
+
lease.release(response.ms, { status: response.status });
|
|
2656
|
+
} else {
|
|
2657
|
+
lease.release();
|
|
2658
|
+
}
|
|
2659
|
+
return void 0;
|
|
2660
|
+
};
|
|
2661
|
+
var releaseFailure = (lease, adaptiveLimiter) => {
|
|
2662
|
+
if (!lease) return void 0;
|
|
2663
|
+
if (adaptiveLimiter) {
|
|
2664
|
+
lease.release(0, { error: true });
|
|
2665
|
+
} else {
|
|
2666
|
+
lease.release();
|
|
2667
|
+
}
|
|
2668
|
+
return void 0;
|
|
2255
2669
|
};
|
|
2256
2670
|
function makeHttpStream(cfg = {}) {
|
|
2257
2671
|
validateMakeHttpConfig(cfg);
|
|
@@ -2261,17 +2675,18 @@ function makeHttpStream(cfg = {}) {
|
|
|
2261
2675
|
const adaptiveLimiter = makeAdaptiveLimiter(cfg);
|
|
2262
2676
|
const pool = adaptiveLimiter ? void 0 : makePool(cfg);
|
|
2263
2677
|
const metrics = makeHttpStats(pool, adaptiveLimiter);
|
|
2678
|
+
const transport = cfg.streamTransport ?? makeFetchStreamTransport();
|
|
2264
2679
|
const run = (req0) => {
|
|
2265
2680
|
const req = normalize(req0);
|
|
2266
2681
|
const url = resolveRequestUrl(req, baseUrl);
|
|
2267
2682
|
if (!(url instanceof URL)) return asyncFail(url);
|
|
2268
2683
|
const timeoutMs = resolvePositiveTimeout(req.timeoutMs ?? cfg.timeoutMs);
|
|
2269
2684
|
return fromPromiseAbortable(
|
|
2270
|
-
async (signal) => {
|
|
2685
|
+
async (signal, env) => {
|
|
2271
2686
|
let lease;
|
|
2272
2687
|
const linkedSignal = linkAbortSignals(signal, req.init?.signal);
|
|
2273
|
-
let cleanupTransferredToBody = false;
|
|
2274
2688
|
try {
|
|
2689
|
+
if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
|
|
2275
2690
|
if (adaptiveLimiter) {
|
|
2276
2691
|
const key = resolveHttpPoolKey(adaptiveLimiter.keyResolver, req, url);
|
|
2277
2692
|
lease = await adaptiveLimiter.acquire(key, linkedSignal.signal, { priority: requestPriority(req) });
|
|
@@ -2279,44 +2694,18 @@ function makeHttpStream(cfg = {}) {
|
|
|
2279
2694
|
const key = resolveHttpPoolKey(pool.keyResolver, req, url);
|
|
2280
2695
|
lease = await pool.acquire(key, linkedSignal.signal);
|
|
2281
2696
|
}
|
|
2282
|
-
const
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
signal: linkedSignal.signal
|
|
2289
|
-
});
|
|
2290
|
-
const headers = headersOf(res);
|
|
2291
|
-
const latencyMs = Math.round(performance.now() - started);
|
|
2292
|
-
const body = streamFromReadableStream(res.body, normalizeHttpError, {
|
|
2293
|
-
signal: linkedSignal.signal,
|
|
2294
|
-
onRelease: linkedSignal.cleanup
|
|
2295
|
-
});
|
|
2296
|
-
cleanupTransferredToBody = res.body !== null;
|
|
2297
|
-
if (adaptiveLimiter && lease) {
|
|
2298
|
-
lease.release(latencyMs, { status: res.status });
|
|
2299
|
-
} else {
|
|
2300
|
-
lease?.release();
|
|
2301
|
-
}
|
|
2697
|
+
const response = await runTransportEffect(
|
|
2698
|
+
transport({ request: req, url, signal: linkedSignal.signal }),
|
|
2699
|
+
env,
|
|
2700
|
+
linkedSignal.signal
|
|
2701
|
+
);
|
|
2702
|
+
lease = releaseSuccess(lease, adaptiveLimiter, response);
|
|
2302
2703
|
lease = void 0;
|
|
2303
|
-
return
|
|
2304
|
-
status: res.status,
|
|
2305
|
-
statusText: res.statusText,
|
|
2306
|
-
headers,
|
|
2307
|
-
body,
|
|
2308
|
-
ms: latencyMs
|
|
2309
|
-
};
|
|
2704
|
+
return response;
|
|
2310
2705
|
} finally {
|
|
2311
|
-
|
|
2312
|
-
linkedSignal.cleanup();
|
|
2313
|
-
}
|
|
2706
|
+
linkedSignal.cleanup();
|
|
2314
2707
|
if (lease) {
|
|
2315
|
-
|
|
2316
|
-
lease.release(0, { error: true });
|
|
2317
|
-
} else {
|
|
2318
|
-
lease.release();
|
|
2319
|
-
}
|
|
2708
|
+
releaseFailure(lease, adaptiveLimiter);
|
|
2320
2709
|
}
|
|
2321
2710
|
}
|
|
2322
2711
|
},
|
|
@@ -2340,16 +2729,18 @@ function makeHttp(cfg = {}) {
|
|
|
2340
2729
|
const adaptiveLimiter = makeAdaptiveLimiter(cfg);
|
|
2341
2730
|
const pool = adaptiveLimiter ? void 0 : makePool(cfg);
|
|
2342
2731
|
const metrics = makeHttpStats(pool, adaptiveLimiter);
|
|
2732
|
+
const transport = cfg.transport ?? makeFetchTransport();
|
|
2343
2733
|
const run = (req0) => {
|
|
2344
2734
|
const req = normalize(req0);
|
|
2345
2735
|
const url = resolveRequestUrl(req, baseUrl);
|
|
2346
2736
|
if (!(url instanceof URL)) return asyncFail(url);
|
|
2347
2737
|
const timeoutMs = resolvePositiveTimeout(req.timeoutMs ?? cfg.timeoutMs);
|
|
2348
2738
|
return fromPromiseAbortable(
|
|
2349
|
-
async (signal) => {
|
|
2739
|
+
async (signal, env) => {
|
|
2350
2740
|
let lease;
|
|
2351
2741
|
const linkedSignal = linkAbortSignals(signal, req.init?.signal);
|
|
2352
2742
|
try {
|
|
2743
|
+
if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
|
|
2353
2744
|
if (adaptiveLimiter) {
|
|
2354
2745
|
const key = resolveHttpPoolKey(adaptiveLimiter.keyResolver, req, url);
|
|
2355
2746
|
lease = await adaptiveLimiter.acquire(key, linkedSignal.signal, { priority: requestPriority(req) });
|
|
@@ -2357,36 +2748,17 @@ function makeHttp(cfg = {}) {
|
|
|
2357
2748
|
const key = resolveHttpPoolKey(pool.keyResolver, req, url);
|
|
2358
2749
|
lease = await pool.acquire(key, linkedSignal.signal);
|
|
2359
2750
|
}
|
|
2360
|
-
const
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
});
|
|
2368
|
-
const bodyText = await res.text();
|
|
2369
|
-
const headers = headersOf(res);
|
|
2370
|
-
const latencyMs = Math.round(performance.now() - started);
|
|
2371
|
-
if (adaptiveLimiter && lease) {
|
|
2372
|
-
lease.release(latencyMs, { status: res.status });
|
|
2373
|
-
lease = void 0;
|
|
2374
|
-
}
|
|
2375
|
-
return {
|
|
2376
|
-
status: res.status,
|
|
2377
|
-
statusText: res.statusText,
|
|
2378
|
-
headers,
|
|
2379
|
-
bodyText,
|
|
2380
|
-
ms: latencyMs
|
|
2381
|
-
};
|
|
2751
|
+
const response = await runTransportEffect(
|
|
2752
|
+
transport({ request: req, url, signal: linkedSignal.signal }),
|
|
2753
|
+
env,
|
|
2754
|
+
linkedSignal.signal
|
|
2755
|
+
);
|
|
2756
|
+
lease = releaseSuccess(lease, adaptiveLimiter, response);
|
|
2757
|
+
return response;
|
|
2382
2758
|
} finally {
|
|
2383
2759
|
linkedSignal.cleanup();
|
|
2384
2760
|
if (lease) {
|
|
2385
|
-
|
|
2386
|
-
lease.release(0, { error: true });
|
|
2387
|
-
} else {
|
|
2388
|
-
lease.release();
|
|
2389
|
-
}
|
|
2761
|
+
releaseFailure(lease, adaptiveLimiter);
|
|
2390
2762
|
}
|
|
2391
2763
|
}
|
|
2392
2764
|
},
|
|
@@ -2482,6 +2854,17 @@ export {
|
|
|
2482
2854
|
AdaptiveLimiter,
|
|
2483
2855
|
validateLifecycleClientConfig,
|
|
2484
2856
|
validateDefaultHttpClientConfig,
|
|
2857
|
+
isTaggedHttpError,
|
|
2858
|
+
isAbortError,
|
|
2859
|
+
normalizeHttpError,
|
|
2860
|
+
headersOf,
|
|
2861
|
+
normalizeHttpHeaders,
|
|
2862
|
+
abortErrorForSignal,
|
|
2863
|
+
linkAbortSignals,
|
|
2864
|
+
makePromiseHttpTransport,
|
|
2865
|
+
promiseHttpTransport,
|
|
2866
|
+
makeFetchTransport,
|
|
2867
|
+
makeFetchStreamTransport,
|
|
2485
2868
|
decorate,
|
|
2486
2869
|
withMiddleware,
|
|
2487
2870
|
normalizeHeadersInit,
|