diff --git a/.github/workflows/js-test-and-release.yml b/.github/workflows/js-test-and-release.yml index 8030ec6..74b2386 100644 --- a/.github/workflows/js-test-and-release.yml +++ b/.github/workflows/js-test-and-release.yml @@ -5,18 +5,16 @@ name: test & maybe release on: push: branches: - - master # with #262 - ${{{ github.default_branch }}} + - master pull_request: - branches: - - master # with #262 - ${{{ github.default_branch }}} jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master @@ -29,16 +27,16 @@ jobs: strategy: matrix: os: [windows-latest, ubuntu-latest, macos-latest] - node: [16] + node: [lts/*] fail-fast: true steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - uses: ipfs/aegir/actions/cache-node-modules@master - run: npm run --if-present test:node - - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0 + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 with: flags: node @@ -46,13 +44,13 @@ jobs: needs: check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master - run: npm run --if-present test:chrome - - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0 + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 with: flags: chrome @@ -60,13 +58,13 @@ jobs: needs: check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master - run: npm run --if-present test:chrome-webworker - - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0 + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 with: flags: chrome-webworker @@ -74,13 +72,13 @@ jobs: needs: check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master - run: npm run --if-present test:firefox - - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0 + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 with: flags: firefox @@ -88,13 +86,13 @@ jobs: needs: check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master - run: npm run --if-present test:firefox-webworker - - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0 + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 with: flags: firefox-webworker @@ -102,13 +100,13 @@ jobs: needs: check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master - run: npx xvfb-maybe npm run --if-present test:electron-main - - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0 + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 with: flags: electron-main @@ -116,25 +114,25 @@ jobs: needs: check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master - run: npx xvfb-maybe npm run --if-present test:electron-renderer - - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0 + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 with: flags: electron-renderer release: needs: [test-node, test-chrome, test-chrome-webworker, test-firefox, test-firefox-webworker, test-electron-main, test-electron-renderer] runs-on: ubuntu-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/master' # with #262 - 'refs/heads/${{{ github.default_branch }}}' + if: github.event_name == 'push' && github.ref == 'refs/heads/master' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: node-version: lts/* - uses: ipfs/aegir/actions/cache-node-modules@master @@ -144,5 +142,5 @@ jobs: docker-username: ${{ secrets.DOCKER_USERNAME }} - run: npm run --if-present release env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.UCI_GITHUB_TOKEN || github.token }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 238a04e..7ad9e67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,66 +1,9 @@ -dist/ - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Typescript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# while testing npm5 +node_modules +build +dist +.docs +.coverage +node_modules package-lock.json yarn.lock -types -docs \ No newline at end of file +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index d4115b1..ed04e6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## [9.0.0](https://github.com/ipfs/js-datastore-fs/compare/v8.0.0...v9.0.0) (2023-03-14) + + +### âš  BREAKING CHANGES + +* interface-datastore 8.x.x has removed the open and close methods as these are implementation specific + +### Bug Fixes + +* fix exports map ([4332006](https://github.com/ipfs/js-datastore-fs/commit/4332006aba3e8e67c80144b110cc81042ce07e03)) + + +### Dependencies + +* update interface-datastore to 8.x.x ([#180](https://github.com/ipfs/js-datastore-fs/issues/180)) ([2ef5f5c](https://github.com/ipfs/js-datastore-fs/commit/2ef5f5cf021b1876cb83c53bafebb5f153c77462)) + + +### Trivial Changes + +* update project config ([62adc6b](https://github.com/ipfs/js-datastore-fs/commit/62adc6b238e64c6040afb4887bf6999de42cde08)) + ## [8.0.0](https://github.com/ipfs/js-datastore-fs/compare/v7.0.0...v8.0.0) (2022-08-12) diff --git a/README.md b/README.md index 65c9cd2..3028612 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ # datastore-fs -[![ipfs.io](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io) -[![IRC](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) -[![Discord](https://img.shields.io/discord/806902334369824788?style=flat-square)](https://discord.gg/ipfs) +[![ipfs.tech](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.tech) +[![Discuss](https://img.shields.io/discourse/https/discuss.ipfs.tech/posts.svg?style=flat-square)](https://discuss.ipfs.tech) [![codecov](https://img.shields.io/codecov/c/github/ipfs/js-datastore-fs.svg?style=flat-square)](https://codecov.io/gh/ipfs/js-datastore-fs) -[![CI](https://img.shields.io/github/workflow/status/ipfs/js-datastore-fs/test%20&%20maybe%20release/master?style=flat-square)](https://github.com/ipfs/js-datastore-fs/actions/workflows/js-test-and-release.yml) +[![CI](https://img.shields.io/github/actions/workflow/status/ipfs/js-datastore-fs/js-test-and-release.yml?branch=master\&style=flat-square)](https://github.com/ipfs/js-datastore-fs/actions/workflows/js-test-and-release.yml?query=branch%3Amaster) > Datastore implementation with file system backend @@ -12,9 +11,9 @@ - [Install](#install) - [Usage](#usage) -- [Contribute](#contribute) +- [API Docs](#api-docs) - [License](#license) -- [Contribute](#contribute-1) +- [Contribute](#contribute) ## Install @@ -30,13 +29,9 @@ import { FSDatastore } from 'datastore-fs' const store = new FSDatastore('path/to/store') ``` -## Contribute - -Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/js-datastore-fs/issues)! +## API Docs -This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). - -[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) +- ## License @@ -47,8 +42,12 @@ Licensed under either of ## Contribute -Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/js-ipfs-unixfs-importer/issues)! +Contributions welcome! Please check out [the issues](https://github.com/ipfs/js-datastore-fs/issues). + +Also see our [contributing document](https://github.com/ipfs/community/blob/master/CONTRIBUTING_JS.md) for more information on how we work, and about contributing in general. + +Please be aware that all interactions related to this repo are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). -This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. [![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) diff --git a/package.json b/package.json index 7459993..98922a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "datastore-fs", - "version": "8.0.0", + "version": "9.0.0", "description": "Datastore implementation with file system backend", "author": "Friedel Ziegelmayer", "license": "Apache-2.0 OR MIT", @@ -25,22 +25,6 @@ }, "type": "module", "types": "./dist/src/index.d.ts", - "typesVersions": { - "*": { - "*": [ - "*", - "dist/*", - "dist/src/*", - "dist/src/*/index" - ], - "src/*": [ - "*", - "dist/*", - "dist/src/*", - "dist/src/*/index" - ] - } - }, "files": [ "src", "dist", @@ -50,7 +34,7 @@ "exports": { ".": { "types": "./dist/src/index.d.ts", - "import": "./src/index.js" + "import": "./dist/src/index.js" } }, "eslintConfig": { @@ -147,35 +131,28 @@ "scripts": { "clean": "aegir clean", "lint": "aegir lint", - "build": "aegir build", + "build": "aegir build --bundle false", "release": "aegir release", - "test": "aegir test", + "test": "aegir test -t node -t electron-main", "test:node": "aegir test -t node", - "dep-check": "aegir dep-check -i rimraf" + "test:electron-main": "aegir test -t electron-main", + "dep-check": "aegir dep-check", + "docs": "aegir docs" }, "dependencies": { - "datastore-core": "^8.0.1", + "datastore-core": "^9.0.1", "fast-write-atomic": "^0.2.0", - "interface-datastore": "^7.0.0", - "it-glob": "^1.0.1", - "it-map": "^1.0.5", - "it-parallel-batch": "^1.0.9", - "mkdirp": "^1.0.4" + "interface-datastore": "^8.0.0", + "interface-store": "^4.0.0", + "it-glob": "^2.0.1", + "it-map": "^2.0.1", + "it-parallel-batch": "^2.0.1" }, "devDependencies": { - "@types/mkdirp": "^1.0.2", - "@types/rimraf": "^3.0.2", - "aegir": "^37.5.0", - "async-iterator-all": "^1.0.0", - "detect-node": "^2.0.4", - "interface-datastore-tests": "^3.0.0", - "ipfs-utils": "^9.0.4", - "memdown": "^6.0.0", - "rimraf": "^3.0.2" - }, - "browser": { - "fs": false, - "path": false, - "util": false + "@types/mkdirp": "^2.0.0", + "@types/rimraf": "^4.0.5", + "aegir": "^38.1.7", + "interface-datastore-tests": "^4.0.0", + "ipfs-utils": "^9.0.4" } } diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 6d7c7df..0000000 --- a/src/index.js +++ /dev/null @@ -1,365 +0,0 @@ -import fs from 'fs' -import glob from 'it-glob' -import mkdirp from 'mkdirp' -import path from 'path' -import { promisify } from 'util' -import { - Key -} from 'interface-datastore' -import { - BaseDatastore, Errors -} from 'datastore-core' -import map from 'it-map' -import parallel from 'it-parallel-batch' -// @ts-ignore no types -import fwa from 'fast-write-atomic' - -// @ts-ignore -const writeAtomic = promisify(fwa) - -/** - * @typedef {import('interface-datastore').Datastore} Datastore - * @typedef {import('interface-datastore').Pair} Pair - * @typedef {import('interface-datastore').Query} Query - * @typedef {import('interface-datastore').KeyQuery} KeyQuery - */ - -/** - * @template TEntry - * @typedef {import('interface-store').AwaitIterable} AwaitIterable - */ - -/** - * Write a file atomically - * - * @param {string} path - * @param {Uint8Array} contents - */ -async function writeFile (path, contents) { - try { - await writeAtomic(path, contents) - } catch (/** @type {any} */ err) { - if (err.code === 'EPERM' && err.syscall === 'rename') { - // fast-write-atomic writes a file to a temp location before renaming it. - // On Windows, if the final file already exists this error is thrown. - // No such error is thrown on Linux/Mac - // Make sure we can read & write to this file - await fs.promises.access(path, fs.constants.F_OK | fs.constants.W_OK) - - // The file was created by another context - this means there were - // attempts to write the same block by two different function calls - return - } - - throw err - } -} - -/** - * A datastore backed by the file system. - * - * Keys need to be sanitized before use, as they are written - * to the file system as is. - * - * @implements {Datastore} - */ -export class FsDatastore extends BaseDatastore { - /** - * @param {string} location - * @param {{ createIfMissing?: boolean, errorIfExists?: boolean, extension?: string, putManyConcurrency?: number } | undefined} [opts] - */ - constructor (location, opts) { - super() - - this.path = path.resolve(location) - this.opts = Object.assign({}, { - createIfMissing: true, - errorIfExists: false, - extension: '.data', - deleteManyConcurrency: 50, - getManyConcurrency: 50, - putManyConcurrency: 50 - }, opts) - } - - open () { - try { - if (!fs.existsSync(this.path)) { - throw Errors.notFoundError(new Error(`Datastore directory: ${this.path} does not exist`)) - } - - if (this.opts.errorIfExists) { - throw Errors.dbOpenFailedError(new Error(`Datastore directory: ${this.path} already exists`)) - } - return Promise.resolve() - } catch (/** @type {any} */ err) { - if (err.code === 'ERR_NOT_FOUND' && this.opts.createIfMissing) { - mkdirp.sync(this.path, { fs: fs }) - return Promise.resolve() - } - - throw err - } - } - - close () { - return Promise.resolve() - } - - /** - * Calculate the directory and file name for a given key. - * - * @private - * @param {Key} key - * @returns {{dir:string, file:string}} - */ - _encode (key) { - const parent = key.parent().toString() - const dir = path.join(this.path, parent) - const name = key.toString().slice(parent.length) - const file = path.join(dir, name + this.opts.extension) - - return { - dir: dir, - file: file - } - } - - /** - * Calculate the original key, given the file name. - * - * @private - * @param {string} file - * @returns {Key} - */ - _decode (file) { - const ext = this.opts.extension - if (path.extname(file) !== ext) { - throw new Error(`Invalid extension: ${path.extname(file)}`) - } - - const keyname = file - .slice(this.path.length, -ext.length) - .split(path.sep) - .join('/') - return new Key(keyname) - } - - /** - * Write to the file system without extension. - * - * @param {Key} key - * @param {Uint8Array} val - * @returns {Promise} - */ - async putRaw (key, val) { - const parts = this._encode(key) - let file = parts.file - - if (this.opts.extension.length) { - file = parts.file.slice(0, -this.opts.extension.length) - } - - await mkdirp(parts.dir, { fs: fs }) - await writeFile(file, val) - } - - /** - * Store the given value under the key - * - * @param {Key} key - * @param {Uint8Array} val - * @returns {Promise} - */ - async put (key, val) { - const parts = this._encode(key) - - try { - await mkdirp(parts.dir, { fs: fs }) - await writeFile(parts.file, val) - } catch (/** @type {any} */ err) { - throw Errors.dbWriteFailedError(err) - } - } - - /** - * @param {AwaitIterable} source - * @returns {AsyncIterable} - */ - async * putMany (source) { - yield * parallel( - map(source, ({ key, value }) => { - return async () => { - await this.put(key, value) - - return { key, value } - } - }), - this.opts.putManyConcurrency - ) - } - - /** - * Read from the file system without extension. - * - * @param {Key} key - * @returns {Promise} - */ - async getRaw (key) { - const parts = this._encode(key) - let file = parts.file - - if (this.opts.extension.length) { - file = file.slice(0, -this.opts.extension.length) - } - - let data - try { - data = await fs.promises.readFile(file) - } catch (/** @type {any} */ err) { - throw Errors.notFoundError(err) - } - return data - } - - /** - * Read from the file system. - * - * @param {Key} key - * @returns {Promise} - */ - async get (key) { - const parts = this._encode(key) - let data - try { - data = await fs.promises.readFile(parts.file) - } catch (/** @type {any} */ err) { - throw Errors.notFoundError(err) - } - return data - } - - /** - * @param {AwaitIterable} source - * @returns {AsyncIterable} - */ - async * getMany (source) { - yield * parallel( - map(source, key => { - return async () => { - return this.get(key) - } - }), - this.opts.getManyConcurrency - ) - } - - /** - * @param {AwaitIterable} source - * @returns {AsyncIterable} - */ - async * deleteMany (source) { - yield * parallel( - map(source, key => { - return async () => { - await this.delete(key) - - return key - } - }), - this.opts.deleteManyConcurrency - ) - } - - /** - * Check for the existence of the given key. - * - * @param {Key} key - * @returns {Promise} - */ - async has (key) { - const parts = this._encode(key) - - try { - await fs.promises.access(parts.file) - } catch (/** @type {any} */ err) { - return false - } - return true - } - - /** - * Delete the record under the given key. - * - * @param {Key} key - * @returns {Promise} - */ - async delete (key) { - const parts = this._encode(key) - try { - await fs.promises.unlink(parts.file) - } catch (/** @type {any} */ err) { - if (err.code === 'ENOENT') { - return - } - - throw Errors.dbDeleteFailedError(err) - } - } - - /** - * @param {Query} q - */ - async * _all (q) { - let prefix = q.prefix || '**' - - // strip leading slashes - prefix = prefix.replace(/^\/+/, '') - - const pattern = `${prefix}/*${this.opts.extension}` - .split(path.sep) - .join('/') - const files = glob(this.path, pattern, { - absolute: true - }) - - for await (const file of files) { - try { - const buf = await fs.promises.readFile(file) - - /** @type {Pair} */ - const pair = { - key: this._decode(file), - value: buf - } - - yield pair - } catch (/** @type {any} */ err) { - // if keys are removed from the datastore while the query is - // running, we may encounter missing files. - if (err.code !== 'ENOENT') { - throw err - } - } - } - } - - /** - * @param {KeyQuery} q - */ - async * _allKeys (q) { - let prefix = q.prefix || '**' - - // strip leading slashes - prefix = prefix.replace(/^\/+/, '') - - const pattern = `${prefix}/*${this.opts.extension}` - .split(path.sep) - .join('/') - const files = glob(this.path, pattern, { - absolute: true - }) - - yield * map(files, f => this._decode(f)) - } -} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..ffad858 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,281 @@ +import fs from 'node:fs/promises' +import glob from 'it-glob' +import path from 'node:path' +import { promisify } from 'util' +import { + Key, KeyQuery, Pair, Query +} from 'interface-datastore' +import { + BaseDatastore, Errors +} from 'datastore-core' +import map from 'it-map' +import parallel from 'it-parallel-batch' +// @ts-expect-error no types +import fwa from 'fast-write-atomic' +import type { AwaitIterable } from 'interface-store' + +const writeAtomic = promisify(fwa) + +/** + * Write a file atomically + */ +async function writeFile (path: string, contents: Uint8Array): Promise { + try { + await writeAtomic(path, contents) + } catch (err: any) { + if (err.code === 'EPERM' && err.syscall === 'rename') { + // fast-write-atomic writes a file to a temp location before renaming it. + // On Windows, if the final file already exists this error is thrown. + // No such error is thrown on Linux/Mac + // Make sure we can read & write to this file + await fs.access(path, fs.constants.F_OK | fs.constants.W_OK) + + // The file was created by another context - this means there were + // attempts to write the same block by two different function calls + return + } + + throw err + } +} + +export interface FsDatastoreInit { + createIfMissing?: boolean + errorIfExists?: boolean + extension?: string + putManyConcurrency?: number + getManyConcurrency?: number + deleteManyConcurrency?: number +} + +/** + * A datastore backed by the file system. + * + * Keys need to be sanitized before use, as they are written + * to the file system as is. + */ +export class FsDatastore extends BaseDatastore { + public path: string + private readonly createIfMissing: boolean + private readonly errorIfExists: boolean + private readonly extension: string + private readonly deleteManyConcurrency: number + private readonly getManyConcurrency: number + private readonly putManyConcurrency: number + + constructor (location: string, init: FsDatastoreInit = {}) { + super() + + this.path = path.resolve(location) + this.createIfMissing = init.createIfMissing ?? true + this.errorIfExists = init.errorIfExists ?? false + this.extension = init.extension ?? '.data' + this.deleteManyConcurrency = init.deleteManyConcurrency ?? 50 + this.getManyConcurrency = init.getManyConcurrency ?? 50 + this.putManyConcurrency = init.putManyConcurrency ?? 50 + } + + async open (): Promise { + try { + await fs.access(this.path, fs.constants.F_OK | fs.constants.W_OK) + + if (this.errorIfExists) { + throw Errors.dbOpenFailedError(new Error(`Datastore directory: ${this.path} already exists`)) + } + return + } catch (err: any) { + if (err.code === 'ENOENT') { + if (this.createIfMissing) { + await fs.mkdir(this.path, { recursive: true }) + return + } else { + throw Errors.notFoundError(new Error(`Datastore directory: ${this.path} does not exist`)) + } + } + + throw err + } + } + + async close (): Promise { + + } + + /** + * Calculate the directory and file name for a given key. + */ + _encode (key: Key): { dir: string, file: string } { + const parent = key.parent().toString() + const dir = path.join(this.path, parent) + const name = key.toString().slice(parent.length) + const file = path.join(dir, name + this.extension) + + return { + dir, + file + } + } + + /** + * Calculate the original key, given the file name. + */ + _decode (file: string): Key { + const ext = this.extension + if (path.extname(file) !== ext) { + throw new Error(`Invalid extension: ${path.extname(file)}`) + } + + const keyname = file + .slice(this.path.length, -ext.length) + .split(path.sep) + .join('/') + + return new Key(keyname) + } + + /** + * Store the given value under the key + */ + async put (key: Key, val: Uint8Array): Promise { + const parts = this._encode(key) + + try { + await fs.mkdir(parts.dir, { + recursive: true + }) + await writeFile(parts.file, val) + } catch (err: any) { + throw Errors.dbWriteFailedError(err) + } + } + + async * putMany (source: AwaitIterable): AsyncIterable { + yield * parallel( + map(source, ({ key, value }) => { + return async () => { + await this.put(key, value) + + return { key, value } + } + }), + this.putManyConcurrency + ) + } + + /** + * Read from the file system + */ + async get (key: Key): Promise { + const parts = this._encode(key) + let data + try { + data = await fs.readFile(parts.file) + } catch (err: any) { + throw Errors.notFoundError(err) + } + return data + } + + async * getMany (source: AwaitIterable): AsyncIterable { + yield * parallel( + map(source, key => { + return async () => { + return await this.get(key) + } + }), + this.getManyConcurrency + ) + } + + async * deleteMany (source: AwaitIterable): AsyncIterable { + yield * parallel( + map(source, key => { + return async () => { + await this.delete(key) + + return key + } + }), + this.deleteManyConcurrency + ) + } + + /** + * Check for the existence of the given key + */ + async has (key: Key): Promise { + const parts = this._encode(key) + + try { + await fs.access(parts.file) + } catch (err: any) { + return false + } + return true + } + + /** + * Delete the record under the given key + */ + async delete (key: Key): Promise { + const parts = this._encode(key) + try { + await fs.unlink(parts.file) + } catch (err: any) { + if (err.code === 'ENOENT') { + return + } + + throw Errors.dbDeleteFailedError(err) + } + } + + async * _all (q: Query): AsyncIterable { + let prefix = q.prefix ?? '**' + + // strip leading slashes + prefix = prefix.replace(/^\/+/, '') + + const pattern = `${prefix}/*${this.extension}` + .split(path.sep) + .join('/') + const files = glob(this.path, pattern, { + absolute: true + }) + + for await (const file of files) { + try { + const buf = await fs.readFile(file) + + const pair: Pair = { + key: this._decode(file), + value: buf + } + + yield pair + } catch (err: any) { + // if keys are removed from the datastore while the query is + // running, we may encounter missing files. + if (err.code !== 'ENOENT') { + throw err + } + } + } + } + + async * _allKeys (q: KeyQuery): AsyncIterable { + let prefix = q.prefix ?? '**' + + // strip leading slashes + prefix = prefix.replace(/^\/+/, '') + + const pattern = `${prefix}/*${this.extension}` + .split(path.sep) + .join('/') + const files = glob(this.path, pattern, { + absolute: true + }) + + yield * map(files, f => this._decode(f)) + } +} diff --git a/test/index.spec.js b/test/index.spec.js deleted file mode 100644 index ae5a8e5..0000000 --- a/test/index.spec.js +++ /dev/null @@ -1,205 +0,0 @@ -/* eslint-env mocha */ -import { expect } from 'aegir/chai' -import path from 'path' -import { promisify } from 'util' -import mkdirp from 'mkdirp' -import rmrf from 'rimraf' -import fs from 'fs' -import { Key } from 'interface-datastore' -import { ShardingDatastore, shard } from 'datastore-core' -import { isNode, isElectronMain } from 'ipfs-utils/src/env.js' -import { interfaceDatastoreTests } from 'interface-datastore-tests' -import { FsDatastore } from '../src/index.js' -import tempdir from 'ipfs-utils/src/temp-dir.js' - -const rimraf = promisify(rmrf) -const utf8Encoder = new TextEncoder() - -describe('FsDatastore', () => { - if (!(isNode || isElectronMain)) { - it('only supports node.js and electron main', () => { - - }) - - return - } - - describe('construction', () => { - it('defaults - folder missing', () => { - const dir = tempdir() - expect( - () => new FsDatastore(dir) - ).to.not.throw() - }) - - it('defaults - folder exists', () => { - const dir = tempdir() - mkdirp.sync(dir) - expect( - () => new FsDatastore(dir) - ).to.not.throw() - }) - }) - - describe('open', () => { - it('createIfMissing: false - folder missing', () => { - const dir = tempdir() - const store = new FsDatastore(dir, { createIfMissing: false }) - expect( - () => store.open() - ).to.throw() - }) - - it('errorIfExists: true - folder exists', () => { - const dir = tempdir() - mkdirp.sync(dir) - const store = new FsDatastore(dir, { errorIfExists: true }) - expect( - () => store.open() - ).to.throw() - }) - }) - - it('_encode and _decode', () => { - const dir = tempdir() - const fs = new FsDatastore(dir) - - expect( - // @ts-ignore - fs._encode(new Key('hello/world')) - ).to.eql({ - dir: path.join(dir, 'hello'), - file: path.join(dir, 'hello', 'world.data') - }) - - expect( - // @ts-ignore - fs._decode(fs._encode(new Key('hello/world/test:other')).file) - ).to.eql( - new Key('hello/world/test:other') - ) - }) - - it('deleting files', async () => { - const dir = tempdir() - const fs = new FsDatastore(dir) - const key = new Key('1234') - - await fs.put(key, Uint8Array.from([0, 1, 2, 3])) - await fs.delete(key) - - try { - await fs.get(key) - throw new Error('Should have errored') - } catch (/** @type {any} */ err) { - expect(err.code).to.equal('ERR_NOT_FOUND') - } - }) - - it('deleting non-existent files', async () => { - const dir = tempdir() - const fs = new FsDatastore(dir) - const key = new Key('5678') - - await fs.delete(key) - - try { - await fs.get(key) - throw new Error('Should have errored') - } catch (/** @type {any} */ err) { - expect(err.code).to.equal('ERR_NOT_FOUND') - } - }) - - it('sharding files', async () => { - const dir = tempdir() - const fstore = new FsDatastore(dir) - await ShardingDatastore.create(fstore, new shard.NextToLast(2)) - - const file = await fs.promises.readFile(path.join(dir, shard.SHARDING_FN)) - expect(file.toString()).to.be.eql('/repo/flatfs/shard/v1/next-to-last/2\n') - - const readme = await fs.promises.readFile(path.join(dir, shard.README_FN)) - expect(readme.toString()).to.be.eql(shard.readme) - await rimraf(dir) - }) - - it('query', async () => { - const fs = new FsDatastore(path.join(process.cwd(), '/test/test-repo/blocks')) - const res = [] - for await (const q of fs.query({})) { - res.push(q) - } - expect(res).to.have.length(23) - }) - - it('interop with go', async () => { - const repodir = path.join(process.cwd(), '/test/test-repo/blocks') - const fstore = new FsDatastore(repodir) - const key = new Key('CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY') - const expected = fs.readFileSync(path.join(repodir, 'VO', key.toString() + '.data')) - const flatfs = await ShardingDatastore.open(fstore) - const res = await flatfs.get(key) - const queryResult = flatfs.query({}) - const results = [] - for await (const result of queryResult) results.push(result) - expect(results).to.have.length(23) - expect(res).to.be.eql(expected) - }) - - describe('interface-datastore', () => { - const dir = tempdir() - - interfaceDatastoreTests({ - setup: () => { - return new FsDatastore(dir) - }, - teardown: () => { - return rimraf(dir) - } - }) - }) - - describe('interface-datastore (sharding(fs))', () => { - const dir = tempdir() - - interfaceDatastoreTests({ - setup: () => { - return new ShardingDatastore(new FsDatastore(dir), new shard.NextToLast(2)) - }, - teardown: () => { - return rimraf(dir) - } - }) - }) - - it('can survive concurrent writes', async () => { - const dir = tempdir() - const fstore = new FsDatastore(dir) - const key = new Key('CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY') - const value = utf8Encoder.encode('Hello world') - - await Promise.all( - new Array(100).fill(0).map(() => fstore.put(key, value)) - ) - - const res = await fstore.get(key) - - expect(res).to.deep.equal(value) - }) - - it('can survive putRaw and getRaw with an empty extension', async () => { - const dir = tempdir() - const fstore = new FsDatastore(dir, { - extension: '' - }) - const key = new Key('CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY') - const value = utf8Encoder.encode('Hello world') - - await fstore.putRaw(key, value) - - const res = await fstore.getRaw(key) - - expect(res).to.deep.equal(value) - }) -}) diff --git a/test/index.spec.ts b/test/index.spec.ts new file mode 100644 index 0000000..96d0963 --- /dev/null +++ b/test/index.spec.ts @@ -0,0 +1,173 @@ +/* eslint-env mocha */ +import { expect } from 'aegir/chai' +import path from 'node:path' +import fs from 'node:fs/promises' +import { Key } from 'interface-datastore' +import { ShardingDatastore, shard } from 'datastore-core' +import { interfaceDatastoreTests } from 'interface-datastore-tests' +import { FsDatastore } from '../src/index.js' +import tempdir from 'ipfs-utils/src/temp-dir.js' + +const utf8Encoder = new TextEncoder() + +describe('FsDatastore', () => { + describe('construction', () => { + it('defaults - folder missing', async () => { + const dir = tempdir() + + await expect( + (async () => { + const store = new FsDatastore(dir) + await store.open() + })() + ).to.eventually.be.undefined() + }) + + it('defaults - folder exists', async () => { + const dir = tempdir() + await fs.mkdir(dir, { + recursive: true + }) + + await expect( + (async () => { + const store = new FsDatastore(dir) + await store.open() + })() + ).to.eventually.be.undefined() + }) + }) + + describe('open', () => { + it('createIfMissing: false - folder missing', async () => { + const dir = tempdir() + const store = new FsDatastore(dir, { createIfMissing: false }) + await expect(store.open()).to.eventually.be.rejected + .with.property('code', 'ERR_NOT_FOUND') + }) + + it('errorIfExists: true - folder exists', async () => { + const dir = tempdir() + await fs.mkdir(dir, { + recursive: true + }) + const store = new FsDatastore(dir, { errorIfExists: true }) + await expect(store.open()).to.eventually.be.rejected + .with.property('code', 'ERR_DB_OPEN_FAILED') + }) + }) + + it('_encode and _decode', async () => { + const dir = tempdir() + const fs = new FsDatastore(dir) + await fs.open() + + expect( + fs._encode(new Key('hello/world')) + ).to.eql({ + dir: path.join(dir, 'hello'), + file: path.join(dir, 'hello', 'world.data') + }) + + expect( + fs._decode(fs._encode(new Key('hello/world/test:other')).file) + ).to.eql( + new Key('hello/world/test:other') + ) + }) + + it('deleting files', async () => { + const dir = tempdir() + const fs = new FsDatastore(dir) + await fs.open() + const key = new Key('1234') + + await fs.put(key, Uint8Array.from([0, 1, 2, 3])) + await fs.delete(key) + + try { + await fs.get(key) + throw new Error('Should have errored') + } catch (err: any) { + expect(err.code).to.equal('ERR_NOT_FOUND') + } + }) + + it('deleting non-existent files', async () => { + const dir = tempdir() + const fs = new FsDatastore(dir) + await fs.open() + const key = new Key('5678') + + await fs.delete(key) + + try { + await fs.get(key) + throw new Error('Should have errored') + } catch (err: any) { + expect(err.code).to.equal('ERR_NOT_FOUND') + } + }) + + it('sharding files', async () => { + const dir = tempdir() + const fstore = new FsDatastore(dir) + await fstore.open() + await ShardingDatastore.create(fstore, new shard.NextToLast(2)) + + const file = await fs.readFile(path.join(dir, shard.SHARDING_FN + '.data')) + expect(file.toString()).to.be.eql('/repo/flatfs/shard/v1/next-to-last/2\n') + + await fs.rm(dir, { + recursive: true + }) + }) + + describe('interface-datastore', () => { + interfaceDatastoreTests({ + async setup () { + const store = new FsDatastore(tempdir()) + await store.open() + + return store + }, + async teardown (store) { + await fs.rm(store.path, { + recursive: true + }) + } + }) + }) + + describe('interface-datastore (sharding(fs))', () => { + interfaceDatastoreTests({ + async setup () { + const store = new FsDatastore(tempdir()) + await store.open() + + const shardedStore = new ShardingDatastore(store, new shard.NextToLast(2)) + await shardedStore.open() + + return shardedStore + }, + teardown () { + + } + }) + }) + + it('can survive concurrent writes', async () => { + const dir = tempdir() + const fstore = new FsDatastore(dir) + const key = new Key('CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY') + const value = utf8Encoder.encode('Hello world') + + await Promise.all( + new Array(100).fill(0).map(async () => { await fstore.put(key, value) }) + ) + + const res = await fstore.get(key) + + expect(res).to.deep.equal(value) + }) +}) diff --git a/test/test-repo/blocks/2F/CIQEUWUVLBXVFYSYCHHSCRTXCYHGIOBXKWUMKFR3UPAFHQ5WK5362FQ.data b/test/test-repo/blocks/2F/CIQEUWUVLBXVFYSYCHHSCRTXCYHGIOBXKWUMKFR3UPAFHQ5WK5362FQ.data deleted file mode 100644 index 4145619..0000000 --- a/test/test-repo/blocks/2F/CIQEUWUVLBXVFYSYCHHSCRTXCYHGIOBXKWUMKFR3UPAFHQ5WK5362FQ.data +++ /dev/null @@ -1,4 +0,0 @@ - -ys# js-ipfs-repo -Implementation of the IPFS repo spec (https://github.com/ipfs/specs/tree/master/repo) in JavaScript -s \ No newline at end of file diff --git a/test/test-repo/blocks/5V/CIQFFRR4O52TS2Z7QLDDTF32OIR4FWLKT5YLL7MLDVIT7DC3NHOK5VA.data b/test/test-repo/blocks/5V/CIQFFRR4O52TS2Z7QLDDTF32OIR4FWLKT5YLL7MLDVIT7DC3NHOK5VA.data deleted file mode 100644 index 951bfe0..0000000 --- a/test/test-repo/blocks/5V/CIQFFRR4O52TS2Z7QLDDTF32OIR4FWLKT5YLL7MLDVIT7DC3NHOK5VA.data +++ /dev/null @@ -1,23 +0,0 @@ - -€ø IPFS Alpha Security Notes - -We try hard to ensure our system is safe and robust, but all software -has bugs, especially new software. This distribution is meant to be an -alpha preview, don't use it for anything mission critical. - -Please note the following: - -- This is alpha software and has not been audited. It is our goal - to conduct a proper security audit once we close in on a 1.0 release. - -- ipfs is a networked program, and may have serious undiscovered - vulnerabilities. It is written in Go, and we do not execute any - user provided data. But please point any problems out to us in a - github issue, or email security@ipfs.io privately. - -- ipfs uses encryption for all communication, but it's NOT PROVEN SECURE - YET! It may be totally broken. For now, the code is included to make - sure we benchmark our operations with encryption in mind. In the future, - there will be an "unsafe" mode for high performance intranet apps. - If this is a blocking feature for you, please contact us. -ø \ No newline at end of file diff --git a/test/test-repo/blocks/75/CIQMB7DLJFKD267QJ2B5FJNHZPTSVA7IB6OHXSQ2XSVEEKMKK6RT75I.data b/test/test-repo/blocks/75/CIQMB7DLJFKD267QJ2B5FJNHZPTSVA7IB6OHXSQ2XSVEEKMKK6RT75I.data deleted file mode 100644 index c9885c4..0000000 Binary files a/test/test-repo/blocks/75/CIQMB7DLJFKD267QJ2B5FJNHZPTSVA7IB6OHXSQ2XSVEEKMKK6RT75I.data and /dev/null differ diff --git a/test/test-repo/blocks/7J/CIQKKLBWAIBQZOIS5X7E32LQAL6236OUKZTMHPQSFIXPWXNZHQOV7JQ.data b/test/test-repo/blocks/7J/CIQKKLBWAIBQZOIS5X7E32LQAL6236OUKZTMHPQSFIXPWXNZHQOV7JQ.data deleted file mode 100644 index 627ffcd..0000000 --- a/test/test-repo/blocks/7J/CIQKKLBWAIBQZOIS5X7E32LQAL6236OUKZTMHPQSFIXPWXNZHQOV7JQ.data +++ /dev/null @@ -1,55 +0,0 @@ - -•  - IPFS -- Inter-Planetary File system - -IPFS is a global, versioned, peer-to-peer filesystem. It combines good ideas -from Git, BitTorrent, Kademlia, SFS, and the Web. It is like a single bit- -torrent swarm, exchanging git objects. IPFS provides an interface as simple -as the HTTP web, but with permanence built in. You can also mount the world -at /ipfs. - -IPFS is a protocol: -- defines a content-addressed file system -- coordinates content delivery -- combines Kademlia + BitTorrent + Git - -IPFS is a filesystem: -- has directories and files -- mountable filesystem (via FUSE) - -IPFS is a web: -- can be used to view documents like the web -- files accessible via HTTP at `http://ipfs.io/` -- browsers or extensions can learn to use `ipfs://` directly -- hash-addressed content guarantees authenticity - -IPFS is modular: -- connection layer over any network protocol -- routing layer -- uses a routing layer DHT (kademlia/coral) -- uses a path-based naming service -- uses bittorrent-inspired block exchange - -IPFS uses crypto: -- cryptographic-hash content addressing -- block-level deduplication -- file integrity + versioning -- filesystem-level encryption + signing support - -IPFS is p2p: -- worldwide peer-to-peer file transfers -- completely decentralized architecture -- **no** central point of failure - -IPFS is a cdn: -- add a file to the filesystem locally, and it's now available to the world -- caching-friendly (content-hash naming) -- bittorrent-based bandwidth distribution - -IPFS has a name service: -- IPNS, an SFS inspired name system -- global namespace based on PKI -- serves to build trust chains -- compatible with other NSes -- can map DNS, .onion, .bit, etc to IPNS - \ No newline at end of file diff --git a/test/test-repo/blocks/AE/CIQONICFQZH7QVU6IPSIM3AK7AD554D3BWZPAGEAQYQOWMFZQDUUAEI.data b/test/test-repo/blocks/AE/CIQONICFQZH7QVU6IPSIM3AK7AD554D3BWZPAGEAQYQOWMFZQDUUAEI.data deleted file mode 100644 index 6860441..0000000 --- a/test/test-repo/blocks/AE/CIQONICFQZH7QVU6IPSIM3AK7AD554D3BWZPAGEAQYQOWMFZQDUUAEI.data +++ /dev/null @@ -1,3 +0,0 @@ -/ -" gq†¸ÿ6\u8~:çò©6~ágÃæÖZ.è¸directT2 -" 6(¤¡•%Ý„»¿þ.À°Ó¾5(û¼Èþ·òû÷ ab recursive·T \ No newline at end of file diff --git a/test/test-repo/blocks/AP/CIQHAKDLTL5GMIFGN5YVY4BA22FPHUIODJEXS4LCTQDWA275XAJDAPI.data b/test/test-repo/blocks/AP/CIQHAKDLTL5GMIFGN5YVY4BA22FPHUIODJEXS4LCTQDWA275XAJDAPI.data deleted file mode 100644 index 74de75a..0000000 Binary files a/test/test-repo/blocks/AP/CIQHAKDLTL5GMIFGN5YVY4BA22FPHUIODJEXS4LCTQDWA275XAJDAPI.data and /dev/null differ diff --git a/test/test-repo/blocks/C4/CIQDDZ5EDQK5AP7LRTLZHQZUR2R3GECRFV3WPKNL7PL2SKFIL2LXC4Y.data b/test/test-repo/blocks/C4/CIQDDZ5EDQK5AP7LRTLZHQZUR2R3GECRFV3WPKNL7PL2SKFIL2LXC4Y.data deleted file mode 100644 index ecce105..0000000 --- a/test/test-repo/blocks/C4/CIQDDZ5EDQK5AP7LRTLZHQZUR2R3GECRFV3WPKNL7PL2SKFIL2LXC4Y.data +++ /dev/null @@ -1,4 +0,0 @@ -5 -" ¸˜µ×¾FØ_ëuØ”álúšzåS?Ž™|Ú²ë­×Pc@ js-ipfs-repoŸ - - \ No newline at end of file diff --git a/test/test-repo/blocks/CY/CIQDMKFEUGKSLXMEXO774EZOYCYNHPRVFD53ZSAU7237F67XDSQGCYQ.data b/test/test-repo/blocks/CY/CIQDMKFEUGKSLXMEXO774EZOYCYNHPRVFD53ZSAU7237F67XDSQGCYQ.data deleted file mode 100644 index bbe6bda..0000000 Binary files a/test/test-repo/blocks/CY/CIQDMKFEUGKSLXMEXO774EZOYCYNHPRVFD53ZSAU7237F67XDSQGCYQ.data and /dev/null differ diff --git a/test/test-repo/blocks/FN/CIQIXBZMUTXFC5QIGMLJNXLLHZOPGSL2PBC65D4UIVWM6TI5F5TAFNI.data b/test/test-repo/blocks/FN/CIQIXBZMUTXFC5QIGMLJNXLLHZOPGSL2PBC65D4UIVWM6TI5F5TAFNI.data deleted file mode 100644 index 3da9259..0000000 --- a/test/test-repo/blocks/FN/CIQIXBZMUTXFC5QIGMLJNXLLHZOPGSL2PBC65D4UIVWM6TI5F5TAFNI.data +++ /dev/null @@ -1,24 +0,0 @@ - -¸°The MIT License (MIT) - -Copyright (c) 2015 IPFS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -° \ No newline at end of file diff --git a/test/test-repo/blocks/GQ/CIQH7OEYWXL34RWYL7VXLWEU4FWPVGT24VJT7DUZPTNLF25N25IGGQA.data b/test/test-repo/blocks/GQ/CIQH7OEYWXL34RWYL7VXLWEU4FWPVGT24VJT7DUZPTNLF25N25IGGQA.data deleted file mode 100644 index ee87b9d..0000000 --- a/test/test-repo/blocks/GQ/CIQH7OEYWXL34RWYL7VXLWEU4FWPVGT24VJT7DUZPTNLF25N25IGGQA.data +++ /dev/null @@ -1,4 +0,0 @@ -0 -" ‹‡,¤îQv3–Ýk>\óIzxEî”ElÏM/fµLICENSE»1 -" JZ•XoRâXÏ!Fwd87U¨Å;£ÀSöWwí README.md{ - \ No newline at end of file diff --git a/test/test-repo/blocks/HD/CIQDDVW2EZIJF4NQH7WJNESD7XHQSXA5EGJVNTPVHD7444C2KLKXHDI.data b/test/test-repo/blocks/HD/CIQDDVW2EZIJF4NQH7WJNESD7XHQSXA5EGJVNTPVHD7444C2KLKXHDI.data deleted file mode 100644 index 5ea0edd..0000000 Binary files a/test/test-repo/blocks/HD/CIQDDVW2EZIJF4NQH7WJNESD7XHQSXA5EGJVNTPVHD7444C2KLKXHDI.data and /dev/null differ diff --git a/test/test-repo/blocks/IL/CIQJFGRQHQ45VCQLM7AJNF2GF5UHUAGGHC6LLAH6VYDEKLQMD4QLILY.data b/test/test-repo/blocks/IL/CIQJFGRQHQ45VCQLM7AJNF2GF5UHUAGGHC6LLAH6VYDEKLQMD4QLILY.data deleted file mode 100644 index 62d1c29..0000000 --- a/test/test-repo/blocks/IL/CIQJFGRQHQ45VCQLM7AJNF2GF5UHUAGGHC6LLAH6VYDEKLQMD4QLILY.data +++ /dev/null @@ -1,8 +0,0 @@ - -ŽCome hang out in our IRC chat room if you have any questions. - -Contact the ipfs dev team: -- Bugs: https://github.com/ipfs/go-ipfs/issues -- Help: irc.freenode.org/#ipfs -- Email: dev@ipfs.io -½ \ No newline at end of file diff --git a/test/test-repo/blocks/LG/CIQJBQD2O6K4CGJVCCTJNUP57QHR4SKHZ74OIITBBGLOMCO3ZOLWLGA.data b/test/test-repo/blocks/LG/CIQJBQD2O6K4CGJVCCTJNUP57QHR4SKHZ74OIITBBGLOMCO3ZOLWLGA.data deleted file mode 100644 index 71be805..0000000 --- a/test/test-repo/blocks/LG/CIQJBQD2O6K4CGJVCCTJNUP57QHR4SKHZ74OIITBBGLOMCO3ZOLWLGA.data +++ /dev/null @@ -1,9 +0,0 @@ - -¿·Some helpful resources for finding your way around ipfs: - -- quick-start: a quick show of various ipfs features. -- ipfs commands: a list of all commands -- ipfs --help: every command describes itself -- https://github.com/ipfs/go-ipfs -- the src repository -- #ipfs on irc.freenode.org -- the community irc channel -· \ No newline at end of file diff --git a/test/test-repo/blocks/O6/CIQOYW2THIZBRGI7IN33ROGCKOFZLXJJ2MPKYZBTV4H3N7GYHXMAO6A.data b/test/test-repo/blocks/O6/CIQOYW2THIZBRGI7IN33ROGCKOFZLXJJ2MPKYZBTV4H3N7GYHXMAO6A.data deleted file mode 100644 index 7b58d6c..0000000 --- a/test/test-repo/blocks/O6/CIQOYW2THIZBRGI7IN33ROGCKOFZLXJJ2MPKYZBTV4H3N7GYHXMAO6A.data +++ /dev/null @@ -1,3 +0,0 @@ -/ -" æ@ŠÃ÷¬šÔ†D¯Éùg«âªçÆA÷»éŠ7directT2 -" “;AÓÔPŒßôY0ßõk®ù}ÃEç=šµp«á û¹ recursiveáT \ No newline at end of file diff --git a/test/test-repo/blocks/QF/CIQGPALRQ24P6NS4OWHTQ7R247ZI7KJWP3QWPQYS43LFULQC5ANLQFI.data b/test/test-repo/blocks/QF/CIQGPALRQ24P6NS4OWHTQ7R247ZI7KJWP3QWPQYS43LFULQC5ANLQFI.data deleted file mode 100644 index a8f9869..0000000 Binary files a/test/test-repo/blocks/QF/CIQGPALRQ24P6NS4OWHTQ7R247ZI7KJWP3QWPQYS43LFULQC5ANLQFI.data and /dev/null differ diff --git a/test/test-repo/blocks/QV/CIQOHMGEIKMPYHAUTL57JSEZN64SIJ5OIHSGJG4TJSSJLGI3PBJLQVI.data b/test/test-repo/blocks/QV/CIQOHMGEIKMPYHAUTL57JSEZN64SIJ5OIHSGJG4TJSSJLGI3PBJLQVI.data deleted file mode 100644 index e69de29..0000000 diff --git a/test/test-repo/blocks/R3/CIQBED3K6YA5I3QQWLJOCHWXDRK5EXZQILBCKAPEDUJENZ5B5HJ5R3A.data b/test/test-repo/blocks/R3/CIQBED3K6YA5I3QQWLJOCHWXDRK5EXZQILBCKAPEDUJENZ5B5HJ5R3A.data deleted file mode 100644 index 389e111..0000000 --- a/test/test-repo/blocks/R3/CIQBED3K6YA5I3QQWLJOCHWXDRK5EXZQILBCKAPEDUJENZ5B5HJ5R3A.data +++ /dev/null @@ -1,28 +0,0 @@ - -ËÃHello and Welcome to IPFS! - -██╗██████╗ ███████╗███████╗ -██║██╔â•â•██╗██╔â•â•â•â•â•██╔â•â•â•â•â• -██║██████╔â•█████╗ ███████╗ -██║██╔â•â•â•╠██╔â•â•╠╚â•â•â•â•██║ -██║██║ ██║ ███████║ -╚â•â•╚â•╠╚â•╠╚â•â•â•â•â•â•â• - -If you're seeing this, you have successfully installed -IPFS and are now interfacing with the ipfs merkledag! - - ------------------------------------------------------- -| Warning: | -| This is alpha software. Use at your own discretion! | -| Much is missing or lacking polish. There are bugs. | -| Not yet secure. Read the security notes for more. | - ------------------------------------------------------- - -Check out some of the other files in this directory: - - ./about - ./help - ./quick-start <-- usage examples - ./readme <-- this file - ./security-notes -à \ No newline at end of file diff --git a/test/test-repo/blocks/S5/CIQHBGZNZRPWVEFNMTLP4OS5EAVHFMCX2HD7FZUC2B3WUU3D4LGKS5A.data b/test/test-repo/blocks/S5/CIQHBGZNZRPWVEFNMTLP4OS5EAVHFMCX2HD7FZUC2B3WUU3D4LGKS5A.data deleted file mode 100644 index 3a99c36..0000000 --- a/test/test-repo/blocks/S5/CIQHBGZNZRPWVEFNMTLP4OS5EAVHFMCX2HD7FZUC2B3WUU3D4LGKS5A.data +++ /dev/null @@ -1,3 +0,0 @@ -4 -" Y”„9_)ažô€Ë¹2¾RÅm™Å–keà9ð˜»ï js-ipfs-repo - \ No newline at end of file diff --git a/test/test-repo/blocks/SHARDING b/test/test-repo/blocks/SHARDING deleted file mode 100644 index a153331..0000000 --- a/test/test-repo/blocks/SHARDING +++ /dev/null @@ -1 +0,0 @@ -/repo/flatfs/shard/v1/next-to-last/2 diff --git a/test/test-repo/blocks/TW/CIQFEAGMNNXXTYKYQSANT6IBNTFN7WR5RPD5F6GN6MBKUUO25DNOTWQ.data b/test/test-repo/blocks/TW/CIQFEAGMNNXXTYKYQSANT6IBNTFN7WR5RPD5F6GN6MBKUUO25DNOTWQ.data deleted file mode 100644 index 10aa2ae..0000000 Binary files a/test/test-repo/blocks/TW/CIQFEAGMNNXXTYKYQSANT6IBNTFN7WR5RPD5F6GN6MBKUUO25DNOTWQ.data and /dev/null differ diff --git a/test/test-repo/blocks/UN/CIQOMBKARLB7PAITVSNH7VEGIQJRPL6J7FT2XYVKAXT4MQPXXPUYUNY.data b/test/test-repo/blocks/UN/CIQOMBKARLB7PAITVSNH7VEGIQJRPL6J7FT2XYVKAXT4MQPXXPUYUNY.data deleted file mode 100644 index b653989..0000000 Binary files a/test/test-repo/blocks/UN/CIQOMBKARLB7PAITVSNH7VEGIQJRPL6J7FT2XYVKAXT4MQPXXPUYUNY.data and /dev/null differ diff --git a/test/test-repo/blocks/VO/CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY.data b/test/test-repo/blocks/VO/CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY.data deleted file mode 100644 index 2dd8056..0000000 --- a/test/test-repo/blocks/VO/CIQGFTQ7FSI2COUXWWLOQ45VUM2GUZCGAXLWCTOKKPGTUWPXHBNIVOY.data +++ /dev/null @@ -1,114 +0,0 @@ - -ž – # 0.1 - Quick Start - -This is a set of short examples with minimal explanation. It is meant as -a "quick start". Soon, we'll write a longer tour :-) - - -Add a file to ipfs: - - echo "hello world" >hello - ipfs add hello - - -View it: - - ipfs cat - - -Try a directory: - - mkdir foo - mkdir foo/bar - echo "baz" > foo/baz - echo "baz" > foo/bar/baz - ipfs add -r foo - - -View things: - - ipfs ls - ipfs ls /bar - ipfs cat /baz - ipfs cat /bar/baz - ipfs cat /bar - ipfs ls /baz - - -References: - - ipfs refs - ipfs refs -r - ipfs refs --help - - -Get: - - ipfs get foo2 - diff foo foo2 - - -Objects: - - ipfs object get - ipfs object get /foo2 - ipfs object --help - - -Pin + GC: - - ipfs pin -r - ipfs gc - ipfs ls - ipfs unpin -r - ipfs gc - - -Daemon: - - ipfs daemon (in another terminal) - ipfs id - - -Network: - - (must be online) - ipfs swarm peers - ipfs id - ipfs cat - - -Mount: - - (warning: fuse is finicky!) - ipfs mount - cd /ipfs/< - - -Tool: - - ipfs version - ipfs update - ipfs commands - ipfs config --help - open http://localhost:5001/webui - - -Browse: - - webui: - - http://localhost:5001/webui - - video: - - http://localhost:8080/ipfs/QmVc6zuAneKJzicnJpfrqCH9gSy6bz54JhcypfJYhGUFQu/play#/ipfs/QmTKZgRNwDNZwHtJSjCp6r5FYefzpULfy37JvMt9DwvXse - - images: - - http://localhost:8080/ipfs/QmZpc3HvfjEXvLWGQPWbHk3AjD5j8NEN4gmFN8Jmrd5g83/cs - - markdown renderer app: - - http://localhost:8080/ipfs/QmX7M9CiYXjVeFnkfVGf3y5ixTZ2ACeSGyL1vBJY1HvQPp/mdown -– \ No newline at end of file diff --git a/test/test-repo/blocks/X3/CIQFTFEEHEDF6KLBT32BFAGLXEZL4UWFNWM4LFTLMXQBCERZ6CMLX3Y.data b/test/test-repo/blocks/X3/CIQFTFEEHEDF6KLBT32BFAGLXEZL4UWFNWM4LFTLMXQBCERZ6CMLX3Y.data deleted file mode 100644 index 9553a94..0000000 --- a/test/test-repo/blocks/X3/CIQFTFEEHEDF6KLBT32BFAGLXEZL4UWFNWM4LFTLMXQBCERZ6CMLX3Y.data +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/test/test-repo/blocks/XO/CIQJGO2B2N75IUEM372FSMG76VV256I4PXBULZZ5ASNLK4FL4EG7XOI.data b/test/test-repo/blocks/XO/CIQJGO2B2N75IUEM372FSMG76VV256I4PXBULZZ5ASNLK4FL4EG7XOI.data deleted file mode 100644 index d899663..0000000 Binary files a/test/test-repo/blocks/XO/CIQJGO2B2N75IUEM372FSMG76VV256I4PXBULZZ5ASNLK4FL4EG7XOI.data and /dev/null differ diff --git a/test/test-repo/blocks/_README b/test/test-repo/blocks/_README deleted file mode 100644 index 23cb090..0000000 --- a/test/test-repo/blocks/_README +++ /dev/null @@ -1,30 +0,0 @@ -This is a repository of IPLD objects. Each IPLD object is in a single file, -named .data. Where is the -"base32" encoding of the CID (as specified in -https://github.com/multiformats/multibase) without the 'B' prefix. -All the object files are placed in a tree of directories, based on a -function of the CID. This is a form of sharding similar to -the objects directory in git repositories. Previously, we used -prefixes, we now use the next-to-last two charters. - - func NextToLast(base32cid string) { - nextToLastLen := 2 - offset := len(base32cid) - nextToLastLen - 1 - return str[offset : offset+nextToLastLen] - } - -For example, an object with a base58 CIDv1 of - - zb2rhYSxw4ZjuzgCnWSt19Q94ERaeFhu9uSqRgjSdx9bsgM6f - -has a base32 CIDv1 of - - BAFKREIA22FLID5AJ2KU7URG47MDLROZIH6YF2KALU2PWEFPVI37YLKRSCA - -and will be placed at - - SC/AFKREIA22FLID5AJ2KU7URG47MDLROZIH6YF2KALU2PWEFPVI37YLKRSCA.data - -with 'SC' being the last-to-next two characters and the 'B' at the -beginning of the CIDv1 string is the multibase prefix that is not -stored in the filename. diff --git a/test/test-repo/config b/test/test-repo/config deleted file mode 100644 index 5811699..0000000 --- a/test/test-repo/config +++ /dev/null @@ -1,88 +0,0 @@ -{ - "Identity": { - "PeerID": "QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A", - "PrivKey": "CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw==" - }, - "Datastore": { - "Type": "", - "Path": "", - "StorageMax": "", - "StorageGCWatermark": 0, - "GCPeriod": "", - "Params": null, - "NoSync": false - }, - "Addresses": { - "Swarm": [ - "/ip4/0.0.0.0/tcp/4001", - "/ip6/::/tcp/4001" - ], - "API": "/ip4/127.0.0.1/tcp/5001", - "Gateway": "/ip4/127.0.0.1/tcp/8080" - }, - "Mounts": { - "IPFS": "/ipfs", - "IPNS": "/ipns", - "FuseAllowOther": false - }, - "Version": { - "Current": "0.4.0-dev", - "Check": "error", - "CheckDate": "0001-01-01T00:00:00Z", - "CheckPeriod": "172800000000000", - "AutoUpdate": "minor" - }, - "Discovery": { - "MDNS": { - "Enabled": true, - "Interval": 10 - } - }, - "Ipns": { - "RepublishPeriod": "", - "RecordLifetime": "", - "ResolveCacheSize": 128 - }, - "Bootstrap": [ - "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", - "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", - "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", - "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", - "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", - "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", - "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", - "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", - "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx" - ], - "Tour": { - "Last": "" - }, - "Gateway": { - "HTTPHeaders": null, - "RootRedirect": "", - "Writable": false - }, - "SupernodeRouting": { - "Servers": [ - "/ip4/104.236.176.52/tcp/4002/ipfs/QmXdb7tWTxdFEQEFgWBqkuYSrZd3mXrC7HxkD4krGNYx2U", - "/ip4/104.236.179.241/tcp/4002/ipfs/QmVRqViDByUxjUMoPnjurjKvZhaEMFDtK35FJXHAM4Lkj6", - "/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH", - "/ip4/162.243.248.213/tcp/4002/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP", - "/ip4/128.199.219.111/tcp/4002/ipfs/Qmb3brdCYmKG1ycwqCbo6LUwWxTuo3FisnJV2yir7oN92R", - "/ip4/104.236.76.40/tcp/4002/ipfs/QmdRBCV8Cz2dGhoKLkD3YjPwVFECmqADQkx5ZteF2c6Fy4", - "/ip4/178.62.158.247/tcp/4002/ipfs/QmUdiMPci7YoEUBkyFZAh2pAbjqcPr7LezyiPD2artLw3v", - "/ip4/178.62.61.185/tcp/4002/ipfs/QmVw6fGNqBixZE4bewRLT2VXX7fAHUHs8JyidDiJ1P7RUN" - ] - }, - "API": { - "HTTPHeaders": null - }, - "Swarm": { - "AddrFilters": null - }, - "Log": { - "MaxSizeMB": 250, - "MaxBackups": 1, - "MaxAgeDays": 0 - } -} \ No newline at end of file diff --git a/test/test-repo/datastore/000002.ldb b/test/test-repo/datastore/000002.ldb deleted file mode 100644 index fc04d66..0000000 Binary files a/test/test-repo/datastore/000002.ldb and /dev/null differ diff --git a/test/test-repo/datastore/000005.ldb b/test/test-repo/datastore/000005.ldb deleted file mode 100644 index 63d9d26..0000000 Binary files a/test/test-repo/datastore/000005.ldb and /dev/null differ diff --git a/test/test-repo/datastore/CURRENT b/test/test-repo/datastore/CURRENT deleted file mode 100644 index ecb0b4b..0000000 --- a/test/test-repo/datastore/CURRENT +++ /dev/null @@ -1 +0,0 @@ -MANIFEST-000036 diff --git a/test/test-repo/datastore/LOCK b/test/test-repo/datastore/LOCK deleted file mode 100644 index e69de29..0000000 diff --git a/test/test-repo/datastore/LOG b/test/test-repo/datastore/LOG deleted file mode 100644 index 4e3a829..0000000 --- a/test/test-repo/datastore/LOG +++ /dev/null @@ -1,3 +0,0 @@ -2017/03/13-13:52:56.574311 70000f009000 Recovering log #35 -2017/03/13-13:52:56.575960 70000f009000 Delete type=0 #35 -2017/03/13-13:52:56.576081 70000f009000 Delete type=3 #34 diff --git a/test/test-repo/datastore/LOG.old b/test/test-repo/datastore/LOG.old deleted file mode 100644 index 27029f4..0000000 --- a/test/test-repo/datastore/LOG.old +++ /dev/null @@ -1,3 +0,0 @@ -2017/03/13-13:52:16.502220 70000f6c7000 Recovering log #33 -2017/03/13-13:52:16.503900 70000f6c7000 Delete type=0 #33 -2017/03/13-13:52:16.504085 70000f6c7000 Delete type=3 #32 diff --git a/test/test-repo/datastore/MANIFEST-000036 b/test/test-repo/datastore/MANIFEST-000036 deleted file mode 100644 index 004f166..0000000 Binary files a/test/test-repo/datastore/MANIFEST-000036 and /dev/null differ diff --git a/test/test-repo/version b/test/test-repo/version deleted file mode 100644 index 7ed6ff8..0000000 --- a/test/test-repo/version +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/tsconfig.json b/tsconfig.json index 8708ca6..13a3599 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,7 @@ { "extends": "aegir/src/config/tsconfig.aegir.json", "compilerOptions": { - "outDir": "dist", - "emitDeclarationOnly": true + "outDir": "dist" }, "include": [ "src",