Skip to content

Commit

Permalink
feat: move blob index logic from upload-api to blob-index lib (#1434)
Browse files Browse the repository at this point in the history
The blob index logic should be an independent module as it will be used
in both client and service code.

---------

Co-authored-by: Alan Shaw <[email protected]>
  • Loading branch information
gammazero and Alan Shaw authored May 14, 2024
1 parent 5618644 commit 797f628
Show file tree
Hide file tree
Showing 31 changed files with 7,394 additions and 8,594 deletions.
1 change: 1 addition & 0 deletions .github/release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
],
"packages": {
"packages/access-client": {},
"packages/blob-index": {},
"packages/filecoin-api": {},
"packages/filecoin-client": {},
"packages/capabilities": {},
Expand Down
1 change: 1 addition & 0 deletions .github/release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"packages/access-client": "18.3.2",
"packages/blob-index": "0.0.0",
"packages/filecoin-api": "6.0.1",
"packages/filecoin-client": "3.3.3",
"packages/capabilities": "17.0.0",
Expand Down
39 changes: 39 additions & 0 deletions .github/workflows/blob-index.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: blob-index
on:
push:
branches:
- main
paths:
- 'packages/blob-index/**'
- 'packages/eslint-config-w3up/**'
- '.github/workflows/blob-index.yml'
- 'pnpm-lock.yaml'
pull_request:
paths:
- 'packages/blob-index/**'
- 'packages/eslint-config-w3up/**'
- '.github/workflows/blob-index.yml'
- 'pnpm-lock.yaml'
jobs:
test:
name: Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./packages/blob-index
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install
uses: pnpm/[email protected]
with:
version: 8
- name: Setup
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://registry.npmjs.org/
cache: 'pnpm'
- run: pnpm --filter '@web3-storage/blob-index...' install
- run: pnpm --filter '@web3-storage/blob-index' lint
- run: pnpm --filter '@web3-storage/blob-index' test
62 changes: 62 additions & 0 deletions packages/blob-index/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# `@web3-storage/blob-index`

An index for slices that may be sharded across multiple blobs.

## Install

```
npm i @web3-storage/blob-index
```

## Usage

Create:

```js
import { ShardedDAGIndex } from '@web3-storage/blob-index'

// Create a brand new index
const index = ShardedDAGIndex.create(rootCID)

// Add index data for slices within a shard
index.setSlice(shardMultihash, sliceMultihash, [offset, length])
// ...

// Create CAR archive
const result = index.archive()

console.log(result.ok) // a Uint8Array
```

Read:

```js
import { ShardedDAGIndex } from '@web3-storage/blob-index'
import { base58btc } from 'multiformats/bases/base58'

const index = ShardedDAGIndex.extract(car)

console.log(index.content)

for (const [shard, slices] of index.shards.entries()) {
console.log(`Shard ${base58btc.encode(shard.bytes)}`)
console.log(' Slices:')
for (const [slice, [offset, length]] of slices.entries()) {
console.log(` ${base58btc.encode(slice.bytes)} @ ${offset} -> ${offset + length}`)
}
}

// Output:
// Shard zQmQKw6B745GGL3eeTcEE5kAoLAJgkBQydJPC5fWv5HA68A
// Slices:
// zQmeHPRNRDxHU5YMPewcBCbPYxzA3jBcadAZQwpQXm3jFFt @ 96 -> 128
// ...
```

## Contributing

Feel free to join in. All welcome. Please [open an issue](https://github.com/web3-storage/w3up/issues)!

## License

Dual-licensed under [MIT + Apache 2.0](https://github.com/web3-storage/w3up/blob/main/license.md)
81 changes: 81 additions & 0 deletions packages/blob-index/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"name": "@web3-storage/blob-index",
"description": "An index for slices that may be sharded across multiple blobs.",
"version": "0.0.0",
"homepage": "https://web3.storage",
"repository": {
"type": "git",
"url": "https://github.com/w3s-project/w3up.git",
"directory": "packages/blob-index"
},
"license": "Apache-2.0 OR MIT",
"type": "module",
"types": "dist/src/index.d.ts",
"main": "src/index.js",
"files": [
"src",
"test",
"dist"
],
"exports": {
".": "./dist/src/index.js",
"./sharded-dag-index": "./dist/src/sharded-dag-index.js",
"./types": "./dist/src/api.js",
"./util": "./dist/src/util.js"
},
"typesVersions": {
"*": {
"types": [
"dist/src/types"
]
}
},
"scripts": {
"attw": "attw --pack .",
"build": "tsc --build",
"check": "tsc --build",
"lint": "tsc --build && eslint '**/*.{js,ts}' && prettier --check '**/*.{js,ts,yml,json}' --ignore-path ../../.gitignore",
"test": "entail test/*.spec.js",
"coverage": "c8 --reporter text --reporter html npm run test"
},
"dependencies": {
"@ipld/dag-cbor": "^9.0.6",
"@ucanto/core": "^10.0.1",
"@ucanto/interface": "^10.0.1",
"@web3-storage/capabilities": "workspace:^",
"multiformats": "^13.0.1",
"uint8arrays": "^5.0.3"
},
"devDependencies": {
"@ipld/car": "^5.1.1",
"@types/assert": "^1.5.6",
"@types/mocha": "^10.0.1",
"@ucanto/transport": "^9.1.1",
"@web-std/blob": "^3.0.5",
"@web3-storage/eslint-config-w3up": "workspace:^",
"c8": "^7.14.0",
"carstream": "^2.1.0",
"entail": "^2.1.2",
"one-webcrypto": "git://github.com/web3-storage/one-webcrypto",
"typescript": "5.2.2"
},
"eslintConfig": {
"extends": [
"@web3-storage/eslint-config-w3up"
],
"parserOptions": {
"project": "./tsconfig.json"
},
"env": {
"mocha": true
},
"ignorePatterns": [
"dist",
"coverage",
"src/types.js"
]
},
"engines": {
"node": ">=16.15"
}
}
File renamed without changes.
33 changes: 33 additions & 0 deletions packages/blob-index/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Result, Failure } from '@ucanto/interface'
import { MultihashDigest, Link, UnknownLink } from 'multiformats'

export type { IPLDBlock } from '@ucanto/interface'
export type { UnknownFormat } from '@web3-storage/capabilities/types'
export type { Result, MultihashDigest, Link, UnknownLink }

export type ShardDigest = MultihashDigest
export type SliceDigest = MultihashDigest
export type Position = [offset: number, length: number]

/**
* A sharded DAG index.
*
* @see https://github.com/w3s-project/specs/blob/main/w3-index.md
*/
export interface ShardedDAGIndex {
/** DAG root CID that the index pertains to. */
content: UnknownLink
/** Index information for shards the DAG is split across. */
shards: Map<ShardDigest, Map<SliceDigest, Position>>
}

export interface ShardedDAGIndexView extends ShardedDAGIndex {
/** Set the offset/length information for the slice a shard. */
setSlice(shard: ShardDigest, slice: SliceDigest, pos: Position): void
/** Encode the index to a CAR file. */
archive(): Promise<Result<Uint8Array>>
}

export interface DecodeFailure extends Failure {
name: 'DecodeFailure'
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as API from './api.js'
import { base58btc } from 'multiformats/bases/base58'

/** @type {WeakMap<Uint8Array, string>} */
const cache = new WeakMap()

/** @param {import('multiformats').MultihashDigest} digest */
/** @param {API.MultihashDigest} digest */
const toBase58String = (digest) => {
let str = cache.get(digest.bytes)
if (!str) {
Expand All @@ -14,7 +15,7 @@ const toBase58String = (digest) => {
}

/**
* @template {import('multiformats').MultihashDigest} Key
* @template {API.MultihashDigest} Key
* @template Value
* @implements {Map<Key, Value>}
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/blob-index/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * as ShardedDAGIndex from './sharded-dag-index.js'
export * from './digest-map.js'
Loading

0 comments on commit 797f628

Please sign in to comment.