@ixo/credentials-kit 0.0.0-stage → 0.1.1

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 (72) hide show
  1. package/README.md +469 -2
  2. package/dist/chunk-2SF56NEJ.js +1053 -0
  3. package/dist/chunk-2SF56NEJ.js.map +1 -0
  4. package/dist/chunk-46VRPQPD.js +176 -0
  5. package/dist/chunk-46VRPQPD.js.map +1 -0
  6. package/dist/chunk-AQ3IINHC.js +138 -0
  7. package/dist/chunk-AQ3IINHC.js.map +1 -0
  8. package/dist/chunk-FSKCDHZ7.js +613 -0
  9. package/dist/chunk-FSKCDHZ7.js.map +1 -0
  10. package/dist/chunk-I6GBYFIJ.js +89 -0
  11. package/dist/chunk-I6GBYFIJ.js.map +1 -0
  12. package/dist/chunk-JBUX6V2Q.js +210 -0
  13. package/dist/chunk-JBUX6V2Q.js.map +1 -0
  14. package/dist/chunk-Q3MZNMCK.js +183 -0
  15. package/dist/chunk-Q3MZNMCK.js.map +1 -0
  16. package/dist/chunk-RKKRO4ZK.js +133 -0
  17. package/dist/chunk-RKKRO4ZK.js.map +1 -0
  18. package/dist/chunk-STMMFNVW.js +391 -0
  19. package/dist/chunk-STMMFNVW.js.map +1 -0
  20. package/dist/chunk-VXKONZK4.js +189 -0
  21. package/dist/chunk-VXKONZK4.js.map +1 -0
  22. package/dist/chunk-WIEGZFUO.js +337 -0
  23. package/dist/chunk-WIEGZFUO.js.map +1 -0
  24. package/dist/chunk-WND2LZ4O.js +66 -0
  25. package/dist/chunk-WND2LZ4O.js.map +1 -0
  26. package/dist/chunk-XREZY53L.js +260 -0
  27. package/dist/chunk-XREZY53L.js.map +1 -0
  28. package/dist/chunk-ZZY4WGQ6.js +13 -0
  29. package/dist/chunk-ZZY4WGQ6.js.map +1 -0
  30. package/dist/did.d.ts +182 -0
  31. package/dist/did.js +6 -0
  32. package/dist/did.js.map +1 -0
  33. package/dist/display.d.ts +117 -0
  34. package/dist/display.js +5 -0
  35. package/dist/display.js.map +1 -0
  36. package/dist/errors-BKQmNpXX.d.ts +11 -0
  37. package/dist/holder.d.ts +85 -0
  38. package/dist/holder.js +8 -0
  39. package/dist/holder.js.map +1 -0
  40. package/dist/http-BhuJ_-RZ.d.ts +25 -0
  41. package/dist/index.d.ts +15 -0
  42. package/dist/index.js +16 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/jose.d.ts +134 -0
  45. package/dist/jose.js +4 -0
  46. package/dist/jose.js.map +1 -0
  47. package/dist/oid4vci.d.ts +428 -0
  48. package/dist/oid4vci.js +11 -0
  49. package/dist/oid4vci.js.map +1 -0
  50. package/dist/oid4vp.d.ts +416 -0
  51. package/dist/oid4vp.js +11 -0
  52. package/dist/oid4vp.js.map +1 -0
  53. package/dist/profile.d.ts +218 -0
  54. package/dist/profile.js +4 -0
  55. package/dist/profile.js.map +1 -0
  56. package/dist/sdjwt.d.ts +133 -0
  57. package/dist/sdjwt.js +5 -0
  58. package/dist/sdjwt.js.map +1 -0
  59. package/dist/sender.d.ts +8 -0
  60. package/dist/sender.js +7 -0
  61. package/dist/sender.js.map +1 -0
  62. package/dist/status.d.ts +108 -0
  63. package/dist/status.js +7 -0
  64. package/dist/status.js.map +1 -0
  65. package/dist/util-DOTEZgTt.d.ts +3 -0
  66. package/dist/verify.d.ts +144 -0
  67. package/dist/verify.js +9 -0
  68. package/dist/verify.js.map +1 -0
  69. package/dist/webhook.d.ts +62 -0
  70. package/dist/webhook.js +7 -0
  71. package/dist/webhook.js.map +1 -0
  72. package/package.json +168 -4
@@ -0,0 +1,183 @@
1
+ import { fromUtf8 } from './chunk-AQ3IINHC.js';
2
+
3
+ // src/internal/http.ts
4
+ var DEFAULT_TIMEOUT_MS = 1e4;
5
+ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
6
+ function isLoopbackHost(hostname) {
7
+ return LOOPBACK_HOSTS.has(hostname.toLowerCase());
8
+ }
9
+ function ipv4Parts(host) {
10
+ const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
11
+ if (!m) return null;
12
+ const parts = m.slice(1).map(Number);
13
+ return parts.every((p) => p <= 255) ? parts : null;
14
+ }
15
+ function isNonPublicIpv4(p) {
16
+ const [a, b] = p;
17
+ return a === 0 || // "this network"
18
+ a === 10 || // private
19
+ a === 127 || // loopback
20
+ a === 100 && b >= 64 && b <= 127 || // CGNAT
21
+ a === 169 && b === 254 || // link-local (cloud metadata)
22
+ a === 172 && b >= 16 && b <= 31 || // private
23
+ a === 192 && b === 168 || // private
24
+ a === 192 && b === 0 || // IETF protocol assignments / 192.0.0.0/24
25
+ a === 198 && (b === 18 || b === 19) || // benchmarking
26
+ a >= 224;
27
+ }
28
+ function ipv6Groups(host) {
29
+ if (!/^[0-9a-f:.]+$/i.test(host) || !host.includes(":")) return null;
30
+ let text = host;
31
+ const lastColon = text.lastIndexOf(":");
32
+ const last = text.slice(lastColon + 1);
33
+ if (last.includes(".")) {
34
+ const v4 = ipv4Parts(last);
35
+ if (!v4) return null;
36
+ const hi = (v4[0] << 8 | v4[1]).toString(16);
37
+ const lo = (v4[2] << 8 | v4[3]).toString(16);
38
+ text = `${text.slice(0, lastColon + 1)}${hi}:${lo}`;
39
+ }
40
+ const halves = text.split("::");
41
+ if (halves.length > 2) return null;
42
+ const parse = (s) => s.length === 0 ? [] : s.split(":").map((g) => Number.parseInt(g, 16));
43
+ const head = parse(halves[0]);
44
+ const rest = halves.length === 2 ? parse(halves[1]) : [];
45
+ if ([...head, ...rest].some((g) => !Number.isInteger(g) || g < 0 || g > 65535))
46
+ return null;
47
+ const missing = 8 - head.length - rest.length;
48
+ if (halves.length === 1 ? missing !== 0 : missing < 0) return null;
49
+ return [...head, ...new Array(missing).fill(0), ...rest];
50
+ }
51
+ function ipv4Of(hi, lo) {
52
+ return [hi >> 8, hi & 255, lo >> 8, lo & 255];
53
+ }
54
+ function isNonPublicIpv6(g) {
55
+ const allZeroUpTo = (n) => g.slice(0, n).every((x) => x === 0);
56
+ if (allZeroUpTo(8)) return true;
57
+ if (allZeroUpTo(7) && g[7] === 1) return true;
58
+ if (allZeroUpTo(5) && (g[5] === 65535 || g[5] === 0)) {
59
+ return isNonPublicIpv4(ipv4Of(g[6], g[7]));
60
+ }
61
+ if (allZeroUpTo(4) && g[4] === 65535 && g[5] === 0) {
62
+ return isNonPublicIpv4(ipv4Of(g[6], g[7]));
63
+ }
64
+ const first = g[0];
65
+ if (first === 8194) return isNonPublicIpv4(ipv4Of(g[1], g[2]));
66
+ if (first === 8193 && (g[1] === 0 || g[1] === 3512)) return true;
67
+ return (first & 65024) === 64512 || // unique-local fc00::/7
68
+ (first & 65472) === 65152 || // link-local fe80::/10
69
+ (first & 65472) === 65216 || // site-local (deprecated) fec0::/10
70
+ (first & 65280) === 65280 || // multicast ff00::/8
71
+ first === 100 || // NAT64 64:ff9b::/96 and 64:ff9b:1::/48 map into IPv4 space
72
+ first === 256;
73
+ }
74
+ var PRIVATE_NAME_SUFFIXES = [
75
+ ".localhost",
76
+ ".local",
77
+ ".internal",
78
+ ".lan",
79
+ ".home.arpa",
80
+ ".home",
81
+ ".corp",
82
+ ".intranet",
83
+ ".private",
84
+ ".localdomain"
85
+ ];
86
+ function isPrivateHost(hostname) {
87
+ let host = hostname.toLowerCase();
88
+ if (host.endsWith(".")) host = host.slice(0, -1);
89
+ if (host.length === 0) return true;
90
+ if (host.startsWith("[") && host.endsWith("]")) {
91
+ const groups = ipv6Groups(host.slice(1, -1));
92
+ return groups === null ? true : isNonPublicIpv6(groups);
93
+ }
94
+ const v4 = ipv4Parts(host);
95
+ if (v4) return isNonPublicIpv4(v4);
96
+ if (!host.includes(".")) return true;
97
+ return PRIVATE_NAME_SUFFIXES.some((suffix) => host.endsWith(suffix));
98
+ }
99
+ function isFetchableUrl(url, policy = {}) {
100
+ let u;
101
+ try {
102
+ u = new URL(url);
103
+ } catch {
104
+ return false;
105
+ }
106
+ if (u.username || u.password || u.hash) return false;
107
+ if (!(policy.allowLocal ?? false) && isPrivateHost(u.hostname)) return false;
108
+ if (u.protocol === "https:") return true;
109
+ return (policy.allowHttp ?? false) && u.protocol === "http:" && isLoopbackHost(u.hostname);
110
+ }
111
+ var HttpError = class extends Error {
112
+ constructor(kind, status = null) {
113
+ super(
114
+ kind === "status" ? `answered HTTP ${status ?? 0}` : `request ${kind}`
115
+ );
116
+ this.kind = kind;
117
+ this.status = status;
118
+ this.name = "HttpError";
119
+ }
120
+ kind;
121
+ status;
122
+ };
123
+ async function readCapped(res, max) {
124
+ const declared = Number(res.headers.get("content-length") ?? "");
125
+ if (Number.isFinite(declared) && declared > max) {
126
+ await res.body?.cancel().catch(() => void 0);
127
+ throw new HttpError("too_large", res.status);
128
+ }
129
+ const reader = res.body?.getReader();
130
+ if (!reader) return "";
131
+ const chunks = [];
132
+ let size = 0;
133
+ for (; ; ) {
134
+ const { done, value } = await reader.read();
135
+ if (done) break;
136
+ size += value.byteLength;
137
+ if (size > max) {
138
+ await reader.cancel().catch(() => void 0);
139
+ throw new HttpError("too_large", res.status);
140
+ }
141
+ chunks.push(value);
142
+ }
143
+ const out = new Uint8Array(size);
144
+ let at = 0;
145
+ for (const c of chunks) {
146
+ out.set(c, at);
147
+ at += c.byteLength;
148
+ }
149
+ return fromUtf8(out);
150
+ }
151
+ async function request(fetchFn, url, opts) {
152
+ let res;
153
+ try {
154
+ res = await fetchFn(url, {
155
+ method: opts.method ?? "GET",
156
+ headers: opts.headers ?? {},
157
+ ...opts.body !== void 0 ? { body: opts.body } : {},
158
+ redirect: "manual",
159
+ signal: AbortSignal.timeout(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS)
160
+ });
161
+ } catch {
162
+ throw new HttpError("unreachable");
163
+ }
164
+ if (res.status >= 300 && res.status < 400) {
165
+ await res.body?.cancel().catch(() => void 0);
166
+ throw new HttpError("status", res.status);
167
+ }
168
+ if (res.type === "opaqueredirect" || res.status === 0) {
169
+ throw new HttpError("status", res.status);
170
+ }
171
+ let text;
172
+ try {
173
+ text = await readCapped(res, opts.maxBytes);
174
+ } catch (e) {
175
+ if (e instanceof HttpError) throw e;
176
+ throw new HttpError("unreachable");
177
+ }
178
+ return { status: res.status, headers: res.headers, text };
179
+ }
180
+
181
+ export { DEFAULT_TIMEOUT_MS, HttpError, isFetchableUrl, isLoopbackHost, isPrivateHost, request };
182
+ //# sourceMappingURL=chunk-Q3MZNMCK.js.map
183
+ //# sourceMappingURL=chunk-Q3MZNMCK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/http.ts"],"names":[],"mappings":"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","file":"chunk-Q3MZNMCK.js","sourcesContent":["/**\n * Outbound HTTP for every module that reaches the network. The caller passes `fetch`; every\n * call sets `redirect: 'manual'` (a 3xx is an error, never followed), a timeout, and reads the\n * body no further than a byte cap.\n *\n * Host policy (SPEC §2.1, §13.2/§13.3): unless the caller passes `allowLocal`, URLs whose host is\n * a loopback, private, link-local, CGNAT, unique-local, multicast or otherwise non-public IP\n * literal (also inside an IPv6 6to4, NAT64, Teredo, IPv4-mapped or IPv4-translated address), a\n * single-label name (`intranet`: DNS search domains resolve it to an internal host), or a name\n * that is `localhost` or ends in a private-use suffix (`.localhost`, `.local`, `.internal`,\n * `.lan`, `.home.arpa`, `.home`, `.corp`, `.intranet`, `.private`, `.localdomain`) is refused.\n * Names are not resolved here: DNS rebinding to a private address still needs the runtime's\n * egress policy (Cloudflare Workers cannot reach private networks).\n */\nimport { fromUtf8 } from './bytes';\n\n/** The subset of `fetch` the kit uses. Pass `globalThis.fetch` (bound) or a test double. */\nexport type FetchLike = (\n input: string,\n init?: RequestInit\n) => Promise<Response>;\n\nexport const DEFAULT_TIMEOUT_MS = 10_000;\n\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);\n\n/** True for localhost, 127.0.0.1 and [::1]. */\nexport function isLoopbackHost(hostname: string): boolean {\n return LOOPBACK_HOSTS.has(hostname.toLowerCase());\n}\n\nfunction ipv4Parts(host: string): number[] | null {\n const m = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(host);\n if (!m) return null;\n const parts = m.slice(1).map(Number);\n return parts.every(p => p <= 255) ? parts : null;\n}\n\nfunction isNonPublicIpv4(p: number[]): boolean {\n const [a, b] = p as [number, number, number, number];\n return (\n a === 0 || // \"this network\"\n a === 10 || // private\n a === 127 || // loopback\n (a === 100 && b >= 64 && b <= 127) || // CGNAT\n (a === 169 && b === 254) || // link-local (cloud metadata)\n (a === 172 && b >= 16 && b <= 31) || // private\n (a === 192 && b === 168) || // private\n (a === 192 && b === 0) || // IETF protocol assignments / 192.0.0.0/24\n (a === 198 && (b === 18 || b === 19)) || // benchmarking\n a >= 224 // multicast, reserved, broadcast\n );\n}\n\n/** Expand an IPv6 literal (no brackets) into 8 16-bit groups; null when it is not one. */\nfunction ipv6Groups(host: string): number[] | null {\n if (!/^[0-9a-f:.]+$/i.test(host) || !host.includes(':')) return null;\n let text = host;\n // A trailing dotted IPv4 part (::ffff:1.2.3.4) becomes its two hex groups.\n const lastColon = text.lastIndexOf(':');\n const last = text.slice(lastColon + 1);\n if (last.includes('.')) {\n const v4 = ipv4Parts(last);\n if (!v4) return null;\n const hi = ((v4[0]! << 8) | v4[1]!).toString(16);\n const lo = ((v4[2]! << 8) | v4[3]!).toString(16);\n text = `${text.slice(0, lastColon + 1)}${hi}:${lo}`;\n }\n const halves = text.split('::');\n if (halves.length > 2) return null;\n const parse = (s: string) =>\n s.length === 0 ? [] : s.split(':').map(g => Number.parseInt(g, 16));\n const head = parse(halves[0]!);\n const rest = halves.length === 2 ? parse(halves[1]!) : [];\n if ([...head, ...rest].some(g => !Number.isInteger(g) || g < 0 || g > 0xffff))\n return null;\n const missing = 8 - head.length - rest.length;\n if (halves.length === 1 ? missing !== 0 : missing < 0) return null;\n return [...head, ...new Array<number>(missing).fill(0), ...rest];\n}\n\n/** The IPv4 address held in two 16-bit groups. */\nfunction ipv4Of(hi: number, lo: number): number[] {\n return [hi >> 8, hi & 0xff, lo >> 8, lo & 0xff];\n}\n\nfunction isNonPublicIpv6(g: number[]): boolean {\n const allZeroUpTo = (n: number) => g.slice(0, n).every(x => x === 0);\n if (allZeroUpTo(8)) return true; // ::\n if (allZeroUpTo(7) && g[7] === 1) return true; // ::1\n // IPv4-mapped (::ffff:a.b.c.d) and IPv4-compatible (::a.b.c.d): judge the IPv4 address.\n if (allZeroUpTo(5) && (g[5] === 0xffff || g[5] === 0)) {\n return isNonPublicIpv4(ipv4Of(g[6]!, g[7]!));\n }\n // IPv4-translated (::ffff:0:a.b.c.d, RFC 2765): judge the IPv4 address.\n if (allZeroUpTo(4) && g[4] === 0xffff && g[5] === 0) {\n return isNonPublicIpv4(ipv4Of(g[6]!, g[7]!));\n }\n const first = g[0]!;\n // 6to4 (2002:a.b.c.d::/48, RFC 3056): the site's IPv4 address is in groups 1-2.\n if (first === 0x2002) return isNonPublicIpv4(ipv4Of(g[1]!, g[2]!));\n // Teredo (2001:0::/32, RFC 4380) tunnels to an obfuscated IPv4 client; documentation\n // (2001:db8::/32): never a credentials host.\n if (first === 0x2001 && (g[1] === 0 || g[1] === 0x0db8)) return true;\n return (\n (first & 0xfe00) === 0xfc00 || // unique-local fc00::/7\n (first & 0xffc0) === 0xfe80 || // link-local fe80::/10\n (first & 0xffc0) === 0xfec0 || // site-local (deprecated) fec0::/10\n (first & 0xff00) === 0xff00 || // multicast ff00::/8\n first === 0x64 || // NAT64 64:ff9b::/96 and 64:ff9b:1::/48 map into IPv4 space\n first === 0x100 // discard-only 100::/64\n );\n}\n\n/** Private-use and local name suffixes (RFC 6761, RFC 8375, ICANN `.internal`, common LAN use). */\nconst PRIVATE_NAME_SUFFIXES = [\n '.localhost',\n '.local',\n '.internal',\n '.lan',\n '.home.arpa',\n '.home',\n '.corp',\n '.intranet',\n '.private',\n '.localdomain',\n];\n\n/**\n * True when `hostname` (as `new URL(...).hostname` gives it: IPv4 normalised, IPv6 in brackets)\n * is not a public internet host: a non-public IP literal (also embedded in 6to4, NAT64, Teredo,\n * IPv4-mapped or IPv4-translated IPv6), a single-label name, `localhost`, or a name ending in\n * `.localhost`, `.local`, `.internal`, `.lan`, `.home.arpa`, `.home`, `.corp`, `.intranet`,\n * `.private` or `.localdomain`.\n */\nexport function isPrivateHost(hostname: string): boolean {\n let host = hostname.toLowerCase();\n if (host.endsWith('.')) host = host.slice(0, -1);\n if (host.length === 0) return true;\n if (host.startsWith('[') && host.endsWith(']')) {\n const groups = ipv6Groups(host.slice(1, -1));\n return groups === null ? true : isNonPublicIpv6(groups);\n }\n const v4 = ipv4Parts(host);\n if (v4) return isNonPublicIpv4(v4);\n // A name without a dot is completed by the resolver's search domains: an internal host.\n if (!host.includes('.')) return true;\n return PRIVATE_NAME_SUFFIXES.some(suffix => host.endsWith(suffix));\n}\n\nexport interface HostPolicy {\n /** http on a loopback host (local development only). */\n allowHttp?: boolean;\n /** Loopback / private / link-local / local-name hosts (local development only). */\n allowLocal?: boolean;\n}\n\n/**\n * An https URL (or, only with `allowHttp`, an http URL on a loopback host) without credentials or\n * fragment, whose host passes the host policy (`allowLocal` lifts it). Local development needs\n * both flags for `http://localhost:…`.\n */\nexport function isFetchableUrl(url: string, policy: HostPolicy = {}): boolean {\n let u: URL;\n try {\n u = new URL(url);\n } catch {\n return false;\n }\n if (u.username || u.password || u.hash) return false;\n if (!(policy.allowLocal ?? false) && isPrivateHost(u.hostname)) return false;\n if (u.protocol === 'https:') return true;\n return (\n (policy.allowHttp ?? false) &&\n u.protocol === 'http:' &&\n isLoopbackHost(u.hostname)\n );\n}\n\nexport class HttpError extends Error {\n constructor(\n readonly kind: 'unreachable' | 'status' | 'too_large',\n readonly status: number | null = null\n ) {\n super(\n kind === 'status' ? `answered HTTP ${status ?? 0}` : `request ${kind}`\n );\n this.name = 'HttpError';\n }\n}\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT';\n headers?: Record<string, string>;\n body?: string;\n maxBytes: number;\n timeoutMs?: number;\n}\n\nexport interface CappedResponse {\n status: number;\n headers: Headers;\n text: string;\n}\n\n/** Read a response body as UTF-8 text, at most `max` bytes (longer throws `too_large`). */\nexport async function readCapped(res: Response, max: number): Promise<string> {\n const declared = Number(res.headers.get('content-length') ?? '');\n if (Number.isFinite(declared) && declared > max) {\n await res.body?.cancel().catch(() => undefined);\n throw new HttpError('too_large', res.status);\n }\n const reader = res.body?.getReader();\n if (!reader) return '';\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > max) {\n await reader.cancel().catch(() => undefined);\n throw new HttpError('too_large', res.status);\n }\n chunks.push(value);\n }\n const out = new Uint8Array(size);\n let at = 0;\n for (const c of chunks) {\n out.set(c, at);\n at += c.byteLength;\n }\n return fromUtf8(out);\n}\n\n/**\n * One request with the kit's rules. Network failure, timeout (also while the body is read), a\n * body that fails mid-read and a 3xx throw `HttpError`; a body over `maxBytes` throws\n * `HttpError('too_large')`; any other status is returned to the caller with its (capped) body.\n */\nexport async function request(\n fetchFn: FetchLike,\n url: string,\n opts: RequestOptions\n): Promise<CappedResponse> {\n let res: Response;\n try {\n res = await fetchFn(url, {\n method: opts.method ?? 'GET',\n headers: opts.headers ?? {},\n ...(opts.body !== undefined ? { body: opts.body } : {}),\n redirect: 'manual',\n signal: AbortSignal.timeout(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS),\n });\n } catch {\n throw new HttpError('unreachable');\n }\n if (res.status >= 300 && res.status < 400) {\n await res.body?.cancel().catch(() => undefined);\n throw new HttpError('status', res.status);\n }\n // A manual redirect in browsers is an opaque response with status 0.\n if (res.type === 'opaqueredirect' || res.status === 0) {\n throw new HttpError('status', res.status);\n }\n // A body that fails half way (connection reset, the timeout firing during the read) is\n // `unreachable` like a failed fetch, never a raw TypeError / AbortError (PD-08). `too_large`\n // stays as it is.\n let text: string;\n try {\n text = await readCapped(res, opts.maxBytes);\n } catch (e) {\n if (e instanceof HttpError) throw e;\n throw new HttpError('unreachable');\n }\n return { status: res.status, headers: res.headers, text };\n}\n"]}
@@ -0,0 +1,133 @@
1
+ import { senderKeyOf } from './chunk-ZZY4WGQ6.js';
2
+ import { request, DEFAULT_TIMEOUT_MS, HttpError, isFetchableUrl } from './chunk-Q3MZNMCK.js';
3
+ import { CredentialsKitError } from './chunk-VXKONZK4.js';
4
+
5
+ // src/holder.ts
6
+ function requestBinding(method, url) {
7
+ return { method: method.toUpperCase(), path: new URL(url).pathname };
8
+ }
9
+ var MAX_ANSWER_BYTES = 64 * 1024;
10
+ var MAX_MESSAGE_LENGTH = 300;
11
+ var MAX_DID_LENGTH = 256;
12
+ var UNREACHABLE = "We couldn't reach the credentials service.";
13
+ var BAD_RESPONSE = "The credentials service's answer wasn't readable.";
14
+ var REFUSED = "The credentials service refused the request.";
15
+ var CredentialsServiceError = class extends CredentialsKitError {
16
+ constructor(code, message, status, reference) {
17
+ super(code, message);
18
+ this.status = status;
19
+ this.reference = reference;
20
+ }
21
+ status;
22
+ reference;
23
+ };
24
+ function checkSender(sender) {
25
+ if (typeof sender !== "string" || sender.length > MAX_DID_LENGTH || senderKeyOf(sender) === null)
26
+ throw new TypeError(
27
+ "sender must be a did:ixo person or entity DID, or a did:web, in canonical form"
28
+ );
29
+ return sender;
30
+ }
31
+ function endpoint(opts, path) {
32
+ if (typeof opts.authorize !== "function")
33
+ throw new TypeError("authorize must be a function");
34
+ if (typeof opts.serviceUrl !== "string" || !isFetchableUrl(opts.serviceUrl, opts))
35
+ throw new TypeError(
36
+ "serviceUrl must be https on a public host (allowHttp / allowLocal for local development)"
37
+ );
38
+ return `${new URL(opts.serviceUrl).origin}${path}`;
39
+ }
40
+ async function holderCall(opts, method, path, query, body) {
41
+ const url = endpoint(opts, path);
42
+ const token = await opts.authorize(requestBinding(method, url));
43
+ if (typeof token !== "string" || token.length === 0)
44
+ throw new TypeError("authorize must return the serialized invocation");
45
+ let res;
46
+ try {
47
+ res = await request(opts.fetch, `${url}${query}`, {
48
+ method,
49
+ headers: {
50
+ authorization: `Bearer ${token}`,
51
+ accept: "application/json",
52
+ ...body !== void 0 ? { "content-type": "application/json" } : {}
53
+ },
54
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {},
55
+ maxBytes: MAX_ANSWER_BYTES,
56
+ timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS
57
+ });
58
+ } catch (err) {
59
+ if (err instanceof HttpError)
60
+ throw new CredentialsServiceError(
61
+ err.kind === "too_large" ? "bad_response" : "unreachable",
62
+ err.kind === "too_large" ? BAD_RESPONSE : UNREACHABLE,
63
+ err.status
64
+ );
65
+ throw err;
66
+ }
67
+ let json;
68
+ try {
69
+ json = JSON.parse(res.text);
70
+ } catch {
71
+ json = void 0;
72
+ }
73
+ if (res.status >= 200 && res.status < 300) return json;
74
+ const envelope = json && typeof json === "object" ? json : {};
75
+ const code = typeof envelope.error === "string" && /^[a-z_]{1,64}$/.test(envelope.error) ? envelope.error : "bad_response";
76
+ const message = typeof envelope.message === "string" && envelope.message.length <= MAX_MESSAGE_LENGTH ? envelope.message : REFUSED;
77
+ const reference = typeof envelope.reference === "string" && envelope.reference.length <= 128 ? envelope.reference : void 0;
78
+ throw new CredentialsServiceError(code, message, res.status, reference);
79
+ }
80
+ function badResponse(status) {
81
+ throw new CredentialsServiceError("bad_response", BAD_RESPONSE, status);
82
+ }
83
+ var isWhole = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0;
84
+ function senderBlockOf(v) {
85
+ if (!v || typeof v !== "object") return null;
86
+ const o = v;
87
+ return typeof o.sender === "string" && isWhole(o.created_at) ? { sender: o.sender, created_at: o.created_at } : null;
88
+ }
89
+ async function blockSender(opts) {
90
+ const sender = checkSender(opts.sender);
91
+ const json = await holderCall(opts, "POST", "/v1/blocks", "", { sender });
92
+ const block = senderBlockOf(json);
93
+ const closed = json?.closed;
94
+ if (!block || !isWhole(closed)) badResponse(200);
95
+ return { ...block, closed };
96
+ }
97
+ async function unblockSender(opts) {
98
+ const sender = checkSender(opts.sender);
99
+ const json = await holderCall(opts, "POST", "/v1/blocks/remove", "", {
100
+ sender
101
+ });
102
+ if (typeof json?.sender !== "string" || typeof json.removed !== "boolean")
103
+ badResponse(200);
104
+ return { sender: json.sender, removed: json.removed };
105
+ }
106
+ async function listBlocks(opts) {
107
+ const params = new URLSearchParams();
108
+ if (opts.limit !== void 0) {
109
+ if (!Number.isInteger(opts.limit) || opts.limit < 1 || opts.limit > 100)
110
+ throw new TypeError("limit must be a whole number from 1 to 100");
111
+ params.set("limit", String(opts.limit));
112
+ }
113
+ if (opts.cursor !== void 0) {
114
+ if (typeof opts.cursor !== "string" || opts.cursor.length > 512)
115
+ throw new TypeError("cursor must be the next_cursor of the last page");
116
+ params.set("cursor", opts.cursor);
117
+ }
118
+ const encoded = params.toString();
119
+ const query = encoded ? `?${encoded}` : "";
120
+ const json = await holderCall(opts, "GET", "/v1/blocks", query);
121
+ if (!Array.isArray(json?.items) || !(json.next_cursor === null || typeof json.next_cursor === "string"))
122
+ badResponse(200);
123
+ const items = json.items.map(senderBlockOf);
124
+ if (items.some((i) => i === null)) badResponse(200);
125
+ return {
126
+ items,
127
+ next_cursor: json.next_cursor
128
+ };
129
+ }
130
+
131
+ export { CredentialsServiceError, blockSender, listBlocks, requestBinding, unblockSender };
132
+ //# sourceMappingURL=chunk-RKKRO4ZK.js.map
133
+ //# sourceMappingURL=chunk-RKKRO4ZK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/holder.ts"],"names":[],"mappings":"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","file":"chunk-RKKRO4ZK.js","sourcesContent":["/**\n * `@ixo/credentials-kit/holder` — a wallet's calls to the Credentials worker as the person\n * (ability `credentials/hold`, principal = the person). For now: the person's block list (SPEC\n * §16.1): `blockSender`, `unblockSender`, `listBlocks`.\n *\n * Conventions (SPEC §5.1, §13.1), the same as every other call to the worker:\n * - every call carries a FRESH, single-use UCAN invocation, minted by the caller's `authorize`\n * for exactly that request: audience = the worker's did:web (its `/.well-known/did.json`),\n * capability `credentials/hold` on `ixo:credentials`, lifetime at most 300 s, and the\n * request-binding fact `{ method, path }` this module passes in (method upper-case, the full\n * path without the query string). The kit does not depend on a UCAN library: mint it with\n * `@ixo/ucan` (`createInvocation` + `serializeInvocation`) or your own;\n * - the worker's URL must pass the kit's host policy (https on a public host; local development\n * passes `allowHttp` / `allowLocal`); requests never follow redirects, always time out, and the\n * answer is read no further than 64 KB.\n *\n * Errors: `CredentialsServiceError` with the worker's error `code` (`blocked`, `too_many_blocks`,\n * `invalid_request`, `unauthenticated`, `forbidden`, `rate_limited`, `unavailable`, …), the HTTP\n * `status`, and `reference` (the worker's request id, for support); `unreachable` (network,\n * timeout, redirect; status null or the 3xx) and `bad_response` (an answer that is not the\n * documented shape) when the worker did not answer properly. A wrong argument throws `TypeError`.\n */\nimport { CredentialsKitError } from './internal/errors';\nimport {\n DEFAULT_TIMEOUT_MS,\n HttpError,\n isFetchableUrl,\n request,\n type FetchLike,\n type HostPolicy,\n} from './internal/http';\nimport type {\n BlockSenderResult,\n SenderBlock,\n SenderBlockList,\n UnblockSenderResult,\n} from './profile';\nimport { senderKeyOf } from './sender';\n\nexport type {\n BlockSenderResult,\n SenderBlock,\n SenderBlockList,\n UnblockSenderResult,\n} from './profile';\n\n/** The request an invocation is bound to (SPEC §13.1). */\nexport interface RequestBinding {\n /** Upper-case HTTP method. */\n method: string;\n /** The full request path, without the query string. */\n path: string;\n}\n\n/** The request-binding fact for `method` + `url` (the path only, never the query). */\nexport function requestBinding(method: string, url: string): RequestBinding {\n return { method: method.toUpperCase(), path: new URL(url).pathname };\n}\n\nexport interface HolderCallOptions extends HostPolicy {\n /** The Credentials worker's origin, e.g. `https://credentials.ixo.world`. */\n serviceUrl: string;\n /**\n * Mint a fresh, single-use UCAN invocation (base64 CAR) bound to `binding`: issuer = the\n * person (or a key the person delegated `credentials/hold` to), audience = the worker's\n * did:web, capability `credentials/hold` on `ixo:credentials`, at most 300 s, and the fact\n * `{ method, path }` equal to `binding`.\n */\n authorize: (binding: RequestBinding) => Promise<string>;\n fetch: FetchLike;\n /** Default 10 s. */\n timeoutMs?: number;\n}\n\nconst MAX_ANSWER_BYTES = 64 * 1024;\nconst MAX_MESSAGE_LENGTH = 300;\nconst MAX_DID_LENGTH = 256;\n\nconst UNREACHABLE = \"We couldn't reach the credentials service.\";\nconst BAD_RESPONSE = \"The credentials service's answer wasn't readable.\";\nconst REFUSED = 'The credentials service refused the request.';\n\n/** A call to the Credentials worker that did not succeed. */\nexport class CredentialsServiceError extends CredentialsKitError {\n constructor(\n code: string,\n message: string,\n /** The HTTP status, or null when the worker could not be reached. */\n readonly status: number | null,\n /** The worker's request id (its `reference`), for support. */\n readonly reference?: string\n ) {\n super(code, message);\n }\n}\n\n/** A sender must be in its canonical form (`senderKeyOf`), or no block could ever match it. */\nfunction checkSender(sender: unknown): string {\n if (\n typeof sender !== 'string' ||\n sender.length > MAX_DID_LENGTH ||\n senderKeyOf(sender) === null\n )\n throw new TypeError(\n 'sender must be a did:ixo person or entity DID, or a did:web, in canonical form'\n );\n return sender;\n}\n\nfunction endpoint(opts: HolderCallOptions, path: string): string {\n if (typeof opts.authorize !== 'function')\n throw new TypeError('authorize must be a function');\n if (\n typeof opts.serviceUrl !== 'string' ||\n !isFetchableUrl(opts.serviceUrl, opts)\n )\n throw new TypeError(\n 'serviceUrl must be https on a public host (allowHttp / allowLocal for local development)'\n );\n return `${new URL(opts.serviceUrl).origin}${path}`;\n}\n\n/** One call: bound invocation, kit HTTP rules, error envelope -> CredentialsServiceError. */\nasync function holderCall(\n opts: HolderCallOptions,\n method: 'GET' | 'POST',\n path: string,\n query: string,\n body?: unknown\n): Promise<unknown> {\n const url = endpoint(opts, path);\n const token = await opts.authorize(requestBinding(method, url));\n if (typeof token !== 'string' || token.length === 0)\n throw new TypeError('authorize must return the serialized invocation');\n let res;\n try {\n res = await request(opts.fetch, `${url}${query}`, {\n method,\n headers: {\n authorization: `Bearer ${token}`,\n accept: 'application/json',\n ...(body !== undefined ? { 'content-type': 'application/json' } : {}),\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n maxBytes: MAX_ANSWER_BYTES,\n timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n });\n } catch (err) {\n if (err instanceof HttpError)\n throw new CredentialsServiceError(\n err.kind === 'too_large' ? 'bad_response' : 'unreachable',\n err.kind === 'too_large' ? BAD_RESPONSE : UNREACHABLE,\n err.status\n );\n throw err;\n }\n let json: unknown;\n try {\n json = JSON.parse(res.text);\n } catch {\n json = undefined;\n }\n if (res.status >= 200 && res.status < 300) return json;\n const envelope =\n json && typeof json === 'object'\n ? (json as { error?: unknown; message?: unknown; reference?: unknown })\n : {};\n const code =\n typeof envelope.error === 'string' && /^[a-z_]{1,64}$/.test(envelope.error)\n ? envelope.error\n : 'bad_response';\n const message =\n typeof envelope.message === 'string' &&\n envelope.message.length <= MAX_MESSAGE_LENGTH\n ? envelope.message\n : REFUSED;\n const reference =\n typeof envelope.reference === 'string' && envelope.reference.length <= 128\n ? envelope.reference\n : undefined;\n throw new CredentialsServiceError(code, message, res.status, reference);\n}\n\nfunction badResponse(status: number): never {\n throw new CredentialsServiceError('bad_response', BAD_RESPONSE, status);\n}\n\nconst isWhole = (v: unknown): v is number =>\n typeof v === 'number' && Number.isInteger(v) && v >= 0;\n\nfunction senderBlockOf(v: unknown): SenderBlock | null {\n if (!v || typeof v !== 'object') return null;\n const o = v as Record<string, unknown>;\n return typeof o.sender === 'string' && isWhole(o.created_at)\n ? { sender: o.sender, created_at: o.created_at }\n : null;\n}\n\n/**\n * `POST /v1/blocks`: the person blocks `sender` (a did:ixo or did:web in canonical form; the\n * block covers exactly this DID, never another DID on the same host, SPEC §17.4). Idempotent. The worker closes the sender's waiting offers and requests for the person as\n * declined (`closed`) and refuses its later deposits with 403 `blocked`. At most 500 blocks per\n * person (`too_many_blocks`).\n */\nexport async function blockSender(\n opts: HolderCallOptions & { sender: string }\n): Promise<BlockSenderResult> {\n const sender = checkSender(opts.sender);\n const json = await holderCall(opts, 'POST', '/v1/blocks', '', { sender });\n const block = senderBlockOf(json);\n const closed = (json as { closed?: unknown } | null)?.closed;\n if (!block || !isWhole(closed)) badResponse(200);\n return { ...block, closed };\n}\n\n/** `POST /v1/blocks/remove`: the person unblocks `sender`. Idempotent (`removed: false`). */\nexport async function unblockSender(\n opts: HolderCallOptions & { sender: string }\n): Promise<UnblockSenderResult> {\n const sender = checkSender(opts.sender);\n const json = (await holderCall(opts, 'POST', '/v1/blocks/remove', '', {\n sender,\n })) as { sender?: unknown; removed?: unknown } | null;\n if (typeof json?.sender !== 'string' || typeof json.removed !== 'boolean')\n badResponse(200);\n return { sender: json.sender, removed: json.removed };\n}\n\n/** `GET /v1/blocks`: one page of the person's blocks, newest first (`limit` 1–100, `cursor`). */\nexport async function listBlocks(\n opts: HolderCallOptions & { cursor?: string; limit?: number }\n): Promise<SenderBlockList> {\n const params = new URLSearchParams();\n if (opts.limit !== undefined) {\n if (!Number.isInteger(opts.limit) || opts.limit < 1 || opts.limit > 100)\n throw new TypeError('limit must be a whole number from 1 to 100');\n params.set('limit', String(opts.limit));\n }\n if (opts.cursor !== undefined) {\n if (typeof opts.cursor !== 'string' || opts.cursor.length > 512)\n throw new TypeError('cursor must be the next_cursor of the last page');\n params.set('cursor', opts.cursor);\n }\n const encoded = params.toString();\n const query = encoded ? `?${encoded}` : '';\n const json = (await holderCall(opts, 'GET', '/v1/blocks', query)) as {\n items?: unknown;\n next_cursor?: unknown;\n } | null;\n if (\n !Array.isArray(json?.items) ||\n !(json.next_cursor === null || typeof json.next_cursor === 'string')\n )\n badResponse(200);\n const items = json.items.map(senderBlockOf);\n if (items.some(i => i === null)) badResponse(200);\n return {\n items: items as SenderBlock[],\n next_cursor: json.next_cursor,\n };\n}\n"]}