@cratestack/cbor 0.19.3 → 0.19.5

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/README.md CHANGED
@@ -170,3 +170,34 @@ for real.
170
170
  ## License
171
171
 
172
172
  MIT
173
+
174
+ ## Signed mode (`@cratestack/cbor/cose`)
175
+
176
+ `createCoseClient` seals requests and opens responses as COSE (ADR 0006), through `cratestack-cose`
177
+ compiled to WASM (browser) or the native addon (Node): all signing, hashing and the canonical query are
178
+ Rust's. The signer is a COSE_Mac0 session key (`{ type: "hmac" }`), an in-memory Ed25519 or P-256 key, or
179
+ an external callback for a non-extractable key:
180
+
181
+ ```ts
182
+ import { createCoseClient, createSealedLink } from "@cratestack/cbor/cose";
183
+
184
+ const cose = await createCoseClient({
185
+ audience: "payments",
186
+ serverKeys: [{ alg: "ed25519", bytes: serverPublicKey }], // the static trust root
187
+ signer: {
188
+ type: "external",
189
+ alg: "esp256",
190
+ publicKey, // SEC1 point
191
+ sign: async (toBeSigned) =>
192
+ new Uint8Array(
193
+ await crypto.subtle.sign({ name: "ECDSA", hash: "SHA-256" }, privateKey, toBeSigned),
194
+ ),
195
+ },
196
+ });
197
+ // RPC: new CratestackRpcRuntime(origin, { links: [createSealedLink({ cose, contracts: OP_CONTRACTS })] })
198
+ // REST: new CratestackRuntime(origin, { fetch: createSealedFetch({ cose, contracts: OP_CONTRACTS }) })
199
+ ```
200
+
201
+ `cose` may be a function `({ route, method }) => CoseClient | undefined` to seal with Sign1 before a session,
202
+ Mac0 after it, and not at all for anonymous calls. Every failed verification rejects with a `CoseFailure`
203
+ whose `code` is `rejected` and whose message is empty.
@@ -0,0 +1,6 @@
1
+ export { createCoseClient } from "@cratestack/cbor-node/cose";
2
+ export type { CoseAlgName, CoseCallBinding, CoseClient, CoseClientOptions, CoseExternalSign, CoseOpened, CoseServerKey, CoseSignerOptions, } from "@cratestack/ts-types";
3
+ export { CoseFailure } from "@cratestack/ts-types";
4
+ export type { CoseClientSource, OpContracts } from "./sealed.js";
5
+ export { createSealedFetch, createSealedLink } from "./sealed.js";
6
+ //# sourceMappingURL=cose-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cose-node.d.ts","sourceRoot":"","sources":["../src/cose-node.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,YAAY,EACV,WAAW,EACX,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ // Node entry of `@cratestack/cbor/cose` (resolved by the `"node"` condition):
2
+ // the COSE signed transport over the native addon. See
3
+ // `@cratestack/cbor-node/cose` for the API; `@cratestack/ts-types` has its types.
4
+ export { createCoseClient } from "@cratestack/cbor-node/cose";
5
+ export { CoseFailure } from "@cratestack/ts-types";
6
+ export { createSealedFetch, createSealedLink } from "./sealed.js";
7
+ //# sourceMappingURL=cose-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cose-node.js","sourceRoot":"","sources":["../src/cose-node.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,uDAAuD;AACvD,kFAAkF;AAElF,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAW9D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { createCoseClient } from "@cratestack/cbor-web/cose";
2
+ export type { CoseAlgName, CoseCallBinding, CoseClient, CoseClientOptions, CoseExternalSign, CoseOpened, CoseServerKey, CoseSignerOptions, } from "@cratestack/ts-types";
3
+ export { CoseFailure } from "@cratestack/ts-types";
4
+ export type { CoseClientSource, OpContracts } from "./sealed.js";
5
+ export { createSealedFetch, createSealedLink } from "./sealed.js";
6
+ //# sourceMappingURL=cose-web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cose-web.d.ts","sourceRoot":"","sources":["../src/cose-web.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,YAAY,EACV,WAAW,EACX,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ // Browser entry of `@cratestack/cbor/cose` (resolved by the `"browser"` and `"default"` conditions):
2
+ // the COSE signed transport over WASM. See
3
+ // `@cratestack/cbor-web/cose` for the API; `@cratestack/ts-types` has its types.
4
+ export { createCoseClient } from "@cratestack/cbor-web/cose";
5
+ export { CoseFailure } from "@cratestack/ts-types";
6
+ export { createSealedFetch, createSealedLink } from "./sealed.js";
7
+ //# sourceMappingURL=cose-web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cose-web.js","sourceRoot":"","sources":["../src/cose-web.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,2CAA2C;AAC3C,iFAAiF;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAW7D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
package/dist/node.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type CborCodecOptions } from "@cratestack/cbor-node";
1
2
  import type { CratestackRpcCodec } from "@cratestack/ts-types";
2
3
  /**
3
4
  * Resolves immediately (no real async work — `@cratestack/cbor-node`'s
@@ -6,7 +7,8 @@ import type { CratestackRpcCodec } from "@cratestack/ts-types";
6
7
  * by the native N-API CBOR codec. Async purely for call-site parity with
7
8
  * the browser build's `createCborCodec()`, not because Node needs it.
8
9
  */
9
- export declare function createCborCodec(): Promise<CratestackRpcCodec>;
10
+ export declare function createCborCodec(options?: CborCodecOptions): Promise<CratestackRpcCodec>;
10
11
  export type { CompactDirection, CompactKeys } from "@cratestack/cbor-node";
11
12
  export { createCompactKeys } from "@cratestack/cbor-node";
13
+ export type { CborCodecOptions };
12
14
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D;;;;;;GAMG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAEnE;AAID,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAE7F;AAID,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
package/dist/node.js CHANGED
@@ -21,7 +21,7 @@
21
21
  // sometimes a real async boundary), which defeats the point of an umbrella
22
22
  // package in the first place. See README.md's "Sync vs. async" section and
23
23
  // issue #288 for the full reasoning.
24
- import { cborCodec } from "@cratestack/cbor-node";
24
+ import { cborCodec, createCborCodec as createNodeCodec, } from "@cratestack/cbor-node";
25
25
  /**
26
26
  * Resolves immediately (no real async work — `@cratestack/cbor-node`'s
27
27
  * underlying native codec is already loaded and synchronous by the time
@@ -29,8 +29,8 @@ import { cborCodec } from "@cratestack/cbor-node";
29
29
  * by the native N-API CBOR codec. Async purely for call-site parity with
30
30
  * the browser build's `createCborCodec()`, not because Node needs it.
31
31
  */
32
- export async function createCborCodec() {
33
- return cborCodec;
32
+ export async function createCborCodec(options) {
33
+ return options ? createNodeCodec(options) : cborCodec;
34
34
  }
35
35
  export { createCompactKeys } from "@cratestack/cbor-node";
36
36
  //# sourceMappingURL=node.js.map
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,8EAA8E;AAC9E,kDAAkD;AAClD,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AACzE,2BAA2B;AAC3B,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,yEAAyE;AACzE,yEAAyE;AACzE,yEAAyE;AACzE,mEAAmE;AACnE,2EAA2E;AAC3E,2EAA2E;AAC3E,qCAAqC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,OAAO,SAAS,CAAC;AACnB,CAAC;AAKD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,8EAA8E;AAC9E,kDAAkD;AAClD,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AACzE,2BAA2B;AAC3B,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,yEAAyE;AACzE,yEAAyE;AACzE,yEAAyE;AACzE,mEAAmE;AACnE,2EAA2E;AAC3E,2EAA2E;AAC3E,qCAAqC;AACrC,OAAO,EAEL,SAAS,EACT,eAAe,IAAI,eAAe,GACnC,MAAM,uBAAuB,CAAC;AAG/B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA0B;IAC9D,OAAO,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAKD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { type CoseClient } from "@cratestack/ts-types";
2
+ /** The `CoseClient` a call is sealed with, or `undefined` to send it unsealed
3
+ * (an anonymous call, an op the client does not seal). A function picks per
4
+ * call, so a Sign1 client can seal the calls before a session and a Mac0
5
+ * client under the session key the calls after it. */
6
+ export type CoseClientSource = CoseClient | undefined | ((call: {
7
+ readonly route: string;
8
+ readonly method: string;
9
+ }) => CoseClient | undefined);
10
+ /** The `OP_CONTRACTS` of a generated client. */
11
+ export type OpContracts = Readonly<Record<string, string>>;
12
+ /** The slice of a generated RPC runtime's link types this file needs. The
13
+ * generated `RpcLink` is structurally this. */
14
+ interface RpcSealRequest {
15
+ readonly kind: "unary" | "batch";
16
+ readonly opId: string;
17
+ readonly fetchFn: typeof fetch;
18
+ }
19
+ type RpcSealLink = <R extends RpcSealRequest, T>(request: R, next: (request: R) => Promise<T>) => Promise<T>;
20
+ /**
21
+ * An `RpcLink` that seals every unary and batch call of a generated RPC client:
22
+ * the route is the op id (`batch` for `/rpc/batch`), the contract digest is
23
+ * `OP_CONTRACTS[route]`. An op with no contract, or one `cose` declines
24
+ * (`undefined`), goes out unsealed. `stream()` is not a link of this chain and
25
+ * is never sealed (chain-mode streams are not implemented).
26
+ *
27
+ * ```ts
28
+ * import { createCoseClient, createSealedLink } from "@cratestack/cbor/cose";
29
+ * import { CratestackRpcRuntime, OP_CONTRACTS } from "./runtime";
30
+ *
31
+ * const runtime = new CratestackRpcRuntime(origin, {
32
+ * links: [createSealedLink({ cose, contracts: OP_CONTRACTS })],
33
+ * });
34
+ * ```
35
+ */
36
+ export declare function createSealedLink(options: {
37
+ cose: CoseClientSource;
38
+ contracts: OpContracts;
39
+ }): RpcSealLink;
40
+ /**
41
+ * A `fetch` that seals every call of a generated REST client, for
42
+ * `CratestackRuntime`'s `fetch` option. The route template and path parameters
43
+ * come from matching the URL path (after `basePath`, the runtime's own) against
44
+ * the `"<METHOD> <template>"` keys of `OP_CONTRACTS`; a call that matches none,
45
+ * or that `cose` declines (`undefined`), goes out unsealed.
46
+ *
47
+ * ```ts
48
+ * const runtime = new CratestackRuntime(origin, {
49
+ * fetch: createSealedFetch({ cose, contracts: OP_CONTRACTS, basePath: "/api" }),
50
+ * });
51
+ * ```
52
+ */
53
+ export declare function createSealedFetch(options: {
54
+ cose: CoseClientSource;
55
+ contracts: OpContracts;
56
+ basePath?: string;
57
+ fetch?: typeof fetch;
58
+ }): typeof fetch;
59
+ export {};
60
+ //# sourceMappingURL=sealed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sealed.d.ts","sourceRoot":"","sources":["../src/sealed.ts"],"names":[],"mappings":"AAUA,OAAO,EAAwB,KAAK,UAAU,EAAe,MAAM,sBAAsB,CAAC;AAE1F;;;uDAGuD;AACvD,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,SAAS,GACT,CAAC,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,UAAU,GAAG,SAAS,CAAC,CAAC;AAoH5F,gDAAgD;AAChD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE3D;gDACgD;AAChD,UAAU,cAAc;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC;CAChC;AACD,KAAK,WAAW,GAAG,CAAC,CAAC,SAAS,cAAc,EAAE,CAAC,EAC7C,OAAO,EAAE,CAAC,EACV,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,KAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CACxB,GAAG,WAAW,CAad;AAuCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,GAAG,OAAO,KAAK,CA2Bf"}
package/dist/sealed.js ADDED
@@ -0,0 +1,192 @@
1
+ // Sealing a call at the `fetch` boundary (issue #1010, ADR 0006 §11): the
2
+ // orchestration around a `CoseClient`, for the generated REST runtime (a
3
+ // `fetch` option) and the generated RPC runtime (an `RpcLink`).
4
+ //
5
+ // It sits at `fetch` because that is where the exact wire bytes (after the
6
+ // codec and after compact keys) and the exact headers (`Idempotency-Key`,
7
+ // `If-Match`, the compact `Content-Type` and `Accept`) exist, and it binds
8
+ // what the request carries, as the Rust client's `request_sealed` does. It
9
+ // holds no crypto and no canonical form: the signature, the hash, the query
10
+ // and the AAD are the `CoseClient`'s (Rust). What is left is header plumbing.
11
+ import { CoseFailure } from "@cratestack/ts-types";
12
+ const CBOR = "application/cbor";
13
+ const NO_BODY_STATUS = new Set([101, 204, 205, 304]);
14
+ const PAYLOAD_TYPE_HEADER = "cratestack-payload-type";
15
+ const hexBytes = (hex) => Uint8Array.from(hex.match(/../g) ?? [], (byte) => Number.parseInt(byte, 16));
16
+ const pick = (source, route, method) => typeof source === "function" ? source({ route, method }) : source;
17
+ async function bodyBytes(body) {
18
+ if (body === null || body === undefined)
19
+ return new Uint8Array();
20
+ if (typeof body === "string")
21
+ return new TextEncoder().encode(body);
22
+ if (body instanceof Uint8Array)
23
+ return body;
24
+ if (body instanceof ArrayBuffer)
25
+ return new Uint8Array(body);
26
+ throw new CoseFailure("misuse", "a sealed call carries a string or bytes body");
27
+ }
28
+ /** The media type of a header value, parameters dropped. */
29
+ const mediaTypeOf = (value) => value.split(";", 1)[0]?.trim().toLowerCase() ?? "";
30
+ /** The URL a `fetch` was given, whatever shape it came in. */
31
+ const urlOf = (input) => new URL(input instanceof Request ? input.url : input.toString());
32
+ /**
33
+ * One sealed round trip: seals `init.body` as the call `route` describes, sends
34
+ * it through `fetchFn`, and opens the answer. Resolves to a `Response` whose
35
+ * body is the opened payload and whose `Content-Type` is the type it was sealed
36
+ * under, so everything downstream of `fetch` is the code an unsealed call runs.
37
+ *
38
+ * - An answer that opens is returned; one that does not rejects with a
39
+ * {@link CoseFailure} `rejected` (tampered, replayed, wrong audience, wrong
40
+ * signer, unrequested type), with no detail.
41
+ * - An unsigned answer to a refused call (`!ok`: a gateway's `401`, the
42
+ * server's `415` or `426`) is returned untouched, a hint and never proof. An
43
+ * unsigned *success* is never believed: it rejects.
44
+ */
45
+ async function sealedFetch(fetchFn, cose, target, input, init = {}) {
46
+ const url = urlOf(input);
47
+ const headers = new Headers(init.headers);
48
+ const payload = await bodyBytes(init.body);
49
+ const payloadType = mediaTypeOf(headers.get("content-type") ?? "") || CBOR;
50
+ const accept = (headers.get("accept") ?? "")
51
+ .split(",")
52
+ .map(mediaTypeOf)
53
+ .filter((type) => type !== "");
54
+ const query = url.search.startsWith("?") ? url.search.slice(1) : url.search;
55
+ const binding = {
56
+ method: (init.method ?? "GET").toUpperCase(),
57
+ route: target.route,
58
+ pathParams: target.pathParams,
59
+ query: query === "" ? undefined : cose.canonicalQuery(query),
60
+ contractSha: target.contractSha,
61
+ idempotencyKey: headers.get("idempotency-key") ?? undefined,
62
+ ifMatch: headers.get("if-match") ?? undefined,
63
+ payloadType,
64
+ payloadAccept: accept.length === 0 ? undefined : accept,
65
+ };
66
+ if (target.route === "batch" &&
67
+ (payloadType !== CBOR || (accept.length > 0 && !accept.includes(CBOR)))) {
68
+ throw new CoseFailure("misuse", "a sealed /rpc/batch is CBOR both ways");
69
+ }
70
+ const sealed = await cose.sealRequest(payload, binding);
71
+ headers.set("content-type", cose.mediaType);
72
+ headers.set("accept", cose.mediaType);
73
+ headers.set("cratestack-contract", cose.contractHeader(target.contractSha));
74
+ for (const name of ["cratestack-payload-type", "cratestack-payload-accept"])
75
+ headers.delete(name);
76
+ for (const [name, value] of Object.entries(cose.selectorHeaders(binding))) {
77
+ headers.set(name, value);
78
+ }
79
+ const response = await fetchFn(url, { ...init, headers, body: sealed });
80
+ const contentType = mediaTypeOf(response.headers.get("content-type") ?? "");
81
+ if (contentType !== mediaTypeOf(cose.mediaType)) {
82
+ if (response.ok) {
83
+ throw new CoseFailure("rejected", "");
84
+ }
85
+ return response;
86
+ }
87
+ const opened = await cose.openResponse(new Uint8Array(await response.arrayBuffer()), binding, sealed, response.status, response.headers.get(PAYLOAD_TYPE_HEADER) ?? undefined);
88
+ const answered = new Headers(response.headers);
89
+ for (const name of ["content-length", "content-encoding", PAYLOAD_TYPE_HEADER]) {
90
+ answered.delete(name);
91
+ }
92
+ answered.set("content-type", opened.payloadType);
93
+ return new Response(NO_BODY_STATUS.has(response.status) ? null : opened.payload, {
94
+ status: response.status,
95
+ statusText: response.statusText,
96
+ headers: answered,
97
+ });
98
+ }
99
+ /**
100
+ * An `RpcLink` that seals every unary and batch call of a generated RPC client:
101
+ * the route is the op id (`batch` for `/rpc/batch`), the contract digest is
102
+ * `OP_CONTRACTS[route]`. An op with no contract, or one `cose` declines
103
+ * (`undefined`), goes out unsealed. `stream()` is not a link of this chain and
104
+ * is never sealed (chain-mode streams are not implemented).
105
+ *
106
+ * ```ts
107
+ * import { createCoseClient, createSealedLink } from "@cratestack/cbor/cose";
108
+ * import { CratestackRpcRuntime, OP_CONTRACTS } from "./runtime";
109
+ *
110
+ * const runtime = new CratestackRpcRuntime(origin, {
111
+ * links: [createSealedLink({ cose, contracts: OP_CONTRACTS })],
112
+ * });
113
+ * ```
114
+ */
115
+ export function createSealedLink(options) {
116
+ return (request, next) => {
117
+ const route = request.kind === "batch" ? "batch" : request.opId;
118
+ const client = pick(options.cose, route, "POST");
119
+ const contract = options.contracts[route];
120
+ if (client === undefined || contract === undefined) {
121
+ return next(request);
122
+ }
123
+ const target = { route, pathParams: [], contractSha: hexBytes(contract) };
124
+ const sealedFetchFn = ((input, init) => sealedFetch(request.fetchFn, client, target, input, init));
125
+ return next({ ...request, fetchFn: sealedFetchFn });
126
+ };
127
+ }
128
+ /** `"<METHOD> <template>"` keys of `OP_CONTRACTS` as matchers over a path. */
129
+ function restTemplates(contracts) {
130
+ const out = [];
131
+ for (const [key, contract] of Object.entries(contracts)) {
132
+ const space = key.indexOf(" ");
133
+ if (space < 0)
134
+ continue;
135
+ const template = key.slice(space + 1);
136
+ const segments = template.split("/");
137
+ const pattern = new RegExp(`^${segments
138
+ .map((segment) => /^\{[^}]+\}$/.test(segment) ? "([^/]+)" : segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
139
+ .join("/")}$`);
140
+ out.push({
141
+ key,
142
+ method: key.slice(0, space),
143
+ template,
144
+ pattern,
145
+ literals: segments.filter((segment) => !/^\{[^}]+\}$/.test(segment)).length,
146
+ contractSha: hexBytes(contract),
147
+ });
148
+ }
149
+ // The most literal template wins (`/widgets/search` before `/widgets/{id}`).
150
+ return out.sort((a, b) => b.literals - a.literals);
151
+ }
152
+ /**
153
+ * A `fetch` that seals every call of a generated REST client, for
154
+ * `CratestackRuntime`'s `fetch` option. The route template and path parameters
155
+ * come from matching the URL path (after `basePath`, the runtime's own) against
156
+ * the `"<METHOD> <template>"` keys of `OP_CONTRACTS`; a call that matches none,
157
+ * or that `cose` declines (`undefined`), goes out unsealed.
158
+ *
159
+ * ```ts
160
+ * const runtime = new CratestackRuntime(origin, {
161
+ * fetch: createSealedFetch({ cose, contracts: OP_CONTRACTS, basePath: "/api" }),
162
+ * });
163
+ * ```
164
+ */
165
+ export function createSealedFetch(options) {
166
+ const templates = restTemplates(options.contracts);
167
+ const basePath = (options.basePath ?? "").replace(/\/+$/, "");
168
+ const underlying = options.fetch ?? fetch.bind(globalThis);
169
+ return (async (input, init) => {
170
+ const url = urlOf(input);
171
+ const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
172
+ const path = basePath !== "" && url.pathname.startsWith(basePath)
173
+ ? url.pathname.slice(basePath.length)
174
+ : url.pathname;
175
+ for (const candidate of templates) {
176
+ const match = candidate.method === method ? candidate.pattern.exec(path) : null;
177
+ if (match === null)
178
+ continue;
179
+ const client = pick(options.cose, candidate.key, method);
180
+ if (client === undefined)
181
+ break;
182
+ const target = {
183
+ route: candidate.template,
184
+ pathParams: match.slice(1).map(decodeURIComponent),
185
+ contractSha: candidate.contractSha,
186
+ };
187
+ return sealedFetch(underlying, client, target, input, init);
188
+ }
189
+ return underlying(input, init);
190
+ });
191
+ }
192
+ //# sourceMappingURL=sealed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sealed.js","sourceRoot":"","sources":["../src/sealed.ts"],"names":[],"mappings":"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"}
package/dist/web.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export type { CompactDirection, CompactKeys } from "@cratestack/cbor-web";
1
+ export type { CborCodecOptions, CompactDirection, CompactKeys } from "@cratestack/cbor-web";
2
2
  export { createCborCodec, createCompactKeys } from "@cratestack/cbor-web";
3
3
  //# sourceMappingURL=web.d.ts.map
package/dist/web.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAaA,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAaA,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratestack/cbor",
3
- "version": "0.19.3",
3
+ "version": "0.19.5",
4
4
  "description": "Umbrella CBOR codec for CrateStack's generated TypeScript RPC clients: conditional exports auto-select @cratestack/cbor-node in Node and @cratestack/cbor-web in the browser behind one import path, one uniform async createCborCodec() API on both platforms.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -44,6 +44,20 @@
44
44
  "./web": {
45
45
  "types": "./dist/web.d.ts",
46
46
  "import": "./dist/web.js"
47
+ },
48
+ "./cose": {
49
+ "node": {
50
+ "types": "./dist/cose-node.d.ts",
51
+ "import": "./dist/cose-node.js"
52
+ },
53
+ "browser": {
54
+ "types": "./dist/cose-web.d.ts",
55
+ "import": "./dist/cose-web.js"
56
+ },
57
+ "default": {
58
+ "types": "./dist/cose-web.d.ts",
59
+ "import": "./dist/cose-web.js"
60
+ }
47
61
  }
48
62
  },
49
63
  "files": [
@@ -57,9 +71,9 @@
57
71
  "lint": "biome check ."
58
72
  },
59
73
  "dependencies": {
60
- "@cratestack/cbor-node": "0.19.3",
61
- "@cratestack/cbor-web": "0.19.3",
62
- "@cratestack/ts-types": "0.19.3"
74
+ "@cratestack/cbor-node": "0.19.5",
75
+ "@cratestack/cbor-web": "0.19.5",
76
+ "@cratestack/ts-types": "0.19.5"
63
77
  },
64
78
  "devDependencies": {
65
79
  "typescript": "^7.0.2",