Skip to content

feat: access-api forwards store/ and upload/ invocations to upload-api#334

Merged
gobengo merged 31 commits into
mainfrom
331-make-it-so-access-api-can-proxy-store-and-upload-invocations-to-upload-api
Jan 14, 2023
Merged

feat: access-api forwards store/ and upload/ invocations to upload-api#334
gobengo merged 31 commits into
mainfrom
331-make-it-so-access-api-can-proxy-store-and-upload-invocations-to-upload-api

Conversation

@gobengo

@gobengo gobengo commented Jan 11, 2023

Copy link
Copy Markdown
Contributor

@gobengo gobengo temporarily deployed to dev January 11, 2023 04:52 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 11, 2023 23:25 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 11, 2023 23:35 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 12, 2023 00:59 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 12, 2023 01:09 — with GitHub Actions Inactive
@gobengo gobengo marked this pull request as ready for review January 12, 2023 01:10
Comment thread packages/access-api/test/store-list.js Outdated
// which will allow the access-api ucanto server to accept
// invocations where aud=web3storageDid
DID: web3storageDid,
PRIVATE_KEY: privateKeyFromEnv ?? process.env.PRIVATE_KEY,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some of this extra stuff is in here because I wanted to support running the tests with the production private key, which works with a non-error result. But if you don't pass that in, the assertions shift slightly to ensuring that it's an error result of the kind that would happen only if the server signer is wrong

Note how this test was run with WEB3_STORAGE_PRIVATE_KEY:

bengo@bengo ~/protocol.ai/w3protocol/packages/access-api ⚡  DID="$PROD_DID_KEY" WEB3_STORAGE_PRIVATE_KEY="$PROD_PRIVATE_KEY" pnpm test -- -f 'upload-api'

> @web3-storage/access-api@4.2.0 test /Users/bengo/protocol.ai/w3protocol/packages/access-api
> pnpm build && mocha --bail --timeout 10s -n no-warnings -n experimental-vm-modules "-f" "upload-api"


> @web3-storage/access-api@4.2.0 build /Users/bengo/protocol.ai/w3protocol/packages/access-api
> scripts/cli.js build



  proxy store/list invocations to upload-api
    ✔ forwards store/list invocations with aud=did:key (648ms)
    ✔ forwards invocations with aud=did:web:web3.storage (460ms)
    ✔ errors when a bad delegation is given as proof (320ms)

  Store.all
    ✔ proxies store/add to upload-api (331ms)
    ✔ proxies store/remove to upload-api (306ms)
    ✔ proxies store/list to upload-api (385ms)

  Upload.all
    ✔ proxies upload/add to upload-api (303ms)
    ✔ proxies upload/remove to upload-api (287ms)
    ✔ proxies upload/list to upload-api (342ms)


  9 passing (3s)

@gobengo gobengo temporarily deployed to dev January 12, 2023 01:21 — with GitHub Actions Inactive

@Gozala Gozala left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added bunch of Nits, which you can completely ignore or address before or after landing. Only thing I do wish is that we had a test(s) where we spin up local store and upload services and route to those in test so that we have passing cases that don't require actual w3up service and all worked in offline mode.

That said it's probably tricky to do it without moving bunch of code from w3infra here so I think it's good enough for now.

Comment thread packages/access-api/src/config.js Outdated
import { Signer } from '@ucanto/principal/ed25519'
import * as DID from '@ipld/dag-ucan/did'
// eslint-disable-next-line no-unused-vars
import * as dagUcan from '@ipld/dag-ucan'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We re-export all of the types from the dag-ucan in the ucanto interface & it would be better to use those instead, so we don't have a chance of having two diff versions of dag-ucan in the tree.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I updated to that, and will prefer importing from ucanto libs in the future instead of dag-ucan.

import { UCAN } from '@ucanto/interface';
import { DID } from '@ucanto/core';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*/
export function service(ctx) {
return {
...UploadApiProxyService.create({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think ...uploadProvider(), ...storeProvider() would be more aligned with other stuff already in use. Also I think it would be a good idea to make fetch optional so we only need to pass it when overriding default.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i agree and will do as fast follow #338

Comment thread packages/access-api/src/service/upload-api-proxy.js Outdated
Comment thread packages/access-api/src/service/upload-api-proxy.js Outdated
Comment thread packages/access-api/src/service/upload-api-proxy.js Outdated
/**
* @implements {Pick<Map<dagUcan.DID, iucanto.Connection<any>>, 'get'>}
*/
class AudienceConnections {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This whole class seems like incidental complexity, things would be a whole lot simpler with just config object and static function for get method.

P.S.: I know that's not a popular opinion, yet I like to share it in a hope to bring peers to a true side :P

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this like what you had in mind? b46dd85

P.S.: I know that's not a popular opinion, yet I like to share it in a hope to bring peers to a true side :P

Eh, I don't disagree necessarily. good suggestion.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly, sorry for not been very clear. In linked version you still have audienceConnections which has get function. When I criticize classes what I mean is:

Separate data part which is basically a state from the behavior which are all the methods

That way it does not matter how you constructed state, you can just pass it into a function and it will compute whatever. Separating data and behavior de-tangles two allowing you to store data in e.g. indexDB and then apply function after reading it from indexDB without having to built a class first. Not the case here but complex class heirerchies also often entangle initialization order.

I think there are only two valid reasons to resort to a classes with methods:

  1. When you have to deal with open-ended variant space. In other sometimes you have many different state options but only one of them will be used in practice. In this scenario dispatching from one function introduces unnecessary coordination and defining interface is better option.
  2. When your methods are simply a convenience sugar for the static functions. I do it all the time to allow method chaining and remove need for importing lot of dependencies. In this case they don't tangle anything they are nothing but a sugar

I would argue use of classes with methods for any other reason just introduces incidental complexity and gets between you and data nothing else.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gozala ah I understand what you mean now.

Separating data and behavior de-tangles two allowing you to store data in e.g. indexDB and then apply function after reading it from indexDB without having to built a class first.

def have run into that. That helped me understand.

Comment thread packages/access-api/src/service/upload-api-proxy.js Outdated
Comment thread packages/access-api/test/helpers/context.js
Comment thread packages/access-api/test/upload-api-proxy.test.js Outdated
Comment thread packages/access-api/test/store-list.js Outdated
@Gozala

Gozala commented Jan 12, 2023

Copy link
Copy Markdown
Contributor

That said it's probably tricky to do it without moving bunch of code from w3infra here so I think it's good enough for now.

Created this issue to that effect storacha/w3infra#127

@gobengo gobengo mentioned this pull request Jan 12, 2023
3 tasks
@gobengo

gobengo commented Jan 12, 2023

Copy link
Copy Markdown
Contributor Author

cc @hugomrdias

@hugomrdias hugomrdias self-requested a review January 12, 2023 17:41
@gobengo gobengo mentioned this pull request Jan 12, 2023
1 task
…tore/upload service types from the capability defs
@gobengo gobengo temporarily deployed to dev January 13, 2023 21:02 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 13, 2023 22:59 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 13, 2023 23:07 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 13, 2023 23:16 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 13, 2023 23:31 — with GitHub Actions Inactive
@gobengo gobengo temporarily deployed to dev January 14, 2023 01:54 — with GitHub Actions Inactive
@gobengo gobengo merged commit b773376 into main Jan 14, 2023
@gobengo gobengo deleted the 331-make-it-so-access-api-can-proxy-store-and-upload-invocations-to-upload-api branch January 14, 2023 02:03
@hugomrdias

Copy link
Copy Markdown
Contributor

i was hoping for another round of review

@hugomrdias

Copy link
Copy Markdown
Contributor

Upon for testing this should work as expected

/**
 * @template {API.Ability} A
 * @template {API.URI} R
 * @template {API.Caveats} C
 * @param {API.CapabilityParser<API.Match<API.ParsedCapability<A, R, API.InferCaveats<C>>>>} capability
 * @param {import('../bindings').RouteContext} ctx
 */
function createProxyProvider(capability, ctx) {
  const provider = Server.provide(
    capability,
    async ({ capability, invocation }) => {
      /** @type {import('@ucanto/interface').ConnectionView<import('@web3-storage/access/types').Service>} */
      const connection = connect({
        // This should be the same did:web as access api
        id: ctx.signer,
        encoder: CAR,
        decoder: CBOR,
        channel: HTTP.open({
          // this is the only new global env var
          url: new URL('https://staging.up.web3.storage'),
          method: 'POST',
        }),
      })

      const inv = ucanto.invoke({
        issuer: ctx.signer,
        // This should be the same did:web as access api
        audience: ctx.signer,
        capability,
        proofs: [invocation],
        expiration: invocation.expiration,
        facts: invocation.facts,
        nonce: invocation.nonce,
        notBefore: invocation.notBefore,
      })
      const [result] = await connection.execute(
        /** @type {API.ServiceInvocation<{can: A, with: R, nb: C}, import('@web3-storage/access/types').Service>} */ (
          inv
        )
      )
      return result
    }
  )

  return provider
}

In the service definition (src/service/index.js) we only need:

/**
 * @param {import('../bindings').RouteContext} ctx
 * @returns {import('@web3-storage/access/types').Service}
 */
export function service(ctx) {
  return {
    store: {
      add: createProxyProvider(Store.add, ctx),
    },
    .....
  }
}

and here https://github.com/web3-storage/w3protocol/blob/b77337692d9e4580031c429c429d4055d6f6ebff/packages/access-client/src/types.ts#L67 we need to add

store: {
    add: ServiceMethod<StoreAdd, StoreAddResponse, Failure>
  }

gobengo pushed a commit that referenced this pull request Jan 17, 2023
🤖 I have created a release *beep* *boop*
---


##
[4.3.0](access-api-v4.2.0...access-api-v4.3.0)
(2023-01-17)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](#334))
([b773376](b773376))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
hugomrdias added a commit that referenced this pull request Jan 31, 2023
🤖 I have created a release *beep* *boop*
---


##
[2.2.0](capabilities-v2.1.0...capabilities-v2.2.0)
(2023-01-30)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](#334))
([b773376](b773376))
* **capabilities:** implement access/authorize and ./update caps
([#387](#387))
([4242ce0](4242ce0)),
closes [#385](#385)
* embedded key resolution
([#312](#312))
([4da91d5](4da91d5))
* update @ucanto/* to ~4.2.3
([#405](#405))
([50c0c80](50c0c80))
* update access-api ucanto proxy to not need a signer
([#390](#390))
([71cbeb7](71cbeb7))


### Bug Fixes

* fix client cli service did resolve
([#292](#292))
([6be9608](6be9608))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
hugomrdias added a commit that referenced this pull request Jan 31, 2023
🤖 I have created a release *beep* *boop*
---


##
[9.3.0](access-v9.2.0...access-v9.3.0)
(2023-01-30)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](#334))
([b773376](b773376))
* access-api handling store/info for space not in db returns failure
with name
([#391](#391))
([9610fcf](9610fcf))
* update @ucanto/* to ~4.2.3
([#405](#405))
([50c0c80](50c0c80))
* update access-api ucanto proxy to not need a signer
([#390](#390))
([71cbeb7](71cbeb7))


### Bug Fixes

* remove unecessary awaits
([#352](#352))
([64da6e5](64da6e5))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
gobengo pushed a commit that referenced this pull request Apr 11, 2023
🤖 I have created a release *beep* *boop*
---


##
[4.3.0](access-api-v4.2.0...access-api-v4.3.0)
(2023-01-17)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](#334))
([6be7217](6be7217))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
gobengo pushed a commit that referenced this pull request Apr 11, 2023
🤖 I have created a release *beep* *boop*
---


##
[2.2.0](capabilities-v2.1.0...capabilities-v2.2.0)
(2023-01-30)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](#334))
([6be7217](6be7217))
* **capabilities:** implement access/authorize and ./update caps
([#387](#387))
([ebe1032](ebe1032)),
closes [#385](#385)
* embedded key resolution
([#312](#312))
([45f367d](45f367d))
* update @ucanto/* to ~4.2.3
([#405](#405))
([ec39443](ec39443))
* update access-api ucanto proxy to not need a signer
([#390](#390))
([163fb74](163fb74))


### Bug Fixes

* fix client cli service did resolve
([#292](#292))
([45e7ad4](45e7ad4))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
gobengo pushed a commit that referenced this pull request Apr 11, 2023
🤖 I have created a release *beep* *boop*
---


##
[9.3.0](access-v9.2.0...access-v9.3.0)
(2023-01-30)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](#334))
([6be7217](6be7217))
* access-api handling store/info for space not in db returns failure
with name
([#391](#391))
([665dac9](665dac9))
* update @ucanto/* to ~4.2.3
([#405](#405))
([ec39443](ec39443))
* update access-api ucanto proxy to not need a signer
([#390](#390))
([163fb74](163fb74))


### Bug Fixes

* remove unecessary awaits
([#352](#352))
([2e8c1a1](2e8c1a1))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
tx-ravenxbsw3 added a commit to tx-ravenxbsw3/w3up that referenced this pull request Sep 29, 2025
🤖 I have created a release *beep* *boop*
---


##
[4.3.0](storacha/w3up@access-api-v4.2.0...access-api-v4.3.0)
(2023-01-17)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](storacha/w3up#334))
([b773376](storacha/w3up@b773376))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
tx-ravenxbsw3 added a commit to tx-ravenxbsw3/w3up that referenced this pull request Sep 29, 2025
🤖 I have created a release *beep* *boop*
---


##
[2.2.0](storacha/w3up@capabilities-v2.1.0...capabilities-v2.2.0)
(2023-01-30)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](storacha/w3up#334))
([b773376](storacha/w3up@b773376))
* **capabilities:** implement access/authorize and ./update caps
([#387](storacha/w3up#387))
([4242ce0](storacha/w3up@4242ce0)),
closes [#385](storacha/w3up#385)
* embedded key resolution
([#312](storacha/w3up#312))
([4da91d5](storacha/w3up@4da91d5))
* update @ucanto/* to ~4.2.3
([#405](storacha/w3up#405))
([50c0c80](storacha/w3up@50c0c80))
* update access-api ucanto proxy to not need a signer
([#390](storacha/w3up#390))
([71cbeb7](storacha/w3up@71cbeb7))


### Bug Fixes

* fix client cli service did resolve
([#292](storacha/w3up#292))
([6be9608](storacha/w3up@6be9608))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
tx-ravenxbsw3 added a commit to tx-ravenxbsw3/w3up that referenced this pull request Sep 29, 2025
🤖 I have created a release *beep* *boop*
---


##
[9.3.0](storacha/w3up@access-v9.2.0...access-v9.3.0)
(2023-01-30)


### Features

* access-api forwards store/ and upload/ invocations to upload-api
([#334](storacha/w3up#334))
([b773376](storacha/w3up@b773376))
* access-api handling store/info for space not in db returns failure
with name
([#391](storacha/w3up#391))
([9610fcf](storacha/w3up@9610fcf))
* update @ucanto/* to ~4.2.3
([#405](storacha/w3up#405))
([50c0c80](storacha/w3up@50c0c80))
* update access-api ucanto proxy to not need a signer
([#390](storacha/w3up#390))
([71cbeb7](storacha/w3up@71cbeb7))


### Bug Fixes

* remove unecessary awaits
([#352](storacha/w3up#352))
([64da6e5](storacha/w3up@64da6e5))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

make it so access-api can proxy store and upload invocations to upload-api

3 participants