@sema-agent/server 7.136.0 → 7.138.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/MIGRATION.md +501 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +149 -34
- package/deploy/sema-up/README.md +14 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/approval-content-kind.d.ts +6 -0
- package/dist/approval-content-kind.js +7 -0
- package/dist/approval-gate-currency.d.ts +48 -6
- package/dist/approval-gate-currency.js +16 -9
- package/dist/approval-hmac.d.ts +13 -1
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.js +3 -3
- package/dist/audit.js +1 -0
- package/dist/auth-bridge.js +2 -2
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- package/dist/boot/execution-env.d.ts +24 -1
- package/dist/boot/execution-env.js +69 -6
- package/dist/boot/governance-seams.d.ts +10 -17
- package/dist/boot/governance-seams.js +5 -17
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +15 -1
- package/dist/boot/resolve-spec.d.ts +7 -0
- package/dist/boot/resolve-spec.js +36 -26
- package/dist/boot/retention-lane.d.ts +11 -5
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +7 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-04-stores.d.ts +2 -13
- package/dist/boot/stage-05-execution-env.d.ts +6 -13
- package/dist/boot/stage-05-execution-env.js +17 -5
- package/dist/boot/stage-06-runners.d.ts +6 -13
- package/dist/boot/stage-06-runners.js +10 -3
- package/dist/boot/stage-07-capability-layer.d.ts +7 -13
- package/dist/boot/stage-07-capability-layer.js +3 -3
- package/dist/boot/stage-08-reapers.d.ts +7 -13
- package/dist/boot/stage-08-reapers.js +2 -1
- package/dist/boot/stage-09-leader.d.ts +7 -13
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +7 -13
- package/dist/boot/stage-10-http-server.js +6 -3
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +3 -3
- package/dist/brain.js +5 -5
- package/dist/broker/broker.d.ts +89 -0
- package/dist/broker/broker.js +287 -0
- package/dist/broker/constants.d.ts +39 -0
- package/dist/broker/constants.js +15 -0
- package/dist/broker/http1.d.ts +111 -0
- package/dist/broker/http1.js +256 -0
- package/dist/broker/lease-book.d.ts +87 -0
- package/dist/broker/lease-book.js +142 -0
- package/dist/broker/lease-file.d.ts +60 -0
- package/dist/broker/lease-file.js +127 -0
- package/dist/broker/main.d.ts +2 -0
- package/dist/broker/main.js +20 -0
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/engine-capabilities.js +1 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capabilities/scenarios.d.ts +23 -8
- package/dist/capabilities/scenarios.js +13 -8
- package/dist/capabilities/skills.d.ts +28 -5
- package/dist/capabilities/skills.js +8 -0
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/center-credential-renewer.js +5 -1
- package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
- package/dist/checkpoint-ctx-seal-m28.js +1 -1
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +16 -7
- package/dist/config-types.d.ts +24 -7
- package/dist/config.d.ts +1 -1
- package/dist/config.js +42 -13
- package/dist/deployment-governance.d.ts +2 -2
- package/dist/deployment-governance.js +7 -9
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/file-history-disclosure.d.ts +4 -2
- package/dist/file-history-disclosure.js +2 -0
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +12 -54
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/http/admission.js +14 -9
- package/dist/http/approval-sweeps.js +4 -3
- package/dist/http/caller-trust.d.ts +2 -1
- package/dist/http/caller-trust.js +1 -3
- package/dist/http/checkpoint-ctx.d.ts +48 -7
- package/dist/http/checkpoint-ctx.js +40 -0
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +18 -10
- package/dist/http/durable-run-leg.d.ts +5 -1
- package/dist/http/durable-run-leg.js +5 -3
- package/dist/http/health-self-report.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/principal-gate.d.ts +15 -10
- package/dist/http/principal-gate.js +48 -9
- package/dist/http/resume-legs.d.ts +7 -31
- package/dist/http/resume-legs.js +185 -126
- package/dist/http/route-ctx.d.ts +38 -53
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +24 -10
- package/dist/http/routes/capabilities.js +23 -11
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -7
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +13 -8
- package/dist/http/routes/session-sync.js +42 -6
- package/dist/http/routes/sessions.js +6 -3
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +794 -780
- package/dist/http/server.d.ts +35 -25
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +6 -1
- package/dist/http/wire-types.d.ts +66 -33
- package/dist/identity-source.d.ts +65 -0
- package/dist/identity-source.js +45 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-store-refusal.d.ts +3 -3
- package/dist/memory-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +2 -0
- package/dist/model-entry-refusal.js +11 -0
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/model-select.d.ts +6 -17
- package/dist/model-select.js +0 -3
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/namespaced-rule-name.d.ts +1 -1
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +17 -1
- package/dist/observability/fail-open.js +17 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/operator-ask.d.ts +2 -2
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +2 -2
- package/dist/org-memory-admission.js +39 -2
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +17 -10
- package/dist/peer-directory.js +2 -0
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- package/dist/permission-rule-list.d.ts +2 -2
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
- package/dist/plugins/checkpoint-store-sql.js +14 -14
- package/dist/plugins/file-history-store-sql.js +10 -16
- package/dist/plugins/file-run-store.js +8 -2
- package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
- package/dist/plugins/k8s-exec-protocol.js +116 -28
- package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
- package/dist/plugins/k8s-pod-delete-failure.js +17 -0
- package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
- package/dist/plugins/k8s-pod-reaper.js +122 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -17
- package/dist/plugins/local-checkpoint-store.js +3 -4
- package/dist/plugins/local-session-store.d.ts +66 -27
- package/dist/plugins/local-session-store.js +60 -28
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-run-store.js +2 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +34 -12
- package/dist/plugins/one-time-migrations.js +51 -9
- package/dist/plugins/permission-rule-store-file.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
- package/dist/plugins/permission-rule-store-sql.js +37 -30
- package/dist/plugins/pg-pool.js +4 -0
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +20 -7
- package/dist/plugins/remote-env-adb.d.ts +6 -1
- package/dist/plugins/remote-env-adb.js +2 -1
- package/dist/plugins/remote-env-device.d.ts +6 -1
- package/dist/plugins/remote-env-device.js +5 -1
- package/dist/plugins/remote-env-e2b.d.ts +5 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-file-error.d.ts +8 -1
- package/dist/plugins/remote-env-file-error.js +7 -1
- package/dist/plugins/remote-env-host.d.ts +10 -2
- package/dist/plugins/remote-env-host.js +8 -2
- package/dist/plugins/remote-env-k8s.d.ts +140 -11
- package/dist/plugins/remote-env-k8s.js +277 -15
- package/dist/plugins/remote-env-local-docker.d.ts +5 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +6 -1
- package/dist/plugins/remote-env-ssh.js +2 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.js +10 -4
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +24 -3
- package/dist/plugins/session-ownership.js +24 -5
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/sql-errors.d.ts +23 -2
- package/dist/plugins/sql-errors.js +15 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/store-contracts.d.ts +10 -1
- package/dist/plugins/store-fault.d.ts +2 -2
- package/dist/plugins/store-fault.js +4 -2
- package/dist/plugins/tidb-pool.js +13 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +18 -7
- package/dist/plugins/tool-result-store-sql.d.ts +13 -6
- package/dist/plugins/tool-result-store-sql.js +8 -7
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +31 -2
- package/dist/request-value-closure.js +7 -1
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +2 -2
- package/dist/rules-consent.js +12 -7
- package/dist/run-local.d.ts +2 -2
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +8 -2
- package/dist/runtime-governance.d.ts +5 -5
- package/dist/sandbox-git-lease.d.ts +49 -0
- package/dist/sandbox-git-lease.js +60 -0
- package/dist/sandbox-git-plane.d.ts +84 -0
- package/dist/sandbox-git-plane.js +105 -0
- package/dist/security.d.ts +16 -4
- package/dist/security.js +8 -3
- package/dist/server-secret-env.d.ts +12 -3
- package/dist/server-secret-env.js +18 -2
- package/dist/session-error-wire.d.ts +14 -6
- package/dist/session-error-wire.js +2 -1
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-policy-wire.js +2 -2
- package/dist/session-sync.d.ts +1 -1
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +44 -14
- package/dist/spec-fields.js +33 -12
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
- package/dist/stored-request-prompt-profile-m30.js +25 -0
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +34 -21
- package/dist/task-mcp.js +46 -22
- package/dist/task-settings.d.ts +2 -2
- package/dist/tool-approval.d.ts +43 -9
- package/dist/tool-approval.js +57 -15
- package/dist/tool-rule-names.d.ts +5 -0
- package/dist/trace/core-keyset-guard.d.ts +34 -19
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +5 -2
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/ledger-sink.d.ts +4 -5
- package/dist/trace/ledger-sink.js +3 -7
- package/dist/trace/project.d.ts +62 -10
- package/dist/trace/project.js +49 -9
- package/dist/trace/redact.d.ts +18 -6
- package/dist/trace/redact.js +154 -60
- package/dist/trace/self-minted-wire.d.ts +500 -7
- package/dist/trace/self-minted-wire.js +182 -1
- package/dist/trace/wire-projection-faces.d.ts +7 -5
- package/dist/trace/wire-projection-faces.js +9 -4
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/apply-effective.js +0 -1
- package/dist/web-admin-client/center-request.d.ts +23 -4
- package/dist/web-admin-client/center-request.js +42 -8
- package/dist/web-admin-client/http-client.js +6 -6
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +31 -18
- package/dist/web-admin-client/types.d.ts +10 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
- package/package.json +3 -3
- package/wire-changes/server@7.137.0.json +825 -0
- package/wire-changes/server@7.138.0.json +446 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import * as http from "node:http";
|
|
2
|
+
import * as net from "node:net";
|
|
3
|
+
import * as tls from "node:tls";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { BROKER_READY_PATH, BROKER_UPSTREAM_CONNECT_MS, BROKER_UPSTREAM_HEADERS_MS } from "./constants.js";
|
|
6
|
+
import { ByteReader, FORWARDED_REQUEST_HEADERS, FORWARDED_RESPONSE_HEADERS, INFO_REFS_QUERIES, MAX_HEAD_BYTES, UPSTREAM_PATH, WireError, judgeRequest, judgeResponseFraming, parseRequestHead, parseResponseHead, readChunked, valuesOf, } from "./http1.js";
|
|
7
|
+
import { LeaseBook, systemMonotonicClock } from "./lease-book.js";
|
|
8
|
+
export function createUpstreamConnector(impl = {}) {
|
|
9
|
+
const tlsConnect = impl.tlsConnect ?? ((opts) => tls.connect(opts));
|
|
10
|
+
const netConnect = impl.netConnect ?? ((opts) => net.connect(opts));
|
|
11
|
+
return (t) => {
|
|
12
|
+
const host = t.hostname.replace(/^\[(.*)\]$/, "$1");
|
|
13
|
+
if (t.protocol === "http:")
|
|
14
|
+
return netConnect({ host, port: t.port });
|
|
15
|
+
return tlsConnect({ host, port: t.port, ...(net.isIP(host) === 0 ? { servername: host } : {}), rejectUnauthorized: true, ALPNProtocols: ["http/1.1"] });
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export const BROKER_UPSTREAM_TIMEOUTS_DEFAULT = { connectMs: BROKER_UPSTREAM_CONNECT_MS, headersMs: BROKER_UPSTREAM_HEADERS_MS };
|
|
19
|
+
export function createBrokerServer(deps) {
|
|
20
|
+
return net.createServer((socket) => void serveOne(socket, deps));
|
|
21
|
+
}
|
|
22
|
+
const REASON = { 200: "OK", 400: "Bad Request", 401: "Unauthorized", 417: "Expectation Failed", 502: "Bad Gateway", 503: "Service Unavailable" };
|
|
23
|
+
const PIECE = 64 * 1024;
|
|
24
|
+
async function serveOne(down, deps) {
|
|
25
|
+
down.on("error", () => { });
|
|
26
|
+
const reader = new ByteReader(down);
|
|
27
|
+
let head;
|
|
28
|
+
try {
|
|
29
|
+
const buf = await reader.readUntil("\r\n\r\n", MAX_HEAD_BYTES);
|
|
30
|
+
if (buf === undefined)
|
|
31
|
+
return void down.destroy();
|
|
32
|
+
head = parseRequestHead(buf);
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
return refuse(down, deps, e instanceof WireError ? e.status : 400, e instanceof WireError ? e.rule : "the request head could not be read");
|
|
36
|
+
}
|
|
37
|
+
if (head.method === "GET" && head.target === BROKER_READY_PATH) {
|
|
38
|
+
const ready = deps.book.ready();
|
|
39
|
+
return answer(down, ready ? 200 : 503, ready ? "ready" : "not ready");
|
|
40
|
+
}
|
|
41
|
+
const verdict = judgeRequest(head, (i) => deps.book.view(i) !== undefined);
|
|
42
|
+
if (!verdict.ok)
|
|
43
|
+
return refuse(down, deps, verdict.status, verdict.rule);
|
|
44
|
+
await forward(down, reader, head, verdict.route, verdict.framing, verdict.expectContinue, deps);
|
|
45
|
+
}
|
|
46
|
+
function refuse(down, deps, status, rule) {
|
|
47
|
+
deps.log({ event: "refused", status, rule });
|
|
48
|
+
answer(down, status, `sandbox git broker: ${rule}`);
|
|
49
|
+
}
|
|
50
|
+
function answer(down, status, text, contentType = "text/plain; charset=utf-8") {
|
|
51
|
+
const body = Buffer.from(`${text}\n`, "utf8");
|
|
52
|
+
down.end(Buffer.concat([Buffer.from(`HTTP/1.1 ${status} ${REASON[status] ?? ""}\r\nContent-Type: ${contentType}\r\nContent-Length: ${body.length}\r\nConnection: close\r\n\r\n`, "latin1"), body]));
|
|
53
|
+
}
|
|
54
|
+
async function within(work, ms, what) {
|
|
55
|
+
let timer;
|
|
56
|
+
const late = new Promise((_, reject) => {
|
|
57
|
+
timer = setTimeout(() => reject(new WireError(502, `upstream_timeout — ${what} within ${ms} ms`)), ms);
|
|
58
|
+
});
|
|
59
|
+
try {
|
|
60
|
+
return await Promise.race([work, late]);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function write(stream, buf) {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
if (stream.destroyed)
|
|
69
|
+
return reject(new Error("the connection is gone"));
|
|
70
|
+
stream.write(buf, (err) => (err ? reject(err) : resolve()));
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const canonical = (name) => name.replace(/(^|-)([a-z])/g, (_m, dash, c) => dash + c.toUpperCase());
|
|
74
|
+
async function forward(down, reader, head, route, framing, expectContinue, deps) {
|
|
75
|
+
const view = deps.book.view(route.i);
|
|
76
|
+
const origin = new URL(view.origin);
|
|
77
|
+
const upstreamPath = `/${route.owner}/${route.repo}/${route.endpoint}${route.service !== undefined ? `?service=${route.service}` : ""}`;
|
|
78
|
+
let up;
|
|
79
|
+
const state = { cut: false, done: false, answered: false };
|
|
80
|
+
const exchange = {
|
|
81
|
+
destroy: () => {
|
|
82
|
+
state.cut = true;
|
|
83
|
+
down.destroy();
|
|
84
|
+
up?.destroy();
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const auth = deps.book.authorize(route.i, exchange);
|
|
88
|
+
try {
|
|
89
|
+
up = deps.connect({ protocol: origin.protocol === "https:" ? "https:" : "http:", hostname: origin.hostname, port: origin.port !== "" ? Number(origin.port) : origin.protocol === "https:" ? 443 : 80 });
|
|
90
|
+
up.on("error", () => { });
|
|
91
|
+
const upReader = new ByteReader(up);
|
|
92
|
+
if (expectContinue)
|
|
93
|
+
down.write("HTTP/1.1 100 Continue\r\n\r\n");
|
|
94
|
+
const lines = [`${head.method} ${upstreamPath} HTTP/1.1`, `Host: ${origin.host}`];
|
|
95
|
+
for (const [n, v] of head.headers)
|
|
96
|
+
if (FORWARDED_REQUEST_HEADERS.has(n))
|
|
97
|
+
lines.push(`${canonical(n)}: ${v}`);
|
|
98
|
+
if (auth !== undefined)
|
|
99
|
+
lines.push(`Authorization: ${auth.authorization}`);
|
|
100
|
+
if (framing.kind === "length")
|
|
101
|
+
lines.push(`Content-Length: ${framing.n}`);
|
|
102
|
+
if (framing.kind === "chunked")
|
|
103
|
+
lines.push("Transfer-Encoding: chunked");
|
|
104
|
+
lines.push("Connection: close");
|
|
105
|
+
const bounds = deps.timeouts ?? BROKER_UPSTREAM_TIMEOUTS_DEFAULT;
|
|
106
|
+
await within(write(up, Buffer.from(`${lines.join("\r\n")}\r\n\r\n`, "latin1")), bounds.connectMs, "the origin did not accept the connection");
|
|
107
|
+
const upstream = up;
|
|
108
|
+
const sent = pumpRequestBody(reader, upstream, framing);
|
|
109
|
+
sent.catch((e) => {
|
|
110
|
+
if (state.done || state.cut)
|
|
111
|
+
return;
|
|
112
|
+
deps.log({ event: "aborted", i: route.i, endpoint: route.endpoint, why: e instanceof WireError ? e.rule : "the request body could not be forwarded" });
|
|
113
|
+
exchange.destroy();
|
|
114
|
+
});
|
|
115
|
+
const res = await readResponseHead(upReader, sent, bounds.headersMs);
|
|
116
|
+
deps.log({ event: "exchange", i: route.i, method: head.method, endpoint: route.endpoint, upstreamStatus: res.status, authenticated: auth !== undefined });
|
|
117
|
+
if (res.status === 401) {
|
|
118
|
+
state.answered = true;
|
|
119
|
+
answerUnauthorized(down, route, auth !== undefined ? (view.rejectedMessage ?? view.unusableMessage) : view.unusableMessage);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const resFraming = judgeResponseFraming(res);
|
|
123
|
+
if ("problem" in resFraming)
|
|
124
|
+
throw new WireError(502, resFraming.problem);
|
|
125
|
+
let location;
|
|
126
|
+
if (res.status >= 300 && res.status < 400) {
|
|
127
|
+
const loc = valuesOf(res.headers, "location");
|
|
128
|
+
location = loc.length === 1 ? rewriteLocation(loc[0], `${view.origin}${upstreamPath}`, view.origin, route.i) : undefined;
|
|
129
|
+
if (location === undefined)
|
|
130
|
+
throw new WireError(502, "the upstream redirected outside this origin's git namespace (not followed)");
|
|
131
|
+
}
|
|
132
|
+
const out = [`HTTP/1.1 ${res.status} ${res.reason.replace(/[^\x20-\x7e]/g, "")}`];
|
|
133
|
+
for (const [n, v] of res.headers)
|
|
134
|
+
if (FORWARDED_RESPONSE_HEADERS.has(n))
|
|
135
|
+
out.push(`${canonical(n)}: ${v}`);
|
|
136
|
+
if (location !== undefined)
|
|
137
|
+
out.push(`Location: ${location}`);
|
|
138
|
+
if (resFraming.kind === "length")
|
|
139
|
+
out.push(`Content-Length: ${resFraming.n}`);
|
|
140
|
+
if (resFraming.kind === "chunked")
|
|
141
|
+
out.push("Transfer-Encoding: chunked");
|
|
142
|
+
out.push("Connection: close");
|
|
143
|
+
state.answered = true;
|
|
144
|
+
await write(down, Buffer.from(`${out.join("\r\n")}\r\n\r\n`, "latin1"));
|
|
145
|
+
await pumpBody(upReader, down, resFraming, "drop", 502);
|
|
146
|
+
state.done = true;
|
|
147
|
+
down.end();
|
|
148
|
+
}
|
|
149
|
+
catch (e) {
|
|
150
|
+
if (state.cut) {
|
|
151
|
+
deps.log({ event: "aborted", i: route.i, endpoint: route.endpoint, why: "cut (lease ended, entry withdrawn, or a side went away)" });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const problem = e instanceof WireError ? e.rule : "the upstream connection failed";
|
|
155
|
+
deps.log({ event: "upstream_failed", i: route.i, endpoint: route.endpoint, problem });
|
|
156
|
+
if (state.answered)
|
|
157
|
+
down.destroy();
|
|
158
|
+
else
|
|
159
|
+
answer(down, 502, `sandbox git broker: ${problem}`);
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
state.done = true;
|
|
163
|
+
auth?.release();
|
|
164
|
+
up?.destroy();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function readResponseHead(upReader, sent, headersMs) {
|
|
168
|
+
const head = (async () => {
|
|
169
|
+
for (;;) {
|
|
170
|
+
const buf = await upReader.readUntil("\r\n\r\n", MAX_HEAD_BYTES);
|
|
171
|
+
if (buf === undefined)
|
|
172
|
+
throw new WireError(502, "the upstream closed before answering");
|
|
173
|
+
const h = parseResponseHead(buf);
|
|
174
|
+
if (h.status >= 200)
|
|
175
|
+
return h;
|
|
176
|
+
}
|
|
177
|
+
})();
|
|
178
|
+
const first = await Promise.race([head.then(() => "head"), sent.then(() => "sent", () => "sent")]);
|
|
179
|
+
return first === "head" ? head : within(head, headersMs, "the origin did not answer the request");
|
|
180
|
+
}
|
|
181
|
+
async function pumpRequestBody(reader, up, framing) {
|
|
182
|
+
await pumpBody(reader, up, framing, "refuse", 400);
|
|
183
|
+
}
|
|
184
|
+
async function pumpBody(from, to, framing, trailers, failStatus) {
|
|
185
|
+
switch (framing.kind) {
|
|
186
|
+
case "none":
|
|
187
|
+
return;
|
|
188
|
+
case "length": {
|
|
189
|
+
let left = framing.n;
|
|
190
|
+
while (left > 0) {
|
|
191
|
+
const piece = await from.readSome(Math.min(left, PIECE));
|
|
192
|
+
if (piece === undefined)
|
|
193
|
+
throw new WireError(failStatus, "the stream ended before its declared length");
|
|
194
|
+
left -= piece.length;
|
|
195
|
+
await write(to, piece);
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
case "chunked": {
|
|
200
|
+
for await (const piece of readChunked(from, trailers, failStatus)) {
|
|
201
|
+
await write(to, Buffer.concat([Buffer.from(`${piece.length.toString(16)}\r\n`, "latin1"), piece, Buffer.from("\r\n", "latin1")]));
|
|
202
|
+
}
|
|
203
|
+
await write(to, Buffer.from("0\r\n\r\n", "latin1"));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
case "close": {
|
|
207
|
+
for (;;) {
|
|
208
|
+
const piece = await from.readSome(PIECE);
|
|
209
|
+
if (piece === undefined)
|
|
210
|
+
return;
|
|
211
|
+
await write(to, piece);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function answerUnauthorized(down, route, sentence) {
|
|
217
|
+
if (route.endpoint !== "info/refs" || route.service === undefined)
|
|
218
|
+
return answer(down, 401, sentence);
|
|
219
|
+
const pkt = (s) => `${(Buffer.byteLength(s, "utf8") + 4).toString(16).padStart(4, "0")}${s}`;
|
|
220
|
+
const body = Buffer.from(`${pkt(`# service=${route.service}\n`)}0000${pkt(`ERR ${sentence}`)}`, "utf8");
|
|
221
|
+
down.end(Buffer.concat([
|
|
222
|
+
Buffer.from(`HTTP/1.1 200 OK\r\nContent-Type: application/x-${route.service}-advertisement\r\nCache-Control: no-cache\r\nContent-Length: ${body.length}\r\nConnection: close\r\n\r\n`, "latin1"),
|
|
223
|
+
body,
|
|
224
|
+
]));
|
|
225
|
+
}
|
|
226
|
+
export function rewriteLocation(location, upstreamUrl, origin, i) {
|
|
227
|
+
if (location.includes("%") || !URL.canParse(location, upstreamUrl))
|
|
228
|
+
return undefined;
|
|
229
|
+
const u = new URL(location, upstreamUrl);
|
|
230
|
+
if (u.origin !== origin || u.username !== "" || u.password !== "" || u.hash !== "")
|
|
231
|
+
return undefined;
|
|
232
|
+
const m = UPSTREAM_PATH.exec(u.pathname);
|
|
233
|
+
if (!m)
|
|
234
|
+
return undefined;
|
|
235
|
+
const endpoint = m[3];
|
|
236
|
+
const query = u.search === "" ? undefined : u.search.slice(1);
|
|
237
|
+
if (endpoint === "info/refs" ? query === undefined || !Object.hasOwn(INFO_REFS_QUERIES, query) : query !== undefined)
|
|
238
|
+
return undefined;
|
|
239
|
+
return `/o/${i}/${m[1]}/${m[2]}/${endpoint}${query !== undefined ? `?${query}` : ""}`;
|
|
240
|
+
}
|
|
241
|
+
export async function runBroker(opts) {
|
|
242
|
+
const book = new LeaseBook({ clock: opts.clock ?? systemMonotonicClock, log: opts.log });
|
|
243
|
+
let last;
|
|
244
|
+
const poll = () => {
|
|
245
|
+
let text;
|
|
246
|
+
try {
|
|
247
|
+
text = readFileSync(opts.leasePath, "utf8");
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
text = "";
|
|
251
|
+
if (last !== "")
|
|
252
|
+
opts.log({ event: "lease_file_unreadable", problem: e.code ?? "read failed" });
|
|
253
|
+
}
|
|
254
|
+
if (text === last)
|
|
255
|
+
return;
|
|
256
|
+
last = text;
|
|
257
|
+
book.load(text);
|
|
258
|
+
};
|
|
259
|
+
poll();
|
|
260
|
+
const timer = setInterval(poll, opts.pollMs);
|
|
261
|
+
const server = createBrokerServer({ book, connect: opts.connect ?? createUpstreamConnector(), log: opts.log });
|
|
262
|
+
await new Promise((resolve, reject) => {
|
|
263
|
+
server.once("error", reject);
|
|
264
|
+
server.listen(opts.port, opts.host, () => resolve());
|
|
265
|
+
});
|
|
266
|
+
const port = server.address().port;
|
|
267
|
+
opts.log({ event: "listening", host: opts.host, port });
|
|
268
|
+
return {
|
|
269
|
+
port,
|
|
270
|
+
book,
|
|
271
|
+
close: () => new Promise((resolve) => {
|
|
272
|
+
clearInterval(timer);
|
|
273
|
+
server.close(() => resolve());
|
|
274
|
+
}),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
export function probeBroker(host, port, timeoutMs) {
|
|
278
|
+
return new Promise((resolve) => {
|
|
279
|
+
const req = http.get({ host, port, path: BROKER_READY_PATH, timeout: timeoutMs, agent: false }, (res) => {
|
|
280
|
+
res.resume();
|
|
281
|
+
resolve(res.statusCode === 200);
|
|
282
|
+
});
|
|
283
|
+
req.on("timeout", () => req.destroy());
|
|
284
|
+
req.on("error", () => resolve(false));
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=broker.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The member git-credential broker's fixed coordinates — the ONE place they are spelled. Both sides read this module: the k8s adapter
|
|
3
|
+
* (which builds the broker container, its lease volume and the agent container's `insteadOf` routes) and the broker program itself (which
|
|
4
|
+
* listens on the port and reads the lease file). Nothing here is a knob: a pod's broker is the same program at the same place on every pod.
|
|
5
|
+
*
|
|
6
|
+
* The program runs from the engine image (`K8S_SANDBOX_BROKER_IMAGE`, recommended = this engine's own image), whose layout is the repo's
|
|
7
|
+
* `Dockerfile`: Bun at `/app`, the TypeScript sources at `/app/src`, no build step — hence the command below. A broker image other than the
|
|
8
|
+
* engine's own must carry the same program at the same path.
|
|
9
|
+
*/
|
|
10
|
+
/** The broker's loopback port inside the pod's network namespace (the agent container reaches it at `127.0.0.1`; nothing outside the pod does). */
|
|
11
|
+
export declare const BROKER_PORT = 47311;
|
|
12
|
+
/** The broker listens on the pod loopback only. */
|
|
13
|
+
export declare const BROKER_HOST = "127.0.0.1";
|
|
14
|
+
/** The broker container's name (`containers[1]`). */
|
|
15
|
+
export declare const BROKER_CONTAINER_NAME = "sema-broker";
|
|
16
|
+
/** The pod volume that projects the lease Secret into the broker container (a reserved name: a deployment patch cannot use it). */
|
|
17
|
+
export declare const BROKER_VOLUME_NAME = "sema-broker-lease";
|
|
18
|
+
/** Where the lease volume is mounted in the broker container (read-only). */
|
|
19
|
+
export declare const BROKER_LEASE_DIR = "/var/run/sema-broker";
|
|
20
|
+
/** The lease Secret's one data key, and the file name in the mounted volume. */
|
|
21
|
+
export declare const BROKER_LEASE_KEY = "broker.json";
|
|
22
|
+
/** The lease file the broker reads. */
|
|
23
|
+
export declare const BROKER_LEASE_PATH = "/var/run/sema-broker/broker.json";
|
|
24
|
+
/** The broker program inside the engine image. */
|
|
25
|
+
export declare const BROKER_ENTRY_PATH = "/app/src/broker/main.ts";
|
|
26
|
+
/** The broker container's fixed command. */
|
|
27
|
+
export declare const BROKER_COMMAND: readonly ["bun", "/app/src/broker/main.ts"];
|
|
28
|
+
/** The argument that turns the same program into its own readiness probe (asks `BROKER_READY_PATH` on the loopback, exits 0 ⇔ 200). */
|
|
29
|
+
export declare const BROKER_PROBE_ARG = "--probe";
|
|
30
|
+
/** The broker's local readiness route (answered by the broker itself, never forwarded). */
|
|
31
|
+
export declare const BROKER_READY_PATH = "/_ready";
|
|
32
|
+
/** How often the broker re-reads the lease file (the kubelet swaps the projected file atomically; a changed text is loaded). */
|
|
33
|
+
export declare const BROKER_LEASE_POLL_MS = 1000;
|
|
34
|
+
/** Every upstream wait is bounded. The connection — TCP, and for https the TLS handshake — must take the request head within this long. */
|
|
35
|
+
export declare const BROKER_UPSTREAM_CONNECT_MS = 10000;
|
|
36
|
+
/** The upstream's response head must arrive within this long after the request was fully sent (a body still uploading is not cut by it:
|
|
37
|
+
* the body has no total bound of its own — an authenticated one is bounded by its lease, `lease-book.ts`). */
|
|
38
|
+
export declare const BROKER_UPSTREAM_HEADERS_MS = 30000;
|
|
39
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const BROKER_PORT = 47311;
|
|
2
|
+
export const BROKER_HOST = "127.0.0.1";
|
|
3
|
+
export const BROKER_CONTAINER_NAME = "sema-broker";
|
|
4
|
+
export const BROKER_VOLUME_NAME = "sema-broker-lease";
|
|
5
|
+
export const BROKER_LEASE_DIR = "/var/run/sema-broker";
|
|
6
|
+
export const BROKER_LEASE_KEY = "broker.json";
|
|
7
|
+
export const BROKER_LEASE_PATH = `${BROKER_LEASE_DIR}/${BROKER_LEASE_KEY}`;
|
|
8
|
+
export const BROKER_ENTRY_PATH = "/app/src/broker/main.ts";
|
|
9
|
+
export const BROKER_COMMAND = ["bun", BROKER_ENTRY_PATH];
|
|
10
|
+
export const BROKER_PROBE_ARG = "--probe";
|
|
11
|
+
export const BROKER_READY_PATH = "/_ready";
|
|
12
|
+
export const BROKER_LEASE_POLL_MS = 1_000;
|
|
13
|
+
export const BROKER_UPSTREAM_CONNECT_MS = 10_000;
|
|
14
|
+
export const BROKER_UPSTREAM_HEADERS_MS = 30_000;
|
|
15
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The broker's own HTTP/1.1 reading — strict, small, and the same under Node and Bun (it runs on plain sockets, not on a runtime's HTTP
|
|
3
|
+
* server, so no runtime's leniency decides what the boundary accepts). One request per downstream connection: the broker answers and
|
|
4
|
+
* closes, so bytes after a request's declared body are never parsed as a second request at all.
|
|
5
|
+
*
|
|
6
|
+
* What is judged here (the rest of the boundary is in `broker.ts`):
|
|
7
|
+
* · the request head: request line (origin-form target, HTTP/1.1), header lines (token names, no obs-fold, no bare CR / LF, no control
|
|
8
|
+
* characters in values) — {@link parseRequestHead};
|
|
9
|
+
* · the request against the route table — target form, path, method + query, Content-Type, framing, Expect, Content-Encoding —
|
|
10
|
+
* {@link judgeRequest};
|
|
11
|
+
* · the response head and its framing (RFC 9112 §6.3) — {@link parseResponseHead}, {@link judgeResponseFraming};
|
|
12
|
+
* · chunked bodies, both directions — {@link readChunked}.
|
|
13
|
+
*/
|
|
14
|
+
import type { Duplex } from "node:stream";
|
|
15
|
+
/** A request / response head larger than this is refused. */
|
|
16
|
+
export declare const MAX_HEAD_BYTES: number;
|
|
17
|
+
/** A wire-level failure: `status` is what the client is told when nothing was answered yet. */
|
|
18
|
+
export declare class WireError extends Error {
|
|
19
|
+
readonly status: number;
|
|
20
|
+
readonly rule: string;
|
|
21
|
+
constructor(status: number, rule: string);
|
|
22
|
+
}
|
|
23
|
+
/** Pull-reader over one socket: buffers what arrives, pauses the socket past a high-water mark, hands out exact amounts. */
|
|
24
|
+
export declare class ByteReader {
|
|
25
|
+
private readonly stream;
|
|
26
|
+
private bufs;
|
|
27
|
+
private len;
|
|
28
|
+
private ended;
|
|
29
|
+
private failure?;
|
|
30
|
+
private wake?;
|
|
31
|
+
constructor(stream: Duplex);
|
|
32
|
+
private notify;
|
|
33
|
+
private wait;
|
|
34
|
+
private take;
|
|
35
|
+
/** Bytes up to and including `delim`; `undefined` = the stream ended first; throws once more than `max` bytes arrive without it. */
|
|
36
|
+
readUntil(delim: string, max: number): Promise<Buffer | undefined>;
|
|
37
|
+
/** Up to `max` bytes as soon as any are there; `undefined` = the stream ended. */
|
|
38
|
+
readSome(max: number): Promise<Buffer | undefined>;
|
|
39
|
+
/** Exactly `n` bytes; throws when the stream ends first. */
|
|
40
|
+
readExact(n: number): Promise<Buffer>;
|
|
41
|
+
}
|
|
42
|
+
export type Headers = ReadonlyArray<readonly [name: string, value: string]>;
|
|
43
|
+
export interface RequestHead {
|
|
44
|
+
readonly method: string;
|
|
45
|
+
readonly target: string;
|
|
46
|
+
/** Header lines in order, names lower-cased, values with surrounding blanks removed. */
|
|
47
|
+
readonly headers: Headers;
|
|
48
|
+
}
|
|
49
|
+
export interface ResponseHead {
|
|
50
|
+
readonly status: number;
|
|
51
|
+
readonly reason: string;
|
|
52
|
+
readonly headers: Headers;
|
|
53
|
+
}
|
|
54
|
+
export declare function parseRequestHead(buf: Buffer): RequestHead;
|
|
55
|
+
export declare function parseResponseHead(buf: Buffer): ResponseHead;
|
|
56
|
+
export declare const valuesOf: (headers: Headers, name: string) => string[];
|
|
57
|
+
/** The three git smart-HTTP endpoints — the only things behind the route. */
|
|
58
|
+
export type GitEndpoint = "info/refs" | "git-upload-pack" | "git-receive-pack";
|
|
59
|
+
export type GitService = "git-upload-pack" | "git-receive-pack";
|
|
60
|
+
export interface Route {
|
|
61
|
+
readonly i: number;
|
|
62
|
+
readonly owner: string;
|
|
63
|
+
readonly repo: string;
|
|
64
|
+
readonly endpoint: GitEndpoint;
|
|
65
|
+
/** info/refs only: the advertised service. */
|
|
66
|
+
readonly service?: GitService;
|
|
67
|
+
}
|
|
68
|
+
/** How a body is framed: none, a declared length, chunked — and, for a response only, delimited by the connection closing. */
|
|
69
|
+
export type Framing = {
|
|
70
|
+
readonly kind: "none";
|
|
71
|
+
} | {
|
|
72
|
+
readonly kind: "length";
|
|
73
|
+
readonly n: number;
|
|
74
|
+
} | {
|
|
75
|
+
readonly kind: "chunked";
|
|
76
|
+
} | {
|
|
77
|
+
readonly kind: "close";
|
|
78
|
+
};
|
|
79
|
+
/** The broker's route, matched on the RAW path (never decoded): `/o/<i>/<owner>/<repo>/<endpoint>`. */
|
|
80
|
+
export declare const ROUTE_PATH: RegExp;
|
|
81
|
+
/** The same namespace on the upstream (a redirect's Location must land in it). */
|
|
82
|
+
export declare const UPSTREAM_PATH: RegExp;
|
|
83
|
+
/** The only two info/refs queries. */
|
|
84
|
+
export declare const INFO_REFS_QUERIES: Readonly<Record<string, GitService>>;
|
|
85
|
+
/** Request headers that cross to the origin as they came (framing is re-stated by the broker; Host / Authorization are the broker's own). */
|
|
86
|
+
export declare const FORWARDED_REQUEST_HEADERS: ReadonlySet<string>;
|
|
87
|
+
/** Response headers that cross back to the agent as they came (framing re-stated; Location only rewritten on a 3xx). */
|
|
88
|
+
export declare const FORWARDED_RESPONSE_HEADERS: ReadonlySet<string>;
|
|
89
|
+
export type RequestVerdict = {
|
|
90
|
+
readonly ok: true;
|
|
91
|
+
readonly route: Route;
|
|
92
|
+
readonly framing: Framing;
|
|
93
|
+
readonly expectContinue: boolean;
|
|
94
|
+
} | {
|
|
95
|
+
readonly ok: false;
|
|
96
|
+
readonly status: 400 | 417;
|
|
97
|
+
readonly rule: string;
|
|
98
|
+
};
|
|
99
|
+
/** Judge one request head against the route (`hasEntry` = the pinned origin table has that index). Pure. */
|
|
100
|
+
export declare function judgeRequest(head: RequestHead, hasEntry: (i: number) => boolean): RequestVerdict;
|
|
101
|
+
/** RFC 9112 §6.3 for an upstream response to a GET / POST. Conflicting or repeated framing headers ⇒ a problem (the response is not forwarded). */
|
|
102
|
+
export declare function judgeResponseFraming(head: ResponseHead): Framing | {
|
|
103
|
+
readonly problem: string;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The data of one chunked body, piece by piece (each ≤ 64 KiB), validated as it goes: chunk-size lines are 1–8 hex digits with no
|
|
107
|
+
* extension; the body ends with a zero chunk and an empty trailer section — any trailer field is a {@link WireError} when
|
|
108
|
+
* `trailers` is `"refuse"` (a request: a Trailer header is refused, so trailer fields are too) and is dropped when `"drop"` (a response).
|
|
109
|
+
*/
|
|
110
|
+
export declare function readChunked(reader: ByteReader, trailers: "refuse" | "drop", failStatus: number): AsyncGenerator<Buffer>;
|
|
111
|
+
//# sourceMappingURL=http1.d.ts.map
|