@cratestack/cbor 0.19.2 → 0.19.4
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 +31 -0
- package/dist/cose-node.d.ts +6 -0
- package/dist/cose-node.d.ts.map +1 -0
- package/dist/cose-node.js +7 -0
- package/dist/cose-node.js.map +1 -0
- package/dist/cose-web.d.ts +6 -0
- package/dist/cose-web.d.ts.map +1 -0
- package/dist/cose-web.js +7 -0
- package/dist/cose-web.js.map +1 -0
- package/dist/node.d.ts +3 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +3 -3
- package/dist/node.js.map +1 -1
- package/dist/sealed.d.ts +60 -0
- package/dist/sealed.d.ts.map +1 -0
- package/dist/sealed.js +192 -0
- package/dist/sealed.js.map +1 -0
- package/dist/web.d.ts +1 -1
- package/dist/web.d.ts.map +1 -1
- package/package.json +18 -4
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"}
|
package/dist/cose-web.js
ADDED
|
@@ -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
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"
|
|
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,
|
|
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"}
|
package/dist/sealed.d.ts
ADDED
|
@@ -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;
|
|
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
|
+
"version": "0.19.4",
|
|
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.
|
|
61
|
-
"@cratestack/cbor-web": "0.19.
|
|
62
|
-
"@cratestack/ts-types": "0.19.
|
|
74
|
+
"@cratestack/cbor-node": "0.19.4",
|
|
75
|
+
"@cratestack/cbor-web": "0.19.4",
|
|
76
|
+
"@cratestack/ts-types": "0.19.4"
|
|
63
77
|
},
|
|
64
78
|
"devDependencies": {
|
|
65
79
|
"typescript": "^7.0.2",
|