@request-seal/core 0.1.0 → 0.3.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.
Files changed (128) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +342 -114
  3. package/dist/accept-signature.d.ts +11 -0
  4. package/dist/accept-signature.js +7 -0
  5. package/dist/adapters/fetch/index.d.ts +10 -0
  6. package/dist/adapters/fetch/index.js +21 -4
  7. package/dist/adapters/fetch/runtime.d.ts +1 -0
  8. package/dist/adapters/fetch/runtime.js +1 -0
  9. package/dist/adapters/node-http/index.d.ts +23 -0
  10. package/dist/adapters/node-http/index.js +28 -8
  11. package/dist/brand.d.ts +5 -0
  12. package/dist/brand.js +12 -0
  13. package/dist/bytes.d.ts +4 -0
  14. package/dist/bytes.js +5 -0
  15. package/dist/constants.d.ts +64 -4
  16. package/dist/constants.js +62 -2
  17. package/dist/context.d.ts +4 -0
  18. package/dist/context.js +3 -0
  19. package/dist/crypto/algorithm.d.ts +9 -0
  20. package/dist/crypto/algorithm.js +12 -0
  21. package/dist/crypto/index.d.ts +12 -2
  22. package/dist/crypto/index.js +34 -11
  23. package/dist/crypto/options.d.ts +3 -0
  24. package/dist/crypto/options.js +15 -0
  25. package/dist/crypto/primitive.d.ts +7 -3
  26. package/dist/crypto/primitive.js +36 -10
  27. package/dist/custody/content_key.d.ts +4 -0
  28. package/dist/custody/content_key.js +4 -2
  29. package/dist/custody/index.d.ts +2 -0
  30. package/dist/custody/index.js +5 -1
  31. package/dist/custody/local.d.ts +17 -1
  32. package/dist/custody/local.js +10 -5
  33. package/dist/custody/ssh-agent/index.d.ts +2 -0
  34. package/dist/custody/ssh-agent/index.js +11 -181
  35. package/dist/custody/ssh-agent/port.d.ts +19 -0
  36. package/dist/custody/ssh-agent/port.js +183 -0
  37. package/dist/digest.d.ts +22 -0
  38. package/dist/digest.js +15 -0
  39. package/dist/discovery/body.d.ts +19 -2
  40. package/dist/discovery/body.js +36 -11
  41. package/dist/discovery/cache.d.ts +21 -2
  42. package/dist/discovery/cache.js +105 -39
  43. package/dist/discovery/headers.d.ts +3 -0
  44. package/dist/discovery/headers.js +27 -1
  45. package/dist/discovery/index.d.ts +13 -1
  46. package/dist/discovery/index.js +31 -7
  47. package/dist/discovery/node-connection.d.ts +1 -1
  48. package/dist/discovery/node-connection.js +2 -2
  49. package/dist/discovery/node-trust.d.ts +2 -0
  50. package/dist/discovery/node-trust.js +9 -0
  51. package/dist/discovery/node.d.ts +9 -1
  52. package/dist/discovery/node.js +150 -26
  53. package/dist/discovery/proof.js +2 -2
  54. package/dist/discovery/snapshot.js +3 -0
  55. package/dist/discovery/source.d.ts +7 -0
  56. package/dist/discovery/source.js +5 -0
  57. package/dist/discovery/support.js +2 -3
  58. package/dist/errors/parity.d.ts +44 -3
  59. package/dist/errors/parity.js +45 -4
  60. package/dist/errors/types.d.ts +17 -3
  61. package/dist/errors/types.js +16 -2
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.js +1 -0
  64. package/dist/jose/header.d.ts +1 -0
  65. package/dist/jose/jwe.d.ts +9 -0
  66. package/dist/jose/jwe.js +17 -3
  67. package/dist/jose/jws.d.ts +11 -0
  68. package/dist/jose/jws.js +14 -2
  69. package/dist/jose/key-management.d.ts +11 -0
  70. package/dist/jose/key-management.js +13 -2
  71. package/dist/jose/nested.d.ts +6 -0
  72. package/dist/jose/nested.js +32 -2
  73. package/dist/json.d.ts +7 -0
  74. package/dist/key_handle.d.ts +12 -3
  75. package/dist/key_handle.js +32 -25
  76. package/dist/key_identity.d.ts +7 -0
  77. package/dist/key_identity.js +10 -2
  78. package/dist/message/index.d.ts +24 -0
  79. package/dist/message/index.js +22 -1
  80. package/dist/numbers.d.ts +6 -0
  81. package/dist/numbers.js +5 -0
  82. package/dist/policy.d.ts +27 -0
  83. package/dist/policy.js +42 -21
  84. package/dist/profile.d.ts +36 -0
  85. package/dist/profile.js +215 -0
  86. package/dist/public_key.d.ts +11 -2
  87. package/dist/public_key.js +31 -8
  88. package/dist/quorum/evaluation.d.ts +1 -1
  89. package/dist/quorum/evaluation.js +18 -4
  90. package/dist/quorum/verification.d.ts +2 -0
  91. package/dist/quorum/verification.js +1 -0
  92. package/dist/quorum.d.ts +9 -0
  93. package/dist/quorum.js +7 -1
  94. package/dist/replay/claim.d.ts +5 -0
  95. package/dist/replay/claim.js +9 -1
  96. package/dist/replay/index.d.ts +6 -0
  97. package/dist/replay/index.js +13 -1
  98. package/dist/replay/postgres.d.ts +3 -0
  99. package/dist/replay/postgres.js +7 -0
  100. package/dist/replay/receipt.d.ts +1 -0
  101. package/dist/replay/receipt.js +1 -0
  102. package/dist/replay/store.d.ts +1 -0
  103. package/dist/replay/store.js +1 -0
  104. package/dist/replay-port.d.ts +6 -1
  105. package/dist/result.d.ts +3 -0
  106. package/dist/result.js +2 -0
  107. package/dist/sign.d.ts +26 -0
  108. package/dist/sign.js +25 -3
  109. package/dist/signature-base/index.d.ts +2 -0
  110. package/dist/signature-base/index.js +5 -1
  111. package/dist/signature-fields.d.ts +5 -1
  112. package/dist/signature-fields.js +9 -1
  113. package/dist/structured-fields/index.d.ts +21 -0
  114. package/dist/structured-fields/index.js +14 -1
  115. package/dist/verification.d.ts +5 -1
  116. package/dist/verification.js +9 -6
  117. package/dist/verify-quorum.d.ts +1 -0
  118. package/dist/verify-quorum.js +30 -8
  119. package/dist/verify.d.ts +23 -0
  120. package/dist/verify.js +46 -14
  121. package/dist/web-bot-auth/index.d.ts +3 -0
  122. package/dist/web-bot-auth/index.js +3 -0
  123. package/dist/web-bot-auth/policy.d.ts +8 -0
  124. package/dist/web-bot-auth/policy.js +8 -4
  125. package/dist/web-bot-auth/verification.d.ts +8 -0
  126. package/dist/web-bot-auth/verification.js +4 -2
  127. package/dist/web-bot-auth/verify.js +2 -2
  128. package/package.json +29 -6
@@ -1,26 +1,37 @@
1
1
  import { type InnerList } from "./structured-fields/index.ts";
2
2
  import { type Message as HttpMessage } from "./message/index.ts";
3
3
  import { type Result } from "./result.ts";
4
+ /** A requested signature label, component list, and negotiation parameters. */
4
5
  export type SignatureRequest = Readonly<{
5
6
  label: string;
6
7
  components: InnerList;
7
8
  parameters: Readonly<Record<string, string | true>>;
8
9
  }>;
10
+ /** A branded ordered collection of signature negotiation requests. */
9
11
  export type AcceptSignature = readonly SignatureRequest[];
12
+ /** Check the private brand of parsed signature negotiation requests. */
10
13
  export declare function isAcceptSignature(v: unknown): v is AcceptSignature;
11
14
  export declare function applicable(requests: AcceptSignature, target: "request" | "response"): Result<AcceptSignature>;
15
+ /** Parse and validate Accept-Signature fields into negotiation requests. */
12
16
  export declare function parseAcceptSignature(wire: unknown, options: unknown): Result<AcceptSignature>;
17
+ /** Serialize branded negotiation requests as an Accept-Signature dictionary. */
13
18
  export declare function serializeAcceptSignature(requests: unknown): Result<Uint8Array>;
19
+ /** A chooser's selected algorithm and optional creation and expiration times. */
14
20
  export type SignatureChoice = Readonly<{
15
21
  algorithm: string;
16
22
  created: number | null;
17
23
  expires: number | null;
18
24
  }>;
25
+ /** Select signing parameters for a signature negotiation request. */
19
26
  export type SignatureChooser = (request: SignatureRequest) => Result<SignatureChoice> | Promise<Result<SignatureChoice>>;
20
27
  /** Fulfill atomically through caller-owned selection and the single-signature API. */
21
28
  export declare function fulfillAcceptSignature(message: unknown, requests: unknown, chooser: unknown, signer: unknown, options?: unknown): Promise<Result<HttpMessage>>;
29
+ /** Signature negotiation parsing, serialization, and fulfillment. */
22
30
  export declare const AcceptSignature: Readonly<{
31
+ /** Parse and validate the supported wire representation. */
23
32
  parse: typeof parseAcceptSignature;
33
+ /** Serialize validated values to their canonical wire representation. */
24
34
  serialize: typeof serializeAcceptSignature;
35
+ /** Select and add applicable requested signatures with caller-owned signing custody. */
25
36
  fulfill: typeof fulfillAcceptSignature;
26
37
  }>;
@@ -24,6 +24,7 @@ const requestDerived = [
24
24
  "@query",
25
25
  "@query-param",
26
26
  ];
27
+ /** Check the private brand of parsed signature negotiation requests. */
27
28
  export function isAcceptSignature(v) {
28
29
  return typeof v === "object" && v !== null && requestsBrand.has(v);
29
30
  }
@@ -43,6 +44,7 @@ export function applicable(requests, target) {
43
44
  return err(bounded(e, "invalid_accept_signature", "negotiation"));
44
45
  }
45
46
  }
47
+ /** Parse and validate Accept-Signature fields into negotiation requests. */
46
48
  export function parseAcceptSignature(wire, options) {
47
49
  try {
48
50
  const a = snapshotOptions(options, ["target"]);
@@ -117,6 +119,7 @@ export function parseAcceptSignature(wire, options) {
117
119
  return err(bounded(e, "invalid_accept_signature", "negotiation"));
118
120
  }
119
121
  }
122
+ /** Serialize branded negotiation requests as an Accept-Signature dictionary. */
120
123
  export function serializeAcceptSignature(requests) {
121
124
  try {
122
125
  ensure(isAcceptSignature(requests), "invalid_accept_signature", "negotiation");
@@ -218,8 +221,12 @@ export async function fulfillAcceptSignature(message, requests, chooser, signer,
218
221
  return err(bounded(e, "negotiation_unfulfillable", "negotiation"));
219
222
  }
220
223
  }
224
+ /** Signature negotiation parsing, serialization, and fulfillment. */
221
225
  export const AcceptSignature = Object.freeze({
226
+ /** Parse and validate the supported wire representation. */
222
227
  parse: parseAcceptSignature,
228
+ /** Serialize validated values to their canonical wire representation. */
223
229
  serialize: serializeAcceptSignature,
230
+ /** Select and add applicable requested signatures with caller-owned signing custody. */
224
231
  fulfill: fulfillAcceptSignature,
225
232
  });
@@ -2,32 +2,42 @@ import { type Message as HttpMessage } from "../../message/index.ts";
2
2
  import type { Verification } from "../../verification.ts";
3
3
  import { type Result } from "../../result.ts";
4
4
  export { FETCH_VERIFICATION_RUNTIMES } from "./runtime.ts";
5
+ /** A Fetch request and its signed lossless message. */
5
6
  export type SignedRequest = Readonly<{
6
7
  request: Request;
7
8
  message: HttpMessage;
8
9
  }>;
10
+ /** A Fetch response and its signed lossless message. */
9
11
  export type SignedResponse = Readonly<{
10
12
  response: Response;
11
13
  message: HttpMessage;
12
14
  }>;
15
+ /** Captured Fetch request bytes accompanied by verification facts. */
13
16
  export type VerifiedRequest = Readonly<{
14
17
  request: Request;
15
18
  message: HttpMessage;
16
19
  verification: Verification;
17
20
  bytes: Uint8Array;
18
21
  }>;
22
+ /** Captured Fetch response bytes accompanied by verification facts. */
19
23
  export type VerifiedResponse = Readonly<{
20
24
  response: Response;
21
25
  message: HttpMessage;
22
26
  verification: Verification;
23
27
  bytes: Uint8Array;
24
28
  }>;
29
+ /** A signed Fetch request, its response, and optional response verification. */
25
30
  export type SignedExchange = Readonly<{
26
31
  response: Response;
27
32
  request: SignedRequest;
28
33
  }>;
34
+ /** Construct a signed Fetch request from an owned body snapshot. */
29
35
  export declare function signRequest(request: unknown, input: unknown, signer: unknown, options?: unknown): Promise<Result<SignedRequest>>;
36
+ /** Construct a signed Fetch response from an owned body snapshot. */
30
37
  export declare function signResponse(response: unknown, input: unknown, signer: unknown, options?: unknown): Promise<Result<SignedResponse>>;
38
+ /** Verify a Fetch request on an explicitly supported wire runtime. */
31
39
  export declare function verifyRequest(request: unknown, policy: unknown, options: unknown): Promise<Result<VerifiedRequest>>;
40
+ /** Verify a Fetch response on an explicitly supported wire runtime. */
32
41
  export declare function verifyResponse(response: unknown, policy: unknown, options: unknown): Promise<Result<VerifiedResponse>>;
42
+ /** Send a signed Fetch request with explicit redirect and response policies. */
33
43
  export declare function signedFetch(input: unknown, init: unknown, signing: unknown, options?: unknown): Promise<Result<SignedExchange>>;
@@ -32,10 +32,14 @@ function headers(message) {
32
32
  h.append(f.name, S.latin(f.value));
33
33
  return h;
34
34
  }
35
+ // Captured once: a runtime without this accessor cannot carry Request streams.
36
+ const requestBodyAccessor = typeof Request === "function"
37
+ ? Object.getOwnPropertyDescriptor(Request.prototype, "body")
38
+ : undefined;
35
39
  function requestBodySupported(request, stage) {
36
40
  // Native ingress can omit GET/HEAD bodies while retaining their declared length.
37
41
  S.need(!["GET", "HEAD"].includes(request.method.toUpperCase()) ||
38
- (request.body === null &&
42
+ (request.body == null &&
39
43
  !(Number(request.headers.get("content-length")) > 0)), "fetch", stage, "invalid_request");
40
44
  }
41
45
  async function bytes(value, max, c, stage) {
@@ -44,6 +48,14 @@ async function bytes(value, max, c, stage) {
44
48
  S.need(!value.bodyUsed, "fetch", stage, "body_unavailable");
45
49
  if (value.body === null)
46
50
  return ok(new Uint8Array());
51
+ if (value instanceof Request && requestBodyAccessor === undefined) {
52
+ // Runtimes without the body accessor cannot accept Request streams.
53
+ // The input is already materialized; this read allocates a complete copy
54
+ // before maxBytes can bound the bytes accepted for signing.
55
+ const data = new Uint8Array(await value.clone().arrayBuffer());
56
+ S.need(data.length <= max, "fetch", stage, "limit");
57
+ return ok(data);
58
+ }
47
59
  const reader = value.body.getReader();
48
60
  const cancel = () => {
49
61
  void reader.cancel().catch(() => { });
@@ -136,6 +148,7 @@ function verifySupported(message, policy, label) {
136
148
  }
137
149
  }
138
150
  }
151
+ /** Construct a signed Fetch request from an owned body snapshot. */
139
152
  export async function signRequest(request, input, signer, options = {}) {
140
153
  return signRequestOperation(request, input, signer, options);
141
154
  }
@@ -173,6 +186,7 @@ async function signRequestOperation(request, input, signer, options, exchangeCon
173
186
  return S.caught(e, "fetch", "sign", "signing_failed");
174
187
  }
175
188
  }
189
+ /** Construct a signed Fetch response from an owned body snapshot. */
176
190
  export async function signResponse(response, input, signer, options = {}) {
177
191
  try {
178
192
  const a = S.take(options, ["context", "maxBytes", "request", "clock", "nonce", "signingTimeout"], "fetch", "sign");
@@ -206,6 +220,7 @@ function related(value, stage = "verify") {
206
220
  }
207
221
  throw S.failure("fetch", stage, "invalid_options");
208
222
  }
223
+ /** Verify a Fetch request on an explicitly supported wire runtime. */
209
224
  export async function verifyRequest(request, policy, options) {
210
225
  // This guard precedes all option access, stream reads, clocks, and resolvers.
211
226
  if (!canVerify)
@@ -246,6 +261,7 @@ export async function verifyRequest(request, policy, options) {
246
261
  return S.caught(e, "fetch", "verify", "request_rejected");
247
262
  }
248
263
  }
264
+ /** Verify a Fetch response on an explicitly supported wire runtime. */
249
265
  export async function verifyResponse(response, policy, options) {
250
266
  if (!canVerify)
251
267
  return err(S.failure("fetch", "verify", "invalid_request"));
@@ -277,6 +293,7 @@ export async function verifyResponse(response, policy, options) {
277
293
  return S.caught(e, "fetch", "verify", "response_rejected");
278
294
  }
279
295
  }
296
+ /** Send a signed Fetch request with explicit redirect and response policies. */
280
297
  export async function signedFetch(input, init, signing, options = {}) {
281
298
  let attempt = 0;
282
299
  try {
@@ -312,6 +329,9 @@ export async function signedFetch(input, init, signing, options = {}) {
312
329
  S.need(typeof input === "string" ||
313
330
  input instanceof URL ||
314
331
  input instanceof Request, "fetch", "attach", "invalid_request");
332
+ if (a.verify !== undefined) {
333
+ S.need(canVerify, "fetch", "verify", "invalid_request");
334
+ }
315
335
  // Constructing from another Request resets referrerPolicy unless explicit.
316
336
  const initialOptions = input instanceof Request &&
317
337
  !Object.hasOwn(i, "referrerPolicy")
@@ -340,9 +360,6 @@ export async function signedFetch(input, init, signing, options = {}) {
340
360
  let data = S.unwrap(await bytes(current, S.maximum(a, "fetch", "attach"), c, "sign"), "fetch", "attach", "body_unavailable");
341
361
  const maxRedirects = S.limitNumber(a.maxRedirects ?? 0, 10, "fetch"), maxRetries = S.limitNumber(a.maxRetries ?? 0, 10, "fetch");
342
362
  let redirects = 0, retries = 0;
343
- if (a.verify !== undefined) {
344
- S.need(canVerify, "fetch", "verify", "invalid_request");
345
- }
346
363
  for (;;) {
347
364
  attempt++;
348
365
  const h = new Headers(current.headers);
@@ -1,3 +1,4 @@
1
+ /** Exact Deno releases permitted for Fetch wire verification. */
1
2
  export declare const FETCH_VERIFICATION_RUNTIMES: readonly ["deno:2.5.6"];
2
3
  export declare const runtime: string;
3
4
  export declare const canVerify: boolean;
@@ -1,5 +1,6 @@
1
1
  import { RUNTIME_MANAGED_FIELDS } from "../support.js";
2
2
  // Evidence: test/fixtures/adapters-fetch-wire.json and adapters-fetch-wire.test.ts.
3
+ /** Exact Deno releases permitted for Fetch wire verification. */
3
4
  export const FETCH_VERIFICATION_RUNTIMES = Object.freeze([
4
5
  "deno:2.5.6",
5
6
  ]);
@@ -6,6 +6,7 @@ export type { WebBotAuthVerification } from "../../web-bot-auth/verification.ts"
6
6
  import type { Verification } from "../../verification.ts";
7
7
  import { type Context } from "../../context.ts";
8
8
  import { type Result } from "../../result.ts";
9
+ /** Lossless incoming Node HTTP method, target, field, and transport facts. */
9
10
  export type Ingress = Readonly<{
10
11
  evidence: "observed";
11
12
  httpVersion: string;
@@ -19,6 +20,7 @@ export type Ingress = Readonly<{
19
20
  scheme: string;
20
21
  declaredScheme: string | null;
21
22
  }>;
23
+ /** Branded Node request capture with owned body bytes and replay access. */
22
24
  export type Capture = Readonly<{
23
25
  message: HttpMessage;
24
26
  ingress: Ingress;
@@ -27,44 +29,65 @@ export type Capture = Readonly<{
27
29
  authority: string;
28
30
  source: "connection" | "forwarded";
29
31
  }>;
32
+ /** Open a fresh readable stream over the retained request body. */
30
33
  replay: () => Result<Readable>;
31
34
  }>;
35
+ /** Captured request bytes accompanied by a single-signature verification. */
32
36
  export type VerifiedRequest = Readonly<{
33
37
  capture: Capture;
34
38
  verification: Verification;
35
39
  bytes: Uint8Array;
36
40
  }>;
41
+ /** Captured request bytes accompanied by a quorum verification. */
37
42
  export type VerifiedQuorumRequest = Readonly<{
38
43
  capture: Capture;
39
44
  verification: QuorumVerification;
40
45
  bytes: Uint8Array;
41
46
  }>;
47
+ /** Captured request bytes accompanied by a Web Bot Auth verification. */
42
48
  export type VerifiedWebBotAuthRequest = Readonly<{
43
49
  capture: Capture;
44
50
  verification: WebBotAuthVerification;
45
51
  bytes: Uint8Array;
46
52
  }>;
53
+ /** A signed Node client response with owned bytes and optional verification. */
47
54
  export type ClientResponse = Readonly<{
48
55
  request: HttpMessage;
49
56
  message: HttpMessage;
50
57
  status: number;
51
58
  bytes: Uint8Array;
52
59
  }>;
60
+ /** Capture and retain a Node incoming request before body parsing. */
53
61
  export declare function captureRequest(req: unknown, options?: unknown): Promise<Result<Capture>>;
62
+ /**
63
+ * Install early Node request capture on a server with explicit limits.
64
+ *
65
+ * Options are `maxBytes`, `timeoutMs` (1 to 300,000 ms, default 5,000), and
66
+ * `trustedProxies`. Each request is captured under its own fresh `timeoutMs` deadline.
67
+ * A `context` is refused with `invalid_options`: one Context is one absolute deadline,
68
+ * and the registration outlives it.
69
+ */
54
70
  export declare function capture(server: unknown, options?: unknown): Result<Readonly<{
71
+ /** Close this capability and release its retained state. */
55
72
  close: () => Result<true>;
56
73
  }>>;
74
+ /** Return a defensive copy of captured Node request body bytes. */
57
75
  export declare function captureBody(req: unknown, bytes: unknown, options?: unknown): Result<Capture>;
76
+ /** Verify a captured Node request once and retain its verification result. */
58
77
  export declare function verifyRequest(req: unknown, policy: unknown, options: unknown): Promise<Result<VerifiedRequest>>;
59
78
  /** Composite verification over the same captured facts. */
60
79
  export declare function verifyQuorum(req: unknown, quorum: unknown, options?: unknown): Promise<Result<VerifiedQuorumRequest>>;
61
80
  /** Web Bot Auth verification over the same captured facts and shared attempt. */
62
81
  export declare function verifyWebBotAuth(req: unknown, policy: unknown, options?: unknown): Promise<Result<VerifiedWebBotAuthRequest>>;
82
+ /** Read the verification result associated with a captured Node request. */
63
83
  export declare function verification(req: unknown): Result<Verification | QuorumVerification | WebBotAuthVerification>;
84
+ /** Sign and write a Node HTTP response using retained body bytes. */
64
85
  export declare function signResponse(res: unknown, input: unknown, signer: unknown, options?: unknown): Promise<Result<HttpMessage>>;
86
+ /** Verify a retained Node client response against its related request. */
65
87
  export declare function verifyResponse(response: unknown, request: unknown, policy: unknown, options: unknown): Promise<Result<Readonly<{
66
88
  message: HttpMessage;
67
89
  verification: Verification;
68
90
  bytes: Uint8Array;
69
91
  }>>>;
92
+ /** Send a signed Node HTTP request with explicit redirect and response policies. */
70
93
  export declare function signedRequest(options: unknown, input: unknown, signer: unknown, ctx?: Context): Promise<Result<ClientResponse>>;
@@ -12,7 +12,8 @@ import { verifyWebBotAuth as coreVerifyWebBotAuth } from "../../web-bot-auth/ver
12
12
  import { parseAddress } from "../../discovery/address.js";
13
13
  import { isPolicy } from "../../policy.js";
14
14
  import { isAcceptSignature } from "../../accept-signature.js";
15
- import { run } from "../../context.js";
15
+ import { run, withDeadline } from "../../context.js";
16
+ import { timeoutMs as validTimeout } from "../../numbers.js";
16
17
  import { err, ok } from "../../result.js";
17
18
  import { MESSAGE_MAX_FIELD_BYTES, MESSAGE_MAX_FIELDS_BYTES, MESSAGE_MAX_OCCURRENCES, } from "../../constants.js";
18
19
  import * as S from "../support.js";
@@ -20,7 +21,6 @@ import { deepFreeze } from "../../brand.js";
20
21
  const captures = new WeakMap();
21
22
  const states = new WeakMap();
22
23
  const branded = new WeakSet();
23
- const verified = new WeakSet();
24
24
  const clientResponses = new WeakSet();
25
25
  const registrations = new WeakSet();
26
26
  function pairs(raw, section, h2) {
@@ -385,6 +385,7 @@ function prepare(req, a, bytes, metadata) {
385
385
  });
386
386
  return capture;
387
387
  }
388
+ /** Capture and retain a Node incoming request before body parsing. */
388
389
  export async function captureRequest(req, options = {}) {
389
390
  try {
390
391
  S.need(req instanceof IncomingMessage || req instanceof Http2ServerRequest, "node-http", "capture", "invalid_request");
@@ -428,11 +429,26 @@ export async function captureRequest(req, options = {}) {
428
429
  return S.caught(e, "node-http", "capture", "invalid_options");
429
430
  }
430
431
  }
432
+ /**
433
+ * Install early Node request capture on a server with explicit limits.
434
+ *
435
+ * Options are `maxBytes`, `timeoutMs` (1 to 300,000 ms, default 5,000), and
436
+ * `trustedProxies`. Each request is captured under its own fresh `timeoutMs` deadline.
437
+ * A `context` is refused with `invalid_options`: one Context is one absolute deadline,
438
+ * and the registration outlives it.
439
+ */
431
440
  export function capture(server, options = {}) {
432
441
  try {
433
- const a = captureOptions(options, ["maxBytes", "context", "trustedProxies"], "attach");
442
+ // A Context is one absolute deadline, so a registration that outlives it takes
443
+ // a per-request timeoutMs instead; each request gets its own fresh deadline.
444
+ const a = captureOptions(options, ["maxBytes", "timeoutMs", "trustedProxies"], "attach");
434
445
  S.maximum(a, "node-http", "attach");
435
- S.context(a, "node-http", "attach");
446
+ const timeout = validTimeout(Object.hasOwn(a, "timeoutMs") ? a.timeoutMs : 5000);
447
+ S.need(timeout.ok, "node-http", "attach", "invalid_options");
448
+ const perRequest = Object.create(null);
449
+ for (const key of ["maxBytes", "trustedProxies"])
450
+ if (Object.hasOwn(a, key))
451
+ perRequest[key] = a[key];
436
452
  S.need(server !== null &&
437
453
  typeof server === "object" &&
438
454
  "prependListener" in server &&
@@ -440,7 +456,8 @@ export function capture(server, options = {}) {
440
456
  "removeListener" in server &&
441
457
  typeof server.removeListener === "function", "node-http", "attach", "invalid_options");
442
458
  const listener = (req) => {
443
- void captureRequest(req, a);
459
+ const context = withDeadline({ timeoutMs: timeout.ok ? timeout.value : 5000 });
460
+ void captureRequest(req, context.ok ? Object.freeze({ ...perRequest, context: context.value }) : perRequest);
444
461
  };
445
462
  server.prependListener("request", listener);
446
463
  const close = () => {
@@ -460,6 +477,7 @@ export function capture(server, options = {}) {
460
477
  return S.caught(e, "node-http", "attach", "invalid_options");
461
478
  }
462
479
  }
480
+ /** Return a defensive copy of captured Node request body bytes. */
463
481
  export function captureBody(req, bytes, options = {}) {
464
482
  try {
465
483
  S.need(req instanceof IncomingMessage || req instanceof Http2ServerRequest, "node-http", "capture", "invalid_request");
@@ -491,6 +509,7 @@ function beginVerification(req, c) {
491
509
  state.verified = err(S.failure("node-http", "verify", "already_verified"));
492
510
  return state;
493
511
  }
512
+ /** Verify a captured Node request once and retain its verification result. */
494
513
  export async function verifyRequest(req, policy, options) {
495
514
  try {
496
515
  const a = S.take(options, ["label", "context", "representation", "digestState"], "node-http", "verify");
@@ -512,7 +531,6 @@ export async function verifyRequest(req, policy, options) {
512
531
  return new Uint8Array(bytes);
513
532
  },
514
533
  });
515
- verified.add(v);
516
534
  const result = ok(v);
517
535
  state.verified = result;
518
536
  return result;
@@ -546,7 +564,6 @@ export async function verifyQuorum(req, quorum, options = {}) {
546
564
  return new Uint8Array(bytes);
547
565
  },
548
566
  });
549
- verified.add(result);
550
567
  state.verified = ok(result);
551
568
  return ok(result);
552
569
  }
@@ -580,7 +597,6 @@ export async function verifyWebBotAuth(req, policy, options = {}) {
580
597
  return new Uint8Array(bytes);
581
598
  },
582
599
  });
583
- verified.add(result);
584
600
  state.verified = ok(result);
585
601
  return ok(result);
586
602
  }
@@ -588,6 +604,7 @@ export async function verifyWebBotAuth(req, policy, options = {}) {
588
604
  return S.caught(e, "node-http", "verify", "request_rejected");
589
605
  }
590
606
  }
607
+ /** Read the verification result associated with a captured Node request. */
591
608
  export function verification(req) {
592
609
  const s = typeof req === "object" && req !== null
593
610
  ? states.get(req)
@@ -598,6 +615,7 @@ export function verification(req) {
598
615
  ? s.verified
599
616
  : err(S.failure("node-http", "verify", "not_captured"));
600
617
  }
618
+ /** Sign and write a Node HTTP response using retained body bytes. */
601
619
  export async function signResponse(res, input, signer, options = {}) {
602
620
  let previousHeaders;
603
621
  let response;
@@ -684,6 +702,7 @@ export async function signResponse(res, input, signer, options = {}) {
684
702
  return S.caught(e, "node-http", "sign", "signing_failed");
685
703
  }
686
704
  }
705
+ /** Verify a retained Node client response against its related request. */
687
706
  export async function verifyResponse(response, request, policy, options) {
688
707
  try {
689
708
  S.need(typeof response === "object" &&
@@ -770,6 +789,7 @@ async function send(url, m, body, a, c, attempt) {
770
789
  req.end(body);
771
790
  }));
772
791
  }
792
+ /** Send a signed Node HTTP request with explicit redirect and response policies. */
773
793
  export async function signedRequest(options, input, signer, ctx) {
774
794
  let attempt = 0;
775
795
  try {
package/dist/brand.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  import { type Result } from './result.ts';
2
+ /** Node and Deno inspection that shows only `view()`. Deno passes a render callback
3
+ * and prints the string it returns; Node formats the returned object itself. */
4
+ export declare function inspection(view: () => unknown): PropertyDescriptorMap;
5
+ /** Deno.customInspect body: render the redacted view through Deno's callback when given. */
6
+ export declare function denoInspection(render: unknown, view: unknown): unknown;
2
7
  /** Snapshot plain data, then freeze the owned structures. Uint8Array copies remain mutable:
3
8
  * JavaScript cannot freeze nonempty typed arrays; caller buffers are never retained.
4
9
  * Accessors and other object types reject without being invoked or frozen.
package/dist/brand.js CHANGED
@@ -1,5 +1,17 @@
1
1
  import { err, ok } from './result.js';
2
2
  import { coreError } from './errors/types.js';
3
+ /** Node and Deno inspection that shows only `view()`. Deno passes a render callback
4
+ * and prints the string it returns; Node formats the returned object itself. */
5
+ export function inspection(view) {
6
+ return {
7
+ [Symbol.for('nodejs.util.inspect.custom')]: { value: view },
8
+ [Symbol.for('Deno.customInspect')]: { value: (render) => denoInspection(render, view()) },
9
+ };
10
+ }
11
+ /** Deno.customInspect body: render the redacted view through Deno's callback when given. */
12
+ export function denoInspection(render, view) {
13
+ return typeof render === 'function' ? render(view) : view;
14
+ }
3
15
  /** Snapshot plain data, then freeze the owned structures. Uint8Array copies remain mutable:
4
16
  * JavaScript cannot freeze nonempty typed arrays; caller buffers are never retained.
5
17
  * Accessors and other object types reject without being invoked or frozen.
package/dist/bytes.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import { type Result } from './result.ts';
2
2
  /** Fetch ByteString: every UTF-16 code unit represents one octet. Always copied. */
3
3
  export declare function byteString(input: unknown): Result<Uint8Array<ArrayBuffer>>;
4
+ /** Encode bytes using the padded standard Base64 alphabet. */
4
5
  export declare const encodeBase64: (bytes: Uint8Array) => string;
6
+ /** Encode bytes using the unpadded URL-safe Base64 alphabet. */
5
7
  export declare const encodeBase64Url: (bytes: Uint8Array) => string;
8
+ /** Decode canonical padded Base64 into owned bytes. */
6
9
  export declare const decodeBase64: (input: unknown) => Result<Uint8Array<ArrayBuffer>>;
10
+ /** Decode canonical unpadded Base64url into owned bytes. */
7
11
  export declare const decodeBase64Url: (input: unknown) => Result<Uint8Array<ArrayBuffer>>;
package/dist/bytes.js CHANGED
@@ -11,6 +11,7 @@ export function byteString(input) {
11
11
  const bytes = new Uint8Array(input.length);
12
12
  for (let i = 0; i < input.length; i++) {
13
13
  const code = input.charCodeAt(i);
14
+ // boundedData in crypto/primitive.ts checks the same rule before copying.
14
15
  if (code > 255)
15
16
  return err(messageError('invalid_message'));
16
17
  bytes[i] = code;
@@ -39,7 +40,9 @@ function encode(bytes, url) {
39
40
  }
40
41
  return out.join('');
41
42
  }
43
+ /** Encode bytes using the padded standard Base64 alphabet. */
42
44
  export const encodeBase64 = (bytes) => encode(bytes, false);
45
+ /** Encode bytes using the unpadded URL-safe Base64 alphabet. */
43
46
  export const encodeBase64Url = (bytes) => encode(bytes, true);
44
47
  function decode(input, url) {
45
48
  const invalid = () => err(joseError('invalid_base64', 'input'));
@@ -67,5 +70,7 @@ function decode(input, url) {
67
70
  return invalid();
68
71
  return ok(bytes);
69
72
  }
73
+ /** Decode canonical padded Base64 into owned bytes. */
70
74
  export const decodeBase64 = (input) => decode(input, false);
75
+ /** Decode canonical unpadded Base64url into owned bytes. */
71
76
  export const decodeBase64Url = (input) => decode(input, true);
@@ -1,9 +1,12 @@
1
- export declare const VERSION = "0.1.0";
1
+ /** The public package version. */
2
+ export declare const VERSION = "0.3.0";
3
+ /** The immutable public conformance corpus release and index digest. */
2
4
  export declare const CORPUS_PIN: Readonly<{
3
- tag: "v0.4.0";
4
- commit: "b2392871933d99641a7cb2ca2726aefd20081dee";
5
- indexSha256: "f37435eca377666ab45c2b8f580287263145268e03d9224c76e324e4afaded6f";
5
+ tag: "v0.5.2";
6
+ commit: "53b6690ccd5036d58b280d08cf0cacc6427262fe";
7
+ indexSha256: "ceb30bf713a6e34e6a15847b658a618d8f7568ee6a6c07bfbbf58fa5d143995e";
6
8
  }>;
9
+ /** Default bounded Structured Fields parser limits. */
7
10
  export declare const STRUCTURED_FIELDS_LIMITS: Readonly<{
8
11
  maxBytes: 65536;
9
12
  maxMembers: 1024;
@@ -13,6 +16,7 @@ export declare const STRUCTURED_FIELDS_LIMITS: Readonly<{
13
16
  maxValueBytes: 16384;
14
17
  maxNodes: 4096;
15
18
  }>;
19
+ /** Default bounded JSON parser limits. */
16
20
  export declare const JSON_LIMITS: Readonly<{
17
21
  maxBytes: 16384;
18
22
  maxDepth: 4;
@@ -20,53 +24,109 @@ export declare const JSON_LIMITS: Readonly<{
20
24
  maxArrayLength: 64;
21
25
  maxStringBytes: 16384;
22
26
  }>;
27
+ /** Maximum compact JOSE wire bytes. */
23
28
  export declare const JOSE_MAX_COMPACT_BYTES = 1048576;
29
+ /** Maximum JOSE plaintext bytes. */
24
30
  export declare const JOSE_MAX_PLAINTEXT_BYTES = 1048576;
31
+ /** Default maximum retained body bytes. */
25
32
  export declare const BODY_MAX_BYTES = 1048576;
33
+ /** Default maximum digest input bytes. */
26
34
  export declare const DIGEST_MAX_BYTES = 16777216;
35
+ /** Fixed maximum cryptographic input byte limit. */
36
+ export declare const CRYPTO_MAX_BYTES_CEILING = 16777216;
37
+ /** Default cryptographic input byte limit. */
38
+ export declare const CRYPTO_DEFAULT_MAX_BYTES = 1048576;
39
+ /** Maximum signature-base bytes. */
27
40
  export declare const SIGNATURE_BASE_MAX_BYTES = 1048576;
41
+ /** Maximum covered signature-base components. */
28
42
  export declare const SIGNATURE_BASE_MAX_COMPONENTS = 256;
43
+ /** Maximum encoded signature or nonce bytes. */
29
44
  export declare const SIGNATURE_MAX_BYTES = 1024;
45
+ /** Maximum raw HTTP target bytes. */
30
46
  export declare const MESSAGE_MAX_TARGET_BYTES = 16384;
47
+ /** Maximum bytes in one HTTP field. */
31
48
  export declare const MESSAGE_MAX_FIELD_BYTES = 65536;
49
+ /** Maximum total HTTP field bytes. */
32
50
  export declare const MESSAGE_MAX_FIELDS_BYTES = 1048576;
51
+ /** Maximum quorum evaluation nodes. */
33
52
  export declare const QUORUM_MAX_NODES = 131072;
53
+ /** Maximum signatures evaluated by a quorum. */
34
54
  export declare const QUORUM_MAX_SIGNATURES = 64;
55
+ /** Default maximum discovery response bytes. */
35
56
  export declare const DISCOVERY_DEFAULT_MAX_BYTES = 65536;
57
+ /** Fixed maximum discovery response bytes. */
36
58
  export declare const DISCOVERY_MAX_BYTES = 1048576;
59
+ /** Maximum supported Unix timestamp in seconds. */
37
60
  export declare const CLOCK_MAX_SECONDS = 253402300799;
61
+ /** Maximum operation timeout in milliseconds. */
38
62
  export declare const TIMEOUT_MAX_MS = 300000;
63
+ /** Default operation timeout in milliseconds. */
39
64
  export declare const TIMEOUT_DEFAULT_MS = 5000;
65
+ /** Maximum absolute Structured Fields integer value. */
40
66
  export declare const SF_MAX_INTEGER = 999999999999999;
67
+ /** Maximum profile metadata members. */
41
68
  export declare const PROFILE_MAX_MEMBERS = 8;
69
+ /** Maximum profile metadata value bytes. */
42
70
  export declare const PROFILE_MAX_VALUE_BYTES = 256;
71
+ /** Maximum profile name or key code points. */
72
+ export declare const PROFILE_MAX_ATOM_CODE_POINTS = 255;
73
+ /** Maximum explicitly permitted discovery addresses. */
43
74
  export declare const DISCOVERY_MAX_PERMITTED_ADDRESSES = 16;
75
+ /** Fixed maximum discovery keys per source. */
44
76
  export declare const DISCOVERY_MAX_KEYS = 256;
77
+ /** Default maximum discovery keys per source. */
45
78
  export declare const DISCOVERY_DEFAULT_MAX_KEYS = 32;
79
+ /** Maximum discovery redirect hops. */
46
80
  export declare const DISCOVERY_MAX_REDIRECTS = 3;
81
+ /** Maximum discovery cache lifetime in seconds. */
47
82
  export declare const DISCOVERY_MAX_TTL_SECONDS = 604800;
83
+ /** Maximum negative discovery cache lifetime in seconds. */
48
84
  export declare const DISCOVERY_MAX_NEGATIVE_TTL_SECONDS = 300;
85
+ /** Maximum client metadata document bytes. */
49
86
  export declare const DISCOVERY_CIMD_MAX_BYTES = 5120;
87
+ /** Maximum encoded key container bytes. */
50
88
  export declare const KEY_MAX_BYTES = 16384;
89
+ /** Maximum key container members. */
51
90
  export declare const KEY_MAX_MEMBERS = 32;
91
+ /** Maximum encoded public key component bytes. */
52
92
  export declare const KEY_COMPONENT_MAX_ENCODED_BYTES = 21846;
93
+ /** Maximum encoded RSA component bytes. */
53
94
  export declare const RSA_COMPONENT_MAX_ENCODED_BYTES = 1366;
95
+ /** Minimum permitted RSA modulus bits. */
54
96
  export declare const RSA_MIN_BITS = 2048;
97
+ /** Maximum permitted RSA modulus bits. */
55
98
  export declare const RSA_MAX_BITS = 8192;
99
+ /** Maximum permitted RSA public exponent. */
56
100
  export declare const RSA_MAX_EXPONENT = 4294967295;
101
+ /** Maximum caller-supplied key identity bytes. */
57
102
  export declare const KEY_IDENTITY_MAX_BYTES = 256;
103
+ /** Minimum HMAC secret bytes. */
58
104
  export declare const HMAC_MIN_BYTES = 32;
105
+ /** Maximum HMAC secret bytes. */
59
106
  export declare const HMAC_MAX_BYTES = 16384;
107
+ /** Maximum DER container nesting depth. */
60
108
  export declare const DER_MAX_DEPTH = 32;
109
+ /** Maximum DER traversal nodes. */
61
110
  export declare const DER_MAX_NODES = 4096;
111
+ /** Maximum JWK algorithm identifier bytes. */
62
112
  export declare const JWK_ALGORITHM_MAX_BYTES = 64;
113
+ /** Maximum JWK operation identifiers. */
63
114
  export declare const JWK_MAX_OPERATIONS = 8;
115
+ /** Maximum custody signature bytes. */
64
116
  export declare const CUSTODY_SIGNATURE_MAX_BYTES = 16384;
117
+ /** Maximum combined HTTP header and trailer occurrences. */
65
118
  export declare const MESSAGE_MAX_OCCURRENCES = 1024;
119
+ /** Maximum HTTP method or field-name bytes. */
66
120
  export declare const MESSAGE_MAX_TOKEN_BYTES = 256;
121
+ /** Maximum HTTP scheme bytes. */
67
122
  export declare const MESSAGE_MAX_SCHEME_BYTES = 64;
123
+ /** Maximum HTTP authority bytes. */
68
124
  export declare const MESSAGE_MAX_AUTHORITY_BYTES = 1024;
125
+ /** Maximum combined HTTP URL bytes. */
69
126
  export declare const MESSAGE_MAX_URL_BYTES: number;
127
+ /** Default maximum signature dictionary members. */
70
128
  export declare const SIGNATURE_DEFAULT_MAX_MEMBERS = 16;
129
+ /** Maximum freshness clock skew in seconds. */
71
130
  export declare const FRESHNESS_MAX_SKEW_SECONDS = 86400;
131
+ /** Random nonce bytes generated during signing. */
72
132
  export declare const SIGNING_NONCE_BYTES = 32;