@hoodfi/sdk 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.
- package/README.md +103 -2
- package/dist/abi.d.ts +106 -0
- package/dist/abi.d.ts.map +1 -0
- package/dist/abi.js +34 -0
- package/dist/abi.js.map +1 -0
- package/dist/client.d.ts +145 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +304 -0
- package/dist/client.js.map +1 -0
- package/dist/coins.d.ts +34 -0
- package/dist/coins.d.ts.map +1 -0
- package/dist/coins.js +53 -0
- package/dist/coins.js.map +1 -0
- package/dist/constants.d.ts +31 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +38 -0
- package/dist/constants.js.map +1 -0
- package/dist/contenthash.d.ts +96 -0
- package/dist/contenthash.d.ts.map +1 -0
- package/dist/contenthash.js +385 -0
- package/dist/contenthash.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/labels.d.ts +45 -0
- package/dist/labels.d.ts.map +1 -0
- package/dist/labels.js +83 -0
- package/dist/labels.js.map +1 -0
- package/dist/xrp.d.ts +24 -0
- package/dist/xrp.d.ts.map +1 -0
- package/dist/xrp.js +43 -0
- package/dist/xrp.js.map +1 -0
- package/package.json +41 -4
- package/src/abi.ts +35 -0
- package/src/client.ts +481 -0
- package/src/coins.ts +76 -0
- package/src/constants.ts +41 -0
- package/src/contenthash.ts +408 -0
- package/src/index.ts +30 -0
- package/src/labels.ts +91 -0
- package/src/xrp.ts +44 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EIP-1577 contenthash — the record that turns a name into a website.
|
|
3
|
+
*
|
|
4
|
+
* Only the IPFS family is handled, which is the whole of what this site can honestly
|
|
5
|
+
* offer: names are minted here, pinned here and served through IPFS gateways here.
|
|
6
|
+
* Swarm and Arweave namespaces exist in the spec and are deliberately not accepted —
|
|
7
|
+
* writing one would produce a record we can't preview, can't link to, and can't tell
|
|
8
|
+
* an owner is working.
|
|
9
|
+
*
|
|
10
|
+
* The stored bytes are <protoCode varint><CID>, so a record is two decisions: which
|
|
11
|
+
* namespace, and a CID the gateways will accept.
|
|
12
|
+
*
|
|
13
|
+
* ## One copy, imported by three packages
|
|
14
|
+
*
|
|
15
|
+
* The site writes records on `/manage` and reads them on `/search`; the MCP worker
|
|
16
|
+
* (`mcp/src/tools.ts`) does both for agents; the gateway's share page is next. Two
|
|
17
|
+
* implementations of a byte format is the thing to avoid above all else here — a
|
|
18
|
+
* contenthash off by one byte is a *well-formed* record that resolves to nothing, on a
|
|
19
|
+
* name whose owner has no way to tell it is broken. So there is exactly one copy, this
|
|
20
|
+
* is it, and the workers import it across the repo by relative path.
|
|
21
|
+
*
|
|
22
|
+
* **Why it sits under `frontend/` rather than a top-level `shared/`:** Turbopack refuses
|
|
23
|
+
* to resolve any import that leaves its project root — a `@shared/*` alias pointing at
|
|
24
|
+
* `../shared` fails the build with "aliased to relative '../shared/…' inside of
|
|
25
|
+
* [project]/" — and Vercel builds this app with `frontend/` as its Root Directory, so a
|
|
26
|
+
* sibling directory is not guaranteed to be in the build at all. The workers have no
|
|
27
|
+
* such restriction: esbuild follows a relative path anywhere. So the file lives where
|
|
28
|
+
* the fussiest consumer can see it, and `shared/` names it for the others.
|
|
29
|
+
*
|
|
30
|
+
* **It has no bare imports on purpose.** Whoever bundles it resolves `node_modules` by
|
|
31
|
+
* walking up from *this* file, which would silently tie the workers to whatever version
|
|
32
|
+
* the site happens to have installed — and break them entirely if the site's install is
|
|
33
|
+
* missing. Everything needed is small, pure and specified: hex, base32, base58 and
|
|
34
|
+
* base36 come to ~60 lines, they are checked vector-by-vector against `multiformats` in
|
|
35
|
+
* `contenthash.test.mjs`, and being dependency-free is what lets that test run under
|
|
36
|
+
* plain `node` with nothing installed.
|
|
37
|
+
*
|
|
38
|
+
* It must also stay clean under `noUncheckedIndexedAccess`, which `mcp/` sets and the
|
|
39
|
+
* site does not. Reasonable for a parser: every index here is into attacker-supplied
|
|
40
|
+
* input.
|
|
41
|
+
*/
|
|
42
|
+
/** uvarint(0xe3) — ipfs-ns. */
|
|
43
|
+
const IPFS_NS = [0xe3, 0x01];
|
|
44
|
+
/** uvarint(0xe5) — ipns-ns. */
|
|
45
|
+
const IPNS_NS = [0xe5, 0x01];
|
|
46
|
+
/** Multicodecs a CID may carry for each namespace. dag-pb is a directory (a site), raw a single file. */
|
|
47
|
+
const IPFS_CODECS = [0x70, 0x55];
|
|
48
|
+
const IPNS_CODEC = 0x72; // libp2p-key
|
|
49
|
+
/*//////////////////////////////////////////////////////////////
|
|
50
|
+
HEX
|
|
51
|
+
//////////////////////////////////////////////////////////////*/
|
|
52
|
+
function hexToBytes(hex) {
|
|
53
|
+
const body = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
54
|
+
if (body.length % 2 !== 0)
|
|
55
|
+
throw new Error("Odd-length hex");
|
|
56
|
+
if (body.length > 0 && !/^[0-9a-f]+$/i.test(body))
|
|
57
|
+
throw new Error("Not hex");
|
|
58
|
+
const bytes = new Uint8Array(body.length / 2);
|
|
59
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
60
|
+
bytes[i] = Number.parseInt(body.slice(i * 2, i * 2 + 2), 16);
|
|
61
|
+
}
|
|
62
|
+
return bytes;
|
|
63
|
+
}
|
|
64
|
+
function bytesToHex(bytes) {
|
|
65
|
+
let out = "";
|
|
66
|
+
for (const byte of bytes)
|
|
67
|
+
out += byte.toString(16).padStart(2, "0");
|
|
68
|
+
return `0x${out}`;
|
|
69
|
+
}
|
|
70
|
+
/*//////////////////////////////////////////////////////////////
|
|
71
|
+
MULTIBASE
|
|
72
|
+
//////////////////////////////////////////////////////////////*/
|
|
73
|
+
const BASE36 = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
74
|
+
/** RFC 4648 base32, upper case, no padding. */
|
|
75
|
+
const BASE32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
76
|
+
/** Bitcoin base58 — no 0, O, I or l, so a CID can survive being read aloud. */
|
|
77
|
+
const BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
78
|
+
/**
|
|
79
|
+
* base-N over a big integer, for the two bases whose digits don't align to bit
|
|
80
|
+
* boundaries. Leading zero bytes are carried explicitly in both directions: a
|
|
81
|
+
* big-integer conversion drops them, and for a CID that would silently change which
|
|
82
|
+
* key the record points at.
|
|
83
|
+
*/
|
|
84
|
+
function bigBaseDecode(input, alphabet) {
|
|
85
|
+
const radix = BigInt(alphabet.length);
|
|
86
|
+
let value = 0n;
|
|
87
|
+
for (const char of input) {
|
|
88
|
+
const digit = alphabet.indexOf(char);
|
|
89
|
+
if (digit < 0)
|
|
90
|
+
throw new Error(`Not base${alphabet.length}`);
|
|
91
|
+
value = value * radix + BigInt(digit);
|
|
92
|
+
}
|
|
93
|
+
const bytes = [];
|
|
94
|
+
while (value > 0n) {
|
|
95
|
+
bytes.unshift(Number(value & 0xffn));
|
|
96
|
+
value >>= 8n;
|
|
97
|
+
}
|
|
98
|
+
const zero = alphabet[0];
|
|
99
|
+
for (const char of input) {
|
|
100
|
+
if (char !== zero)
|
|
101
|
+
break;
|
|
102
|
+
bytes.unshift(0);
|
|
103
|
+
}
|
|
104
|
+
return new Uint8Array(bytes);
|
|
105
|
+
}
|
|
106
|
+
function bigBaseEncode(bytes, alphabet) {
|
|
107
|
+
const radix = BigInt(alphabet.length);
|
|
108
|
+
let value = 0n;
|
|
109
|
+
for (const byte of bytes)
|
|
110
|
+
value = (value << 8n) | BigInt(byte);
|
|
111
|
+
let out = "";
|
|
112
|
+
while (value > 0n) {
|
|
113
|
+
out = alphabet[Number(value % radix)] + out;
|
|
114
|
+
value /= radix;
|
|
115
|
+
}
|
|
116
|
+
for (const byte of bytes) {
|
|
117
|
+
if (byte !== 0)
|
|
118
|
+
break;
|
|
119
|
+
out = `${alphabet[0]}${out}`;
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
/** base36, lowercase — multibase prefix `k`, the form IPNS names are published in. */
|
|
124
|
+
function base36Decode(input) {
|
|
125
|
+
return bigBaseDecode(input, BASE36);
|
|
126
|
+
}
|
|
127
|
+
function base36Encode(bytes) {
|
|
128
|
+
return bigBaseEncode(bytes, BASE36);
|
|
129
|
+
}
|
|
130
|
+
/** base58, no checksum — the encoding inside a `Qm…` CIDv0. */
|
|
131
|
+
function base58Decode(input) {
|
|
132
|
+
return bigBaseDecode(input, BASE58);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* base32 with no padding, lowercase — multibase prefix `b`, the canonical CIDv1 form.
|
|
136
|
+
*
|
|
137
|
+
* Bit-accumulator rather than a big integer: base32's 5 bits divide into bytes, so the
|
|
138
|
+
* only thing to get right is the tail. Encoding pads the last group with zero bits;
|
|
139
|
+
* decoding drops a remainder of fewer than 8 bits rather than emitting a byte from it,
|
|
140
|
+
* which is what makes an unpadded string round-trip.
|
|
141
|
+
*/
|
|
142
|
+
function base32Decode(input) {
|
|
143
|
+
const upper = input.toUpperCase();
|
|
144
|
+
const bytes = [];
|
|
145
|
+
let bits = 0;
|
|
146
|
+
let value = 0;
|
|
147
|
+
for (const char of upper) {
|
|
148
|
+
const digit = BASE32.indexOf(char);
|
|
149
|
+
if (digit < 0)
|
|
150
|
+
throw new Error("Not base32");
|
|
151
|
+
value = (value << 5) | digit;
|
|
152
|
+
bits += 5;
|
|
153
|
+
if (bits >= 8) {
|
|
154
|
+
bits -= 8;
|
|
155
|
+
bytes.push((value >> bits) & 0xff);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return new Uint8Array(bytes);
|
|
159
|
+
}
|
|
160
|
+
function base32Encode(bytes) {
|
|
161
|
+
let out = "";
|
|
162
|
+
let bits = 0;
|
|
163
|
+
let value = 0;
|
|
164
|
+
for (const byte of bytes) {
|
|
165
|
+
value = (value << 8) | byte;
|
|
166
|
+
bits += 8;
|
|
167
|
+
while (bits >= 5) {
|
|
168
|
+
bits -= 5;
|
|
169
|
+
out += BASE32[(value >> bits) & 0x1f];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (bits > 0)
|
|
173
|
+
out += BASE32[(value << (5 - bits)) & 0x1f];
|
|
174
|
+
return out.toLowerCase();
|
|
175
|
+
}
|
|
176
|
+
/*//////////////////////////////////////////////////////////////
|
|
177
|
+
VARINT
|
|
178
|
+
//////////////////////////////////////////////////////////////*/
|
|
179
|
+
/** Reads an unsigned varint, returning the value and where it ended. */
|
|
180
|
+
function readVarint(bytes, offset) {
|
|
181
|
+
let value = 0;
|
|
182
|
+
let shift = 0;
|
|
183
|
+
let i = offset;
|
|
184
|
+
while (i < bytes.length) {
|
|
185
|
+
const byte = bytes[i];
|
|
186
|
+
if (byte === undefined)
|
|
187
|
+
break;
|
|
188
|
+
value |= (byte & 0x7f) << shift;
|
|
189
|
+
i += 1;
|
|
190
|
+
if ((byte & 0x80) === 0)
|
|
191
|
+
return [value >>> 0, i];
|
|
192
|
+
shift += 7;
|
|
193
|
+
if (shift > 28)
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
throw new Error("Malformed varint");
|
|
197
|
+
}
|
|
198
|
+
/*//////////////////////////////////////////////////////////////
|
|
199
|
+
CID
|
|
200
|
+
//////////////////////////////////////////////////////////////*/
|
|
201
|
+
/**
|
|
202
|
+
* Rejects anything that isn't a well-formed CIDv1 for the namespace it claims.
|
|
203
|
+
*
|
|
204
|
+
* The length check is what catches a truncated paste. A CID is base-encoded, so half a
|
|
205
|
+
* CID decodes to bytes perfectly happily — only the multihash's own length prefix says
|
|
206
|
+
* how many bytes should have followed it, and a record written from a half-CID resolves
|
|
207
|
+
* to nothing forever with no error anywhere to explain why.
|
|
208
|
+
*/
|
|
209
|
+
function isValidCid(bytes, codecs) {
|
|
210
|
+
try {
|
|
211
|
+
if (bytes[0] !== 0x01)
|
|
212
|
+
return false;
|
|
213
|
+
const [codec, afterCodec] = readVarint(bytes, 1);
|
|
214
|
+
if (!codecs.includes(codec))
|
|
215
|
+
return false;
|
|
216
|
+
const [, afterHashCode] = readVarint(bytes, afterCodec);
|
|
217
|
+
const [digestLength, afterLength] = readVarint(bytes, afterHashCode);
|
|
218
|
+
return bytes.length - afterLength === digestLength && digestLength > 0;
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** Decodes any multibase form a user might paste into raw CID bytes. */
|
|
225
|
+
function decodeMultibase(id) {
|
|
226
|
+
try {
|
|
227
|
+
// CIDv0 — a bare base58 multihash, always dag-pb. Kept as its own case because it
|
|
228
|
+
// has no multibase prefix at all: the leading `Qm` is part of the hash.
|
|
229
|
+
if (/^Qm[1-9A-HJ-NP-Za-km-z]{44}$/.test(id)) {
|
|
230
|
+
return new Uint8Array([0x01, 0x70, ...base58Decode(id)]);
|
|
231
|
+
}
|
|
232
|
+
if (/^b[a-z2-7]+$/i.test(id))
|
|
233
|
+
return base32Decode(id.slice(1));
|
|
234
|
+
if (/^k[0-9a-z]+$/.test(id))
|
|
235
|
+
return base36Decode(id.slice(1));
|
|
236
|
+
// A raw libp2p peer id, which is how IPNS names were published before base36.
|
|
237
|
+
if (/^1[1-9A-HJ-NP-Za-km-z]{10,}$/.test(id)) {
|
|
238
|
+
return new Uint8Array([0x01, IPNS_CODEC, ...base58Decode(id)]);
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/*//////////////////////////////////////////////////////////////
|
|
247
|
+
PUBLIC INTERFACE
|
|
248
|
+
//////////////////////////////////////////////////////////////*/
|
|
249
|
+
/**
|
|
250
|
+
* Reads what the registry holds. Returns null for an unset record and — deliberately —
|
|
251
|
+
* for a record in a namespace this site doesn't handle, so callers can't offer a
|
|
252
|
+
* "Visit" button pointing somewhere they were never able to check.
|
|
253
|
+
*/
|
|
254
|
+
export function decodeContenthash(stored) {
|
|
255
|
+
if (!stored || stored === "0x")
|
|
256
|
+
return null;
|
|
257
|
+
try {
|
|
258
|
+
const bytes = hexToBytes(stored);
|
|
259
|
+
const [namespace, offset] = readVarint(bytes, 0);
|
|
260
|
+
const cid = bytes.slice(offset);
|
|
261
|
+
if (namespace === 0xe3 && isValidCid(cid, IPFS_CODECS)) {
|
|
262
|
+
const id = `b${base32Encode(cid)}`;
|
|
263
|
+
return { protocol: "ipfs", id, uri: `ipfs://${id}` };
|
|
264
|
+
}
|
|
265
|
+
if (namespace === 0xe5 && isValidCid(cid, [IPNS_CODEC])) {
|
|
266
|
+
const id = `k${base36Encode(cid)}`;
|
|
267
|
+
return { protocol: "ipns", id, uri: `ipns://${id}` };
|
|
268
|
+
}
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Whatever an owner pasted -> the bytes to store, or null if it can't be one.
|
|
277
|
+
*
|
|
278
|
+
* Generous about the input because everything people copy is a different shape of the
|
|
279
|
+
* same CID: the URI form, a bare CID, a gateway link with the CID in the path, and a
|
|
280
|
+
* subdomain gateway link with it in the host. Every one of those is unambiguous, and
|
|
281
|
+
* refusing them would only teach owners to hand-edit a URL until it looks like ours.
|
|
282
|
+
*/
|
|
283
|
+
export function encodeContenthash(input) {
|
|
284
|
+
const parsed = parseContentInput(input);
|
|
285
|
+
if (!parsed)
|
|
286
|
+
return null;
|
|
287
|
+
const namespace = parsed.protocol === "ipfs" ? IPFS_NS : IPNS_NS;
|
|
288
|
+
return bytesToHex(new Uint8Array([...namespace, ...parsed.cid]));
|
|
289
|
+
}
|
|
290
|
+
/** The same parse, exposed for the editor's "what you're about to publish" preview. */
|
|
291
|
+
export function parseContenthash(input) {
|
|
292
|
+
const parsed = parseContentInput(input);
|
|
293
|
+
if (!parsed)
|
|
294
|
+
return null;
|
|
295
|
+
const id = parsed.protocol === "ipfs"
|
|
296
|
+
? `b${base32Encode(parsed.cid)}`
|
|
297
|
+
: `k${base36Encode(parsed.cid)}`;
|
|
298
|
+
return { protocol: parsed.protocol, id, uri: `${parsed.protocol}://${id}` };
|
|
299
|
+
}
|
|
300
|
+
function parseContentInput(input) {
|
|
301
|
+
let value = input.trim();
|
|
302
|
+
if (!value)
|
|
303
|
+
return null;
|
|
304
|
+
let protocol = null;
|
|
305
|
+
// A gateway link: the CID sits either in the path (/ipfs/<cid>) or, on a subdomain
|
|
306
|
+
// gateway, in the host (<cid>.ipfs.dweb.link).
|
|
307
|
+
const httpMatch = value.match(/^https?:\/\/([^/]+)(\/.*)?$/i);
|
|
308
|
+
if (httpMatch) {
|
|
309
|
+
const host = httpMatch[1] ?? "";
|
|
310
|
+
const path = httpMatch[2] ?? "";
|
|
311
|
+
const pathMatch = path.match(/\/(ipfs|ipns)\/([^/?#]+)/i);
|
|
312
|
+
const hostMatch = host.match(/^([^.]+)\.(ipfs|ipns)\./i);
|
|
313
|
+
// Every group read below is inside its own alternative and non-optional in the
|
|
314
|
+
// pattern, so it is present whenever the match is — but the checks are spelled out
|
|
315
|
+
// because a bundler that strips them would leave the string "undefined" being
|
|
316
|
+
// parsed as a CID.
|
|
317
|
+
if (pathMatch?.[1] && pathMatch[2]) {
|
|
318
|
+
protocol = pathMatch[1].toLowerCase();
|
|
319
|
+
value = pathMatch[2];
|
|
320
|
+
}
|
|
321
|
+
else if (hostMatch?.[1] && hostMatch[2]) {
|
|
322
|
+
protocol = hostMatch[2].toLowerCase();
|
|
323
|
+
value = hostMatch[1];
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const uriMatch = value.match(/^(ipfs|ipns):\/\/(?:(?:ipfs|ipns)\/)?(.+)$/i);
|
|
330
|
+
if (uriMatch?.[1] && uriMatch[2]) {
|
|
331
|
+
protocol = uriMatch[1].toLowerCase();
|
|
332
|
+
value = uriMatch[2];
|
|
333
|
+
}
|
|
334
|
+
// A CID can carry a trailing path — the record can't, and storing the CID alone
|
|
335
|
+
// would quietly point at a different page than the one that was pasted.
|
|
336
|
+
const id = value.replace(/\/+$/, "");
|
|
337
|
+
if (id.includes("/") || id.includes("?") || id.includes("#"))
|
|
338
|
+
return null;
|
|
339
|
+
let cid = decodeMultibase(id);
|
|
340
|
+
if (!cid)
|
|
341
|
+
return null;
|
|
342
|
+
// A `Qm…` peer id and a `Qm…` file CID are the same 34 bytes; only the prefix that
|
|
343
|
+
// was typed tells them apart, so an explicit ipns:// re-labels it as a key.
|
|
344
|
+
if (protocol === "ipns" && cid[0] === 0x01 && cid[1] === 0x70) {
|
|
345
|
+
cid = new Uint8Array([0x01, IPNS_CODEC, ...cid.slice(2)]);
|
|
346
|
+
}
|
|
347
|
+
// Otherwise the CID itself says which namespace it belongs to, and it outranks the
|
|
348
|
+
// prefix: `ipfs://k51…` is a key, not a file, however it was pasted.
|
|
349
|
+
if (isValidCid(cid, IPFS_CODECS))
|
|
350
|
+
return { protocol: "ipfs", cid };
|
|
351
|
+
if (isValidCid(cid, [IPNS_CODEC]))
|
|
352
|
+
return { protocol: "ipns", cid };
|
|
353
|
+
// Everything left is a CID in a codec no gateway would serve as a page.
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* A URL that serves the site today, for anyone in an ordinary browser.
|
|
358
|
+
*
|
|
359
|
+
* Deliberately a *subdomain* gateway: a path gateway (`/ipfs/<cid>/`) serves every page
|
|
360
|
+
* from one origin, so a site's own absolute links, its styles and its scripts resolve
|
|
361
|
+
* against the gateway root and the page arrives unstyled. The subdomain form gives the
|
|
362
|
+
* CID its own origin and the site loads as its author built it.
|
|
363
|
+
*
|
|
364
|
+
* Not our own Pinata gateway, which serves only what this account pinned and 403s
|
|
365
|
+
* everything else — owners publish their sites wherever they like.
|
|
366
|
+
*/
|
|
367
|
+
export function contentGatewayUrl(content) {
|
|
368
|
+
return `https://${content.id}.${content.protocol}.dweb.link/`;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* The address the name itself answers on.
|
|
372
|
+
*
|
|
373
|
+
* This is the point of setting the record — the CID link above is the fallback that
|
|
374
|
+
* always works, this is the one worth telling people.
|
|
375
|
+
*
|
|
376
|
+
* `.eth.link` and `.eth.limo` both serve a hoodfi subname (verified on gm.hoodfi.eth
|
|
377
|
+
* once the first record existed) and both are run by eth.limo, so this is a naming
|
|
378
|
+
* call rather than a technical one: `.link` reads as what it is. Kept as one function
|
|
379
|
+
* so every place that shows an owner their address and sends a visitor to it can
|
|
380
|
+
* never drift apart.
|
|
381
|
+
*/
|
|
382
|
+
export function nameUrl(label) {
|
|
383
|
+
return `https://${label}.hoodfi.eth.link/`;
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=contenthash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contenthash.js","sourceRoot":"","sources":["../src/contenthash.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createHoodfiClient, HoodfiError, type HoodfiClient, type HoodfiClientOptions, type HoodfiErrorCode, type NameCheck, type NameProfile, type SendAddress, type AddressLookup, type OwnedName, type Registration, type TxStep, type TextKey, } from './client.js';
|
|
2
|
+
export { CHAINS, SEND_CHAINS, paymentCaveat, type SendChain } from './coins.js';
|
|
3
|
+
export { checkHoodfiName, checkLabel, fullName, normalizeLabel, tierOf, MAX_LABEL_LENGTH, PUBLIC_MIN_LENGTH, STATUS_TEXT, type NameStatus, } from './labels.js';
|
|
4
|
+
export { decodeContenthash, type ContentHash } from './contenthash.js';
|
|
5
|
+
export { registrarAbi, registryAbi } from './abi.js';
|
|
6
|
+
export * from './constants.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,KAAK,OAAO,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AAC/E,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,cAAc,EACd,MAAM,EACN,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,KAAK,UAAU,GAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACpD,cAAc,gBAAgB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createHoodfiClient, HoodfiError, } from './client.js';
|
|
2
|
+
export { CHAINS, SEND_CHAINS, paymentCaveat } from './coins.js';
|
|
3
|
+
export { checkHoodfiName, checkLabel, fullName, normalizeLabel, tierOf, MAX_LABEL_LENGTH, PUBLIC_MIN_LENGTH, STATUS_TEXT, } from './labels.js';
|
|
4
|
+
export { decodeContenthash } from './contenthash.js';
|
|
5
|
+
export { registrarAbi, registryAbi } from './abi.js';
|
|
6
|
+
export * from './constants.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,WAAW,GAYZ,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAkB,MAAM,YAAY,CAAA;AAC/E,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,cAAc,EACd,MAAM,EACN,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,GAEZ,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,iBAAiB,EAAoB,MAAM,kBAAkB,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACpD,cAAc,gBAAgB,CAAA"}
|
package/dist/labels.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label rules, mirroring LabelUtils.sol (and mcp/src/labels.ts). The contract enforces
|
|
3
|
+
* the same rules; this exists so a bad name fails with a sentence before any RPC call.
|
|
4
|
+
*/
|
|
5
|
+
export declare const MAX_LABEL_LENGTH = 32;
|
|
6
|
+
/** Shortest label at the $3 floor. 1-3 characters are premium tiers ($15 / $10 / $5). */
|
|
7
|
+
export declare const PUBLIC_MIN_LENGTH = 4;
|
|
8
|
+
export type LabelCheck = {
|
|
9
|
+
ok: true;
|
|
10
|
+
label: string;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
reason: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Accepts `foo`, `foo.hoodfi.eth` or `foo.eth` and returns the bare label.
|
|
17
|
+
*
|
|
18
|
+
* Only for minting, where "you typed vitalik.eth, here is vitalik.hoodfi.eth" is a
|
|
19
|
+
* convenience. Never use it to decide who to pay: see {@link checkHoodfiName}.
|
|
20
|
+
*/
|
|
21
|
+
export declare function normalizeLabel(input: string): string;
|
|
22
|
+
export declare function checkLabel(input: string): LabelCheck;
|
|
23
|
+
export type HoodfiNameCheck = {
|
|
24
|
+
ok: true;
|
|
25
|
+
labels: string[];
|
|
26
|
+
name: string;
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
reason: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* For reading or paying a name: its labels under hoodfi.eth, or a reason to refuse.
|
|
33
|
+
*
|
|
34
|
+
* Stricter than {@link normalizeLabel} on purpose. `vitalik.eth` is NOT rewritten to
|
|
35
|
+
* `vitalik.hoodfi.eth`: that is a different name anyone can mint, so "pay vitalik.eth"
|
|
36
|
+
* would pay whoever did. Only a bare label or a name ending in `.hoodfi.eth` passes.
|
|
37
|
+
*/
|
|
38
|
+
export declare function checkHoodfiName(input: string): HoodfiNameCheck;
|
|
39
|
+
/** Tier index 0-3 (1 char, 2 chars, 3 chars, 4+). Mirrors LabelUtils.tierOf. */
|
|
40
|
+
export declare function tierOf(label: string): 0 | 1 | 2 | 3;
|
|
41
|
+
export declare function fullName(label: string): string;
|
|
42
|
+
export type NameStatus = 'available' | 'taken' | 'locked' | 'invalid' | 'blocked';
|
|
43
|
+
/** HoodfiRegistrar.status() codes, in words. */
|
|
44
|
+
export declare const STATUS_TEXT: Record<number, NameStatus>;
|
|
45
|
+
//# sourceMappingURL=labels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,yFAAyF;AACzF,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAElC,MAAM,MAAM,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAapD;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1G;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAuB9D;AAED,gFAAgF;AAChF,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAEnD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAA;AAEjF,gDAAgD;AAChD,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAMlD,CAAA"}
|
package/dist/labels.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label rules, mirroring LabelUtils.sol (and mcp/src/labels.ts). The contract enforces
|
|
3
|
+
* the same rules; this exists so a bad name fails with a sentence before any RPC call.
|
|
4
|
+
*/
|
|
5
|
+
import { PARENT } from './constants.js';
|
|
6
|
+
export const MAX_LABEL_LENGTH = 32;
|
|
7
|
+
/** Shortest label at the $3 floor. 1-3 characters are premium tiers ($15 / $10 / $5). */
|
|
8
|
+
export const PUBLIC_MIN_LENGTH = 4;
|
|
9
|
+
/**
|
|
10
|
+
* Accepts `foo`, `foo.hoodfi.eth` or `foo.eth` and returns the bare label.
|
|
11
|
+
*
|
|
12
|
+
* Only for minting, where "you typed vitalik.eth, here is vitalik.hoodfi.eth" is a
|
|
13
|
+
* convenience. Never use it to decide who to pay: see {@link checkHoodfiName}.
|
|
14
|
+
*/
|
|
15
|
+
export function normalizeLabel(input) {
|
|
16
|
+
return input.trim().toLowerCase().replace(/\.hoodfi\.eth$/, '').replace(/\.eth$/, '');
|
|
17
|
+
}
|
|
18
|
+
export function checkLabel(input) {
|
|
19
|
+
const label = normalizeLabel(input);
|
|
20
|
+
if (label.length === 0)
|
|
21
|
+
return { ok: false, reason: 'Name is empty' };
|
|
22
|
+
if (label.length > MAX_LABEL_LENGTH)
|
|
23
|
+
return { ok: false, reason: `Names are at most ${MAX_LABEL_LENGTH} characters` };
|
|
24
|
+
if (!/^[a-z0-9-]+$/.test(label))
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
reason: 'Names may only contain a-z, 0-9 and hyphens. Unicode and uppercase are rejected on-chain.',
|
|
28
|
+
};
|
|
29
|
+
if (label.startsWith('-') || label.endsWith('-'))
|
|
30
|
+
return { ok: false, reason: 'Names cannot start or end with a hyphen' };
|
|
31
|
+
return { ok: true, label };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* For reading or paying a name: its labels under hoodfi.eth, or a reason to refuse.
|
|
35
|
+
*
|
|
36
|
+
* Stricter than {@link normalizeLabel} on purpose. `vitalik.eth` is NOT rewritten to
|
|
37
|
+
* `vitalik.hoodfi.eth`: that is a different name anyone can mint, so "pay vitalik.eth"
|
|
38
|
+
* would pay whoever did. Only a bare label or a name ending in `.hoodfi.eth` passes.
|
|
39
|
+
*/
|
|
40
|
+
export function checkHoodfiName(input) {
|
|
41
|
+
const name = input.trim().toLowerCase();
|
|
42
|
+
const suffix = `.${PARENT}`;
|
|
43
|
+
let labels;
|
|
44
|
+
if (name.endsWith(suffix))
|
|
45
|
+
labels = name.slice(0, -suffix.length).split('.');
|
|
46
|
+
else if (!name.includes('.'))
|
|
47
|
+
labels = [name];
|
|
48
|
+
else if (name === PARENT)
|
|
49
|
+
return { ok: false, reason: `${PARENT} is the parent name itself, not a name anyone holds.` };
|
|
50
|
+
else if (name.endsWith('.eth'))
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
reason: `${name} is not a hoodfi.eth name. ${name.slice(0, -'.eth'.length)}${suffix} would be a different name, possibly held by someone else, so it is not substituted. Resolve ${name} with ENS on Ethereum instead.`,
|
|
54
|
+
};
|
|
55
|
+
else
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
reason: `"${name}" is not a hoodfi.eth name. Give a bare name ("gm") or the full name ending in ${suffix} ("jack.gm${suffix}").`,
|
|
59
|
+
};
|
|
60
|
+
for (const label of labels) {
|
|
61
|
+
const check = checkLabel(label);
|
|
62
|
+
if (!check.ok)
|
|
63
|
+
return { ok: false, reason: `"${label}": ${check.reason}` };
|
|
64
|
+
// checkLabel would also strip a trailing ".eth"; a label here never contains a dot.
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, labels, name: `${labels.join('.')}${suffix}` };
|
|
67
|
+
}
|
|
68
|
+
/** Tier index 0-3 (1 char, 2 chars, 3 chars, 4+). Mirrors LabelUtils.tierOf. */
|
|
69
|
+
export function tierOf(label) {
|
|
70
|
+
return (label.length >= 4 ? 3 : label.length - 1);
|
|
71
|
+
}
|
|
72
|
+
export function fullName(label) {
|
|
73
|
+
return `${label}.${PARENT}`;
|
|
74
|
+
}
|
|
75
|
+
/** HoodfiRegistrar.status() codes, in words. */
|
|
76
|
+
export const STATUS_TEXT = {
|
|
77
|
+
0: 'available',
|
|
78
|
+
1: 'taken',
|
|
79
|
+
2: 'locked',
|
|
80
|
+
3: 'invalid',
|
|
81
|
+
4: 'blocked',
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"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"}
|
package/dist/xrp.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two shapes ENSIP-9 stores for the XRP Ledger, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* The library's coder is base58check over the XRP alphabet and checks the checksum but
|
|
5
|
+
* not the payload, and the XRPL uses that same encoding for its *secrets*: a family
|
|
6
|
+
* seed (`s…`, version 0x21) and an ed25519 seed (`sEd…`) decode just as cleanly as an
|
|
7
|
+
* address. Without this, someone pasting the wrong line from their wallet export would
|
|
8
|
+
* publish their seed in a public record. Testnet X-addresses (`T…`) are refused too —
|
|
9
|
+
* a payment record that resolves to a testnet account loses whatever is sent to it.
|
|
10
|
+
*
|
|
11
|
+
* - r-address: version 0x00 + 20-byte account ID = 21 bytes.
|
|
12
|
+
* - X-address (mainnet): 0x05 0x44 + account ID + tag flag (0/1) + 4-byte tag + 4
|
|
13
|
+
* reserved zero bytes = 31 bytes. It carries the destination tag inside it.
|
|
14
|
+
*
|
|
15
|
+
* Its own module, with no imports of ours, so `xrp.test.mjs` can load it directly.
|
|
16
|
+
* `frontend/lib/ens.ts` applies the same rule — see the header of coins.ts for why the
|
|
17
|
+
* policy is duplicated rather than shared.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isXrpRecord(bytes: Uint8Array): boolean;
|
|
20
|
+
/** Address text -> stored bytes. Throws on anything but a mainnet r- or X-address. */
|
|
21
|
+
export declare function decodeXrpRecord(value: string): Uint8Array;
|
|
22
|
+
/** Stored bytes -> address text. Throws on bytes that are not one of the two shapes. */
|
|
23
|
+
export declare function encodeXrpRecord(bytes: Uint8Array): string;
|
|
24
|
+
//# sourceMappingURL=xrp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xrp.d.ts","sourceRoot":"","sources":["../src/xrp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAMtD;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAIzD;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAGzD"}
|
package/dist/xrp.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two shapes ENSIP-9 stores for the XRP Ledger, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* The library's coder is base58check over the XRP alphabet and checks the checksum but
|
|
5
|
+
* not the payload, and the XRPL uses that same encoding for its *secrets*: a family
|
|
6
|
+
* seed (`s…`, version 0x21) and an ed25519 seed (`sEd…`) decode just as cleanly as an
|
|
7
|
+
* address. Without this, someone pasting the wrong line from their wallet export would
|
|
8
|
+
* publish their seed in a public record. Testnet X-addresses (`T…`) are refused too —
|
|
9
|
+
* a payment record that resolves to a testnet account loses whatever is sent to it.
|
|
10
|
+
*
|
|
11
|
+
* - r-address: version 0x00 + 20-byte account ID = 21 bytes.
|
|
12
|
+
* - X-address (mainnet): 0x05 0x44 + account ID + tag flag (0/1) + 4-byte tag + 4
|
|
13
|
+
* reserved zero bytes = 31 bytes. It carries the destination tag inside it.
|
|
14
|
+
*
|
|
15
|
+
* Its own module, with no imports of ours, so `xrp.test.mjs` can load it directly.
|
|
16
|
+
* `frontend/lib/ens.ts` applies the same rule — see the header of coins.ts for why the
|
|
17
|
+
* policy is duplicated rather than shared.
|
|
18
|
+
*/
|
|
19
|
+
import { decodeXrpAddress, encodeXrpAddress, } from '@ensdomains/address-encoder/coders';
|
|
20
|
+
export function isXrpRecord(bytes) {
|
|
21
|
+
if (bytes.length === 21)
|
|
22
|
+
return bytes[0] === 0x00;
|
|
23
|
+
if (bytes.length !== 31 || bytes[0] !== 0x05 || bytes[1] !== 0x44)
|
|
24
|
+
return false;
|
|
25
|
+
const flag = bytes[22];
|
|
26
|
+
if (flag !== 0 && flag !== 1)
|
|
27
|
+
return false;
|
|
28
|
+
return bytes.slice(27).every((b) => b === 0);
|
|
29
|
+
}
|
|
30
|
+
/** Address text -> stored bytes. Throws on anything but a mainnet r- or X-address. */
|
|
31
|
+
export function decodeXrpRecord(value) {
|
|
32
|
+
const bytes = decodeXrpAddress(value);
|
|
33
|
+
if (!isXrpRecord(bytes))
|
|
34
|
+
throw new Error('not an XRP Ledger address');
|
|
35
|
+
return bytes;
|
|
36
|
+
}
|
|
37
|
+
/** Stored bytes -> address text. Throws on bytes that are not one of the two shapes. */
|
|
38
|
+
export function encodeXrpRecord(bytes) {
|
|
39
|
+
if (!isXrpRecord(bytes))
|
|
40
|
+
throw new Error('not an XRP Ledger address');
|
|
41
|
+
return encodeXrpAddress(bytes);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=xrp.js.map
|
package/dist/xrp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xrp.js","sourceRoot":"","sources":["../src/xrp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,oCAAoC,CAAA;AAE3C,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACjD,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAC/E,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAA;IACtB,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1C,OAAO,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;AAC9C,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACrC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;IACrE,OAAO,KAAK,CAAA;AACd,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;IACrE,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAA;AAChC,CAAC"}
|