-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Use Indexing Service when feature flag is present #132
Changes from 1 commit
85d63ae
a630ca1
17e5bdf
4c84ec2
c5fa39d
82e9820
fc870e4
5bfa90e
6a8d430
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
declare module '@web3-storage/w3cli/lib.js' { | ||
import { Client } from '@web3-storage/w3up-client' | ||
declare module '@storacha/cli/lib.js' { | ||
import { Client } from '@storacha/client' | ||
export declare function getClient(): Promise<Client> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,147 @@ | ||
import sade from 'sade' | ||
import { getClient } from '@web3-storage/w3cli/lib.js' | ||
import { getClient } from '@storacha/cli/lib.js' | ||
import { Space } from '@web3-storage/capabilities' | ||
import * as serve from '../src/capabilities/serve.js' | ||
/** | ||
* @import * as Ucanto from '@ucanto/interface' | ||
*/ | ||
|
||
const cli = sade('delegate-serve.js [space] [token] [accountDID] [gatewayDID]') | ||
/** | ||
* @template {string} Method | ||
* @param {string} str | ||
* @param {Method} [method] | ||
* @returns {str is Ucanto.DID<Method>} | ||
*/ | ||
const isDID = (str, method) => | ||
str.startsWith(`did:${method ? `${method}:` : ''}`) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could use ucanto schema for this. import { Schema } from '@ucanto/core'
Schema.did({ method }).is(str) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aha! I couldn't figure out how to get that to work before. Not sure what wasn't clicking, but it all makes sense now. Pushed as |
||
|
||
cli | ||
.option('--space', 'The space DID to delegate. If not provided, a new space will be created.') | ||
.option('--token', 'The auth token to use. If not provided, the delegation will not be authenticated.') | ||
/** | ||
* @param {string} str | ||
* @returns {str is `did:mailto:${string}:${string}`} | ||
*/ | ||
const isMailtoDID = (str) => /^did:mailto:.*:.*$/.test(str) | ||
|
||
sade('delegate-serve.js [space]') | ||
.option( | ||
'--token', | ||
'The auth token to use. If not provided, the delegation will not be authenticated.' | ||
) | ||
.option('--accountDID', 'The account DID to use when creating a new space.') | ||
.option('--gatewayDID', 'The gateway DID to use when delegating the space/content/serve capability. Defaults to did:web:staging.w3s.link.') | ||
.option( | ||
'--gatewayDID', | ||
'The gateway DID to use when delegating the space/content/serve capability. Defaults to did:web:staging.w3s.link.' | ||
) | ||
.describe( | ||
`Delegates ${Space.contentServe.can} to the Gateway for a test space generated by the script, with an optional auth token. Outputs a base64url string suitable for the stub_delegation query parameter. Pipe the output to pbcopy or similar for the quickest workflow.` | ||
`Delegates ${Space.contentServe.can} to the Gateway for a test space generated by the script, with an optional auth token. Outputs a base64url string suitable for the stub_delegation query parameter.` | ||
) | ||
.action(async (space, token, accountDID, gatewayDID, options) => { | ||
const { space: spaceOption, token: tokenOption, accountDID: accountDIDOption, gatewayDID: gatewayDIDOption } = options | ||
space = spaceOption || undefined | ||
token = tokenOption || undefined | ||
accountDID = accountDIDOption || undefined | ||
gatewayDID = gatewayDIDOption || 'did:web:staging.w3s.link' | ||
const client = await getClient() | ||
.action( | ||
/** | ||
* @param {string} [space] | ||
* @param {object} [options] | ||
* @param {string} [options.token] | ||
* @param {string} [options.accountDID] | ||
* @param {string} [options.gatewayDID] | ||
*/ | ||
async ( | ||
space, | ||
{ token, accountDID, gatewayDID = 'did:web:staging.w3s.link' } = {} | ||
) => { | ||
const client = await getClient() | ||
|
||
space ??= await createSpace(client, accountDID) | ||
|
||
let spaceDID | ||
let proofs = [] | ||
if (!space) { | ||
const provider = /** @type {`did:web:${string}`} */ (client.defaultProvider()) | ||
const account = client.accounts()[accountDID] | ||
const newSpace = await client.agent.createSpace('test') | ||
const provision = await account.provision(newSpace.did(), { provider }) | ||
if (provision.error) throw provision.error | ||
await newSpace.save() | ||
const authProof = await newSpace.createAuthorization(client.agent) | ||
proofs = [authProof] | ||
spaceDID = newSpace.did() | ||
} else { | ||
client.addSpace(space) | ||
spaceDID = space | ||
proofs = client.proofs([ | ||
if (!isDID(space)) { | ||
throw new Error(`Invalid space DID: ${space}`) | ||
} | ||
|
||
const proofs = client.proofs([ | ||
{ | ||
can: Space.contentServe.can, | ||
with: spaceDID | ||
} | ||
with: space, | ||
}, | ||
]) | ||
} | ||
|
||
/** @type {import('@ucanto/client').Principal<`did:${string}:${string}`>} */ | ||
const gatewayIdentity = { | ||
did: () => gatewayDID | ||
} | ||
if (proofs.length === 0) { | ||
throw new Error( | ||
`No proofs found. Are you authorized to ${serve.star.can} ${space}?` | ||
) | ||
} | ||
|
||
// @ts-expect-error - The client still needs to be updated to support the capability type | ||
const delegation = await client.createDelegation(gatewayIdentity, [Space.contentServe.can], { | ||
expiration: Infinity, | ||
proofs | ||
}) | ||
if (!isDID(gatewayDID)) { | ||
throw new Error(`Invalid gateway DID: ${gatewayDID}`) | ||
} | ||
|
||
await client.capability.access.delegate({ | ||
delegations: [delegation] | ||
}) | ||
const gatewayIdentity = { | ||
did: () => gatewayDID, | ||
} | ||
|
||
const carResult = await delegation.archive() | ||
if (carResult.error) throw carResult.error | ||
const base64Url = Buffer.from(carResult.ok).toString('base64url') | ||
process.stdout.write(`Agent Proofs: ${proofs.flatMap(p => p.capabilities).map(c => `${c.can} with ${c.with}`).join('\n')}\n`) | ||
process.stdout.write(`Issuer: ${client.agent.issuer.did()}\n`) | ||
process.stdout.write(`Audience: ${gatewayIdentity.did()}\n`) | ||
process.stdout.write(`Space: ${spaceDID}\n`) | ||
process.stdout.write(`Token: ${token ?? 'none'}\n`) | ||
process.stdout.write(`Delegation: ${delegation.capabilities.map(c => `${c.can} with ${c.with}`).join('\n')}\n`) | ||
process.stdout.write(`Stubs: stub_space=${spaceDID}&stub_delegation=${base64Url}&authToken=${token ?? ''}\n`) | ||
}) | ||
// NOTE: This type assertion is wrong. It's a hack to let us use this | ||
// ability. `client.createDelegation` currently only accepts abilities it | ||
// knows about. That should probably be expanded, but this little script | ||
// isn't going to be the reason to go change that, as it involves updating | ||
// multiple packages. | ||
const ability = /** @type {"*"} */ (Space.contentServe.can) | ||
|
||
const delegation = await client.createDelegation( | ||
gatewayIdentity, | ||
[ability], | ||
{ | ||
expiration: Infinity, | ||
proofs, | ||
} | ||
) | ||
|
||
await client.capability.access.delegate({ | ||
delegations: [delegation], | ||
}) | ||
|
||
const carResult = await delegation.archive() | ||
if (carResult.error) throw carResult.error | ||
const base64Url = Buffer.from(carResult.ok).toString('base64url') | ||
process.stdout.write( | ||
`Agent Proofs: ${proofs | ||
.flatMap((p) => p.capabilities) | ||
.map((c) => `${c.can} with ${c.with}`) | ||
.join('\n')}\n` | ||
) | ||
process.stdout.write(`Issuer: ${client.agent.issuer.did()}\n`) | ||
process.stdout.write(`Audience: ${gatewayIdentity.did()}\n`) | ||
process.stdout.write(`Space: ${space}\n`) | ||
process.stdout.write(`Token: ${token ?? 'none'}\n`) | ||
process.stdout.write( | ||
`Delegation: ${delegation.capabilities | ||
.map((c) => `${c.can} with ${c.with}`) | ||
.join('\n')}\n` | ||
) | ||
process.stdout.write( | ||
`Stubs: stub_space=${space}&stub_delegation=${base64Url}&authToken=${ | ||
token ?? '' | ||
}\n` | ||
) | ||
} | ||
) | ||
.parse(process.argv) | ||
|
||
cli.parse(process.argv) | ||
/** | ||
* @param {import('@storacha/client').Client} client | ||
* @param {string} [accountDID] | ||
*/ | ||
async function createSpace(client, accountDID) { | ||
const provider = client.defaultProvider() | ||
if (!isDID(provider, 'web')) { | ||
throw new Error(`Invalid provider DID: ${provider}`) | ||
} | ||
if (!accountDID) { | ||
throw new Error('Must provide an account DID to create a space') | ||
} | ||
if (!isMailtoDID(accountDID)) { | ||
throw new Error(`Invalid account DID: ${accountDID}`) | ||
} | ||
const account = client.accounts()[accountDID] | ||
const newSpace = await client.agent.createSpace('test') | ||
const provision = await account.provision(newSpace.did(), { provider }) | ||
if (provision.error) throw provision.error | ||
await newSpace.save() | ||
await newSpace.createAuthorization(client.agent) | ||
return newSpace.did() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { Delegation } from '@ucanto/core' | ||
import { spaceScopedLocator } from '../util.js' | ||
|
||
/** | ||
* @import * as Ucanto from '@ucanto/interface' | ||
|
@@ -53,21 +54,7 @@ export const withDelegationStubs = (handler) => async (request, env, ctx) => { | |
delegationProofs: [], // Delegation proofs are set by withAuthorizedSpace handler | ||
locator: | ||
stubSpace && isDIDKey(stubSpace) | ||
? { | ||
locate: async (digest, options) => { | ||
const locateResult = await ctx.locator.locate(digest, options) | ||
if (locateResult.error) return locateResult | ||
return { | ||
ok: { | ||
...locateResult.ok, | ||
site: locateResult.ok.site.map((site) => ({ | ||
...site, | ||
space: stubSpace | ||
})) | ||
} | ||
} | ||
} | ||
} | ||
? spaceScopedLocator(ctx.locator, [stubSpace]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A Space given as a stub ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha - for testing right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly—that's what this middleware is for. |
||
: ctx.locator | ||
}) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs update before merge.