Skip to content

Commit

Permalink
feat: move access-api delegation bytes out of d1 and into r2 (#578)
Browse files Browse the repository at this point in the history
Motivation:
* first PR on #571

todo
* [x] initial `DbDelegationsStorageWithR2` that passes tests as a
`DelegationsStorage`
* [x] rm unused access-ws package
#596
* [x] access-api should use `DbDelegationsStorageWithR2` and not
`DbDelegationsStorage` (without r2) and still pass tests
#599

informed by review
* [x] add r2 bucket name binding to wrangler.toml for staging,
production
#578 (comment)

unblocks:
* `DbDelegationsStorageWithR2` supports deletes
* we don't need this to support current `DelegationsStorage`, but
probably will before long, but doesn't need to block this PR
* optimization where r2 stores all the CIDs with varying multibases but
for the same hash only once
* safe to remove `DbDelegationsStorage`, `DelegationsV2Row`,
`DelegationsV2Tables`

---------

Co-authored-by: Irakli Gozalishvili <contact@gozala.io>
  • Loading branch information
gobengo and Gozala authored Mar 23, 2023
1 parent 9c34bf7 commit 4510c9a
Show file tree
Hide file tree
Showing 18 changed files with 584 additions and 886 deletions.
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
"lint-staged": "^13.2.0",
"prettier": "2.8.3",
"typedoc-plugin-markdown": "^3.14.0",
"typescript": "4.9.5",
"wrangler": "^2.12.3"
"typescript": "4.9.5"
},
"prettier": {
"trailingComma": "es5",
Expand All @@ -36,7 +35,7 @@
},
"dependencies": {
"depcheck": "^1.4.3",
"typedoc": "^0.23.26",
"typedoc": "^0.23.28",
"typedoc-plugin-missing-exports": "^1.0.0"
},
"packageManager": "pnpm@7.24.3",
Expand Down
20 changes: 20 additions & 0 deletions packages/access-api/migrations/0007_add_delegations_v3.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Migration number: 0007 2023-03-20T23:48:40.469Z

/*
goal: add a new table to store delegations in
which doesn't have a 'bytes' column.
context: we're going to start storing bytes outside of the database (e.g. in R2)
*/

CREATE TABLE
IF NOT EXISTS delegations_v3 (
/* cidv1 dag-ucan/dag-cbor sha2-256 */
cid TEXT NOT NULL PRIMARY KEY,
audience TEXT NOT NULL,
issuer TEXT NOT NULL,
expiration TEXT,
inserted_at TEXT NOT NULL DEFAULT (strftime ('%Y-%m-%dT%H:%M:%fZ', 'now')),
updated_at TEXT NOT NULL DEFAULT (strftime ('%Y-%m-%dT%H:%M:%fZ', 'now')),
UNIQUE (cid)
);
9 changes: 5 additions & 4 deletions packages/access-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@web3-storage/capabilities": "workspace:^",
"@web3-storage/worker-utils": "0.4.3-dev",
"kysely": "^0.23.4",
"kysely-d1": "^0.1.0",
"kysely-d1": "^0.3.0",
"multiformats": "^11.0.2",
"p-retry": "^5.1.2",
"preact": "^10.11.3",
Expand All @@ -38,9 +38,10 @@
"toucan-js": "^2.7.0"
},
"devDependencies": {
"@cloudflare/workers-types": "^3.18.0",
"@cloudflare/workers-types": "^3.19.0",
"@databases/split-sql-query": "^1.0.3",
"@databases/sql": "^3.2.0",
"@miniflare/r2": "^2.12.1",
"@sentry/cli": "2.7.0",
"@types/assert": "^1.5.6",
"@types/git-rev-sync": "^2.0.0",
Expand All @@ -55,14 +56,14 @@
"git-rev-sync": "^3.0.2",
"hd-scripts": "^4.0.0",
"is-subset": "^0.1.1",
"miniflare": "^2.11.0",
"miniflare": "^2.12.1",
"mocha": "^10.2.0",
"p-wait-for": "^5.0.0",
"process": "^0.11.10",
"readable-stream": "^4.2.0",
"sade": "^1.8.1",
"typescript": "4.9.5",
"wrangler": "^2.8.0"
"wrangler": "^2.13.0"
},
"eslintConfig": {
"extends": [
Expand Down
16 changes: 5 additions & 11 deletions packages/access-api/src/bindings.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import type { Logging } from '@web3-storage/worker-utils/logging'
import type {
AccountTable,
DelegationTable,
SpaceTable,
} from '@web3-storage/access/types'
import type { Handler as _Handler } from '@web3-storage/worker-utils/router'
import { Spaces } from './models/spaces.js'
import { Validations } from './models/validations.js'
Expand All @@ -12,6 +7,7 @@ import { ConnectionView, Signer as EdSigner } from '@ucanto/principal/ed25519'
import { Accounts } from './models/accounts.js'
import { DelegationsStorage as Delegations } from './types/delegations.js'
import { ProvisionsStorage } from './types/provisions.js'
import { R2Bucket } from '@miniflare/r2'

export {}

Expand Down Expand Up @@ -53,6 +49,10 @@ export interface Env {
SPACES: KVNamespace
VALIDATIONS: KVNamespace
W3ACCESS_METRICS: AnalyticsEngine
/**
* will be used for storing env.models.delegations CARs
*/
DELEGATIONS_BUCKET: R2Bucket
// eslint-disable-next-line @typescript-eslint/naming-convention
__D1_BETA__: D1Database
}
Expand Down Expand Up @@ -108,9 +108,3 @@ export interface ModuleWorker {
export interface D1ErrorRaw extends Error {
cause: Error & { code: string }
}

export interface D1Schema {
spaces: SpaceTable
accounts: AccountTable
delegations: DelegationTable
}
7 changes: 7 additions & 0 deletions packages/access-api/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export function loadConfig(env) {
}
}

if (typeof env.DELEGATIONS_BUCKET !== 'object') {
throw new TypeError(
`expected env.DELEGATIONS_BUCKET to be an R2Bucket object, but got ${typeof env.DELEGATIONS_BUCKET}`
)
}

return {
DEBUG: boolValue(vars.DEBUG),
ENV: parseRuntimeEnv(vars.ENV),
Expand Down Expand Up @@ -67,6 +73,7 @@ export function loadConfig(env) {
SPACES: env.SPACES,
VALIDATIONS: env.VALIDATIONS,
DB: /** @type {D1Database} */ (env.__D1_BETA__),
DELEGATIONS_BUCKET: env.DELEGATIONS_BUCKET,
}
}

Expand Down
20 changes: 7 additions & 13 deletions packages/access-api/src/models/accounts.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,29 @@
// eslint-disable-next-line no-unused-vars
import * as Ucanto from '@ucanto/interface'
import { Kysely } from 'kysely'
import { D1Dialect } from 'kysely-d1'
import { GenericPlugin } from '../utils/d1.js'

/**
* @typedef {import('@web3-storage/access/src/types.js').DelegationRecord} DelegationRecord
*/

/**
* Accounts
*/
export class Accounts {
/**
*
* @param {D1Database} d1
*/
constructor(d1) {
/** @type {GenericPlugin<DelegationRecord>} */
const objectPlugin = new GenericPlugin({
// eslint-disable-next-line unicorn/no-null
expires_at: (v) => (typeof v === 'string' ? new Date(v) : null),
inserted_at: (v) => new Date(v),
updated_at: (v) => new Date(v),
})
this.d1 = /** @type {Kysely<import('../bindings').D1Schema>} */ (
new Kysely({
dialect: new D1Dialect({ database: d1 }),
plugins: [objectPlugin],
})
)
this.d1 =
/** @type {Kysely<{ accounts: import('@web3-storage/access/src/types.js').AccountTable }>} */ (
new Kysely({
dialect: new D1Dialect({ database: d1 }),
plugins: [objectPlugin],
})
)
}

/**
Expand Down
Loading

0 comments on commit 4510c9a

Please sign in to comment.