@slicegrid/anchor-client 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +12 -2
- package/dist/client.d.ts +26 -0
- package/dist/client.js +99 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/envelope.d.ts +27 -0
- package/dist/envelope.js +59 -0
- package/dist/envelope.js.map +1 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.js +130 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.d.ts +18 -0
- package/dist/http.js +135 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Slice (bagcollective.io)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @slicegrid/anchor-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Client for one Slice anchor. It has no default URL.
|
|
4
|
+
|
|
5
|
+
Set `AGENT_PRIME_ANCHOR_URL` to that anchor (for example `http://127.0.0.1:9420`). Unset throws `ANCHOR_NOT_CONFIGURED` and does not open a connection. `AGENT_PRIME_ANCHOR_TIMEOUT_MS` defaults to 25000. That covers a 15 second Wasm child boot plus the 2 second run budget.
|
|
6
|
+
|
|
7
|
+
The caller holds the holder Ed25519 key. `buildEnvelopeClaims` returns unsigned claims. Sign them with core `signJws` (`alg` EdDSA, `typ` JWT, `kid` = holder PeerId, `jwk`). Then `redeem({ envelopeJws, moduleBytes })`. This package does not retry and does not decide the redeem; the anchor does. `verifyReceipt` checks the receipt locally. Pass `expectedPeerId` and `genesisPeerIds` to check against a trusted identity. When either pin is omitted, that field is filled from the anchor document.
|
|
8
|
+
|
|
9
|
+
`ANCHOR_UNREACHABLE` means the request never reached the anchor (`ECONNREFUSED`, `ENOTFOUND`, `EAI_AGAIN`, `EHOSTUNREACH`, `ENETUNREACH`). Resending the same bytes is safe. `ANCHOR_TIMEOUT` and `ANCHOR_CONNECTION_LOST` use `resign_and_retry` with `outcome_unknown: true`: the anchor may have processed the redeem, the voucher may be spent, a retry returns `REPLAY`, and the receipt cannot be fetched again. A `REPLAY` after that is not a new failure. On `GET /.well-known/agent-prime.json` that is harmless: discover is idempotent and does not spend anything.
|
|
10
|
+
|
|
11
|
+
`PREDICATE_INVALID`, `PREDICATE_UNSUPPORTED`, and `PREDICATE_MISMATCH` are not retried. A mismatch means the voucher is already spent.
|
|
12
|
+
|
|
13
|
+
Every failure is an `AnchorClientError` with `code`, optional `http`, `source` (`anchor` or `client`), and `retry`. The `retry.note` is the only human text. Exception messages are not forwarded.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type AnchorWellKnown, type RedeemReceipt } from "@slicegrid/core";
|
|
2
|
+
export type AnchorClient = {
|
|
3
|
+
discover(): Promise<AnchorWellKnown>;
|
|
4
|
+
redeem(input: {
|
|
5
|
+
envelopeJws: string;
|
|
6
|
+
moduleBytes: Uint8Array;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
status: "OK" | "FAULT";
|
|
9
|
+
receipt_jws: string;
|
|
10
|
+
}>;
|
|
11
|
+
verifyReceipt(receiptJws: string, opts?: {
|
|
12
|
+
expectedPeerId?: string;
|
|
13
|
+
genesisPeerIds?: readonly string[];
|
|
14
|
+
}): Promise<{
|
|
15
|
+
ok: true;
|
|
16
|
+
receipt: RedeemReceipt;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
code: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
export declare function createAnchorClient(opts: {
|
|
23
|
+
url: string;
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
fetchImpl?: typeof fetch;
|
|
26
|
+
}): AnchorClient;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ANCHOR_WELL_KNOWN_SCHEMA, ANCHOR_WELL_KNOWN_SCHEMA_VERSION, verifyReceipt as verifyReceiptJws, JwsError, } from "@slicegrid/core";
|
|
2
|
+
import { DEFAULT_ANCHOR_TIMEOUT_MS, parseAnchorUrl } from "./config.js";
|
|
3
|
+
import { AnchorClientError } from "./errors.js";
|
|
4
|
+
import { anchorFetch } from "./http.js";
|
|
5
|
+
const CACHE_MS = 30_000;
|
|
6
|
+
const CODE_RE = /^[A-Z0-9_]+$/;
|
|
7
|
+
function asObject(value) {
|
|
8
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
9
|
+
return undefined;
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function interpret(result, wk) {
|
|
13
|
+
let parsed;
|
|
14
|
+
try {
|
|
15
|
+
parsed = JSON.parse(result.body);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new AnchorClientError("ANCHOR_BAD_RESPONSE", { http: result.status, source: "client", wk });
|
|
19
|
+
}
|
|
20
|
+
if (result.status !== 200) {
|
|
21
|
+
const row = asObject(parsed);
|
|
22
|
+
const code = row?.code;
|
|
23
|
+
if (typeof code !== "string" || !CODE_RE.test(code)) {
|
|
24
|
+
throw new AnchorClientError("ANCHOR_BAD_RESPONSE", { http: result.status, source: "client", wk });
|
|
25
|
+
}
|
|
26
|
+
throw new AnchorClientError(code, { http: result.status, source: "anchor", wk });
|
|
27
|
+
}
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
export function createAnchorClient(opts) {
|
|
31
|
+
const origin = parseAnchorUrl(opts.url);
|
|
32
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_ANCHOR_TIMEOUT_MS;
|
|
33
|
+
let cache;
|
|
34
|
+
async function discover() {
|
|
35
|
+
if (cache && Date.now() - cache.at < CACHE_MS)
|
|
36
|
+
return cache.doc;
|
|
37
|
+
const result = await anchorFetch(origin, "/.well-known/agent-prime.json", {
|
|
38
|
+
method: "GET",
|
|
39
|
+
timeoutMs,
|
|
40
|
+
fetchImpl: opts.fetchImpl,
|
|
41
|
+
});
|
|
42
|
+
const parsed = interpret(result);
|
|
43
|
+
const doc = asObject(parsed);
|
|
44
|
+
if (!doc || doc.schema !== ANCHOR_WELL_KNOWN_SCHEMA || doc.schema_version !== ANCHOR_WELL_KNOWN_SCHEMA_VERSION) {
|
|
45
|
+
throw new AnchorClientError("ANCHOR_BAD_RESPONSE", { http: result.status, source: "client" });
|
|
46
|
+
}
|
|
47
|
+
const wellKnown = parsed;
|
|
48
|
+
cache = { at: Date.now(), doc: wellKnown };
|
|
49
|
+
return wellKnown;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
discover,
|
|
53
|
+
async redeem(input) {
|
|
54
|
+
if (!input.envelopeJws || input.envelopeJws.length > 16_384) {
|
|
55
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
56
|
+
}
|
|
57
|
+
const frame = Buffer.concat([
|
|
58
|
+
Buffer.from(input.envelopeJws, "ascii"),
|
|
59
|
+
Buffer.from("\n"),
|
|
60
|
+
Buffer.from(input.moduleBytes),
|
|
61
|
+
]);
|
|
62
|
+
const result = await anchorFetch(origin, "/redeem", {
|
|
63
|
+
method: "POST",
|
|
64
|
+
timeoutMs,
|
|
65
|
+
body: frame,
|
|
66
|
+
contentType: "application/octet-stream",
|
|
67
|
+
fetchImpl: opts.fetchImpl,
|
|
68
|
+
});
|
|
69
|
+
let wk;
|
|
70
|
+
if (cache && Date.now() - cache.at < CACHE_MS)
|
|
71
|
+
wk = cache.doc;
|
|
72
|
+
const parsed = asObject(interpret(result, wk));
|
|
73
|
+
const status = parsed?.status;
|
|
74
|
+
const receipt = parsed?.receipt_jws;
|
|
75
|
+
if ((status !== "OK" && status !== "FAULT") || typeof receipt !== "string" || receipt.length === 0) {
|
|
76
|
+
throw new AnchorClientError("ANCHOR_BAD_RESPONSE", { http: result.status, source: "client", wk });
|
|
77
|
+
}
|
|
78
|
+
return { status, receipt_jws: receipt };
|
|
79
|
+
},
|
|
80
|
+
async verifyReceipt(receiptJws, pin) {
|
|
81
|
+
let expectedPeerId = pin?.expectedPeerId;
|
|
82
|
+
let genesisPeerIds = pin?.genesisPeerIds ? [...pin.genesisPeerIds] : undefined;
|
|
83
|
+
if (!expectedPeerId || !genesisPeerIds) {
|
|
84
|
+
const doc = await discover();
|
|
85
|
+
expectedPeerId ??= doc.peer_id;
|
|
86
|
+
genesisPeerIds ??= doc.skim_ack.members;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const receipt = verifyReceiptJws(receiptJws, { expectedPeerId, genesisPeerIds });
|
|
90
|
+
return { ok: true, receipt };
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
const code = e instanceof JwsError ? e.code : "SIG_INVALID";
|
|
94
|
+
return { ok: false, code };
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Wasm child boot is 15s and the run budget is 2s. 25s covers both. */
|
|
2
|
+
export declare const DEFAULT_ANCHOR_TIMEOUT_MS = 25000;
|
|
3
|
+
/** http(s) origin only. No userinfo, no fragment. Path and query are dropped. */
|
|
4
|
+
export declare function parseAnchorUrl(raw: string): string;
|
|
5
|
+
/** AGENT_PRIME_ANCHOR_URL has no default. Unset throws before any network call. */
|
|
6
|
+
export declare function anchorUrlFromEnv(env?: NodeJS.ProcessEnv): {
|
|
7
|
+
url: string;
|
|
8
|
+
timeoutMs: number;
|
|
9
|
+
};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AnchorClientError } from "./errors.js";
|
|
2
|
+
/** Wasm child boot is 15s and the run budget is 2s. 25s covers both. */
|
|
3
|
+
export const DEFAULT_ANCHOR_TIMEOUT_MS = 25_000;
|
|
4
|
+
/** http(s) origin only. No userinfo, no fragment. Path and query are dropped. */
|
|
5
|
+
export function parseAnchorUrl(raw) {
|
|
6
|
+
let url;
|
|
7
|
+
try {
|
|
8
|
+
url = new URL(raw);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
throw new AnchorClientError("ANCHOR_URL_INVALID", { source: "client" });
|
|
12
|
+
}
|
|
13
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
14
|
+
throw new AnchorClientError("ANCHOR_URL_INVALID", { source: "client" });
|
|
15
|
+
}
|
|
16
|
+
if (url.username !== "" || url.password !== "") {
|
|
17
|
+
throw new AnchorClientError("ANCHOR_URL_INVALID", { source: "client" });
|
|
18
|
+
}
|
|
19
|
+
if (url.hash !== "") {
|
|
20
|
+
throw new AnchorClientError("ANCHOR_URL_INVALID", { source: "client" });
|
|
21
|
+
}
|
|
22
|
+
return url.origin;
|
|
23
|
+
}
|
|
24
|
+
/** AGENT_PRIME_ANCHOR_URL has no default. Unset throws before any network call. */
|
|
25
|
+
export function anchorUrlFromEnv(env = process.env) {
|
|
26
|
+
const raw = env.AGENT_PRIME_ANCHOR_URL;
|
|
27
|
+
if (raw == null || raw.trim() === "") {
|
|
28
|
+
throw new AnchorClientError("ANCHOR_NOT_CONFIGURED", { source: "client" });
|
|
29
|
+
}
|
|
30
|
+
const timeoutRaw = env.AGENT_PRIME_ANCHOR_TIMEOUT_MS;
|
|
31
|
+
let timeoutMs = DEFAULT_ANCHOR_TIMEOUT_MS;
|
|
32
|
+
if (timeoutRaw != null && timeoutRaw !== "") {
|
|
33
|
+
const n = Number(timeoutRaw);
|
|
34
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
35
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
36
|
+
}
|
|
37
|
+
timeoutMs = n;
|
|
38
|
+
}
|
|
39
|
+
return { url: parseAnchorUrl(raw), timeoutMs };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,wEAAwE;AACxE,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD,iFAAiF;AACjF,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,iBAAiB,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,iBAAiB,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,iBAAiB,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,iBAAiB,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,gBAAgB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACnE,MAAM,GAAG,GAAG,GAAG,CAAC,sBAAsB,CAAC;IACvC,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,iBAAiB,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,UAAU,GAAG,GAAG,CAAC,6BAA6B,CAAC;IACrD,IAAI,SAAS,GAAG,yBAAyB,CAAC;IAC1C,IAAI,UAAU,IAAI,IAAI,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,iBAAiB,CAAC,eAAe,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,SAAS,GAAG,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Canonical standard base64, padded or unpadded. No whitespace. Empty is invalid. */
|
|
2
|
+
export declare function decodeModuleB64(moduleB64: string): Uint8Array;
|
|
3
|
+
export type EnvelopeClaims = {
|
|
4
|
+
v: 1;
|
|
5
|
+
aud: string;
|
|
6
|
+
sub: string;
|
|
7
|
+
voucher: string;
|
|
8
|
+
mod: string;
|
|
9
|
+
ts: number;
|
|
10
|
+
nonce: string;
|
|
11
|
+
};
|
|
12
|
+
/** Unsigned claims. The caller signs them with the holder key. randomBytes here is a nonce, not a key. */
|
|
13
|
+
export declare function buildEnvelopeClaims(input: {
|
|
14
|
+
voucherJws: string;
|
|
15
|
+
moduleBytes: Uint8Array;
|
|
16
|
+
holderPeerId: string;
|
|
17
|
+
anchorPeerId: string;
|
|
18
|
+
nowSec?: number;
|
|
19
|
+
nonce?: string;
|
|
20
|
+
}): EnvelopeClaims;
|
|
21
|
+
/** Payload decode only. Does not verify the signature. */
|
|
22
|
+
export declare function decodeVoucherClaims(jws: string): {
|
|
23
|
+
sub?: string;
|
|
24
|
+
aud?: string;
|
|
25
|
+
exp?: number;
|
|
26
|
+
mod?: string;
|
|
27
|
+
};
|
package/dist/envelope.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { AnchorClientError } from "./errors.js";
|
|
3
|
+
const MODULE_B64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
4
|
+
/** Canonical standard base64, padded or unpadded. No whitespace. Empty is invalid. */
|
|
5
|
+
export function decodeModuleB64(moduleB64) {
|
|
6
|
+
if (!MODULE_B64_RE.test(moduleB64) || moduleB64.length === 0 || moduleB64.length % 4 === 1) {
|
|
7
|
+
throw new AnchorClientError("MODULE_B64_INVALID", { source: "client" });
|
|
8
|
+
}
|
|
9
|
+
const padLen = (4 - (moduleB64.length % 4)) % 4;
|
|
10
|
+
const padded = moduleB64 + "=".repeat(padLen);
|
|
11
|
+
const bytes = Buffer.from(padded, "base64");
|
|
12
|
+
if (Buffer.from(bytes).toString("base64") !== padded) {
|
|
13
|
+
throw new AnchorClientError("MODULE_B64_INVALID", { source: "client" });
|
|
14
|
+
}
|
|
15
|
+
return new Uint8Array(bytes);
|
|
16
|
+
}
|
|
17
|
+
/** Unsigned claims. The caller signs them with the holder key. randomBytes here is a nonce, not a key. */
|
|
18
|
+
export function buildEnvelopeClaims(input) {
|
|
19
|
+
if (!input.voucherJws || !input.holderPeerId || !input.anchorPeerId) {
|
|
20
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
21
|
+
}
|
|
22
|
+
const nonce = input.nonce ?? randomBytes(16).toString("base64url");
|
|
23
|
+
if (!/^[A-Za-z0-9_-]{16,64}$/.test(nonce)) {
|
|
24
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
v: 1,
|
|
28
|
+
aud: input.anchorPeerId,
|
|
29
|
+
sub: input.holderPeerId,
|
|
30
|
+
voucher: input.voucherJws,
|
|
31
|
+
mod: createHash("sha256").update(input.moduleBytes).digest("hex"),
|
|
32
|
+
ts: input.nowSec ?? Math.floor(Date.now() / 1000),
|
|
33
|
+
nonce,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Payload decode only. Does not verify the signature. */
|
|
37
|
+
export function decodeVoucherClaims(jws) {
|
|
38
|
+
const part = jws.split(".")[1];
|
|
39
|
+
if (!part)
|
|
40
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
41
|
+
let payload;
|
|
42
|
+
try {
|
|
43
|
+
payload = JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
47
|
+
}
|
|
48
|
+
if (!payload || typeof payload !== "object") {
|
|
49
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
50
|
+
}
|
|
51
|
+
const row = payload;
|
|
52
|
+
return {
|
|
53
|
+
sub: typeof row.sub === "string" ? row.sub : undefined,
|
|
54
|
+
aud: typeof row.aud === "string" ? row.aud : undefined,
|
|
55
|
+
exp: typeof row.exp === "number" ? row.exp : undefined,
|
|
56
|
+
mod: typeof row.mod === "string" ? row.mod : undefined,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AnchorWellKnown } from "@slicegrid/core";
|
|
2
|
+
export type RetryAction = "none" | "resend_same" | "resign_and_retry" | "wait_then_resign";
|
|
3
|
+
export type RetryHint = {
|
|
4
|
+
retryable: boolean;
|
|
5
|
+
action: RetryAction;
|
|
6
|
+
after_ms?: number;
|
|
7
|
+
note: string;
|
|
8
|
+
/** Set when the anchor may already have spent the voucher. */
|
|
9
|
+
outcome_unknown?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type WellKnownRate = {
|
|
12
|
+
limits?: {
|
|
13
|
+
rate?: {
|
|
14
|
+
per_sec?: number;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare function retryHint(code: string, wk?: WellKnownRate): RetryHint;
|
|
19
|
+
export declare function retryHintCodes(): string[];
|
|
20
|
+
export declare class AnchorClientError extends Error {
|
|
21
|
+
readonly code: string;
|
|
22
|
+
readonly http?: number;
|
|
23
|
+
readonly source: "anchor" | "client";
|
|
24
|
+
readonly retry: RetryHint;
|
|
25
|
+
constructor(code: string, opts?: {
|
|
26
|
+
http?: number;
|
|
27
|
+
source: "anchor" | "client";
|
|
28
|
+
wk?: AnchorWellKnown | WellKnownRate;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export {};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
function none(note) {
|
|
2
|
+
return { retryable: false, action: "none", note };
|
|
3
|
+
}
|
|
4
|
+
function wait(after_ms, note) {
|
|
5
|
+
return { retryable: true, action: "wait_then_resign", after_ms, note };
|
|
6
|
+
}
|
|
7
|
+
const OUTCOME_UNKNOWN = "The anchor may have processed this redeem. If it did, the voucher is spent, any retry returns REPLAY, and the receipt cannot be fetched again. A REPLAY after this is not a new failure.";
|
|
8
|
+
function lost() {
|
|
9
|
+
return {
|
|
10
|
+
retryable: true,
|
|
11
|
+
action: "resign_and_retry",
|
|
12
|
+
after_ms: 2000,
|
|
13
|
+
outcome_unknown: true,
|
|
14
|
+
note: OUTCOME_UNKNOWN,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function rateAfter(wk) {
|
|
18
|
+
const per = wk?.limits?.rate?.per_sec;
|
|
19
|
+
if (typeof per === "number" && per > 0 && Number.isFinite(per))
|
|
20
|
+
return Math.ceil(1000 / per);
|
|
21
|
+
return 1000;
|
|
22
|
+
}
|
|
23
|
+
const BUSY = "The nonce was consumed. Wait, then retry with a fresh nonce and ts.";
|
|
24
|
+
const HINTS = {
|
|
25
|
+
NOT_FOUND: () => none("That path is not served."),
|
|
26
|
+
BODY_TOO_LARGE: () => none("The framed body exceeds the anchor limit."),
|
|
27
|
+
RATE_LIMITED: (wk) => ({
|
|
28
|
+
retryable: true,
|
|
29
|
+
action: "resend_same",
|
|
30
|
+
after_ms: rateAfter(wk),
|
|
31
|
+
note: "Rejected before the body was read, so the nonce was not consumed.",
|
|
32
|
+
}),
|
|
33
|
+
ENVELOPE_INVALID: () => none("The envelope framing or header is not acceptable."),
|
|
34
|
+
SHAPE_INVALID: () => none("The envelope or voucher shape was rejected."),
|
|
35
|
+
ENVELOPE_STALE: () => ({
|
|
36
|
+
retryable: true,
|
|
37
|
+
action: "resign_and_retry",
|
|
38
|
+
note: "ts is outside the 60 second skew. Resign with a fresh ts and check the clock.",
|
|
39
|
+
}),
|
|
40
|
+
WRONG_SUB: () => none("Envelope sub, holder, and voucher sub do not match."),
|
|
41
|
+
REVOKED: () => none("The voucher, jti, or peer is revoked."),
|
|
42
|
+
REDEEM_HALTED: () => wait(60_000, "Redeem is halted. Wait, then send a fresh envelope."),
|
|
43
|
+
REVOCATION_SEQ: () => none("The revocation sequence was rejected."),
|
|
44
|
+
RUNTIME_BUSY: () => wait(2000, BUSY),
|
|
45
|
+
WRONG_HOST: () => none("Envelope aud is not this anchor."),
|
|
46
|
+
MOD_MISMATCH: () => none("The module does not match the voucher."),
|
|
47
|
+
REPLAY: () => none("This jti or nonce was already used."),
|
|
48
|
+
OVERSELL: () => none("The anchor residual cannot cover this voucher."),
|
|
49
|
+
NBF: () => ({
|
|
50
|
+
retryable: true,
|
|
51
|
+
action: "wait_then_resign",
|
|
52
|
+
note: "Wait until the voucher nbf, then resign the envelope.",
|
|
53
|
+
}),
|
|
54
|
+
EXPIRED: () => none("The voucher is expired."),
|
|
55
|
+
MOD_HASH_MISMATCH: () => none("sha256(module) does not match the envelope and the voucher."),
|
|
56
|
+
MODULE_TOO_LARGE: () => none("The module exceeds the wasm size limit."),
|
|
57
|
+
MODULE_INVALID: () => none("The module is not a valid wasm binary."),
|
|
58
|
+
WASM_IMPORT_DENIED: () => none("The module imports a denied symbol."),
|
|
59
|
+
WASM_MEMORY_CAP: () => none("The module memory exceeds the cap."),
|
|
60
|
+
TABLE_CAP: () => none("The module table exceeds the cap."),
|
|
61
|
+
MODULE_BYTES_REQUIRED: () => none("Redeem requires module bytes."),
|
|
62
|
+
RUNTIME_UNSUPPORTED: () => none("This anchor only runs wasm."),
|
|
63
|
+
SCHEMA: () => none("The payload schema was rejected."),
|
|
64
|
+
MOD_REQUIRED: () => none("The voucher is missing mod."),
|
|
65
|
+
VECTOR_INVALID: () => none("The resource vector was rejected."),
|
|
66
|
+
VECTOR_EMPTY: () => none("The resource vector has no active dimension."),
|
|
67
|
+
TAU_INVALID: () => none("tau_horizon_sec was rejected."),
|
|
68
|
+
TAU_PAST_EXP: () => none("tau extends past the voucher exp."),
|
|
69
|
+
TAU_UNSUPPORTED: () => none("This voucher tau is not supported."),
|
|
70
|
+
PREDICATE_INVALID: () => none("predicate_hash must be 64 lowercase hex on a wasm voucher."),
|
|
71
|
+
PREDICATE_UNSUPPORTED: () => none("This host has no wasm runtime to compare predicate_hash."),
|
|
72
|
+
PREDICATE_MISMATCH: () => none("The wasm output did not match predicate_hash. The voucher is spent."),
|
|
73
|
+
TAU_CAP: () => wait(2000, BUSY),
|
|
74
|
+
JWS_MALFORMED: () => none("The JWS is malformed."),
|
|
75
|
+
HEADER_PARSE: () => none("The JWS header did not parse."),
|
|
76
|
+
ALG: () => none("The JWS alg is not EdDSA."),
|
|
77
|
+
KID: () => none("The JWS kid was rejected."),
|
|
78
|
+
JWK_REQUIRED: () => none("The JWS header is missing jwk."),
|
|
79
|
+
INVALID_KEY: () => none("The JWS key is not Ed25519."),
|
|
80
|
+
KID_PEER_MISMATCH: () => none("The JWS kid does not match the key."),
|
|
81
|
+
PEER_MISMATCH: () => none("The JWS peer does not match."),
|
|
82
|
+
SIG_MALFORMED: () => none("The JWS signature is malformed."),
|
|
83
|
+
SIG_INVALID: () => none("The JWS signature did not verify."),
|
|
84
|
+
PAYLOAD_PARSE: () => none("The JWS payload did not parse."),
|
|
85
|
+
CASH_FIELD: () => none("A cash field was rejected."),
|
|
86
|
+
ISS_PEER_MISMATCH: () => none("The voucher issuer does not match the signing peer."),
|
|
87
|
+
VAULT_UNAVAILABLE: () => wait(2000, BUSY),
|
|
88
|
+
SKIM_UNAVAILABLE: () => wait(2000, BUSY),
|
|
89
|
+
INTERNAL: () => wait(5000, "The anchor returned INTERNAL. Retry once with a fresh envelope."),
|
|
90
|
+
ANCHOR_NOT_CONFIGURED: () => none("Set AGENT_PRIME_ANCHOR_URL. There is no default."),
|
|
91
|
+
ANCHOR_URL_INVALID: () => none("The anchor URL must be http or https, with no userinfo and no fragment."),
|
|
92
|
+
ANCHOR_UNREACHABLE: () => ({
|
|
93
|
+
retryable: true,
|
|
94
|
+
action: "resend_same",
|
|
95
|
+
after_ms: 2000,
|
|
96
|
+
note: "The request never reached the anchor. Resending the same bytes is safe.",
|
|
97
|
+
}),
|
|
98
|
+
ANCHOR_TIMEOUT: () => lost(),
|
|
99
|
+
ANCHOR_CONNECTION_LOST: () => lost(),
|
|
100
|
+
ANCHOR_BAD_RESPONSE: () => none("The anchor response was not a JSON object with an error code."),
|
|
101
|
+
INPUT_INVALID: () => none("The inputs are not usable."),
|
|
102
|
+
MODULE_B64_INVALID: () => none("module_b64 is not canonical standard base64."),
|
|
103
|
+
RESPONSE_TOO_LARGE: () => none("The response exceeds 1 MiB."),
|
|
104
|
+
};
|
|
105
|
+
export function retryHint(code, wk) {
|
|
106
|
+
const row = HINTS[code];
|
|
107
|
+
if (!row)
|
|
108
|
+
return none("The anchor refused this code.");
|
|
109
|
+
return row(wk);
|
|
110
|
+
}
|
|
111
|
+
export function retryHintCodes() {
|
|
112
|
+
return Object.keys(HINTS);
|
|
113
|
+
}
|
|
114
|
+
export class AnchorClientError extends Error {
|
|
115
|
+
code;
|
|
116
|
+
http;
|
|
117
|
+
source;
|
|
118
|
+
retry;
|
|
119
|
+
constructor(code, opts = {
|
|
120
|
+
source: "client",
|
|
121
|
+
}) {
|
|
122
|
+
super(code);
|
|
123
|
+
this.code = code;
|
|
124
|
+
this.name = "AnchorClientError";
|
|
125
|
+
this.http = opts.http;
|
|
126
|
+
this.source = opts.source;
|
|
127
|
+
this.retry = retryHint(code, opts.wk);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type AnchorFetchInit = {
|
|
2
|
+
method: "GET" | "POST";
|
|
3
|
+
timeoutMs: number;
|
|
4
|
+
body?: Uint8Array;
|
|
5
|
+
contentType?: string;
|
|
6
|
+
fetchImpl?: typeof fetch;
|
|
7
|
+
};
|
|
8
|
+
export type AnchorFetchResult = {
|
|
9
|
+
status: number;
|
|
10
|
+
body: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Count bytes as they arrive. Cancel the reader only while a read is still pending.
|
|
14
|
+
* A body that already finished is returned even if the signal aborts in the same turn.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readBodyCapped(res: Response, signal: AbortSignal, cap?: number): Promise<string>;
|
|
17
|
+
/** The only network call site in the distribution adapters. */
|
|
18
|
+
export declare function anchorFetch(origin: string, path: string, init: AnchorFetchInit): Promise<AnchorFetchResult>;
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { AnchorClientError } from "./errors.js";
|
|
2
|
+
const ALLOWED = new Set(["/.well-known/agent-prime.json", "/redeem"]);
|
|
3
|
+
function chain(e) {
|
|
4
|
+
const out = [];
|
|
5
|
+
let cur = e;
|
|
6
|
+
for (let i = 0; i < 5 && cur instanceof Error; i++) {
|
|
7
|
+
out.push(cur);
|
|
8
|
+
cur = cur.cause;
|
|
9
|
+
}
|
|
10
|
+
return out;
|
|
11
|
+
}
|
|
12
|
+
const NEVER_DELIVERED = new Set(["ECONNREFUSED", "ENOTFOUND", "EAI_AGAIN", "EHOSTUNREACH", "ENETUNREACH"]);
|
|
13
|
+
function netError(e) {
|
|
14
|
+
const errors = chain(e);
|
|
15
|
+
if (errors.some((err) => err.name === "TimeoutError" || err.name === "AbortError")) {
|
|
16
|
+
return new AnchorClientError("ANCHOR_TIMEOUT", { source: "client" });
|
|
17
|
+
}
|
|
18
|
+
const text = errors.map((err) => `${err.name} ${err.message}`).join("\n");
|
|
19
|
+
if (/redirect/i.test(text)) {
|
|
20
|
+
return new AnchorClientError("ANCHOR_BAD_RESPONSE", { source: "client" });
|
|
21
|
+
}
|
|
22
|
+
const code = errors.map((err) => err.code).find((item) => typeof item === "string");
|
|
23
|
+
if (typeof code === "string" && NEVER_DELIVERED.has(code)) {
|
|
24
|
+
return new AnchorClientError("ANCHOR_UNREACHABLE", { source: "client" });
|
|
25
|
+
}
|
|
26
|
+
return new AnchorClientError("ANCHOR_CONNECTION_LOST", { source: "client" });
|
|
27
|
+
}
|
|
28
|
+
const MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
29
|
+
function abortReason(signal, fallback) {
|
|
30
|
+
if (signal.reason instanceof Error)
|
|
31
|
+
return signal.reason;
|
|
32
|
+
if (fallback instanceof Error && (fallback.name === "TimeoutError" || fallback.name === "AbortError")) {
|
|
33
|
+
return fallback;
|
|
34
|
+
}
|
|
35
|
+
return new DOMException("The operation was aborted due to timeout", "TimeoutError");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Count bytes as they arrive. Cancel the reader only while a read is still pending.
|
|
39
|
+
* A body that already finished is returned even if the signal aborts in the same turn.
|
|
40
|
+
*/
|
|
41
|
+
export async function readBodyCapped(res, signal, cap = MAX_RESPONSE_BYTES) {
|
|
42
|
+
const declared = res.headers.get("content-length");
|
|
43
|
+
if (declared != null && declared !== "") {
|
|
44
|
+
const n = Number(declared);
|
|
45
|
+
if (Number.isFinite(n) && n > cap) {
|
|
46
|
+
await res.body?.cancel().catch(() => undefined);
|
|
47
|
+
throw new AnchorClientError("RESPONSE_TOO_LARGE", { http: res.status, source: "client" });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!res.body)
|
|
51
|
+
return "";
|
|
52
|
+
const reader = res.body.getReader();
|
|
53
|
+
const decoder = new TextDecoder();
|
|
54
|
+
let text = "";
|
|
55
|
+
let total = 0;
|
|
56
|
+
let reading = false;
|
|
57
|
+
let finished = false;
|
|
58
|
+
const onAbort = () => {
|
|
59
|
+
queueMicrotask(() => {
|
|
60
|
+
if (!finished && reading)
|
|
61
|
+
void reader.cancel(signal.reason).catch(() => undefined);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
if (!signal.aborted)
|
|
65
|
+
signal.addEventListener("abort", onAbort);
|
|
66
|
+
try {
|
|
67
|
+
for (;;) {
|
|
68
|
+
reading = true;
|
|
69
|
+
let next;
|
|
70
|
+
try {
|
|
71
|
+
next = await reader.read();
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
reading = false;
|
|
75
|
+
if (e instanceof AnchorClientError)
|
|
76
|
+
throw e;
|
|
77
|
+
if (signal.aborted)
|
|
78
|
+
throw abortReason(signal, e);
|
|
79
|
+
throw e;
|
|
80
|
+
}
|
|
81
|
+
reading = false;
|
|
82
|
+
if (next.done) {
|
|
83
|
+
finished = true;
|
|
84
|
+
text += decoder.decode();
|
|
85
|
+
try {
|
|
86
|
+
reader.releaseLock();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
/* already released by cancel */
|
|
90
|
+
}
|
|
91
|
+
return text;
|
|
92
|
+
}
|
|
93
|
+
total += next.value.byteLength;
|
|
94
|
+
if (total > cap) {
|
|
95
|
+
finished = true;
|
|
96
|
+
await reader.cancel().catch(() => undefined);
|
|
97
|
+
throw new AnchorClientError("RESPONSE_TOO_LARGE", { http: res.status, source: "client" });
|
|
98
|
+
}
|
|
99
|
+
text += decoder.decode(next.value, { stream: true });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
finished = true;
|
|
104
|
+
signal.removeEventListener("abort", onAbort);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** The only network call site in the distribution adapters. */
|
|
108
|
+
export async function anchorFetch(origin, path, init) {
|
|
109
|
+
if (!ALLOWED.has(path)) {
|
|
110
|
+
throw new AnchorClientError("INPUT_INVALID", { source: "client" });
|
|
111
|
+
}
|
|
112
|
+
const url = new URL(path, origin.endsWith("/") ? origin : `${origin}/`);
|
|
113
|
+
const headers = {};
|
|
114
|
+
if (init.contentType)
|
|
115
|
+
headers["content-type"] = init.contentType;
|
|
116
|
+
const signal = AbortSignal.timeout(init.timeoutMs);
|
|
117
|
+
const request = {
|
|
118
|
+
method: init.method,
|
|
119
|
+
redirect: "error",
|
|
120
|
+
signal,
|
|
121
|
+
headers,
|
|
122
|
+
body: init.body ? new Uint8Array(init.body) : undefined,
|
|
123
|
+
};
|
|
124
|
+
try {
|
|
125
|
+
const res = init.fetchImpl ? await init.fetchImpl(url, request) : await fetch(url, request);
|
|
126
|
+
const body = await readBodyCapped(res, signal);
|
|
127
|
+
return { status: res.status, body };
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
if (e instanceof AnchorClientError)
|
|
131
|
+
throw e;
|
|
132
|
+
throw netError(e);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DEFAULT_ANCHOR_TIMEOUT_MS, anchorUrlFromEnv, parseAnchorUrl } from "./config.js";
|
|
2
|
+
export { createAnchorClient, type AnchorClient } from "./client.js";
|
|
3
|
+
export { buildEnvelopeClaims, decodeModuleB64, decodeVoucherClaims, type EnvelopeClaims } from "./envelope.js";
|
|
4
|
+
export { AnchorClientError, retryHint, retryHintCodes, type RetryHint, type RetryAction } from "./errors.js";
|
|
5
|
+
export { anchorFetch, readBodyCapped } from "./http.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { DEFAULT_ANCHOR_TIMEOUT_MS, anchorUrlFromEnv, parseAnchorUrl } from "./config.js";
|
|
2
|
+
export { createAnchorClient } from "./client.js";
|
|
3
|
+
export { buildEnvelopeClaims, decodeModuleB64, decodeVoucherClaims } from "./envelope.js";
|
|
4
|
+
export { AnchorClientError, retryHint, retryHintCodes } from "./errors.js";
|
|
5
|
+
export { anchorFetch, readBodyCapped } from "./http.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAqB,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAuB,MAAM,eAAe,CAAC;AAC/G,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slicegrid/anchor-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "HTTP client for one Slice anchor. The caller supplies the holder-signed envelope.",
|
|
5
|
+
"author": "Slice <team@bagcollective.io>",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/slicegrid/slice-alpha.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/slicegrid/slice-alpha#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/slicegrid/slice-alpha/issues"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22"
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@slicegrid/core": "^0.3.1"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"slicegrid",
|
|
38
|
+
"wasm-sandbox",
|
|
39
|
+
"p2p-compute",
|
|
40
|
+
"agent-to-agent"
|
|
41
|
+
],
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|