UNPKG

16.9 kBMarkdownView Raw
1# IPFS Repo JavaScript Implementation <!-- omit in toc -->
2
3[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
4[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
5[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
6[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
7[![Travis CI](https://flat.badgen.net/travis/ipfs/js-ipfs-repo)](https://travis-ci.com/ipfs/js-ipfs-repo)
8[![codecov](https://codecov.io/gh/ipfs/js-ipfs-repo/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/js-ipfs-repo) [![Dependency Status](https://david-dm.org/ipfs/js-ipfs-repo.svg?style=flat-square)](https://david-dm.org/ipfs/js-ipfs-repo)
9[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
10![](https://img.shields.io/badge/npm-%3E%3D6.0.0-orange.svg?style=flat-square)
11![](https://img.shields.io/badge/Node.js-%3E%3D10.0.0-orange.svg?style=flat-square)
12
13> Implementation of the IPFS repo spec (https://github.com/ipfs/specs/blob/master/REPO.md) in JavaScript
14
15This is the implementation of the [IPFS repo spec](https://github.com/ipfs/specs/blob/master/REPO.md) in JavaScript.
16
17## Lead Maintainer <!-- omit in toc -->
18
19[Alex Potsides](https://github.com/achingbrain)
20
21## Table of Contents <!-- omit in toc -->
22
23- [Background](#background)
24- [Install](#install)
25 - [npm](#npm)
26 - [Use in Node.js](#use-in-nodejs)
27 - [Use in a browser with browserify, webpack or any other bundler](#use-in-a-browser-with-browserify-webpack-or-any-other-bundler)
28 - [Use in a browser Using a script tag](#use-in-a-browser-using-a-script-tag)
29- [Usage](#usage)
30- [API](#api)
31 - [Setup](#setup)
32 - [`new Repo(path[, options])`](#new-repopath-options)
33 - [`Promise repo.init()`](#promise-repoinit)
34 - [`Promise repo.open()`](#promise-repoopen)
35 - [`Promise repo.close()`](#promise-repoclose)
36 - [`Promise<boolean> repo.exists()`](#promiseboolean-repoexists)
37 - [`Promise<Boolean> repo.isInitialized()`](#promiseboolean-repoisinitialized)
38 - [Repos](#repos)
39 - [`Promise repo.put(key, value:Buffer)`](#promise-repoputkey-valuebuffer)
40 - [`Promise<Buffer> repo.get(key)`](#promisebuffer-repogetkey)
41 - [Blocks](#blocks)
42 - [`Promise<Block> repo.blocks.put(block:Block)`](#promiseblock-repoblocksputblockblock)
43 - [`AsyncIterator<Block> repo.blocks.putMany(source)`](#asynciteratorblock-repoblocksputmanysource)
44 - [`Promise<Buffer> repo.blocks.get(cid)`](#promisebuffer-repoblocksgetcid)
45 - [`AsyncIterable<Buffer> repo.blocks.getMany(source)`](#asynciterablebuffer-repoblocksgetmanysource)
46 - [`Promise<CID> repo.blocks.delete(cid:CID)`](#promisecid-repoblocksdeletecidcid)
47 - [`AsyncIterator<CID> repo.blocks.deleteMany(source)`](#asynciteratorcid-repoblocksdeletemanysource)
48 - [Datastore](#datastore)
49 - [`repo.datastore`](#repodatastore)
50 - [Config](#config)
51 - [`Promise repo.config.set(key:string, value)`](#promise-repoconfigsetkeystring-value)
52 - [`Promise repo.config.replace(value)`](#promise-repoconfigreplacevalue)
53 - [`Promise<?> repo.config.get(key:string)`](#promise-repoconfiggetkeystring)
54 - [`Promise<Object> repo.config.getAll()`](#promiseobject-repoconfiggetall)
55 - [`Promise<boolean> repo.config.exists()`](#promiseboolean-repoconfigexists)
56 - [Version](#version)
57 - [`Promise<Number> repo.version.get()`](#promisenumber-repoversionget)
58 - [`Promise repo.version.set (version:Number)`](#promise-repoversionset-versionnumber)
59 - [API Addr](#api-addr)
60 - [`Promise<String> repo.apiAddr.get()`](#promisestring-repoapiaddrget)
61 - [`Promise repo.apiAddr.set(value)`](#promise-repoapiaddrsetvalue)
62 - [Status](#status)
63 - [`Promise<Object> repo.stat()`](#promiseobject-repostat)
64 - [Lock](#lock)
65 - [`Promise lock.lock(dir)`](#promise-locklockdir)
66 - [`Promise closer.close()`](#promise-closerclose)
67 - [`Promise<boolean> lock.locked(dir)`](#promiseboolean-locklockeddir)
68- [Notes](#notes)
69 - [Migrations](#migrations)
70- [Contribute](#contribute)
71- [License](#license)
72
73## Background
74
75Here is the architectural reasoning for this repo:
76
77```bash
78 ┌────────────────────────────────────────┐
79 │ IPFSRepo │
80 └────────────────────────────────────────┘
81 ┌─────────────────┐
82 │ / │
83 ├─────────────────┤
84 │ Datastore │
85 └─────────────────┘
86 ┌───────────┴───────────┐
87 ┌─────────────────┐ ┌─────────────────┐
88 │ /blocks │ │ /datastore │
89 ├─────────────────┤ ├─────────────────┤
90 │ Datastore │ │ LevelDatastore │
91 └─────────────────┘ └─────────────────┘
92
93┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐
94│ IPFSRepo - Default Node.js │ │ IPFSRepo - Default Browser │
95└────────────────────────────────────────┘ └────────────────────────────────────────┘
96 ┌─────────────────┐ ┌─────────────────┐
97 │ / │ │ / │
98 ├─────────────────┤ ├─────────────────┤
99 │ FsDatastore │ │ IdbDatastore │
100 └─────────────────┘ └─────────────────┘
101 ┌───────────┴───────────┐ ┌───────────┴───────────┐
102┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
103│ /blocks │ │ /datastore │ │ /blocks │ │ /datastore │
104├─────────────────┤ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤
105│ FlatfsDatastore │ │LevelDBDatastore │ │ IdbDatastore │ │ IdbDatastore │
106└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘
107```
108
109This provides a well defined interface for creating and interacting with an IPFS repo.
110
111## Install
112
113### npm
114
115```sh
116> npm install ipfs-repo
117```
118
119### Use in Node.js
120
121```js
122var IPFSRepo = require('ipfs-repo')
123```
124
125### Use in a browser with browserify, webpack or any other bundler
126
127```js
128var IPFSRepo = require('ipfs-repo')
129```
130
131### Use in a browser Using a script tag
132
133Loading this module through a script tag will make the `IpfsRepo` obj available in the global namespace.
134
135```html
136<script src="https://unpkg.com/ipfs-repo/dist/index.min.js"></script>
137<!-- OR -->
138<script src="https://unpkg.com/ipfs-repo/dist/index.js"></script>
139```
140
141## Usage
142
143Example:
144
145```js
146const Repo = require('ipfs-repo')
147const repo = new Repo('/tmp/ipfs-repo')
148
149await repo.init({ cool: 'config' })
150await repo.open()
151console.log('repo is ready')
152```
153
154This now has created the following structure, either on disk or as an in memory representation:
155
156```
157├── blocks
158│   ├── SHARDING
159│ └── _README
160├── config
161├── datastore
162├── keys
163└── version
164```
165
166## API
167
168### Setup
169
170#### `new Repo(path[, options])`
171
172Creates an IPFS Repo.
173
174Arguments:
175
176* `path` (string, mandatory): the path for this repo
177* `options` (object, optional): may contain the following values
178 * `autoMigrate` (bool, defaults to `true`): controls automatic migrations of repository.
179 * `lock` ([Lock](#lock) or string *Deprecated*): what type of lock to use. Lock has to be acquired when opening. string can be `"fs"` or `"memory"`.
180 * `storageBackends` (object, optional): may contain the following values, which should each be a class implementing the [datastore interface](https://github.com/ipfs/interface-datastore#readme):
181 * `root` (defaults to [`datastore-fs`](https://github.com/ipfs/js-datastore-fs#readme) in Node.js and [`datastore-level`](https://github.com/ipfs/js-datastore-level#readme) in the browser). Defines the back-end type used for gets and puts of values at the root (`repo.set()`, `repo.get()`)
182 * `blocks` (defaults to [`datastore-fs`](https://github.com/ipfs/js-datastore-fs#readme) in Node.js and [`datastore-level`](https://github.com/ipfs/js-datastore-level#readme) in the browser). Defines the back-end type used for gets and puts of values at `repo.blocks`.
183 * `keys` (defaults to [`datastore-fs`](https://github.com/ipfs/js-datastore-fs#readme) in Node.js and [`datastore-level`](https://github.com/ipfs/js-datastore-level#readme) in the browser). Defines the back-end type used for gets and puts of encrypted keys at `repo.keys`
184 * `datastore` (defaults to [`datastore-level`](https://github.com/ipfs/js-datastore-level#readme)). Defines the back-end type used as the key-value store used for gets and puts of values at `repo.datastore`.
185
186```js
187const repo = new Repo('path/to/repo')
188```
189
190#### `Promise repo.init()`
191
192Creates the necessary folder structure inside the repo
193
194#### `Promise repo.open()`
195
196[Locks](https://en.wikipedia.org/wiki/Record_locking) the repo to prevent conflicts arising from simultaneous access
197
198#### `Promise repo.close()`
199
200Unlocks the repo.
201
202#### `Promise<boolean> repo.exists()`
203
204Tells whether this repo exists or not. Returned promise resolves to a `boolean`
205
206#### `Promise<Boolean> repo.isInitialized()`
207
208The returned promise resolves to `false` if the repo has not been initialized and `true` if it has
209
210### Repos
211
212Root repo:
213
214#### `Promise repo.put(key, value:Buffer)`
215
216Put a value at the root of the repo
217
218* `key` can be a buffer, a string or a [Key][]
219
220#### `Promise<Buffer> repo.get(key)`
221
222Get a value at the root of the repo
223
224* `key` can be a buffer, a string or a [Key][]
225
226### Blocks
227
228#### `Promise<Block> repo.blocks.put(block:Block)`
229
230* `block` should be of type [Block][]
231
232#### `AsyncIterator<Block> repo.blocks.putMany(source)`
233
234Put many blocks.
235
236* `source` should be an AsyncIterable that yields entries of type [Block][]
237
238#### `Promise<Buffer> repo.blocks.get(cid)`
239
240Get block.
241
242* `cid` is the content id of type [CID][]
243
244#### `AsyncIterable<Buffer> repo.blocks.getMany(source)`
245
246Get block.
247
248* `source` should be an AsyncIterable that yields entries of type [CID][]
249
250#### `Promise<CID> repo.blocks.delete(cid:CID)`
251
252* `cid` should be of the type [CID][]
253
254Delete a block
255
256#### `AsyncIterator<CID> repo.blocks.deleteMany(source)`
257
258* `source` should be an Iterable or AsyncIterable that yields entries of the type [CID][]
259
260Delete many blocks
261
262### Datastore
263
264#### `repo.datastore`
265
266This contains a full implementation of [the `interface-datastore` API](https://github.com/ipfs/interface-datastore#api).
267
268### Config
269
270Instead of using `repo.set('config')` this exposes an API that allows you to set and get a decoded config object, as well as, in a safe manner, change any of the config values individually.
271
272#### `Promise repo.config.set(key:string, value)`
273
274Set a config value. `value` can be any object that is serializable to JSON.
275
276* `key` is a string specifying the object path. Example:
277
278```js
279await repo.config.set('a.b.c', 'c value')
280const config = await repo.config.get()
281assert.equal(config.a.b.c, 'c value')
282```
283
284#### `Promise repo.config.replace(value)`
285
286Set the whole config value. `value` can be any object that is serializable to JSON.
287
288#### `Promise<?> repo.config.get(key:string)`
289
290Get a config value. Returned promise resolves to the same type that was set before.
291
292* `key` is a string specifying the object path. Example:
293
294```js
295const value = await repo.config.get('a.b.c')
296console.log('config.a.b.c = ', value)
297```
298
299#### `Promise<Object> repo.config.getAll()`
300
301Get the entire config value.
302
303#### `Promise<boolean> repo.config.exists()`
304
305Whether the config sub-repo exists.
306
307### Version
308
309#### `Promise<Number> repo.version.get()`
310
311Gets the repo version (an integer).
312
313#### `Promise repo.version.set (version:Number)`
314
315Sets the repo version
316
317### API Addr
318
319#### `Promise<String> repo.apiAddr.get()`
320
321Gets the API address.
322
323#### `Promise repo.apiAddr.set(value)`
324
325Sets the API address.
326
327* `value` should be a [Multiaddr][] or a String representing a valid one.
328
329### Status
330
331#### `Promise<Object> repo.stat()`
332
333Gets the repo status.
334
335Returned promise resolves to an `Object` with the following keys:
336
337- `numObjects`
338- `repoPath`
339- `repoSize`
340- `version`
341- `storageMax`
342
343### Lock
344
345IPFS Repo comes with two built in locks: memory and fs. These can be imported via the following:
346
347```js
348const fsLock = require('ipfs-repo/src/lock') // Default in Node.js
349const memoryLock = require('ipfs-repo/src/lock-memory') // Default in browser
350```
351
352You can also provide your own custom Lock. It must be an object with the following interface:
353
354#### `Promise lock.lock(dir)`
355
356Sets the lock if one does not already exist. If a lock already exists, should throw an error.
357
358`dir` is a string to the directory the lock should be created at. The repo typically creates the lock at its root.
359
360Returns `closer`, where `closer` has a `close` method for removing the lock.
361
362#### `Promise closer.close()`
363
364Closes the lock created by `lock.open`
365
366If no error was thrown, the lock was successfully removed.
367
368#### `Promise<boolean> lock.locked(dir)`
369
370Checks the existence of the lock.
371
372`dir` is the path to the directory to check for the lock. The repo typically checks for the lock at its root.
373
374Returned promise resolves to a `boolean` indicating the existence of the lock.
375
376## Notes
377
378- [Explanation of how repo is structured](https://github.com/ipfs/js-ipfs-repo/pull/111#issuecomment-279948247)
379
380### Migrations
381
382When there is a new repo migration and the version of repo is increased, don't
383forget to propagate the changes into the test repo (`test/test-repo`).
384
385**For tools that run mainly in the browser environment, be aware that disabling automatic
386migrations leaves the user with no way to run the migrations because there is no CLI in the browser. In such
387a case, you should provide a way to trigger migrations manually.**
388
389## Contribute
390
391There are some ways you can make this module better:
392
393- Consult our [open issues](https://github.com/ipfs/js-ipfs-repo/issues) and take on one of them
394- Help our tests reach 100% coverage!
395
396This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
397
398[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)
399
400## License
401
402[MIT](LICENSE)
403
404[CID]: https://github.com/multiformats/js-cid
405[Key]: https://github.com/ipfs/interface-datastore#keys
406[Block]: https://github.com/ipld/js-ipld-block
407[Multiaddr]: https://github.com/multiformats/js-multiaddr