@artblocks/abx-storage 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/arweave-identity.d.ts +25 -0
- package/dist/arweave-identity.d.ts.map +1 -0
- package/dist/arweave-identity.js +14 -0
- package/dist/arweave-identity.js.map +1 -0
- package/dist/arweave.d.ts +259 -0
- package/dist/arweave.d.ts.map +1 -0
- package/dist/arweave.js +458 -0
- package/dist/arweave.js.map +1 -0
- package/dist/backend.d.ts +87 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +39 -0
- package/dist/backend.js.map +1 -0
- package/dist/cloud.d.ts +105 -0
- package/dist/cloud.d.ts.map +1 -0
- package/dist/cloud.js +203 -0
- package/dist/cloud.js.map +1 -0
- package/dist/content-index.d.ts +22 -0
- package/dist/content-index.d.ts.map +1 -0
- package/dist/content-index.js +26 -0
- package/dist/content-index.js.map +1 -0
- package/dist/fs.d.ts +23 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +50 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/ipfs.d.ts +62 -0
- package/dist/ipfs.d.ts.map +1 -0
- package/dist/ipfs.js +135 -0
- package/dist/ipfs.js.map +1 -0
- package/dist/resolve.d.ts +29 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +43 -0
- package/dist/resolve.js.map +1 -0
- package/package.json +52 -0
package/dist/ipfs.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { ContentIndex } from './content-index.js';
|
|
2
|
+
const trim = (u) => u.replace(/\/+$/, '');
|
|
3
|
+
export class IpfsBackend {
|
|
4
|
+
cfg;
|
|
5
|
+
id = 'ipfs';
|
|
6
|
+
index;
|
|
7
|
+
constructor(cfg, dataDir) {
|
|
8
|
+
this.cfg = cfg;
|
|
9
|
+
this.index = new ContentIndex(dataDir);
|
|
10
|
+
}
|
|
11
|
+
async put(hash, content) {
|
|
12
|
+
const cid = this.cfg.mode === 'pinata' ? await this.addPinata(content) : await this.addKubo(content);
|
|
13
|
+
this.index.set(hash, { pointer: cid, contentType: content.contentType });
|
|
14
|
+
}
|
|
15
|
+
async get(hash) {
|
|
16
|
+
const entry = this.index.get(hash);
|
|
17
|
+
if (!entry)
|
|
18
|
+
return null;
|
|
19
|
+
const res = await fetch(`${trim(this.cfg.gateway)}/ipfs/${entry.pointer}`);
|
|
20
|
+
if (res.status === 404)
|
|
21
|
+
return null;
|
|
22
|
+
if (!res.ok)
|
|
23
|
+
throw new Error(`IPFS gateway GET failed (${res.status})`);
|
|
24
|
+
// Gateways don't reliably echo the original content type — use what we stored.
|
|
25
|
+
return { bytes: new Uint8Array(await res.arrayBuffer()), contentType: entry.contentType };
|
|
26
|
+
}
|
|
27
|
+
async has(hash) {
|
|
28
|
+
return this.index.has(hash);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The **gateway HTTPS URL** for the pinned bytes (`<gateway>/ipfs/<cid>`) — the production-safe
|
|
32
|
+
* form an NFT `image` needs, since browsers, wallets, and most marketplaces can't render a raw
|
|
33
|
+
* `ipfs://<cid>`. The CID is content-addressed so the bytes are resolvable through *any* gateway
|
|
34
|
+
* (and verifiable against the on-chain keccak256); we serve a concrete, reachable one. A pinning
|
|
35
|
+
* service + a public gateway is therefore part of operating IPFS custody — a local gateway
|
|
36
|
+
* (`127.0.0.1`/`localhost`) produces a URL only this machine can resolve. Null until pinned.
|
|
37
|
+
*/
|
|
38
|
+
async locator(hash) {
|
|
39
|
+
const entry = this.index.get(hash);
|
|
40
|
+
return entry ? `${trim(this.cfg.gateway)}/ipfs/${entry.pointer}` : null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Pin a directory of files as ONE IPFS object and return its gateway base
|
|
44
|
+
* (`<gateway>/ipfs/<dirCID>`), so `<base>/0.png` resolves. The CID is content-addressed →
|
|
45
|
+
* gateway-agnostic integrity for the whole set. Pinata only (kubo directory add is deferred).
|
|
46
|
+
*/
|
|
47
|
+
async putDirectory(entries) {
|
|
48
|
+
if (this.cfg.mode !== 'pinata') {
|
|
49
|
+
throw new Error('IPFS directory upload currently requires pinata mode (kubo recursive add is not yet wired)');
|
|
50
|
+
}
|
|
51
|
+
if (!this.cfg.pinataJwt)
|
|
52
|
+
throw new Error('IPFS pinata mode needs PINATA_JWT');
|
|
53
|
+
const fd = new FormData();
|
|
54
|
+
// Each file is appended under a common wrapping folder; Pinata returns that folder's CID,
|
|
55
|
+
// so the entries are addressable as `<gateway>/ipfs/<cid>/<name>`.
|
|
56
|
+
for (const e of entries) {
|
|
57
|
+
fd.append('file', new Blob([e.bytes], { type: e.contentType }), `abx/${e.name}`);
|
|
58
|
+
}
|
|
59
|
+
fd.append('pinataOptions', JSON.stringify({ cidVersion: 1 }));
|
|
60
|
+
const res = await fetch(`${trim(this.cfg.pinataEndpoint ?? 'https://api.pinata.cloud')}/pinning/pinFileToIPFS`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: { authorization: `Bearer ${this.cfg.pinataJwt}` },
|
|
63
|
+
body: fd,
|
|
64
|
+
});
|
|
65
|
+
if (!res.ok)
|
|
66
|
+
throw new Error(`Pinata directory pin failed (${res.status}): ${await res.text()}`);
|
|
67
|
+
const cid = (await res.json()).IpfsHash;
|
|
68
|
+
if (!cid)
|
|
69
|
+
throw new Error('Pinata directory pin returned no CID');
|
|
70
|
+
return { base: `${trim(this.cfg.gateway)}/ipfs/${cid}` };
|
|
71
|
+
}
|
|
72
|
+
async health() {
|
|
73
|
+
try {
|
|
74
|
+
if (this.cfg.mode === 'pinata') {
|
|
75
|
+
if (!this.cfg.pinataJwt)
|
|
76
|
+
return { ok: false, detail: 'PINATA_JWT not set' };
|
|
77
|
+
const res = await fetch(`${trim(this.cfg.pinataEndpoint ?? 'https://api.pinata.cloud')}/data/testAuthentication`, {
|
|
78
|
+
headers: { authorization: `Bearer ${this.cfg.pinataJwt}` },
|
|
79
|
+
});
|
|
80
|
+
return { ok: res.ok, detail: res.ok ? `pinata auth ok · gateway ${this.cfg.gateway}` : `pinata auth failed (${res.status})` };
|
|
81
|
+
}
|
|
82
|
+
if (!this.cfg.apiUrl)
|
|
83
|
+
return { ok: false, detail: 'kubo apiUrl not set' };
|
|
84
|
+
const res = await fetch(`${trim(this.cfg.apiUrl)}/api/v0/version`, { method: 'POST' });
|
|
85
|
+
return { ok: res.ok, detail: res.ok ? `kubo ${this.cfg.apiUrl} · gateway ${this.cfg.gateway}` : `kubo unreachable (${res.status})` };
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
return { ok: false, detail: e.message };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
form(content) {
|
|
92
|
+
const fd = new FormData();
|
|
93
|
+
fd.set('file', new Blob([content.bytes], { type: content.contentType }), 'content');
|
|
94
|
+
return fd;
|
|
95
|
+
}
|
|
96
|
+
async addKubo(content) {
|
|
97
|
+
if (!this.cfg.apiUrl)
|
|
98
|
+
throw new Error('IPFS kubo mode needs an apiUrl (e.g. http://127.0.0.1:5001)');
|
|
99
|
+
const res = await fetch(`${trim(this.cfg.apiUrl)}/api/v0/add?pin=true&cid-version=1`, { method: 'POST', body: this.form(content) });
|
|
100
|
+
if (!res.ok)
|
|
101
|
+
throw new Error(`IPFS add failed (${res.status}): ${await res.text()}`);
|
|
102
|
+
const last = (await res.text()).trim().split('\n').pop() ?? '';
|
|
103
|
+
const cid = JSON.parse(last).Hash;
|
|
104
|
+
if (!cid)
|
|
105
|
+
throw new Error('IPFS add returned no CID');
|
|
106
|
+
return cid;
|
|
107
|
+
}
|
|
108
|
+
async addPinata(content) {
|
|
109
|
+
if (!this.cfg.pinataJwt)
|
|
110
|
+
throw new Error('IPFS pinata mode needs PINATA_JWT');
|
|
111
|
+
const res = await fetch(`${trim(this.cfg.pinataEndpoint ?? 'https://api.pinata.cloud')}/pinning/pinFileToIPFS`, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: { authorization: `Bearer ${this.cfg.pinataJwt}` },
|
|
114
|
+
body: this.form(content),
|
|
115
|
+
});
|
|
116
|
+
if (!res.ok)
|
|
117
|
+
throw new Error(`Pinata pin failed (${res.status}): ${await res.text()}`);
|
|
118
|
+
const cid = (await res.json()).IpfsHash;
|
|
119
|
+
if (!cid)
|
|
120
|
+
throw new Error('Pinata pin returned no CID');
|
|
121
|
+
return cid;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Build an IPFS config from the environment (non-secret values; PINATA_JWT is the secret). */
|
|
125
|
+
export function ipfsConfigFromEnv() {
|
|
126
|
+
const mode = (process.env.ABX_IPFS_MODE ?? (process.env.PINATA_JWT ? 'pinata' : 'kubo'));
|
|
127
|
+
return {
|
|
128
|
+
mode,
|
|
129
|
+
gateway: process.env.ABX_IPFS_GATEWAY ?? (mode === 'pinata' ? 'https://gateway.pinata.cloud' : 'http://127.0.0.1:8080'),
|
|
130
|
+
apiUrl: process.env.ABX_IPFS_API_URL ?? 'http://127.0.0.1:5001',
|
|
131
|
+
pinataEndpoint: process.env.ABX_PINATA_ENDPOINT ?? 'https://api.pinata.cloud',
|
|
132
|
+
pinataJwt: process.env.PINATA_JWT,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=ipfs.js.map
|
package/dist/ipfs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipfs.js","sourceRoot":"","sources":["../src/ipfs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type CloudStorageConfig } from './cloud.js';
|
|
2
|
+
import { type IpfsConfig } from './ipfs.js';
|
|
3
|
+
import { type ArweaveConfig } from './arweave.js';
|
|
4
|
+
import type { StorageBackend } from './backend.js';
|
|
5
|
+
export interface ResolveStorageOptions {
|
|
6
|
+
/** Backend id; defaults to `ABX_STORAGE_BACKEND`, then `fs`. */
|
|
7
|
+
backend?: string;
|
|
8
|
+
/** Data directory for the `fs` backend and the `ipfs` content index. */
|
|
9
|
+
dataDir?: string;
|
|
10
|
+
/** Full cloud config (the CLI merges non-secret config + env secrets). Falls back to env. */
|
|
11
|
+
cloud?: CloudStorageConfig;
|
|
12
|
+
/** Full IPFS config (the CLI merges non-secret config + env secrets). Falls back to env. */
|
|
13
|
+
ipfs?: IpfsConfig;
|
|
14
|
+
/** Full Arweave config (the CLI merges non-secret config + env secrets). Falls back to env. */
|
|
15
|
+
arweave?: ArweaveConfig;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Pick a storage backend. Built backends: **`fs`** (local disk, zero-dep floor) ·
|
|
19
|
+
* **`cloud`** / `s3` (S3-compatible: AWS S3, R2, B2, MinIO) · **`ipfs`** (self-hosted
|
|
20
|
+
* Kubo node or managed Pinata). Each implements the same {@link StorageBackend}
|
|
21
|
+
* interface, so the indexer and token API never change. Non-secret config is passed
|
|
22
|
+
* in via `opts` (the CLI resolves it from flags → env → default); secrets come from env.
|
|
23
|
+
* With no `opts`, every backend falls back to building entirely from env.
|
|
24
|
+
*
|
|
25
|
+
* `arweave` is pay-once permanent storage — retrieval dep-free via a gateway,
|
|
26
|
+
* upload through an injectable bundler.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveBackend(opts?: ResolveStorageOptions): StorageBackend;
|
|
29
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAA0C,KAAK,kBAAkB,EAAC,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAiC,KAAK,UAAU,EAAC,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAuC,KAAK,aAAa,EAAC,MAAM,cAAc,CAAC;AACtF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,4FAA4F;IAC5F,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAaD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,qBAA0B,GAAG,cAAc,CAkB/E"}
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { LocalFsBackend } from './fs.js';
|
|
2
|
+
import { CloudStorageBackend, cloudConfigFromEnv } from './cloud.js';
|
|
3
|
+
import { IpfsBackend, ipfsConfigFromEnv } from './ipfs.js';
|
|
4
|
+
import { ArweaveBackend, arweaveConfigFromEnv } from './arweave.js';
|
|
5
|
+
function assertCloud(cfg) {
|
|
6
|
+
const missing = ['endpoint', 'bucket', 'accessKeyId', 'secretAccessKey'].filter((k) => !cfg[k]);
|
|
7
|
+
if (missing.length) {
|
|
8
|
+
throw new Error(`Cloud storage is missing ${missing.join(', ')}. Pass non-secret values as flags ` +
|
|
9
|
+
`(\`--backend cloud --endpoint <url> --bucket <b> --region <r>\`) or set env vars ` +
|
|
10
|
+
`(ABX_S3_ENDPOINT / ABX_S3_BUCKET / ABX_S3_REGION); credentials in .env (ABX_S3_ACCESS_KEY_ID / ABX_S3_SECRET_ACCESS_KEY).`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Pick a storage backend. Built backends: **`fs`** (local disk, zero-dep floor) ·
|
|
15
|
+
* **`cloud`** / `s3` (S3-compatible: AWS S3, R2, B2, MinIO) · **`ipfs`** (self-hosted
|
|
16
|
+
* Kubo node or managed Pinata). Each implements the same {@link StorageBackend}
|
|
17
|
+
* interface, so the indexer and token API never change. Non-secret config is passed
|
|
18
|
+
* in via `opts` (the CLI resolves it from flags → env → default); secrets come from env.
|
|
19
|
+
* With no `opts`, every backend falls back to building entirely from env.
|
|
20
|
+
*
|
|
21
|
+
* `arweave` is pay-once permanent storage — retrieval dep-free via a gateway,
|
|
22
|
+
* upload through an injectable bundler.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveBackend(opts = {}) {
|
|
25
|
+
const id = opts.backend ?? process.env.ABX_STORAGE_BACKEND ?? 'fs';
|
|
26
|
+
switch (id) {
|
|
27
|
+
case 'fs':
|
|
28
|
+
return new LocalFsBackend(opts.dataDir);
|
|
29
|
+
case 'cloud':
|
|
30
|
+
case 's3': {
|
|
31
|
+
const cfg = opts.cloud ?? cloudConfigFromEnv();
|
|
32
|
+
assertCloud(cfg);
|
|
33
|
+
return new CloudStorageBackend(cfg);
|
|
34
|
+
}
|
|
35
|
+
case 'ipfs':
|
|
36
|
+
return new IpfsBackend(opts.ipfs ?? ipfsConfigFromEnv(), opts.dataDir);
|
|
37
|
+
case 'arweave':
|
|
38
|
+
return new ArweaveBackend(opts.arweave ?? arweaveConfigFromEnv(), opts.dataDir);
|
|
39
|
+
default:
|
|
40
|
+
throw new Error(`Unknown storage backend '${id}'. Built: fs | cloud (alias s3) | ipfs | arweave.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AACvC,OAAO,EAAC,mBAAmB,EAAE,kBAAkB,EAA0B,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAC,WAAW,EAAE,iBAAiB,EAAkB,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAC,cAAc,EAAE,oBAAoB,EAAqB,MAAM,cAAc,CAAC;AAgBtF,SAAS,WAAW,CAAC,GAAuB;IAC1C,MAAM,OAAO,GAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,iBAAiB,CAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3G,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,4BAA4B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,oCAAoC;YAChF,mFAAmF;YACnF,2HAA2H,CAC9H,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B,EAAE;IAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,IAAI,CAAC;IACnE,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,IAAI;YACP,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,KAAK,OAAO,CAAC;QACb,KAAK,IAAI,CAAC,CAAC,CAAC;YACV,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,kBAAkB,EAAE,CAAC;YAC/C,WAAW,CAAC,GAAG,CAAC,CAAC;YACjB,OAAO,IAAI,mBAAmB,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QACD,KAAK,MAAM;YACT,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,IAAI,iBAAiB,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACzE,KAAK,SAAS;YACZ,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,IAAI,oBAAoB,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAClF;YACE,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,mDAAmD,CAAC,CAAC;IACvG,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@artblocks/abx-storage",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
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.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.5.0"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/ArtBlocks/abx.git",
|
|
25
|
+
"directory": "packages/storage"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/ArtBlocks/abx#readme",
|
|
28
|
+
"bugs": "https://github.com/ArtBlocks/abx/issues",
|
|
29
|
+
"keywords": [
|
|
30
|
+
"abx",
|
|
31
|
+
"nft",
|
|
32
|
+
"storage",
|
|
33
|
+
"ipfs",
|
|
34
|
+
"arweave",
|
|
35
|
+
"art-blocks"
|
|
36
|
+
],
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"viem": "^2.21.0",
|
|
42
|
+
"@artblocks/abx-sdk": "0.1.0-alpha.0"
|
|
43
|
+
},
|
|
44
|
+
"optionalDependencies": {
|
|
45
|
+
"@ardrive/turbo-sdk": "^1.23.0",
|
|
46
|
+
"@dha-team/arbundles": "^1.0.4"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsc -b tsconfig.build.json"
|
|
50
|
+
},
|
|
51
|
+
"types": "./dist/index.d.ts"
|
|
52
|
+
}
|