From 1274e71bdbc76f854c92c94216d3ffda811b135e Mon Sep 17 00:00:00 2001 From: Travis Vachon Date: Mon, 8 Jan 2024 12:44:00 -0800 Subject: [PATCH 1/5] feat: add a function to verify and return Abilities. Given a list of strings representing capability names (Abilities), verify that all the strings are valid Abilities and return Abilities[]. Abilities[] is still just a list of strings, but this helps us play nice with Typescript. Inspired by https://github.com/web3-storage/w3up/issues/1250 --- packages/w3up-client/src/client.js | 22 ++++++++++++++++++++++ packages/w3up-client/test/client.test.js | 13 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/packages/w3up-client/src/client.js b/packages/w3up-client/src/client.js index c77d6d61d..bd13e7199 100644 --- a/packages/w3up-client/src/client.js +++ b/packages/w3up-client/src/client.js @@ -6,6 +6,7 @@ import { import { Store as StoreCapabilities, Upload as UploadCapabilities, + abilitiesAsStrings, } from '@web3-storage/capabilities' import { CAR } from '@ucanto/transport' import { Base } from './base.js' @@ -54,6 +55,27 @@ export class Client extends Base { this.coupon = new CouponAPI(agentData, options) } + /** + * Verify and return Abilities. + * + * Given a list of strings representing capability names (Abilities), + * verify that all the strings are valid Abilities and return Abilities[]. + * + * Abilities[] is still just a list of strings, but this helps us play + * nice with Typescript. + * + * @param {string[]} abilities + * @returns {import('@web3-storage/access').Abilities[]} + */ + static abilities(abilities) { + for (const ability of abilities) { + if (!abilitiesAsStrings.includes(/** @type {import('@web3-storage/access').Abilities} */(ability))) { + throw new Error(`${ability} is not a supported capability`) + } + } + return /** @type {import('@web3-storage/access').Abilities[]} */(abilities) + } + did() { return this._agent.did() } diff --git a/packages/w3up-client/test/client.test.js b/packages/w3up-client/test/client.test.js index 3d92d3748..553dd9bef 100644 --- a/packages/w3up-client/test/client.test.js +++ b/packages/w3up-client/test/client.test.js @@ -480,4 +480,17 @@ describe('Client', () => { assert.equal(typeof client.capability.upload.remove, 'function') }) }) + + describe('abilities', () => { + it('should return the passed argument if all abilities are valid', async () => { + const abilities = ['store/add', 'upload/add'] + assert.equal(Client.abilities(abilities), abilities) + }) + + it('should throw an error if one of the abilities is not supported', async () => { + assert.throws(() => { + Client.abilities(['foo/bar']) + }) + }) + }) }) From 8bd315a4ab19ffa799b7f37286f646ee2f89ddfb Mon Sep 17 00:00:00 2001 From: Travis Vachon Date: Mon, 8 Jan 2024 12:56:08 -0800 Subject: [PATCH 2/5] chore: lint --- packages/w3up-client/src/client.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/w3up-client/src/client.js b/packages/w3up-client/src/client.js index bd13e7199..d18bc6a1a 100644 --- a/packages/w3up-client/src/client.js +++ b/packages/w3up-client/src/client.js @@ -57,23 +57,27 @@ export class Client extends Base { /** * Verify and return Abilities. - * - * Given a list of strings representing capability names (Abilities), + * + * Given a list of strings representing capability names (Abilities), * verify that all the strings are valid Abilities and return Abilities[]. - * + * * Abilities[] is still just a list of strings, but this helps us play * nice with Typescript. - * + * * @param {string[]} abilities * @returns {import('@web3-storage/access').Abilities[]} */ static abilities(abilities) { for (const ability of abilities) { - if (!abilitiesAsStrings.includes(/** @type {import('@web3-storage/access').Abilities} */(ability))) { + if ( + !abilitiesAsStrings.includes( + /** @type {import('@web3-storage/access').Abilities} */ (ability) + ) + ) { throw new Error(`${ability} is not a supported capability`) } } - return /** @type {import('@web3-storage/access').Abilities[]} */(abilities) + return /** @type {import('@web3-storage/access').Abilities[]} */ (abilities) } did() { From d5a5701bb6f7abd6d05fb394301b7a30d984ea59 Mon Sep 17 00:00:00 2001 From: Travis Vachon Date: Mon, 8 Jan 2024 15:04:25 -0800 Subject: [PATCH 3/5] fix: updates from PR --- packages/capabilities/src/types.ts | 14 ++++++++-- packages/w3up-client/src/ability.js | 32 +++++++++++++++++++++++ packages/w3up-client/src/client.js | 26 ------------------ packages/w3up-client/src/index.js | 1 + packages/w3up-client/test/ability.test.js | 21 +++++++++++++++ packages/w3up-client/test/client.test.js | 13 --------- 6 files changed, 66 insertions(+), 41 deletions(-) create mode 100644 packages/w3up-client/src/ability.js create mode 100644 packages/w3up-client/test/ability.test.js diff --git a/packages/capabilities/src/types.ts b/packages/capabilities/src/types.ts index 7eb8bf111..35ae9a2c0 100644 --- a/packages/capabilities/src/types.ts +++ b/packages/capabilities/src/types.ts @@ -633,9 +633,9 @@ export type PlanGetFailure = PlanNotFound // Top export type Top = InferInvokedCapability -export type Abilities = TupleToUnion +export type Ability = TupleToUnion -export type AbilitiesArray = [ +export type AbilityArray = [ Top['can'], ProviderAdd['can'], Space['can'], @@ -677,3 +677,13 @@ export type AbilitiesArray = [ Usage['can'], UsageReport['can'] ] + +/** + * @deprecated use Ability + */ +export type Abilities = Ability + +/** + * @deprecated use AbilityArray + */ +export type AbilitiesArray = AbilityArray diff --git a/packages/w3up-client/src/ability.js b/packages/w3up-client/src/ability.js new file mode 100644 index 000000000..a944e386d --- /dev/null +++ b/packages/w3up-client/src/ability.js @@ -0,0 +1,32 @@ +import { abilitiesAsStrings } from '@web3-storage/capabilities' + +const setOfAbilities = new Set(abilitiesAsStrings) + +/** + * Verify and return Abilities. + * + * Given a list of strings representing capability names (Abilities), + * verify that all the strings are valid Abilities and return Abilities[]. + * + * Abilities[] is still just a list of strings, but this helps us play + * nice with Typescript. + * + * @param {string[]} abilities + * @returns {import('@web3-storage/capabilities/types').Ability[]} + */ +export function asAbilities(abilities) { + for (const ability of abilities) { + if ( + !setOfAbilities.has( + /** @type {import('@web3-storage/capabilities/types').Ability} */ ( + ability + ) + ) + ) { + throw new Error(`${ability} is not a supported capability`) + } + } + return /** @type {import('@web3-storage/capabilities/types').Ability[]} */ ( + abilities + ) +} diff --git a/packages/w3up-client/src/client.js b/packages/w3up-client/src/client.js index d18bc6a1a..c77d6d61d 100644 --- a/packages/w3up-client/src/client.js +++ b/packages/w3up-client/src/client.js @@ -6,7 +6,6 @@ import { import { Store as StoreCapabilities, Upload as UploadCapabilities, - abilitiesAsStrings, } from '@web3-storage/capabilities' import { CAR } from '@ucanto/transport' import { Base } from './base.js' @@ -55,31 +54,6 @@ export class Client extends Base { this.coupon = new CouponAPI(agentData, options) } - /** - * Verify and return Abilities. - * - * Given a list of strings representing capability names (Abilities), - * verify that all the strings are valid Abilities and return Abilities[]. - * - * Abilities[] is still just a list of strings, but this helps us play - * nice with Typescript. - * - * @param {string[]} abilities - * @returns {import('@web3-storage/access').Abilities[]} - */ - static abilities(abilities) { - for (const ability of abilities) { - if ( - !abilitiesAsStrings.includes( - /** @type {import('@web3-storage/access').Abilities} */ (ability) - ) - ) { - throw new Error(`${ability} is not a supported capability`) - } - } - return /** @type {import('@web3-storage/access').Abilities[]} */ (abilities) - } - did() { return this._agent.did() } diff --git a/packages/w3up-client/src/index.js b/packages/w3up-client/src/index.js index ebfdecf31..5d38b5363 100644 --- a/packages/w3up-client/src/index.js +++ b/packages/w3up-client/src/index.js @@ -11,6 +11,7 @@ import { generate } from '@ucanto/principal/rsa' import { Client } from './client.js' export * as Result from './result.js' export * as Account from './account.js' +export * from './ability.js' /** * Create a new w3up client. diff --git a/packages/w3up-client/test/ability.test.js b/packages/w3up-client/test/ability.test.js new file mode 100644 index 000000000..87d807f2c --- /dev/null +++ b/packages/w3up-client/test/ability.test.js @@ -0,0 +1,21 @@ +import assert from 'assert' +import { asAbilities } from '../src/ability.js' + +describe('abilities', () => { + it('should return the passed argument if all abilities are valid', async () => { + const abilities = ['store/add', 'upload/add'] + assert.equal(asAbilities(abilities), abilities) + }) + + it('should throw an error if one of the abilities is not supported', async () => { + assert.throws( + () => { + asAbilities(['foo/bar']) + }, + { + name: 'Error', + message: 'foo/bar is not a supported capability', + } + ) + }) +}) diff --git a/packages/w3up-client/test/client.test.js b/packages/w3up-client/test/client.test.js index 553dd9bef..3d92d3748 100644 --- a/packages/w3up-client/test/client.test.js +++ b/packages/w3up-client/test/client.test.js @@ -480,17 +480,4 @@ describe('Client', () => { assert.equal(typeof client.capability.upload.remove, 'function') }) }) - - describe('abilities', () => { - it('should return the passed argument if all abilities are valid', async () => { - const abilities = ['store/add', 'upload/add'] - assert.equal(Client.abilities(abilities), abilities) - }) - - it('should throw an error if one of the abilities is not supported', async () => { - assert.throws(() => { - Client.abilities(['foo/bar']) - }) - }) - }) }) From 92281dc7b7213f9c3b5f6bc8698107518bf37a63 Mon Sep 17 00:00:00 2001 From: Travis Vachon Date: Mon, 8 Jan 2024 15:08:57 -0800 Subject: [PATCH 4/5] fix: re-rename Ability to avoid conflicting with ucanto --- packages/capabilities/src/types.ts | 8 ++++---- packages/w3up-client/src/ability.js | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/capabilities/src/types.ts b/packages/capabilities/src/types.ts index 35ae9a2c0..c5c825c13 100644 --- a/packages/capabilities/src/types.ts +++ b/packages/capabilities/src/types.ts @@ -633,9 +633,9 @@ export type PlanGetFailure = PlanNotFound // Top export type Top = InferInvokedCapability -export type Ability = TupleToUnion +export type W3UpAbility = TupleToUnion -export type AbilityArray = [ +export type W3UpAbilityArray = [ Top['can'], ProviderAdd['can'], Space['can'], @@ -681,9 +681,9 @@ export type AbilityArray = [ /** * @deprecated use Ability */ -export type Abilities = Ability +export type Abilities = W3UpAbility /** * @deprecated use AbilityArray */ -export type AbilitiesArray = AbilityArray +export type AbilitiesArray = W3UpAbilityArray diff --git a/packages/w3up-client/src/ability.js b/packages/w3up-client/src/ability.js index a944e386d..0c9b0f7da 100644 --- a/packages/w3up-client/src/ability.js +++ b/packages/w3up-client/src/ability.js @@ -12,13 +12,13 @@ const setOfAbilities = new Set(abilitiesAsStrings) * nice with Typescript. * * @param {string[]} abilities - * @returns {import('@web3-storage/capabilities/types').Ability[]} + * @returns {import('@web3-storage/capabilities/types').W3UpAbility[]} */ export function asAbilities(abilities) { for (const ability of abilities) { if ( !setOfAbilities.has( - /** @type {import('@web3-storage/capabilities/types').Ability} */ ( + /** @type {import('@web3-storage/capabilities/types').W3UpAbility} */ ( ability ) ) @@ -26,7 +26,7 @@ export function asAbilities(abilities) { throw new Error(`${ability} is not a supported capability`) } } - return /** @type {import('@web3-storage/capabilities/types').Ability[]} */ ( + return /** @type {import('@web3-storage/capabilities/types').W3UpAbility[]} */ ( abilities ) } From ffa5be29abe117a229231c792ac837fe85e7e8d3 Mon Sep 17 00:00:00 2001 From: Travis Vachon Date: Thu, 11 Jan 2024 14:28:29 -0800 Subject: [PATCH 5/5] feat: s/W3UpAbility/ServiceAbility/ Per PR conversation --- packages/capabilities/src/types.ts | 12 ++++++------ packages/w3up-client/src/ability.js | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/capabilities/src/types.ts b/packages/capabilities/src/types.ts index c5c825c13..e921cff6b 100644 --- a/packages/capabilities/src/types.ts +++ b/packages/capabilities/src/types.ts @@ -633,9 +633,9 @@ export type PlanGetFailure = PlanNotFound // Top export type Top = InferInvokedCapability -export type W3UpAbility = TupleToUnion +export type ServiceAbility = TupleToUnion -export type W3UpAbilityArray = [ +export type ServiceAbilityArray = [ Top['can'], ProviderAdd['can'], Space['can'], @@ -679,11 +679,11 @@ export type W3UpAbilityArray = [ ] /** - * @deprecated use Ability + * @deprecated use ServiceAbility */ -export type Abilities = W3UpAbility +export type Abilities = ServiceAbility /** - * @deprecated use AbilityArray + * @deprecated use ServiceAbilityArray */ -export type AbilitiesArray = W3UpAbilityArray +export type AbilitiesArray = ServiceAbilityArray diff --git a/packages/w3up-client/src/ability.js b/packages/w3up-client/src/ability.js index 0c9b0f7da..062bd92a4 100644 --- a/packages/w3up-client/src/ability.js +++ b/packages/w3up-client/src/ability.js @@ -12,13 +12,13 @@ const setOfAbilities = new Set(abilitiesAsStrings) * nice with Typescript. * * @param {string[]} abilities - * @returns {import('@web3-storage/capabilities/types').W3UpAbility[]} + * @returns {import('@web3-storage/capabilities/types').ServiceAbility[]} */ export function asAbilities(abilities) { for (const ability of abilities) { if ( !setOfAbilities.has( - /** @type {import('@web3-storage/capabilities/types').W3UpAbility} */ ( + /** @type {import('@web3-storage/capabilities/types').ServiceAbility} */ ( ability ) ) @@ -26,7 +26,7 @@ export function asAbilities(abilities) { throw new Error(`${ability} is not a supported capability`) } } - return /** @type {import('@web3-storage/capabilities/types').W3UpAbility[]} */ ( + return /** @type {import('@web3-storage/capabilities/types').ServiceAbility[]} */ ( abilities ) }