1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 | import { uploadFailed } from './errors.js';
import { checkGate } from './gate.js';
import * as http from './http.js';
/** GET /ipfs/pins — List your pins (offset-paginated). */
export const listPins = (client, query) => http.get(client, '/ipfs/pins', { query });
/** Every pin, following offset pagination (page `limit` defaults to 100). */
export const listAllPins = (client, query) => http.paginateOffset(client, '/ipfs/pins', 'pins', { query });
/** POST /ipfs/pins — Pin by CID (202; billing starts once pinned). */
export const pin = (client, body) => http.post(client, '/ipfs/pins', { body });
/** GET /ipfs/pins/{id} — Pin detail. */
export const getPin = (client, id) => http.get(client, '/ipfs/pins/{id}', { params: { id } });
/** DELETE /ipfs/pins/{id} — Unpin (202; free). */
export const unpin = (client, id) => http.del(client, '/ipfs/pins/{id}', { params: { id } });
/**
* POST /ipfs/uploads — Start a direct upload. Issues a short-lived
* single-use grant `{ upload: { url, token, ... } }`; POST the raw bytes to
* that URL (see `http.uploadBytes`) then poll `getUpload`.
*/
export const startUpload = (client, body) => http.post(client, '/ipfs/uploads', { body });
/** GET /ipfs/uploads/{id} — Upload status (issued/completed/failed/expired). */
export const getUpload = (client, id) => http.get(client, '/ipfs/uploads/{id}', { params: { id } });
/** GET /ipfs/names — List your IPNS names. */
export const listNames = (client) => http.get(client, '/ipfs/names');
/** POST /ipfs/names — Create an IPNS name. */
export const createName = (client, body) => http.post(client, '/ipfs/names', { body });
/** GET /ipfs/names/{id} — IPNS name detail. */
export const getName = (client, id) => http.get(client, '/ipfs/names/{id}', { params: { id } });
/** DELETE /ipfs/names/{id} — Delete an IPNS name (202). */
export const deleteName = (client, id) => http.del(client, '/ipfs/names/{id}', { params: { id } });
/** PUT /ipfs/names/{id}/target — Publish a new target for an IPNS name. */
export const publishTarget = (client, id, body) => http.put(client, '/ipfs/names/{id}/target', { params: { id }, body });
/** GET /ipfs/domains — List your gateway domains. */
export const listDomains = (client) => http.get(client, '/ipfs/domains');
/**
* POST /ipfs/domains — Attach your own domain as an IPFS gateway. Gated on
* `domain`. The response's `dns_target` is the gateway IPv4 the domain's A
* record must point at on manually mapped rows.
*/
export const attachDomain = async (client, body) => {
await checkGate(client, 'POST /ipfs/domains', { domain: body.domain });
return http.post(client, '/ipfs/domains', { body });
};
/** GET /ipfs/domains/{id} — Gateway domain detail. */
export const getDomain = (client, id) => http.get(client, '/ipfs/domains/{id}', { params: { id } });
/** GET /ipfs/domains/{id}/pins — The pins a gateway domain serves, oldest attachment first. */
export const listDomainPins = (client, id, query) => http.get(client, '/ipfs/domains/{id}/pins', { params: { id }, query });
/** Every pin a gateway domain serves, following offset pagination. */
export const listAllDomainPins = (client, id, query) => http.paginateOffset(client, '/ipfs/domains/{id}/pins', 'pins', { params: { id }, query });
/** Resolve the gateway's domain name (only when gated) and run the gate. */
const checkGatewayGate = async (client, op, id) => {
if (!client.gate)
return;
const { domain } = await getDomain(client, id);
await checkGate(client, op, { domain: domain?.domain });
};
/**
* POST /ipfs/domains/{id}/pins — Attach or detach the pins a gateway
* domain serves (`add` / `remove` pin ids; idempotent delta). Gated on the
* gateway's domain (resolved via `getDomain` when a gate is set).
*/
export const updateDomainPins = async (client, id, body) => {
await checkGatewayGate(client, 'POST /ipfs/domains/{id}/pins', id);
return http.post(client, '/ipfs/domains/{id}/pins', { params: { id }, body });
};
/** DELETE /ipfs/domains/{id} — Detach a gateway domain (202). Gated on the gateway's domain. */
export const detachDomain = async (client, id) => {
await checkGatewayGate(client, 'DELETE /ipfs/domains/{id}', id);
return http.del(client, '/ipfs/domains/{id}', { params: { id } });
};
/** GET /ipfs/usage — Storage usage and cost. */
export const usage = (client) => http.get(client, '/ipfs/usage');
const UPLOAD_TERMINAL = new Set(['completed', 'failed', 'expired']);
const toUploadSource = async (source) => {
if (typeof source !== 'string')
return source;
const { readFile } = await import('node:fs/promises');
return new Uint8Array(await readFile(source));
};
/**
* Upload local content to IPFS end to end: start an upload grant, POST the
* bytes to the grant URL, poll until the upload completes, and return the
* final upload (with `cid` and `pin_id`). SOURCE is a file path, bytes, a
* Blob, or a ReadableStream. Throws an uploadFailed error when the upload
* fails or expires, or a timeout error when the deadline passes first.
*/
export const addFile = async (client, source, options = {}) => {
const { name, format, meta } = options;
const startBody = {
...(name === undefined ? {} : { name }),
...(format === undefined ? {} : { format }),
...(meta === undefined ? {} : { meta: { ...meta } }),
};
const { upload } = await startUpload(client, Object.keys(startBody).length === 0 ? undefined : startBody);
await http.uploadBytes(upload.url, upload.token, await toUploadSource(source), { format, fetch: client.fetch });
const { upload: final } = await http.pollUntil(() => getUpload(client, upload.id), (r) => UPLOAD_TERMINAL.has(r.upload.status), {
intervalMs: options.intervalMs,
timeoutMs: options.timeoutMs ?? 300000,
message: `Timed out waiting for IPFS upload ${upload.id}`,
sleep: client.sleep,
});
if (final.status === 'completed')
return final;
throw uploadFailed(`IPFS upload ${final.id} ${final.status}`, final);
};
|