@artblocks/abx-storage 0.1.0-alpha.9 → 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 (48) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/dist/arweave.d.ts +34 -47
  3. package/dist/arweave.d.ts.map +1 -1
  4. package/dist/arweave.js +64 -160
  5. package/dist/arweave.js.map +1 -1
  6. package/dist/backend.d.ts +1 -4
  7. package/dist/backend.d.ts.map +1 -1
  8. package/dist/backend.js +4 -33
  9. package/dist/backend.js.map +1 -1
  10. package/dist/content-index.d.ts.map +1 -1
  11. package/dist/content-index.js +3 -1
  12. package/dist/content-index.js.map +1 -1
  13. package/dist/content-plan.d.ts +78 -0
  14. package/dist/content-plan.d.ts.map +1 -0
  15. package/dist/content-plan.js +68 -0
  16. package/dist/content-plan.js.map +1 -0
  17. package/dist/fs.d.ts.map +1 -1
  18. package/dist/fs.js +3 -1
  19. package/dist/fs.js.map +1 -1
  20. package/dist/index.d.ts +7 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +7 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/ipfs.d.ts +17 -1
  25. package/dist/ipfs.d.ts.map +1 -1
  26. package/dist/ipfs.js +60 -2
  27. package/dist/ipfs.js.map +1 -1
  28. package/dist/migrate.d.ts +37 -0
  29. package/dist/migrate.d.ts.map +1 -0
  30. package/dist/migrate.js +55 -0
  31. package/dist/migrate.js.map +1 -0
  32. package/dist/probe.d.ts +66 -0
  33. package/dist/probe.d.ts.map +1 -0
  34. package/dist/probe.js +155 -0
  35. package/dist/probe.js.map +1 -0
  36. package/dist/readiness.d.ts +72 -6
  37. package/dist/readiness.d.ts.map +1 -1
  38. package/dist/readiness.js +62 -34
  39. package/dist/readiness.js.map +1 -1
  40. package/dist/upload-readiness.d.ts +89 -0
  41. package/dist/upload-readiness.d.ts.map +1 -0
  42. package/dist/upload-readiness.js +85 -0
  43. package/dist/upload-readiness.js.map +1 -0
  44. package/dist/upload.d.ts +28 -0
  45. package/dist/upload.d.ts.map +1 -0
  46. package/dist/upload.js +41 -0
  47. package/dist/upload.js.map +1 -0
  48. package/package.json +17 -9
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The storage half of a resolver migration: re-pinning node-custody images to a durable backend.
3
+ *
4
+ * The rest of the migration — reconciling a destination resolver's off-chain state against a
5
+ * source resolver's served JSON (`buildMigrationPlan`/`verifyParity`) — is pure fetch-based
6
+ * reconciliation with no storage dependency, so it lives in `@artblocks/abx-sdk`'s `migrate.ts`.
7
+ * This module is the one piece that needs an actual byte-custody backend: turning a
8
+ * {@link NodeCustodyImage} (bytes that live only on the soon-to-be-decommissioned source host)
9
+ * into a portable, durable locator.
10
+ */
11
+ import { type StorageBackend } from './backend.js';
12
+ import type { NodeCustodyImage } from '@artblocks/abx-sdk';
13
+ /**
14
+ * Re-pin node-custody images to a DURABLE backend so the destination never depends on the
15
+ * (soon-to-be-decommissioned) source host. For each image: fetch the bytes from the source,
16
+ * **verify** them against the on-chain hash (trustless — we trust the chain, not the old node),
17
+ * then `put` them to the destination operator's own backend and read back a portable locator.
18
+ *
19
+ * If the configured backend isn't durable (no `locator` — fs/cloud serve only through their own
20
+ * node, so re-pinning there just moves the single-host dependency), we re-pin NOTHING and report
21
+ * every image as `needsDurableBackend`: the right move is to configure IPFS/Arweave and re-run,
22
+ * never to bridge a URL that points back at the dying host.
23
+ */
24
+ export interface RepinResult {
25
+ /** hash → new durable locator, ready to bridge to the destination. */
26
+ repinned: Record<string, string>;
27
+ /** Re-pinned token ids (for reporting). */
28
+ repinnedTokens: string[];
29
+ /** Bytes fetched but their hash didn't match the on-chain commitment — NOT trusted, NOT pinned. */
30
+ mismatched: NodeCustodyImage[];
31
+ /** Couldn't fetch the bytes from the source (host down, 404). */
32
+ unreachable: NodeCustodyImage[];
33
+ /** Skipped because no durable backend is configured — these need IPFS/Arweave + a re-run. */
34
+ needsDurableBackend: NodeCustodyImage[];
35
+ }
36
+ export declare function repinNodeCustody(images: NodeCustodyImage[], backend: StorageBackend): Promise<RepinResult>;
37
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAc,KAAK,cAAc,EAAC,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAGzD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2CAA2C;IAC3C,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,mGAAmG;IACnG,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,iEAAiE;IACjE,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,6FAA6F;IAC7F,mBAAmB,EAAE,gBAAgB,EAAE,CAAC;CACzC;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,CAyChH"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The storage half of a resolver migration: re-pinning node-custody images to a durable backend.
3
+ *
4
+ * The rest of the migration — reconciling a destination resolver's off-chain state against a
5
+ * source resolver's served JSON (`buildMigrationPlan`/`verifyParity`) — is pure fetch-based
6
+ * reconciliation with no storage dependency, so it lives in `@artblocks/abx-sdk`'s `migrate.ts`.
7
+ * This module is the one piece that needs an actual byte-custody backend: turning a
8
+ * {@link NodeCustodyImage} (bytes that live only on the soon-to-be-decommissioned source host)
9
+ * into a portable, durable locator.
10
+ */
11
+ import { hashContent } from './backend.js';
12
+ export async function repinNodeCustody(images, backend) {
13
+ const result = { repinned: {}, repinnedTokens: [], mismatched: [], unreachable: [], needsDurableBackend: [] };
14
+ if (!images.length)
15
+ return result;
16
+ // A backend is "durable" for migration iff it can hand back a node-independent locator.
17
+ if (!backend.locator) {
18
+ result.needsDurableBackend = [...images];
19
+ return result;
20
+ }
21
+ for (const img of images) {
22
+ let bytes;
23
+ let contentType;
24
+ try {
25
+ const resp = await fetch(img.imageUrl);
26
+ if (!resp.ok) {
27
+ result.unreachable.push(img);
28
+ continue;
29
+ }
30
+ bytes = new Uint8Array(await resp.arrayBuffer());
31
+ contentType = resp.headers.get('content-type') ?? 'application/octet-stream';
32
+ }
33
+ catch {
34
+ result.unreachable.push(img);
35
+ continue;
36
+ }
37
+ // Trustless: re-hash the fetched bytes and compare to the ON-CHAIN commitment.
38
+ if (hashContent(bytes).toLowerCase() !== img.hash.toLowerCase()) {
39
+ result.mismatched.push(img);
40
+ continue;
41
+ }
42
+ await backend.put(img.hash, { bytes, contentType });
43
+ const loc = await backend.locator(img.hash);
44
+ if (loc) {
45
+ result.repinned[img.hash.toLowerCase()] = loc;
46
+ result.repinnedTokens.push(img.tokenId);
47
+ }
48
+ else {
49
+ // Stored, but the backend still can't produce a portable locator — treat as not durable.
50
+ result.needsDurableBackend.push(img);
51
+ }
52
+ }
53
+ return result;
54
+ }
55
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAC,WAAW,EAAsB,MAAM,cAAc,CAAC;AA4B9D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAA0B,EAAE,OAAuB;IACxF,MAAM,MAAM,GAAgB,EAAC,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAC,CAAC;IACzH,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC;IAElC,wFAAwF;IACxF,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,mBAAmB,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,KAAiB,CAAC;QACtB,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC7B,SAAS;YACX,CAAC;YACD,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YACjD,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,0BAA0B,CAAC;QAC/E,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC7B,SAAS;QACX,CAAC;QACD,+EAA+E;QAC/E,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YAChE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;QACD,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAW,EAAE,EAAC,KAAK,EAAE,WAAW,EAAC,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAW,CAAC,CAAC;QACnD,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,GAAG,CAAC;YAC9C,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,yFAAyF;YACzF,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,66 @@
1
+ import type { StorageBackend } from './backend.js';
2
+ import type { CloudStorageConfig } from './cloud.js';
3
+ import { type ArweaveConfig } from './arweave.js';
4
+ import { type ResolveStorageOptions } from './resolve.js';
5
+ /**
6
+ * `abx storage show --check` / `abx doctor`'s storage section — go beyond "is this backend
7
+ * CONFIGURED" (what {@link resolveBackend} plus each backend's own `health()` already answer) to
8
+ * "does a write actually reach the URL a token would bake on-chain."
9
+ *
10
+ * The gap this closes is the R2/S3 endpoint-vs-public-base confusion: a backend's `health()` signs
11
+ * a request against the API `endpoint` — proving credentials work — but never touches the SEPARATE
12
+ * `publicBase` a marketplace would actually fetch from. Those can point at different buckets (or one
13
+ * can simply be wrong) with `health()` reporting green the whole time. A PUT through the API,
14
+ * fetched back over the PUBLIC base with a plain unsigned GET, is the only check that proves the two
15
+ * agree.
16
+ *
17
+ * `fs` and `ipfs` are NOT reimplemented here — their existing `health()` already does exactly what's
18
+ * asked (fs: writability; ipfs: gateway/API reachability, no upload) and duplicating that logic is
19
+ * how the two copies drift. `arweave` layers a balance READ (never a paid upload) on top of its
20
+ * existing identity check. `cloud` gets the new round trip.
21
+ */
22
+ export interface StorageCheckResult {
23
+ backend: string;
24
+ ok: boolean;
25
+ detail: string;
26
+ /** Set on a `cloud` check — the API write target and the public read URL, so a mismatch between
27
+ * them (the R2/S3 endpoint-vs-public-base trap) is visible on failure rather than a bare
28
+ * "fetch failed". Equal in shape, not necessarily in host — that's exactly what's being checked. */
29
+ putUrl?: string;
30
+ publicUrl?: string;
31
+ }
32
+ export interface StorageCheckOptions {
33
+ /** Bound on each network step. A backend method with no abort hook (cloud's `putObject`/
34
+ * `getObject`, arweave's balance read) is raced against this rather than truly cancelled — good
35
+ * enough to keep a caller (doctor) from hanging, not a guarantee the underlying request stopped. */
36
+ timeoutMs?: number;
37
+ /** Injectable for tests — used for the public-base GET only (the PUT/API side goes through the
38
+ * resolved backend, which owns its own signing). */
39
+ fetchFn?: typeof fetch;
40
+ }
41
+ /** fs + ipfs (and any future backend with nothing more to add): delegate straight to the existing
42
+ * `health()` — see the module doc for why this is reuse, not a stand-in pending real logic. */
43
+ export declare function checkViaHealth(backend: StorageBackend, opts?: StorageCheckOptions): Promise<StorageCheckResult>;
44
+ /**
45
+ * `cloud`: PUT a tiny probe object through the signed API, then GET it back with a plain,
46
+ * UNSIGNED fetch against `publicBase` — the same request a marketplace/browser would make. Reuses
47
+ * one well-known key (`abx-probe/check.txt`) rather than minting a new one per run, so repeated
48
+ * checks don't litter the bucket. `cfg` (when given) names the API write target too — the R2/S3
49
+ * endpoint-vs-public-base trap is only diagnosable if BOTH URLs are on screen, not just the one
50
+ * that failed.
51
+ */
52
+ export declare function checkCloudBackend(backend: StorageBackend, cfg?: CloudStorageConfig, opts?: StorageCheckOptions): Promise<StorageCheckResult>;
53
+ /**
54
+ * `arweave`: the existing `health()` (gateway reachability + identity presence) plus a Turbo
55
+ * BALANCE read when an identity already exists — never a paid upload (no identity yet is reported
56
+ * as-is: it's created free on first real upload, so there's nothing to check).
57
+ */
58
+ export declare function checkArweaveBackend(backend: StorageBackend, cfg: ArweaveConfig | undefined, opts?: StorageCheckOptions): Promise<StorageCheckResult>;
59
+ /**
60
+ * The one storage-config probe both `abx storage show --check` and `abx doctor` call — dispatches to
61
+ * the right per-backend check above. Resolving the backend can throw (missing required config, e.g.
62
+ * cloud with no endpoint/bucket) — same as every other `resolveBackend` call site, and the caller's
63
+ * existing try/catch around it is the right place to handle that, not this function.
64
+ */
65
+ export declare function probeStorageBackend(opts: ResolveStorageOptions, checkOpts?: StorageCheckOptions): Promise<StorageCheckResult>;
66
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,YAAY,CAAC;AACnD,OAAO,EAAqE,KAAK,aAAa,EAAC,MAAM,cAAc,CAAC;AACpH,OAAO,EAAiB,KAAK,qBAAqB,EAAC,MAAM,cAAc,CAAC;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf;;yGAEqG;IACrG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC;;yGAEqG;IACrG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;yDACqD;IACrD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAqBD;gGACgG;AAChG,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAYzH;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,kBAAkB,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA+DtJ;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,GAAG,SAAS,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA0B9J;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,qBAAqB,EAAE,SAAS,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAKvI"}
package/dist/probe.js ADDED
@@ -0,0 +1,155 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { arweaveFunding, turboIdentity, turboIdentityAddress, isEthIdentity } from './arweave.js';
3
+ import { resolveBackend } from './resolve.js';
4
+ /** Matches readiness.ts's gateway-probe default — this module's other real-network default. */
5
+ const DEFAULT_CHECK_TIMEOUT_MS = 6000;
6
+ /** Race a call against a `ms` deadline, rejecting with `message` if it wins. Most methods probed
7
+ * here have no abort hook of their own, so this stops WAITING for a hung request rather than
8
+ * cancelling it — good enough to keep a caller (doctor) from hanging. Always clears its timer, so
9
+ * a fast call doesn't leave one pending. */
10
+ async function race(p, ms, message) {
11
+ let timer;
12
+ const timeout = new Promise((_, reject) => {
13
+ timer = setTimeout(() => reject(new Error(message)), ms);
14
+ });
15
+ try {
16
+ return await Promise.race([p, timeout]);
17
+ }
18
+ finally {
19
+ clearTimeout(timer);
20
+ }
21
+ }
22
+ /** fs + ipfs (and any future backend with nothing more to add): delegate straight to the existing
23
+ * `health()` — see the module doc for why this is reuse, not a stand-in pending real logic. */
24
+ export async function checkViaHealth(backend, opts = {}) {
25
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS;
26
+ try {
27
+ const h = await race(backend.health?.() ?? Promise.resolve({ ok: true, detail: 'no check defined for this backend' }), timeoutMs, `timed out after ${timeoutMs}ms`);
28
+ return { backend: backend.id, ok: h.ok, detail: h.detail ?? '' };
29
+ }
30
+ catch (e) {
31
+ return { backend: backend.id, ok: false, detail: e.message };
32
+ }
33
+ }
34
+ /**
35
+ * `cloud`: PUT a tiny probe object through the signed API, then GET it back with a plain,
36
+ * UNSIGNED fetch against `publicBase` — the same request a marketplace/browser would make. Reuses
37
+ * one well-known key (`abx-probe/check.txt`) rather than minting a new one per run, so repeated
38
+ * checks don't litter the bucket. `cfg` (when given) names the API write target too — the R2/S3
39
+ * endpoint-vs-public-base trap is only diagnosable if BOTH URLs are on screen, not just the one
40
+ * that failed.
41
+ */
42
+ export async function checkCloudBackend(backend, cfg, opts = {}) {
43
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS;
44
+ const key = 'abx-probe/check.txt';
45
+ const putUrl = cfg ? `${cfg.endpoint.replace(/\/+$/, '')}/${cfg.bucket}/${key}` : undefined;
46
+ if (!backend.publicBase) {
47
+ return {
48
+ backend: 'cloud',
49
+ ok: false,
50
+ detail: "no public read base configured — set ABX_S3_PUBLIC_BASE (or --public-base) to the bucket's public URL.",
51
+ putUrl,
52
+ };
53
+ }
54
+ if (!backend.putObject || !backend.getObject) {
55
+ return { backend: 'cloud', ok: false, detail: 'this cloud backend has no putObject/getObject — cannot round-trip check it.', putUrl };
56
+ }
57
+ const publicUrl = `${backend.publicBase.replace(/\/+$/, '')}/${key}`;
58
+ const token = randomBytes(8).toString('hex');
59
+ const body = `abx storage check ${token}`;
60
+ const bytes = new TextEncoder().encode(body);
61
+ try {
62
+ await race(backend.putObject(key, { bytes, contentType: 'text/plain' }), timeoutMs, `PUT timed out after ${timeoutMs}ms`);
63
+ }
64
+ catch (e) {
65
+ return { backend: 'cloud', ok: false, detail: `PUT via the API failed: ${e.message}`, putUrl, publicUrl };
66
+ }
67
+ const fetchFn = opts.fetchFn ?? fetch;
68
+ const ctrl = new AbortController();
69
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
70
+ try {
71
+ const res = await fetchFn(publicUrl, { signal: ctrl.signal });
72
+ if (!res.ok) {
73
+ return {
74
+ backend: 'cloud',
75
+ ok: false,
76
+ detail: `GET via the public base failed (${res.status}) — the public base may point at a different bucket/endpoint than the write API.`,
77
+ putUrl,
78
+ publicUrl,
79
+ };
80
+ }
81
+ const got = new TextDecoder().decode(new Uint8Array(await res.arrayBuffer()));
82
+ if (got !== body) {
83
+ return {
84
+ backend: 'cloud',
85
+ ok: false,
86
+ detail: 'GET via the public base returned different bytes than were PUT — check for a caching layer or a public base pointed at a different bucket.',
87
+ putUrl,
88
+ publicUrl,
89
+ };
90
+ }
91
+ return { backend: 'cloud', ok: true, detail: `round-trip ok via ${publicUrl}`, putUrl, publicUrl };
92
+ }
93
+ catch (e) {
94
+ const aborted = e.name === 'AbortError';
95
+ return {
96
+ backend: 'cloud',
97
+ ok: false,
98
+ detail: aborted ? `GET via the public base timed out after ${timeoutMs}ms` : `GET via the public base failed: ${e.message}`,
99
+ putUrl,
100
+ publicUrl,
101
+ };
102
+ }
103
+ finally {
104
+ clearTimeout(timer);
105
+ }
106
+ }
107
+ /**
108
+ * `arweave`: the existing `health()` (gateway reachability + identity presence) plus a Turbo
109
+ * BALANCE read when an identity already exists — never a paid upload (no identity yet is reported
110
+ * as-is: it's created free on first real upload, so there's nothing to check).
111
+ */
112
+ export async function checkArweaveBackend(backend, cfg, opts = {}) {
113
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_CHECK_TIMEOUT_MS;
114
+ let base;
115
+ try {
116
+ base = await race(backend.health?.() ?? Promise.resolve({ ok: true, detail: '' }), timeoutMs, `timed out after ${timeoutMs}ms`);
117
+ }
118
+ catch (e) {
119
+ base = { ok: false, detail: e.message };
120
+ }
121
+ if (!cfg)
122
+ return { backend: 'arweave', ok: base.ok, detail: base.detail ?? '' };
123
+ const id = turboIdentity(cfg);
124
+ if (!id) {
125
+ return { backend: 'arweave', ok: base.ok, detail: [base.detail, 'no identity yet — created free on first upload (nothing to check)'].filter(Boolean).join(' · ') };
126
+ }
127
+ try {
128
+ const funding = await arweaveFunding(cfg);
129
+ const { credits } = await race(funding.balance(), timeoutMs, `balance check timed out after ${timeoutMs}ms`);
130
+ const address = turboIdentityAddress(id);
131
+ return {
132
+ backend: 'arweave',
133
+ ok: base.ok,
134
+ detail: [base.detail, `${credits} credits (identity ${address}${isEthIdentity(id) ? ', eth' : ''})`].filter(Boolean).join(' · '),
135
+ };
136
+ }
137
+ catch (e) {
138
+ return { backend: 'arweave', ok: base.ok, detail: [base.detail, `balance check failed: ${e.message}`].filter(Boolean).join(' · ') };
139
+ }
140
+ }
141
+ /**
142
+ * The one storage-config probe both `abx storage show --check` and `abx doctor` call — dispatches to
143
+ * the right per-backend check above. Resolving the backend can throw (missing required config, e.g.
144
+ * cloud with no endpoint/bucket) — same as every other `resolveBackend` call site, and the caller's
145
+ * existing try/catch around it is the right place to handle that, not this function.
146
+ */
147
+ export async function probeStorageBackend(opts, checkOpts = {}) {
148
+ const backend = resolveBackend(opts);
149
+ if (backend.id === 'cloud' || backend.id === 's3')
150
+ return checkCloudBackend(backend, opts.cloud, checkOpts);
151
+ if (backend.id === 'arweave')
152
+ return checkArweaveBackend(backend, opts.arweave, checkOpts);
153
+ return checkViaHealth(backend, checkOpts);
154
+ }
155
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,6 @@
1
+ import { type LocatorNetwork } from '@artblocks/abx-sdk';
2
+ export { gatewayUrlFor } from '@artblocks/abx-sdk';
3
+ export type { LocatorNetwork } from '@artblocks/abx-sdk';
1
4
  /**
2
5
  * Is a locator **retrievable** yet — not just accepted?
3
6
  *
@@ -15,8 +18,6 @@
15
18
  * "your gateway doesn't have it" and "the network doesn't have it" are different answers, and only
16
19
  * one of them means something is wrong.
17
20
  */
18
- /** The locator's network, which decides which gateways can be asked about it. */
19
- export type LocatorNetwork = 'arweave' | 'ipfs' | 'http';
20
21
  export type Readiness =
21
22
  /** The gateway this toolkit would actually use serves the bytes. Safe to reference. */
22
23
  'ready'
@@ -72,13 +73,29 @@ export declare function parseLocator(locator: string): {
72
73
  network: LocatorNetwork;
73
74
  id: string;
74
75
  };
75
- /** Build the URL that asks `gateway` for `id`. A locator that is already an absolute URL is asked
76
- * verbatim — rewriting someone's URL would answer a question they didn't ask. */
77
- export declare function gatewayUrlFor(network: LocatorNetwork, id: string, gateway: string): string;
76
+ /**
77
+ * The gateway BASE for a locator network — **override → env → generic public default**
78
+ * (`ABX_IPFS_GATEWAY`/`ABX_ARWEAVE_GATEWAY`, then `ipfs.io`/`arweave.net`). This is the READ-TIME
79
+ * default for resolving an arbitrary on-chain locator whose upload backend is unknown to the
80
+ * resolver — distinct from {@link ipfsConfigFromEnv}/{@link arweaveConfigFromEnv}'s MODE-aware
81
+ * defaults for a backend this toolkit itself configured to write through (e.g. a `kubo` IPFS
82
+ * gateway defaults to `127.0.0.1:8080`, a locator resolver has no such context and must default
83
+ * to something that resolves for anyone). `http` locators carry their own base (they are already
84
+ * an absolute URL) and never reach here — callers return them verbatim before consulting a gateway.
85
+ *
86
+ * A thin compose over the SDK's split: {@link resolveGatewayBase} used to own the
87
+ * `override ?? env ?? default` line itself (`process.env` read inline); now the pure decision
88
+ * lives in `@artblocks/abx-sdk`'s `resolveGatewayBase` (src/gateways.ts) and the env read in its
89
+ * `gatewayConfigFromEnv`, so this function's whole body is just wiring override → (env or
90
+ * nothing) → the SDK's pure default. Kept here, under this same name and signature, because
91
+ * every existing caller (this package's own `locatorStatus`, token-api's `resolveLocatorUrl`)
92
+ * still wants exactly this three-rung precedence with one call.
93
+ */
94
+ export declare function resolveGatewayBase(network: LocatorNetwork, override?: string): string;
78
95
  /**
79
96
  * Ask one gateway whether it serves these bytes, reading **headers only**.
80
97
  *
81
- * A ranged request (`Range: bytes=0-0`) is what keeps this cheap: the art in question can be tens of
98
+ * A ranged request (`Range: bytes=0-0`) is what keeps this cheap: the content in question can be tens of
82
99
  * megabytes and the question is only whether it is there. Gateways that ignore `Range` answer 200
83
100
  * with the whole body, so the body is cancelled rather than read — without that, checking a large
84
101
  * locator would download it.
@@ -89,4 +106,53 @@ export declare function probeGateway(url: string, opts?: {
89
106
  }): Promise<GatewayProbe>;
90
107
  /** Accepted-vs-retrievable for one locator, across the gateway that matters and a couple of others. */
91
108
  export declare function locatorStatus(locator: string, opts?: LocatorStatusOptions): Promise<LocatorStatus>;
109
+ /** One poll attempt from {@link awaitLocatorReady} — lets a caller narrate progress (a CLI spinner,
110
+ * a log line) without this module printing anything itself (the SDK/storage layers never print). */
111
+ export interface AwaitLocatorReadyEvent {
112
+ /** 1-indexed poll attempt. */
113
+ attempt: number;
114
+ /** Milliseconds since {@link awaitLocatorReady} was called. */
115
+ elapsedMs: number;
116
+ status: LocatorStatus;
117
+ }
118
+ export interface AwaitLocatorReadyOptions {
119
+ /** Forwarded to every {@link locatorStatus} probe. */
120
+ gateway?: string;
121
+ primaryOnly?: boolean;
122
+ /** Per-probe network timeout, forwarded as {@link LocatorStatusOptions.timeoutMs} (NOT the
123
+ * poll's overall deadline — see `timeoutMs` below). Default 6000ms, same as `locatorStatus`. */
124
+ probeTimeoutMs?: number;
125
+ fetchFn?: typeof fetch;
126
+ /** Give up polling once this much total time has elapsed, returning the last status with
127
+ * `ready: false` rather than throwing — a caller decides what "still not ready" means for its
128
+ * own flow. Default 5 minutes: long enough for typical Arweave propagation (this module's whole
129
+ * reason to exist — see the module doc, "the gap runs to minutes"). */
130
+ timeoutMs?: number;
131
+ /** Base delay for the linear backoff between polls (`attempt * pollBaseMs`, via the SDK's
132
+ * {@link linearBackoffDelay} — the same primitive `service.ts`'s retry ladder uses). Default
133
+ * 3000ms, so the very first re-poll is quick and later ones back off. */
134
+ pollBaseMs?: number;
135
+ onEvent?: (e: AwaitLocatorReadyEvent) => void;
136
+ }
137
+ export interface AwaitLocatorReadyResult {
138
+ /** The last status observed — `'ready'` iff {@link ready} is true. */
139
+ status: LocatorStatus;
140
+ attempts: number;
141
+ elapsedMs: number;
142
+ /** False when the deadline was hit before `status.readiness` reached `'ready'`. */
143
+ ready: boolean;
144
+ }
145
+ /**
146
+ * Poll {@link locatorStatus} until it reports `'ready'` or the deadline passes.
147
+ *
148
+ * `locatorStatus` alone answers "right now" — the natural next question, for a caller that would
149
+ * otherwise upload during a mint and write the locator into a token that renders broken for its
150
+ * first minutes of life (see the module doc), is "wait until it's actually there." This is that,
151
+ * factored out once so a caller doesn't hand-roll its own poll/backoff loop around a one-shot check.
152
+ *
153
+ * `'propagating'` is treated the same as `'unreachable'` here — both mean "not yet what THIS caller
154
+ * can rely on" — but every intermediate status still reaches `onEvent`, so a caller that wants to
155
+ * distinguish "provably on the network, just behind" from "no evidence yet" can from the events.
156
+ */
157
+ export declare function awaitLocatorReady(locator: string, opts?: AwaitLocatorReadyOptions): Promise<AwaitLocatorReadyResult>;
92
158
  //# sourceMappingURL=readiness.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzD,MAAM,MAAM,SAAS;AACnB,uFAAuF;AACrF,OAAO;AACT;8BAC8B;GAC5B,aAAa;AACf;;6DAE6D;GAC3D,aAAa,CAAC;AAElB,MAAM,WAAW,YAAY;IAC3B,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;gGAC4F;IAC5F,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,SAAS,CAAC;IACrB;6CACyC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,oGAAoG;IACpG,UAAU,EAAE,YAAY,EAAE,CAAC;CAC5B;AAcD,MAAM,WAAW,oBAAoB;IACnC;2FACuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;wGACoG;IACpG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG;IAAC,OAAO,EAAE,cAAc,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAC,CAiBnF;AAED;kFACkF;AAClF,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAK1F;AAQD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;CAAM,GACtD,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAED,uGAAuG;AACvG,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,oBAAyB,GAAG,OAAO,CAAC,aAAa,CAAC,CAsB5G"}
1
+ {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"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"}
package/dist/readiness.js CHANGED
@@ -1,20 +1,6 @@
1
- /**
2
- * Is a locator **retrievable** yet — not just accepted?
3
- *
4
- * An upload service answers "accepted" the moment it has your bytes; a gateway answers "serving"
5
- * only once they have propagated to it, and on Arweave that gap runs to minutes. Nothing in the
6
- * upload result distinguishes the two, so the natural implementation — upload during a mint, write
7
- * the locator into the token — mints a token that renders broken for the first minutes of its life.
8
- *
9
- * Two independent integrators hit this eight days apart. The first rebuilt this layer themselves
10
- * (ranged GETs, a propagating/ready model, retry ladders lengthened after measuring real times) and
11
- * concluded "every serious integrator will rebuild some version of this." The second published 32
12
- * renders and found **32/32 404ing on `arweave.net` while 22/32 already served from `permagate.io`
13
- * and `vilenarios.com`**, with the uploader reporting `CONFIRMED` throughout. That second
14
- * observation is why this probes several gateways rather than one: propagation is per-gateway, so
15
- * "your gateway doesn't have it" and "the network doesn't have it" are different answers, and only
16
- * one of them means something is wrong.
17
- */
1
+ import { gatewayConfigFromEnv, gatewayUrlFor, linearBackoffDelay, resolveGatewayBase as sdkResolveGatewayBase, sleep, } from '@artblocks/abx-sdk';
2
+ // Re-export the SDK gateway types and helpers unchanged so this package's public API remains stable.
3
+ export { gatewayUrlFor } from '@artblocks/abx-sdk';
18
4
  /**
19
5
  * Gateways probed as alternates, per network. Kept short on purpose — this is a diagnosis, not a
20
6
  * survey, and each entry is a request someone waits on. The Arweave pair is the one the second
@@ -48,26 +34,35 @@ export function parseLocator(locator) {
48
34
  return { network: 'ipfs', id: raw };
49
35
  throw new Error(`'${locator}' isn't a recognisable locator. Expected ar://<txid>, ipfs://<cid>, an https:// gateway URL, or a bare txid/CID.`);
50
36
  }
51
- /** Build the URL that asks `gateway` for `id`. A locator that is already an absolute URL is asked
52
- * verbatim — rewriting someone's URL would answer a question they didn't ask. */
53
- export function gatewayUrlFor(network, id, gateway) {
54
- if (/^https?:\/\//i.test(id))
55
- return id;
56
- const base = gateway.replace(/\/+$/, '');
57
- // A path suffix (a directory manifest entry, e.g. `<txid>/index.html`) rides along untouched.
58
- return network === 'ipfs' ? `${base}/ipfs/${id}` : `${base}/${id}`;
59
- }
60
- function defaultGateway(network) {
61
- if (network === 'ipfs')
62
- return process.env.ABX_IPFS_GATEWAY ?? 'https://ipfs.io';
63
- if (network === 'arweave')
64
- return process.env.ABX_ARWEAVE_GATEWAY ?? 'https://arweave.net';
65
- return '';
37
+ /**
38
+ * The gateway BASE for a locator network — **override → env → generic public default**
39
+ * (`ABX_IPFS_GATEWAY`/`ABX_ARWEAVE_GATEWAY`, then `ipfs.io`/`arweave.net`). This is the READ-TIME
40
+ * default for resolving an arbitrary on-chain locator whose upload backend is unknown to the
41
+ * resolver — distinct from {@link ipfsConfigFromEnv}/{@link arweaveConfigFromEnv}'s MODE-aware
42
+ * defaults for a backend this toolkit itself configured to write through (e.g. a `kubo` IPFS
43
+ * gateway defaults to `127.0.0.1:8080`, a locator resolver has no such context and must default
44
+ * to something that resolves for anyone). `http` locators carry their own base (they are already
45
+ * an absolute URL) and never reach here — callers return them verbatim before consulting a gateway.
46
+ *
47
+ * A thin compose over the SDK's split: {@link resolveGatewayBase} used to own the
48
+ * `override ?? env ?? default` line itself (`process.env` read inline); now the pure decision
49
+ * lives in `@artblocks/abx-sdk`'s `resolveGatewayBase` (src/gateways.ts) and the env read in its
50
+ * `gatewayConfigFromEnv`, so this function's whole body is just wiring override → (env or
51
+ * nothing) → the SDK's pure default. Kept here, under this same name and signature, because
52
+ * every existing caller (this package's own `locatorStatus`, token-api's `resolveLocatorUrl`)
53
+ * still wants exactly this three-rung precedence with one call.
54
+ */
55
+ export function resolveGatewayBase(network, override) {
56
+ if (network === 'http')
57
+ return '';
58
+ if (override)
59
+ return sdkResolveGatewayBase(network, network === 'ipfs' ? { ipfs: override } : { arweave: override });
60
+ return sdkResolveGatewayBase(network, gatewayConfigFromEnv());
66
61
  }
67
62
  /**
68
63
  * Ask one gateway whether it serves these bytes, reading **headers only**.
69
64
  *
70
- * A ranged request (`Range: bytes=0-0`) is what keeps this cheap: the art in question can be tens of
65
+ * A ranged request (`Range: bytes=0-0`) is what keeps this cheap: the content in question can be tens of
71
66
  * megabytes and the question is only whether it is there. Gateways that ignore `Range` answer 200
72
67
  * with the whole body, so the body is cancelled rather than read — without that, checking a large
73
68
  * locator would download it.
@@ -117,7 +112,7 @@ export async function probeGateway(url, opts = {}) {
117
112
  /** Accepted-vs-retrievable for one locator, across the gateway that matters and a couple of others. */
118
113
  export async function locatorStatus(locator, opts = {}) {
119
114
  const { network, id } = parseLocator(locator);
120
- const primaryGateway = opts.gateway ?? defaultGateway(network);
115
+ const primaryGateway = resolveGatewayBase(network, opts.gateway);
121
116
  const primaryUrl = gatewayUrlFor(network, id, primaryGateway);
122
117
  // `http` locators have no notion of an alternate — the URL IS the address, so a second host would
123
118
  // be answering about different bytes.
@@ -134,6 +129,39 @@ export async function locatorStatus(locator, opts = {}) {
134
129
  : 'unreachable';
135
130
  return { locator, network, id, readiness, primary, alternates };
136
131
  }
132
+ const DEFAULT_AWAIT_TIMEOUT_MS = 5 * 60_000;
133
+ const DEFAULT_POLL_BASE_MS = 3000;
134
+ /**
135
+ * Poll {@link locatorStatus} until it reports `'ready'` or the deadline passes.
136
+ *
137
+ * `locatorStatus` alone answers "right now" — the natural next question, for a caller that would
138
+ * otherwise upload during a mint and write the locator into a token that renders broken for its
139
+ * first minutes of life (see the module doc), is "wait until it's actually there." This is that,
140
+ * factored out once so a caller doesn't hand-roll its own poll/backoff loop around a one-shot check.
141
+ *
142
+ * `'propagating'` is treated the same as `'unreachable'` here — both mean "not yet what THIS caller
143
+ * can rely on" — but every intermediate status still reaches `onEvent`, so a caller that wants to
144
+ * distinguish "provably on the network, just behind" from "no evidence yet" can from the events.
145
+ */
146
+ export async function awaitLocatorReady(locator, opts = {}) {
147
+ const deadlineMs = opts.timeoutMs ?? DEFAULT_AWAIT_TIMEOUT_MS;
148
+ const pollBaseMs = opts.pollBaseMs ?? DEFAULT_POLL_BASE_MS;
149
+ const started = Date.now();
150
+ const probeOpts = { gateway: opts.gateway, primaryOnly: opts.primaryOnly, timeoutMs: opts.probeTimeoutMs, fetchFn: opts.fetchFn };
151
+ let attempt = 0;
152
+ for (;;) {
153
+ attempt++;
154
+ const status = await locatorStatus(locator, probeOpts);
155
+ const elapsedMs = Date.now() - started;
156
+ opts.onEvent?.({ attempt, elapsedMs, status });
157
+ if (status.readiness === 'ready')
158
+ return { status, attempts: attempt, elapsedMs, ready: true };
159
+ const delay = linearBackoffDelay(attempt, pollBaseMs);
160
+ if (elapsedMs + delay >= deadlineMs)
161
+ return { status, attempts: attempt, elapsedMs, ready: false };
162
+ await sleep(delay);
163
+ }
164
+ }
137
165
  /** Total size from a ranged response's `content-range` (`bytes 0-0/12345`), else `content-length`
138
166
  * when the gateway ignored the range and answered 200 with the whole thing. */
139
167
  function totalBytesFrom(contentRange, contentLength, status) {
@@ -1 +1 @@
1
- {"version":3,"file":"readiness.js","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"readiness.js","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,IAAI,qBAAqB,EAC3C,KAAK,GAEN,MAAM,oBAAoB,CAAC;AAE5B,qGAAqG;AACrG,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAgEjD;;;;GAIG;AACH,MAAM,kBAAkB,GAAyC;IAC/D,OAAO,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;IAC3D,IAAI,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,CAAC;CAChD,CAAC;AAEF,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAahC,6DAA6D;AAC7D,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAC,CAAC;IAC7F,IAAI,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAC,CAAC;IAC5F,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,+FAA+F;QAC/F,iGAAiG;QACjG,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,EAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAC,CAAC;QACpF,IAAI,uDAAuD,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,EAAC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAC,CAAC;QAC5G,OAAO,EAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAC,CAAC;IACpC,CAAC;IACD,wFAAwF;IACxF,IAAI,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAC,CAAC;IAC1E,IAAI,6DAA6D,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAC,CAAC;IAC/G,MAAM,IAAI,KAAK,CACb,IAAI,OAAO,kHAAkH,CAC9H,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAuB,EAAE,QAAiB;IAC3E,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAClC,IAAI,QAAQ;QAAE,OAAO,qBAAqB,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAC,OAAO,EAAE,QAAQ,EAAC,CAAC,CAAC;IACjH,OAAO,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,EAAE,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,OAAqD,EAAE;IAEvD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC,CAAC;IACnF,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAC,OAAO,EAAE,EAAC,KAAK,EAAE,WAAW,EAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAC,CAAC,CAAC;QACzG,wFAAwF;QACxF,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,0DAA0D;QAC5D,CAAC;QACD,OAAO;YACL,GAAG;YACH,OAAO;YACP,OAAO,EAAE,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;YAC9C,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;YAC5C,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC;YACtG,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;SACzB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAI,GAAa,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;QAC5E,OAAO;YACL,GAAG;YACH,OAAO;YACP,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,IAAI;YACX,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,kBAAkB,IAAI,CAAC,SAAS,IAAI,kBAAkB,IAAI,CAAC,CAAC,CAAE,GAAa,CAAC,OAAO;SACrG,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,uGAAuG;AACvG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,OAA6B,EAAE;IAClF,MAAM,EAAC,OAAO,EAAE,EAAE,EAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,cAAc,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;IAE9D,kGAAkG;IAClG,sCAAsC;IACtC,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACjG,MAAM,aAAa,GAAG,cAAc;SACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;SAC/C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,EAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAC,CAAC,CAAC;IACjG,MAAM,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAErG,MAAM,SAAS,GAAc,OAAO,CAAC,OAAO;QAC1C,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACjC,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,aAAa,CAAC;IAEpB,OAAO,EAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAC,CAAC;AAChE,CAAC;AAyCD,MAAM,wBAAwB,GAAG,CAAC,GAAG,MAAM,CAAC;AAC5C,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAe,EAAE,OAAiC,EAAE;IAC1F,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,IAAI,wBAAwB,CAAC;IAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,oBAAoB,CAAC;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAyB,EAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAC,CAAC;IACtJ,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,SAAS,CAAC;QACR,OAAO,EAAE,CAAC;QACV,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAC,CAAC,CAAC;QAC7C,IAAI,MAAM,CAAC,SAAS,KAAK,OAAO;YAAE,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAC,CAAC;QAC7F,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACtD,IAAI,SAAS,GAAG,KAAK,IAAI,UAAU;YAAE,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAC,CAAC;QACjG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;AACH,CAAC;AAED;gFACgF;AAChF,SAAS,cAAc,CAAC,YAA2B,EAAE,aAA4B,EAAE,MAAc;IAC/F,MAAM,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAChD,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,MAAM,KAAK,GAAG,IAAI,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC;QAAE,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC;IACjG,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC"}