@artblocks/abx-storage 0.1.0-alpha.4 → 0.1.0-alpha.41

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 +69 -0
  2. package/dist/arweave.d.ts +45 -44
  3. package/dist/arweave.d.ts.map +1 -1
  4. package/dist/arweave.js +98 -155
  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 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +7 -1
  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 +158 -0
  37. package/dist/readiness.d.ts.map +1 -0
  38. package/dist/readiness.js +183 -0
  39. package/dist/readiness.js.map +1 -0
  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,89 @@
1
+ import type { ResolveStorageOptions } from './resolve.js';
2
+ import { type ArweaveConfig } from './arweave.js';
3
+ /**
4
+ * Deploy-time storage readiness — what a REAL upload needs, decided from local facts (and, for the
5
+ * best-effort USD estimate, one price-API call) so "dry-run passes, then the real deploy fails at
6
+ * upload" can't happen. Three questions, each pure aside from the one noted network call:
7
+ *
8
+ * - {@link planTurboUpload} — is THIS ONE file free (Turbo's 100 KiB tier) or chargeable?
9
+ * - {@link assessStorageReadiness} — across every backend, what does a real upload of `sizes` need
10
+ * (Arweave credits, a Pinata JWT, a cloud public base)?
11
+ * - {@link assessTurboFunds} — does the resolved Turbo identity have ENOUGH prepaid credits for
12
+ * `sizes`, and (when it's short) does the creator's own wallet already hold some?
13
+ *
14
+ * None of this mints or spends anything — it only INTERROGATES the resolved provider. Identity
15
+ * creation is the caller's job (the CLI's managed-key flow owns the key file location; see
16
+ * `arweave-identity.ts` / `ArweaveConfig.ensureJwk`), so `assessTurboFunds` expects a config that
17
+ * already has one.
18
+ */
19
+ /** Whether `opts` resolves to Arweave via the Turbo (prepaid-credits) provider — the only provider
20
+ * with a free tier and a funds balance to check; `http-bundler` skips every readiness/funds
21
+ * question below (it has its own auth, not a balance this package knows how to read). */
22
+ export declare function isTurboArweave(opts: ResolveStorageOptions): boolean;
23
+ export interface TurboUploadPlan {
24
+ /** Whether this upload is over Turbo's 100 KiB free tier (so it draws on prepaid credits). */
25
+ chargeable: boolean;
26
+ /** `size` in KB, formatted to 1 decimal — for the free-vs-credit readout. */
27
+ sizeKb: string;
28
+ }
29
+ /** The free-vs-credit decision for ONE Turbo upload of `size` bytes — from the local byte size
30
+ * alone, so it works under `--dry-run` too. Null when `opts` doesn't resolve to Turbo-Arweave
31
+ * (nothing to decide). */
32
+ export declare function planTurboUpload(opts: ResolveStorageOptions, size: number): TurboUploadPlan | null;
33
+ /** Per-backend readiness facts for a real upload of `sizes` (per-file byte counts). Each variant
34
+ * carries only what its backend needs checked; a backend with nothing to check (`fs`, or anything
35
+ * this package doesn't know about) reports `'other'` — a literal, not the resolved id, so the
36
+ * union stays a real discriminated union (a plain `string` member would swallow the other
37
+ * branches on narrowing) — callers that branch on `backend` never needed the id anyway. */
38
+ export type StorageReadinessReport = {
39
+ backend: 'arweave';
40
+ overCount: number;
41
+ totalCount: number;
42
+ totalKb: number;
43
+ usd: number | null;
44
+ } | {
45
+ backend: 'ipfs';
46
+ pinataMissingJwt: boolean;
47
+ } | {
48
+ backend: 'cloud';
49
+ missingPublicBase: boolean;
50
+ } | {
51
+ backend: 'other';
52
+ };
53
+ /**
54
+ * What a REAL deploy against `opts` needs, from `sizes` (per-file byte sizes) alone — Arweave
55
+ * credit needs (plus a best-effort USD estimate for the chargeable bytes), a missing Pinata JWT, or
56
+ * a missing cloud public base. The one network call (Turbo's price API) is best-effort: a failure
57
+ * there degrades `usd` to `null` rather than failing the whole check.
58
+ */
59
+ export declare function assessStorageReadiness(opts: ResolveStorageOptions, sizes: number[]): Promise<StorageReadinessReport>;
60
+ export interface TurboFundsCheck {
61
+ /** True when the resolved identity does NOT have enough prepaid credits for `sizes`. */
62
+ short: boolean;
63
+ address: string;
64
+ /** Whether the identity is an EVM one (`.env` key or a remote wallet) rather than the CLI-managed
65
+ * Arweave key — decides which recovery message applies. */
66
+ isEth: boolean;
67
+ haveWinc: number;
68
+ needWinc: number;
69
+ /** How many of `sizes` are over the free tier (what this shortfall is actually for). */
70
+ chargeableCount: number;
71
+ /** Set only when checked (short, a non-eth identity, and a wallet address was given): the
72
+ * creator's OWN wallet's Turbo balance, queryable by address with no key — so "spend those
73
+ * instead of topping up again" can be recommended before ever proposing a top-up. Null if that
74
+ * wallet has never had a Turbo balance. */
75
+ walletCredits?: {
76
+ winc: number;
77
+ credits: string;
78
+ } | null;
79
+ }
80
+ /**
81
+ * The pre-upload funds decision for a Turbo (Arweave) upload of `sizes` (per-file byte sizes):
82
+ * chargeable bytes → the Winston cost → compare against the identity's prepaid balance. `cfg` must
83
+ * already have a resolved identity (`jwk`/`ethSignerKey`/`remoteEth`) — this module only
84
+ * INTERROGATES the resolved provider, never mints one (see the module doc). Returns `null` when
85
+ * nothing is chargeable (every file is free) or the provider can't be reached right now — a
86
+ * best-effort check never false-blocks; the upload itself will surface any real error.
87
+ */
88
+ export declare function assessTurboFunds(cfg: ArweaveConfig, sizes: number[], walletAddr?: string): Promise<TurboFundsCheck | null>;
89
+ //# sourceMappingURL=upload-readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-readiness.d.ts","sourceRoot":"","sources":["../src/upload-readiness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,cAAc,CAAC;AACxD,OAAO,EAAyG,KAAK,aAAa,EAAC,MAAM,cAAc,CAAC;AAExJ;;;;;;;;;;;;;;;GAeG;AAEH;;0FAE0F;AAC1F,wBAAgB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAEnE;AAED,MAAM,WAAW,eAAe;IAC9B,8FAA8F;IAC9F,UAAU,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;2BAE2B;AAC3B,wBAAgB,eAAe,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAGjG;AAED;;;;4FAI4F;AAC5F,MAAM,MAAM,sBAAsB,GAC9B;IAAC,OAAO,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAC,GAChG;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAA;CAAC,GAC5C;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAC,GAC9C;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAAC;AAEvB;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAc1H;AAED,MAAM,WAAW,eAAe;IAC9B,wFAAwF;IACxF,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB;gEAC4D;IAC5D,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,eAAe,EAAE,MAAM,CAAC;IACxB;;;gDAG4C;IAC5C,aAAa,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAuBhI"}
@@ -0,0 +1,85 @@
1
+ import { ARWEAVE_FREE_UPLOAD_LIMIT, arweaveFunding, turboBalanceForAddress, turboUploadCostUsd, turboUploadWinc } from './arweave.js';
2
+ /**
3
+ * Deploy-time storage readiness — what a REAL upload needs, decided from local facts (and, for the
4
+ * best-effort USD estimate, one price-API call) so "dry-run passes, then the real deploy fails at
5
+ * upload" can't happen. Three questions, each pure aside from the one noted network call:
6
+ *
7
+ * - {@link planTurboUpload} — is THIS ONE file free (Turbo's 100 KiB tier) or chargeable?
8
+ * - {@link assessStorageReadiness} — across every backend, what does a real upload of `sizes` need
9
+ * (Arweave credits, a Pinata JWT, a cloud public base)?
10
+ * - {@link assessTurboFunds} — does the resolved Turbo identity have ENOUGH prepaid credits for
11
+ * `sizes`, and (when it's short) does the creator's own wallet already hold some?
12
+ *
13
+ * None of this mints or spends anything — it only INTERROGATES the resolved provider. Identity
14
+ * creation is the caller's job (the CLI's managed-key flow owns the key file location; see
15
+ * `arweave-identity.ts` / `ArweaveConfig.ensureJwk`), so `assessTurboFunds` expects a config that
16
+ * already has one.
17
+ */
18
+ /** Whether `opts` resolves to Arweave via the Turbo (prepaid-credits) provider — the only provider
19
+ * with a free tier and a funds balance to check; `http-bundler` skips every readiness/funds
20
+ * question below (it has its own auth, not a balance this package knows how to read). */
21
+ export function isTurboArweave(opts) {
22
+ return opts.backend === 'arweave' && (opts.arweave?.provider ?? 'turbo') === 'turbo';
23
+ }
24
+ /** The free-vs-credit decision for ONE Turbo upload of `size` bytes — from the local byte size
25
+ * alone, so it works under `--dry-run` too. Null when `opts` doesn't resolve to Turbo-Arweave
26
+ * (nothing to decide). */
27
+ export function planTurboUpload(opts, size) {
28
+ if (!isTurboArweave(opts))
29
+ return null;
30
+ return { chargeable: size >= ARWEAVE_FREE_UPLOAD_LIMIT, sizeKb: (size / 1024).toFixed(1) };
31
+ }
32
+ /**
33
+ * What a REAL deploy against `opts` needs, from `sizes` (per-file byte sizes) alone — Arweave
34
+ * credit needs (plus a best-effort USD estimate for the chargeable bytes), a missing Pinata JWT, or
35
+ * a missing cloud public base. The one network call (Turbo's price API) is best-effort: a failure
36
+ * there degrades `usd` to `null` rather than failing the whole check.
37
+ */
38
+ export async function assessStorageReadiness(opts, sizes) {
39
+ if (opts.backend === 'arweave') {
40
+ const chargeable = sizes.filter((s) => s >= ARWEAVE_FREE_UPLOAD_LIMIT);
41
+ const usd = chargeable.length ? await turboUploadCostUsd(chargeable.reduce((a, b) => a + b, 0)) : null;
42
+ const totalKb = Math.round(sizes.reduce((a, b) => a + b, 0) / 1024);
43
+ return { backend: 'arweave', overCount: chargeable.length, totalCount: sizes.length, totalKb, usd };
44
+ }
45
+ if (opts.backend === 'ipfs') {
46
+ return { backend: 'ipfs', pinataMissingJwt: (opts.ipfs?.mode ?? 'pinata') === 'pinata' && !opts.ipfs?.pinataJwt };
47
+ }
48
+ if (opts.backend === 'cloud') {
49
+ return { backend: 'cloud', missingPublicBase: !opts.cloud?.publicBase };
50
+ }
51
+ return { backend: 'other' };
52
+ }
53
+ /**
54
+ * The pre-upload funds decision for a Turbo (Arweave) upload of `sizes` (per-file byte sizes):
55
+ * chargeable bytes → the Winston cost → compare against the identity's prepaid balance. `cfg` must
56
+ * already have a resolved identity (`jwk`/`ethSignerKey`/`remoteEth`) — this module only
57
+ * INTERROGATES the resolved provider, never mints one (see the module doc). Returns `null` when
58
+ * nothing is chargeable (every file is free) or the provider can't be reached right now — a
59
+ * best-effort check never false-blocks; the upload itself will surface any real error.
60
+ */
61
+ export async function assessTurboFunds(cfg, sizes, walletAddr) {
62
+ const chargeable = sizes.filter((s) => s >= ARWEAVE_FREE_UPLOAD_LIMIT);
63
+ if (chargeable.length === 0)
64
+ return null; // all free
65
+ const funding = await arweaveFunding(cfg);
66
+ let address;
67
+ let haveWinc;
68
+ try {
69
+ address = await funding.address();
70
+ haveWinc = Number((await funding.balance()).winc) || 0;
71
+ }
72
+ catch {
73
+ return null; // can't reach Turbo to check — don't false-block; the upload will surface any real error
74
+ }
75
+ const needWinc = (await turboUploadWinc(chargeable.reduce((a, b) => a + b, 0))) ?? 0;
76
+ const short = needWinc > 0 ? haveWinc < needWinc : haveWinc <= 0;
77
+ const isEth = !!(cfg.ethSignerKey || cfg.remoteEth);
78
+ let walletCredits;
79
+ if (short && !isEth && walletAddr) {
80
+ const wb = await turboBalanceForAddress(walletAddr, 'ethereum');
81
+ walletCredits = wb ? { winc: Number(wb.winc) || 0, credits: wb.credits } : null;
82
+ }
83
+ return { short, address, isEth, haveWinc, needWinc, chargeableCount: chargeable.length, walletCredits };
84
+ }
85
+ //# sourceMappingURL=upload-readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-readiness.js","sourceRoot":"","sources":["../src/upload-readiness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `abx storage upload` core — upload ONE file and return a public locator that PRESERVES the
3
+ * filename, so the declared mimeType survives when the locator is later attached (`abx attach`).
4
+ * The on-chain metadata field has no MIME slot: the URL extension IS the type declaration, so a
5
+ * bare content-addressed locator (`ar://<txid>`, `<gw>/ipfs/<cid>`) — which has no extension —
6
+ * would make the attached artifact `application/octet-stream`. Extracted from main.ts so the
7
+ * capability-based branch (the exact bug this guards) is unit-testable with fake backends.
8
+ */
9
+ import type { StorageBackend, StoredContent } from './backend.js';
10
+ export interface UploadResult {
11
+ /** A fetchable public URL for the file. */
12
+ locator: string;
13
+ /** True when `locator` carries the filename (extension → correct declared type on attach). */
14
+ filenamePreserved: boolean;
15
+ /** Set when we had to fall back to a bare (extension-less) locator — the caller warns. */
16
+ fallbackReason?: string;
17
+ }
18
+ /**
19
+ * Store `content` under `name` and return the best available public locator. Preference order:
20
+ * 1. path-addressed host (cloud/S3/R2): the object key IS the filename → `<publicBase>/<name>`.
21
+ * 2. content-addressed host with directory support (ipfs/arweave): wrap the single file in a
22
+ * one-entry directory → `<base>/<name>` (filename preserved).
23
+ * 3. bare content-addressed locator (e.g. kubo IPFS with no dir-add): `<gw>/ipfs/<cid>` — no
24
+ * extension; `filenamePreserved: false` so the caller can warn about the octet-stream type.
25
+ * Throws for a backend that can't produce any public URL (e.g. `fs`).
26
+ */
27
+ export declare function uploadAndLocate(backend: StorageBackend, name: string, content: StoredContent): Promise<UploadResult>;
28
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAC,cAAc,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AAGhE,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,iBAAiB,EAAE,OAAO,CAAC;IAC3B,0FAA0F;IAC1F,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAID;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAyB1H"}
package/dist/upload.js ADDED
@@ -0,0 +1,41 @@
1
+ import { hashContent } from './backend.js';
2
+ const trimSlash = (s) => s.replace(/\/+$/, '');
3
+ /**
4
+ * Store `content` under `name` and return the best available public locator. Preference order:
5
+ * 1. path-addressed host (cloud/S3/R2): the object key IS the filename → `<publicBase>/<name>`.
6
+ * 2. content-addressed host with directory support (ipfs/arweave): wrap the single file in a
7
+ * one-entry directory → `<base>/<name>` (filename preserved).
8
+ * 3. bare content-addressed locator (e.g. kubo IPFS with no dir-add): `<gw>/ipfs/<cid>` — no
9
+ * extension; `filenamePreserved: false` so the caller can warn about the octet-stream type.
10
+ * Throws for a backend that can't produce any public URL (e.g. `fs`).
11
+ */
12
+ export async function uploadAndLocate(backend, name, content) {
13
+ if (backend.publicBase && backend.putObject) {
14
+ await backend.putObject(name, content);
15
+ return { locator: `${trimSlash(backend.publicBase)}/${name}`, filenamePreserved: true };
16
+ }
17
+ if (backend.putDirectory && backend.locator) {
18
+ try {
19
+ const { base } = await backend.putDirectory([{ name, bytes: content.bytes, contentType: content.contentType }]);
20
+ return { locator: `${trimSlash(base)}/${name}`, filenamePreserved: true };
21
+ }
22
+ catch (e) {
23
+ const hash = hashContent(content.bytes);
24
+ await backend.put(hash, content);
25
+ const loc = await backend.locator(hash);
26
+ if (!loc)
27
+ throw e;
28
+ return { locator: loc, filenamePreserved: false, fallbackReason: e.message };
29
+ }
30
+ }
31
+ if (backend.locator) {
32
+ const hash = hashContent(content.bytes);
33
+ await backend.put(hash, content);
34
+ const loc = await backend.locator(hash);
35
+ if (!loc)
36
+ throw new Error(`backend '${backend.id}' stored the file but returned no durable locator`);
37
+ return { locator: loc, filenamePreserved: false };
38
+ }
39
+ throw new Error(`backend '${backend.id}' can't produce a public URL for an attached file — use ipfs, arweave, or cloud (with a public base).`);
40
+ }
41
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AASA,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAWzC,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAuB,EAAE,IAAY,EAAE,OAAsB;IACjG,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAC5C,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,EAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAC,CAAC;IACxF,CAAC;IACD,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,EAAC,IAAI,EAAC,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,EAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAC,CAAC,CAAC,CAAC;YAC5G,OAAO,EAAC,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAC,CAAC;QAC1E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACjC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,GAAG;gBAAE,MAAM,CAAC,CAAC;YAClB,OAAO,EAAC,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,cAAc,EAAG,CAAW,CAAC,OAAO,EAAC,CAAC;QACxF,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,CAAC,EAAE,mDAAmD,CAAC,CAAC;QACrG,OAAO,EAAC,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAC,CAAC;IAClD,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,CAAC,EAAE,uGAAuG,CAAC,CAAC;AACjJ,CAAC"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@artblocks/abx-storage",
3
- "version": "0.1.0-alpha.4",
3
+ "version": "0.1.0-alpha.41",
4
4
  "license": "MIT",
5
- "description": "ABX Self-Host Toolkit (Layer 3) — the reference byte-custody / storage service. Holds the source-of-truth bytes a token's content commitment points at, content-addressed by hash, behind a pluggable backend interface.",
5
+ "description": "Storage adapters for ABX content using filesystem, S3-compatible, IPFS, or Arweave backends.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
8
8
  "exports": {
@@ -13,18 +13,19 @@
13
13
  },
14
14
  "files": [
15
15
  "dist",
16
+ "CHANGELOG.md",
16
17
  "LICENSE"
17
18
  ],
18
19
  "sideEffects": false,
19
20
  "engines": {
20
- "node": ">=22.5.0"
21
+ "node": ">=22.13.0"
21
22
  },
22
23
  "repository": {
23
24
  "type": "git",
24
25
  "url": "git+https://github.com/ArtBlocks/abx.git",
25
26
  "directory": "packages/storage"
26
27
  },
27
- "homepage": "https://github.com/ArtBlocks/abx#readme",
28
+ "homepage": "https://docs.abx.io",
28
29
  "bugs": "https://github.com/ArtBlocks/abx/issues",
29
30
  "keywords": [
30
31
  "abx",
@@ -38,12 +39,19 @@
38
39
  "access": "public"
39
40
  },
40
41
  "dependencies": {
41
- "viem": "^2.21.0",
42
- "@artblocks/abx-sdk": "0.1.0-alpha.4"
42
+ "viem": "^2.56.5",
43
+ "@artblocks/abx-sdk": "0.1.0-alpha.41"
43
44
  },
44
- "optionalDependencies": {
45
- "@ardrive/turbo-sdk": "^1.23.0",
46
- "@dha-team/arbundles": "^1.0.4"
45
+ "peerDependencies": {
46
+ "@artblocks/abx-storage-arweave": ">=0.1.0-alpha.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "@artblocks/abx-storage-arweave": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "devDependencies": {
54
+ "@artblocks/abx-storage-arweave": "0.1.0-alpha.5"
47
55
  },
48
56
  "scripts": {
49
57
  "build": "tsc -b tsconfig.build.json"