@melra/http-runtime 0.3.0-alpha.11 → 0.3.0-alpha.13

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/dist/index.d.ts CHANGED
@@ -11,10 +11,11 @@ export interface HttpRuntimeOptions extends NetworkPolicy {
11
11
  * One governed HTTP call.
12
12
  *
13
13
  * The interesting part is which socket opens. `assertSafeDestination` resolves
14
- * the name and checks every answer, then this connects to the address it just
15
- * checked rather than to the name — the same pinning `PinningProxy` does for the
16
- * browser, and for the same reason: a resolver that answers public once and
17
- * private the second time would otherwise make the check meaningless.
14
+ * the name and checks every answer, then this connects through a `lookup` that
15
+ * answers only with those checked addresses, never by resolving the name again
16
+ * — the same pinning `PinningProxy` does for the browser, and for the same
17
+ * reason: a resolver that answers public once and private the second time
18
+ * would otherwise make the check meaningless. TLS still verifies the name.
18
19
  */
19
20
  export declare class HttpRuntime {
20
21
  private readonly options;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,kBAAkB;IAElD,OAAO,CACX,SAAS,EAAE,aAAa,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAuIpC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,kBAAkB;IAElD,OAAO,CACX,SAAS,EAAE,aAAa,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CA4JpC"}
package/dist/index.js CHANGED
@@ -8,10 +8,11 @@ import { assertSafeDestination, classifyOperation, } from "@melra/policy-core";
8
8
  * One governed HTTP call.
9
9
  *
10
10
  * The interesting part is which socket opens. `assertSafeDestination` resolves
11
- * the name and checks every answer, then this connects to the address it just
12
- * checked rather than to the name — the same pinning `PinningProxy` does for the
13
- * browser, and for the same reason: a resolver that answers public once and
14
- * private the second time would otherwise make the check meaningless.
11
+ * the name and checks every answer, then this connects through a `lookup` that
12
+ * answers only with those checked addresses, never by resolving the name again
13
+ * — the same pinning `PinningProxy` does for the browser, and for the same
14
+ * reason: a resolver that answers public once and private the second time
15
+ * would otherwise make the check meaningless. TLS still verifies the name.
15
16
  */
16
17
  export class HttpRuntime {
17
18
  options;
@@ -19,24 +20,28 @@ export class HttpRuntime {
19
20
  this.options = options;
20
21
  }
21
22
  async execute(operation, signal) {
22
- const { url, address } = await assertSafeDestination(operation.url, this.options);
23
+ const { url, host, lookup } = await assertSafeDestination(operation.url, this.options);
23
24
  // Checked here and not only in the router: the destination check above is
24
25
  // an await, and a cancel that lands inside that window would otherwise be
25
26
  // lost and the request would go out anyway.
26
- if (signal?.aborted === true)
27
+ const cancelled = () => signal?.aborted === true;
28
+ if (cancelled())
27
29
  throw new Error("task_cancelled");
28
30
  const secure = url.protocol === "https:";
29
31
  const send = secure ? httpsRequest : httpRequest;
30
- // Brokered against the destination that was *checked*, not the one the
31
- // caller wrote: pinning already collapsed the name to an address, and a
32
- // credential scoped by host has to be scoped by the same host the socket
33
- // will actually talk to.
32
+ // Brokered against the host that was *checked*: the name, or an IPv6
33
+ // literal without the brackets `URL.hostname` keeps, so `[::1]` and a
34
+ // credential scoped to `::1` are the same host.
34
35
  const { capability, target } = classifyOperation(operation);
35
36
  const brokered = await this.options.credentials?.headersFor({
36
- host: url.hostname,
37
+ host,
37
38
  capability,
38
39
  target,
39
40
  });
41
+ // Again: reading a credential from a file is an await too, and the abort
42
+ // listener below only hears an abort that comes after it is added.
43
+ if (cancelled())
44
+ throw new Error("task_cancelled");
40
45
  const headers = {
41
46
  // Lowercased before the merge, or `Authorization: guess` from the caller
42
47
  // and `authorization: <secret>` from the broker are two distinct keys and
@@ -48,8 +53,7 @@ export class HttpRuntime {
48
53
  // Last, so a caller cannot name the same header and have its own value
49
54
  // ride out under a credential's name.
50
55
  ...brokered?.headers,
51
- // `Host` carries the name so a name-based virtual host still resolves at
52
- // the far end even though the socket was opened to a literal address.
56
+ // The URL's authority exactly as the caller wrote it.
53
57
  host: url.host,
54
58
  ...(operation.idempotencyKey === undefined
55
59
  ? {}
@@ -58,17 +62,22 @@ export class HttpRuntime {
58
62
  if (operation.content !== undefined) {
59
63
  headers["content-length"] = String(Buffer.byteLength(operation.content));
60
64
  }
65
+ let deadline;
61
66
  return await new Promise((resolve, reject) => {
62
67
  const call = send({
63
- host: address,
68
+ host,
69
+ lookup,
64
70
  port: url.port === "" ? (secure ? 443 : 80) : Number(url.port),
65
71
  method: operation.method,
66
72
  path: `${url.pathname}${url.search}`,
67
73
  headers,
68
- // TLS is validated against the name the caller asked for, not the
69
- // address the socket went to, or pinning would break every https URL.
70
- ...(secure ? { servername: url.hostname } : {}),
71
- timeout: operation.timeoutMs,
74
+ // A fresh connection per effect, never one from Node's keep-alive
75
+ // pool. A pooled socket the server has already closed takes the whole
76
+ // request and then resets, and below that reads as "the far end may
77
+ // have acted" — a request that never reached anyone parked for
78
+ // reconciliation. On a connection of its own, a reset after the write
79
+ // really is an unknown outcome.
80
+ agent: false,
72
81
  }, (response) => {
73
82
  const chunks = [];
74
83
  let bytes = 0;
@@ -85,6 +94,14 @@ export class HttpRuntime {
85
94
  chunks.push(chunk);
86
95
  });
87
96
  const finish = () => {
97
+ // The headers arrived, so the request did too: a body cut off
98
+ // before its end is an answer that stopped, not a call that never
99
+ // happened, and only `outcomeUnknown` says so. Stopping at the
100
+ // size cap is the one deliberate exception.
101
+ if (!response.complete && !truncated) {
102
+ reject(outcomeUnknown("http_response_incomplete"));
103
+ return;
104
+ }
88
105
  const status = response.statusCode ?? 0;
89
106
  resolve({
90
107
  // The far end's own word, which is all HTTP can offer. A caller
@@ -119,7 +136,7 @@ export class HttpRuntime {
119
136
  };
120
137
  response.on("end", finish);
121
138
  response.on("close", finish);
122
- response.on("error", reject);
139
+ response.on("error", (error) => reject(outcomeUnknown(error.message)));
123
140
  });
124
141
  // Whether the request made it out. A socket error before this is a
125
142
  // request that never happened; after it, the far end may have done the
@@ -127,19 +144,25 @@ export class HttpRuntime {
127
144
  // `bytesWritten` is not the signal — it counts headers buffered on a
128
145
  // socket that never connected, so ECONNREFUSED reports a nonzero count.
129
146
  const failed = (error) => {
147
+ // When every pinned address refuses, Node reports one AggregateError
148
+ // with an empty message; the per-address errors say what happened.
149
+ if (error instanceof AggregateError && error.message === "") {
150
+ error = new Error(error.errors.map((inner) => inner.message).join("; "));
151
+ }
130
152
  reject(call.writableFinished ? outcomeUnknown(error.message) : error);
131
153
  };
132
- // A timeout fires the event but does not end the request; without this an
133
- // unresponsive host holds the socket for the life of the process.
134
- call.on("timeout", () => {
135
- call.destroy(new Error("http_timeout"));
136
- });
154
+ // One deadline for the whole exchange. Node's own `timeout` only notices
155
+ // a socket that goes quiet, so a server sending a byte at a time held the
156
+ // call, and any verification or reconciliation waiting on it, for as
157
+ // long as it liked.
158
+ deadline = setTimeout(() => call.destroy(new Error("http_timeout")), operation.timeoutMs);
159
+ deadline.unref();
137
160
  call.on("error", failed);
138
161
  signal?.addEventListener("abort", () => call.destroy(new Error("task_cancelled")), { once: true });
139
162
  if (operation.content !== undefined)
140
163
  call.write(operation.content);
141
164
  call.end();
142
- });
165
+ }).finally(() => clearTimeout(deadline));
143
166
  }
144
167
  }
145
168
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melra/http-runtime",
3
- "version": "0.3.0-alpha.11",
3
+ "version": "0.3.0-alpha.13",
4
4
  "description": "HTTP/API reference effect adapter for the MELRA kernel.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -21,13 +21,13 @@
21
21
  "dist"
22
22
  ],
23
23
  "dependencies": {
24
- "@melra/policy-core": "0.3.0-alpha.11",
25
- "@melra/protocol": "0.3.0-alpha.11"
24
+ "@melra/policy-core": "0.3.0-alpha.13",
25
+ "@melra/protocol": "0.3.0-alpha.13"
26
26
  },
27
27
  "scripts": {
28
28
  "build": "tsc -p tsconfig.json",
29
29
  "clean": "rm -rf dist",
30
30
  "test": "vitest run",
31
- "typecheck": "tsc -p tsconfig.json --noEmit"
31
+ "typecheck": "tsc -p tsconfig.test.json"
32
32
  }
33
33
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
@@ -1,119 +0,0 @@
1
- // Copyright 2026 XAGI Labs Private Limited
2
- // SPDX-License-Identifier: Apache-2.0
3
- import { createServer } from "node:http";
4
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
5
- import { HttpOperationSchema } from "@melra/protocol";
6
- import { HttpRuntime } from "./index.js";
7
- let server;
8
- let origin;
9
- /** Last request the fixture saw, so header and body handling is assertable. */
10
- let seen;
11
- beforeAll(async () => {
12
- server = createServer((req, res) => {
13
- const chunks = [];
14
- req.on("data", (chunk) => chunks.push(chunk));
15
- req.on("end", () => {
16
- seen = {
17
- method: req.method ?? "",
18
- url: req.url ?? "",
19
- headers: req.headers,
20
- body: Buffer.concat(chunks).toString("utf8"),
21
- };
22
- if (req.url === "/teapot") {
23
- res.writeHead(418).end("no coffee");
24
- return;
25
- }
26
- if (req.url === "/big") {
27
- res.writeHead(200).end("x".repeat(50_000));
28
- return;
29
- }
30
- // Accepts the request and never answers, which is the case MELRA must not
31
- // report as "the effect did not happen".
32
- if (req.url === "/silent")
33
- return;
34
- res.writeHead(201, { "content-type": "application/json" });
35
- res.end(JSON.stringify({ created: true }));
36
- });
37
- });
38
- await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
39
- origin = `http://127.0.0.1:${server.address().port}`;
40
- });
41
- afterAll(async () => {
42
- await new Promise((resolve) => server.close(() => resolve()));
43
- });
44
- const runtime = () => new HttpRuntime({ allowedDomains: ["*"], allowLocalhost: true });
45
- const operation = (fields) => HttpOperationSchema.parse({ kind: "http", action: "request", ...fields });
46
- describe("http runtime", () => {
47
- it("posts a body and reports the response status", async () => {
48
- const result = await runtime().execute(operation({
49
- method: "POST",
50
- url: `${origin}/orders`,
51
- content: JSON.stringify({ item: "widget" }),
52
- headers: { "content-type": "application/json" },
53
- idempotencyKey: "order-42",
54
- }));
55
- expect(seen.method).toBe("POST");
56
- expect(seen.body).toBe('{"item":"widget"}');
57
- expect(seen.headers["idempotency-key"]).toBe("order-42");
58
- expect(result.status).toBe(201);
59
- expect(result.success).toBe(true);
60
- expect(result.content).toBe('{"created":true}');
61
- });
62
- it("reports a failing status as an unsuccessful effect", async () => {
63
- const result = await runtime().execute(operation({ url: `${origin}/teapot` }));
64
- expect(result.status).toBe(418);
65
- // The adapter never asserts its own success: a 418 is a completed call and
66
- // a failed effect, and verification is what turns that into `partial`.
67
- expect(result.success).toBe(false);
68
- });
69
- it("stops reading a body past the cap instead of buffering it", async () => {
70
- const result = await runtime().execute(operation({ url: `${origin}/big`, maxResponseBytes: 1_000 }));
71
- expect(result.truncated).toBe(true);
72
- expect(String(result.content).length).toBeLessThan(50_000);
73
- });
74
- it("refuses a private destination before any socket opens", async () => {
75
- const guarded = new HttpRuntime({
76
- allowedDomains: ["*"],
77
- allowLocalhost: false,
78
- });
79
- await expect(guarded.execute(operation({ url: "http://169.254.169.254/latest/meta-data/" }))).rejects.toThrow("destination_private_blocked");
80
- });
81
- it("refuses a host outside the allowlist", async () => {
82
- const guarded = new HttpRuntime({
83
- allowedDomains: ["example.com"],
84
- allowLocalhost: false,
85
- });
86
- await expect(guarded.execute(operation({ url: "http://attacker.test/" }))).rejects.toThrow("destination_domain_not_allowed");
87
- });
88
- it("rejects an unknown field", () => {
89
- expect(() => operation({ url: `${origin}/`, followRedirects: true })).toThrow();
90
- });
91
- it("cancels in flight when the task signal aborts", async () => {
92
- const controller = new AbortController();
93
- const pending = runtime().execute(operation({ url: `${origin}/orders` }), controller.signal);
94
- controller.abort();
95
- await expect(pending).rejects.toThrow("task_cancelled");
96
- });
97
- it("marks the outcome unknown when a sent request goes unanswered", async () => {
98
- // The far end has the request and may already have acted on it. Claiming
99
- // failure here would be the kernel asserting something it cannot know.
100
- await expect(runtime().execute(operation({
101
- method: "POST",
102
- url: `${origin}/silent`,
103
- content: "charge",
104
- timeoutMs: 300,
105
- }))).rejects.toThrow("effect_outcome_unknown:http_timeout");
106
- });
107
- it("reports a plain failure when the request never left the machine", async () => {
108
- const closed = createServer();
109
- await new Promise((resolve) => closed.listen(0, "127.0.0.1", resolve));
110
- const port = closed.address().port;
111
- await new Promise((resolve) => closed.close(() => resolve()));
112
- const attempt = runtime().execute(operation({ method: "POST", url: `http://127.0.0.1:${port}/charges` }));
113
- // Nothing reached a server, so this one really did not happen — and must
114
- // not be parked for reconciliation.
115
- await expect(attempt).rejects.toThrow(/ECONNREFUSED/);
116
- await expect(attempt).rejects.not.toThrow(/effect_outcome_unknown/);
117
- });
118
- });
119
- //# sourceMappingURL=index.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}