Skip to content

Commit

Permalink
fix: find delegations
Browse files Browse the repository at this point in the history
  • Loading branch information
fforbeck committed Feb 13, 2025
1 parent 6bbca27 commit 1f52c9e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"start": "npm run dev",
"test:integration": "npm run build:debug && mocha --experimental-vm-modules --recursive test/integration/**/*.spec.js --require test/fixtures/worker-fixture.js",
"test:miniflare": "npm run build:debug && mocha --experimental-vm-modules --recursive test/miniflare/**/*.spec.js",
"test:unit": "npm run build:debug && mocha --experimental-vm-modules --recursive test/unit/**/*.spec.js"
"test:unit": "npm run build:debug && mocha --experimental-vm-modules --recursive test/unit/**/*.spec.js",
"test:unit:only": "npm run build:debug && mocha --experimental-vm-modules"
},
"dependencies": {
"@microlabs/otel-cf-workers": "^1.0.0-rc.48",
Expand Down
5 changes: 3 additions & 2 deletions src/middleware/withDelegationsStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ function createStorage (env) {
/** @type {Ucanto.Delegation<Ucanto.Capabilities>[]} */
const delegations = []
const result = await env.CONTENT_SERVE_DELEGATIONS_STORE.list({ prefix: space })
result.keys.forEach(async (key) => {
await Promise.all(result.keys.map(async (key) => {
const delegation = await env.CONTENT_SERVE_DELEGATIONS_STORE.get(key.name, 'arrayBuffer')
if (delegation) {
const d = await Delegation.extract(new Uint8Array(delegation))
if (d.ok) delegations.push(d.ok)
else console.error('error while extracting delegation', d.error)
}
})
}))
return ok(delegations)
},

Expand Down
81 changes: 81 additions & 0 deletions test/unit/middleware/withDelegationsStorage.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import { describe, it, afterEach } from 'mocha'
import { expect } from 'chai'
import sinon from 'sinon'
import { ed25519 } from '@ucanto/principal'
import * as raw from 'multiformats/codecs/raw'
import { withDelegationsStorage } from '../../../src/middleware/withDelegationsStorage.js'
import { contentServe } from '@web3-storage/capabilities/space'
import { sha256 } from 'multiformats/hashes/sha2'
import { Link } from '@web3-storage/capabilities/store'
import { randomBytes } from 'node:crypto'

const kvStoreMock = {
get: sinon.stub(),
Expand All @@ -25,6 +30,12 @@ const kvStoreMock = {
const gatewaySigner = (await ed25519.Signer.generate()).signer
const gatewayIdentity = gatewaySigner.withDID('did:web:test.w3s.link')

const randomCid = async () => {
const input = new Uint8Array(randomBytes(138))
const cid = Link.create(raw.code, await sha256.digest(input))
return cid
}

const ctx =
/** @satisfies {DelegationsStorageContext} */
({
Expand Down Expand Up @@ -66,6 +77,76 @@ describe('withDelegationsStorage', async () => {
expect(mockHandler.firstCall.args[2]).to.have.property('delegationsStorage')
expect(mockHandler.firstCall.args[2].delegationsStorage).to.be.an('object')
})

it('should call the find method of the delegationsStorage and return the delegation', async () => {
// @ts-expect-error - Dummy handler that uses delegationsStorage
const mockHandler = async (request, env, ctx) => {
const result = await ctx.delegationsStorage.find(space)
return new Response(JSON.stringify(result))
}

const request = new Request('http://example.com/')

/** @type {import('@web3-storage/capabilities/types').SpaceDID} */
const space = 'did:key:z6MkeTvzPkRVhu4HcGu95ZCP23pMdtk3p144umfsPE68tZ4a'
const alice = await ed25519.Signer.generate()

// Create a sample delegation to be returned by the List and Find functions
const delegation = await contentServe.delegate({
issuer: alice,
audience: gatewayIdentity,
with: space,
expiration: 1000
})
const { ok: bytes } = await delegation.archive()
const delegations = [
{
id: `${space}:${await randomCid()}`,
expires: 1000,
content: bytes
},
{
id: `${space}:${await randomCid()}`,
expires: 1000,
content: bytes
},
{
id: `${space}:${await randomCid()}`,
expires: 1000,
content: bytes
}
]

// Simulate external request to the KV store
kvStoreMock.list.callsFake(async () => {
// Simulate network delay
await new Promise(resolve => setTimeout(resolve, Math.random() * 100))
return {
keys: delegations.map((d) => ({ name: d.id }))
}
})
kvStoreMock.get.onCall(0).resolves(delegations[0].content)
kvStoreMock.get.onCall(1).resolves(delegations[1].content)
kvStoreMock.get.onCall(2).resolves(delegations[2].content)

const env = {
FF_DELEGATIONS_STORAGE_ENABLED: 'true',
CONTENT_SERVE_DELEGATIONS_STORE: kvStoreMock // simulate results
}

const response = await withDelegationsStorage(mockHandler)(request, env, ctx)
const result = await response.json()
const delegationsFound = result.ok
// Assert results
expect(delegationsFound).to.be.an('array')
expect(delegationsFound.length).to.equal(3)

// Assert KV calls
expect(kvStoreMock.list.firstCall.calledWith({ prefix: space })).to.be.true
expect(kvStoreMock.get.firstCall.calledWith(delegations[0].id)).to.be.true
expect(kvStoreMock.get.secondCall.calledWith(delegations[1].id)).to.be.true
expect(kvStoreMock.get.thirdCall.calledWith(delegations[2].id)).to.be.true
})
})

it('should not set delegationsStorage in context when FF_DELEGATIONS_STORAGE_ENABLED is not true', async () => {
Expand Down

0 comments on commit 1f52c9e

Please sign in to comment.