Skip to content
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

Rebasing nft.storage on top of web3.storage #167

Open
Gozala opened this issue Nov 15, 2022 · 26 comments
Open

Rebasing nft.storage on top of web3.storage #167

Gozala opened this issue Nov 15, 2022 · 26 comments
Assignees
Milestone

Comments

@Gozala
Copy link
Contributor

Gozala commented Nov 15, 2022

We've discussed viable path for the MVP, such that enables us handle nft.storage use case with following goals:

  1. nft.storage can fund the storage
  2. nft.storage can list all the uploads that users made
  3. users can list all their uploads to nft.storage funded space

We decided that best solution for the MVP is following:

  1. We allow store/* and upload/* capabilities to be tagged with arbitrary string.
  2. ☝️ nft.storage would be able to setup own "space" that it funds.
  3. nft.storage could delegate tagged store/* and upload/* capabilities with users
    • nft.storage could decide terms for delegating those capabilities.
    • nft.storage could decide what kind of "user verification" takes place.
    • nft.storage could tag capabilities with a user identifier and decide what that identifier is (e.g. sha256 of the email, did primary key in db).
  4. Users will be able to upload into nft.storage "space" through delegated capabilities
  5. Users uploads will be tagged per "nft.storage" issued tag, allowing them to track which users uploaded what.
  6. Users will be able to list their own uploads because store/list and upload/list capabilities will be tagged per user identifier.
  7. nft.storage could also delegate user multiple tags if the so choose, or write access into one tag and read access into multiple tags in other words slice and dice it as they please.

How is this better than creating dedicated spaces for each nft.storage user ?

  • This is simpler because nft.storage does not need to manage more did / keypairs etc...
  • It is functionally equivalent
  • In fact nft.storage could created dedicated spaces if they so choose but it's just going to be more complex

Why tags and not paths ?

  • Paths imply hierarchies that are inherently more complex than flat structures
  • Tags are essentially sets and logic around them is simple
    • Adding same thing to the set is noop
    • Adding different thing under the same path is conflict (by using tags => sets we don't deal with conflicts)
@Gozala Gozala added this to the w3up phase 1 milestone Nov 15, 2022
@jchris
Copy link
Contributor

jchris commented Nov 15, 2022

why does the delegation we already have not accomplish this? eg nft storage would have a paid space on web3-storage. nft storage would run a lambda that delegates UCAN access to upload to that space, to anyone with an nft storage API key

@jchris
Copy link
Contributor

jchris commented Nov 15, 2022

is it because that means NFT storage also would have to manage a database mapping NFTuser -> web3space, if there was gonna be one space per user? I think that is OK to ask our customers to do. They will probably do it anyway

@Gozala
Copy link
Contributor Author

Gozala commented Nov 15, 2022

why does the delegation we already have not accomplish this? eg nft storage would have a paid space on web3-storage. nft storage would run a lambda that delegates UCAN access to upload to that space, to anyone

It would work, but that would imply that nft.storage either delegates "list" capability allowing users to list everyone's uploads or it does not delegate "list" capability not allowing users to list any uploads.

By adding tags we simply provide a way for nft.storage to delegate limited "list" capability by that tag.

with an nft storage API key

I'm not sure I follow this bit, although I think it is irrelevant how nft.storage chooses who to delegate capability to

@Gozala
Copy link
Contributor Author

Gozala commented Nov 15, 2022

is it because that means NFT storage also would have to manage a database mapping NFTuser -> web3space, if there was gonna be one space per user? I think that is OK to ask our customers to do. They will probably do it anyway

I think you're asking why not make nft.storage create a new "space" per user. They could, but that adds complexity:

  1. Who own the space user or the nft.storage ?
  2. How are the keys for spaces stored and managed ?
  3. How does nft.storage list all updates across all users (request per user does not sound scalable) ?

With tags above complexity is gone.

  1. nft.storage owns their own space, just delegates some capabilities to users.
  2. No more keys to manage (well just one, their own).
  3. Just send list request without a tag and you get them all

@Gozala
Copy link
Contributor Author

Gozala commented Nov 15, 2022

I have though a bit more about one vs many tags and I have came around to supporting many tags idea because:

  1. I think there is reasonable way to define intersection vs union semantics.
  2. Multiple tags allow delegates to further restrict sub-delegations which is something we'll probably need as soon as we think about cases where user and service are separated by several intermediaries.
  3. Implying intersection semantics on capabilities is a right default, because union could be achieved by issuing delegation per tag.

Limitations

Implying "intersection" behavior implies that "*/list" on tag unions can not be expressed (or at least with current ucanto toolchain, because it does not has support for compounding multiple delegations together)

However I do think we could address join listing use case differently, more on this later.

Proposal

We add tags: Tags field to our capabilities where Tags has following type signature:

type Tag = string | Pattern<string>

// Prefix implies match semantics as in anything that starts with `T`.
type Prefix<T extends string> = `${T}*`

// Keys are all the tags with intersection semantics
type Tags = {[key:Tag]: true}

This allows nft.storage to delegate sub(space) prefixed with alice tag, allowing her to add / list things tagged with alice, alice/photos, alicenfts etc...

Alice can add more tags on add / write as well.

[
  {
     can: 'store/add',
     with: 'did:key:space',
     tags: { ['alice*']: true }
  },
  {
     can: 'store/list',
     with: 'did:key:space',
     tags: { ["alice*"]: true }
  }
]

Alice can (sub)delegate tagged (sub)space by adding more tags

[
  {
     can: 'store/add',
     with: 'did:key:space',
     tags: { alice: true, bob: true }
  },
  {
     can: 'store/list',
     with: 'did:key:space',
     tags: { alice: true, public: true }
  }
  {
     can: 'store/list',
     with: 'did:key:space',
     tags: { alice: true, bob: true }
  }
]

Alice could also sub-delegate (sub) space to Mallory be extending a tag prefix, allowing Mallory to add / list things tagged as alice+mallory or alice+mallory/photos or alice+mallory+photos etc...

[
  {
    can: 'store/add',
     with: 'did:key:space',
     tags: {["alice+mallory*"]:true}
  },
  {
     can: 'store/list',
     with: 'did:key:space',
     tags: {["alice+mallory*"]: true}
  }
]

Why objects and not arrays ?

Arrays elements have order which affects hashes etc... IPLD codecs take care of encoding object keys in deterministic order making things more hash consistent.

Why tag prefixes doesn't multiple tags give us that ?

Multiple tags could be used to narrow down scope, but if you then want to list things tagged as {alice: true, bob:true} or {alice:true mallory:true} you would have to do two list requests and join locally. It's probably not a big deal on small joins but clearly won't scale to large joins.

Using tag prefixes a pragmatic solution by tagging things "alice/bob" and "alice/mallory" and then listing things that are tagged alice/*.

Hold on a second aren't you just recreating paths and hierarchies you claimed where bad ?

Nope!

Problem with paths isn't the paths themself but with implied semantics adding different things to same paths causes conflict. Tagging multiple things with a same path on the other hand isn't a conflict, so we avoid conflicts by making them impossible.

@dchoi27
Copy link
Contributor

dchoi27 commented Nov 16, 2022

why does the delegation we already have not accomplish this? eg nft storage would have a paid space on web3-storage. nft storage would run a lambda that delegates UCAN access to upload to that space, to anyone with an nft storage API key

i had a similar question (not because i disagree, but just don't know)

  • we can query usage of users using the second order DIDs, right? and then NFT.Storage can do a join of those DIDs with email addresses or whatever they're using to track?
  • what's stopping non-NFT.Storage users from just adding the nftstorage tag to their uploads? wouldn't it be better to use the same protocol for the ability to verifiably store in NFT.Storage's space and to track this storage (i.e., why would we make the tracking not part of the verifiable protocol)?

@jchris not sure i understand your second question as much - i think we're aligned here that there would just be one NFT.Storage space?

@Gozala
Copy link
Contributor Author

Gozala commented Nov 16, 2022

we can query usage of users using the second order DIDs, right? and then NFT.Storage can do a join of those DIDs with email addresses or whatever they're using to track?

we can, but users won’t because such capability wouldn’t be express-able and there for would not be possible to delegate.

what's stopping non-NFT.Storage users from just adding the nftstorage tag to their uploads?

Nothing they can tag their uploads as they want but those uploads will land in user space not nft.storage space so user will be billed instead.

wouldn't it be better to use the same protocol for the ability to verifiably store in NFT.Storage's space and to track this storage (i.e., why would we make the tracking not part of the verifiable protocol)?

you lost me here. We’re not proposing any new protocols here just adding extra field to capabilities so delegations could be constrained.

if you are asking why not limit queries based on delegation chain, e.g why not limit list based on ucan.proof.aud I’d day because:

  1. It goes against fundamental UCAN design, where things are based on capability delegated not who it is delegated to.
  2. Delegation chains may not correspond to user relationships.y phone will have diff delegation chain than my laptop and even though they were obtained by same email there will be no direct correlation.
  3. If I want to further sub delegate to my users end the give them namespaced permissions we no longer have solution.
  • we could try and get even more clever in trying to show only things based on chain depth etc… but that seems a lot more complex and error prone & of course misaligned with UCAN design

Just adding a field to are capabilities is lot simpler, can be queried more efficiently and has non of the above listed issues. It is also a lot more flexible allowing nft.storage to organize space as it makes most sense for that use case as opposed to us trying to infer desired behavior from delegation chain and if we get it right for nft.storage it’s unlikely to be the right one for slightly different use case

@Gozala
Copy link
Contributor Author

Gozala commented Nov 16, 2022

With UCANs it best to always think of them as movie 🎟️. If I have to ask for id in addition or know every pair hands it exchanged before it got here I’m doing it wrong.

In other words delegation chain should not be used for anything other than validation of claimed capability check. Everything else should be in the capabilities, if that’s not enough we should add more stuff into capacities

@Gozala
Copy link
Contributor Author

Gozala commented Nov 16, 2022

I think even better rule of thumb is:

I should be able to swap a UCAN delegation chain with another valid chain without affecting behavior.

@olizilla
Copy link
Contributor

Nice! That works for me.

May we have ucanto accept a Set<string | Pattern<string> { ['alice*']: true }or have atags()` helper function so app developers don't have to think about the IPLD friendly encoding?

Listing and pagination in DynamoDB is limited. You can only get n results from a previous item key and any filtering is applied after the data is fetched, so there will be queries where we fetch and discard many pages of results that don't match a tag. It's probably a minor perf/cost hit in practice, but we need to double check how this would work in practice with the current stack.

@olizilla
Copy link
Contributor

In the examples why do the tags not appear in the nb field?

@Gozala
Copy link
Contributor Author

Gozala commented Nov 16, 2022

May we have ucanto accept a Set<string | Pattern<string> { ['alice*']: true }or have atags()` helper function so app developers don't have to think about the IPLD friendly encoding?

Perhaps, I'm bit hesitant because experience may be bit of a surprise for a user, right now having set will simply throw an exception.

I also had some chats during IPFS Camp and chances are we might get set data structure in IPLD data model in which case it would be no brainer.

Also on related note I had attempted to have something like that for URLs instances, but that end up been problematic so I end up ripping it out, mostly because intention is clear on encode side, but not necessarily on decode side (do you mean actual object or do you mean set ?)

In the meantime our SDK can take sets and turn those into objects so end user does not have to care about IPLD representation details

Listing and pagination in DynamoDB is limited. You can only get n results from a previous item key and any filtering is applied after the data is fetched, so there will be queries where we fetch and discard many pages of results that don't match a tag. It's probably a minor perf/cost hit in practice, but we need to double check how this would work in practice with the current stack.

I mean listing API should have pagination, and if it does not we should fix that. Also I don't want to tie our protocol to the DynamoDB as we may use something in the future. Others implementing same protocol may never reach for dynamo etc...

@olizilla
Copy link
Contributor

Yes, I'm not proposing we adjust things to suit dynamo. I'm flagging that dynamo might be less of a good fit here, but it's not gonna be a blocker.

@olizilla
Copy link
Contributor

the meantime our SDK can take sets and turn those into objects so end user does not have to care about IPLD representation details

Works for me!

@Gozala
Copy link
Contributor Author

Gozala commented Nov 17, 2022

Had a call with @mikeal @jchris @dchoi27 about this proposal where @mikeal raised serious concerns over it. I may not be able to convey all of the points, but I'll try and let @mikeal correct me and fill all the gaps where needed.

  1. We should not use tags but rather use spaces instead, because tags would force secondary indexes which are hard to scale.
    • I'm personally not sure why tag would imply different data / table layout, but it is true that I was at least thinking about a table like (spaceDID, cid, tag).
  2. This goal is not requirement "nft.storage can list all the uploads that users made". If anything we should optimize user query over nft.storage query, which is why dedicated spaces make more sense.
  3. For views across user spaces we probably should have notion of space as union of spaces (I'm likely butchering this, but this is what I understood & I think it's more along the lines of original approach we were going for where adding new did simply created another top level ID representing join of existing space and new one)

At the end of the day I think there no real difference that I can see from the table layout boiling down to the table like follows

Please note that I've called it sharedID which could be a tag or a space

spaceDID sharedID dataCID
did:dns:nft.storage did:key:zAlice bag...one
did:dns:nft.storage did:key:zBob bag...two
did:dns:nft.storage did:key:zAlice bag...three
did:dns:nft.storage did:key:zBob bag...three

That said using dedicated "space" over tags forces a single tag, which is what I was advocating initially as well. But then again last two records in the example above are still adding same CID to the same table but with two different "contract ID" which I don't think we can prevent in any way so in other words we wind up with two tables if we want to optimize for size

spaceDID dataCID
did:dns:nft.storage bag...one
did:dns:nft.storage bag...two
did:dns:nft.storage bag...three
sharedID dataCID
did:key:zAlice bag...one
did:key:zBob bag...two
did:key:zAlice bag...three
did:key:zBob bag...three

Or alternatively with layout like

sharedID dataCID
did:key:zAlice bag...one
did:key:zBob bag...two
did:key:zAlice bag...three
did:key:zBob bag...three
spaceDID sharedID
did:dns:nft.storage did:key:zAlice
did:dns:nft.storage did:key:zBob
did:dns:free.web3.storage did:key:zMallory
did:dns:basic.web3.storage did:key:zJordan

If I'm understand correctly ☝️ is more along the lines of what @mikeal has in mind, but instead of spaceCID it's more of a "customerID" that can be billed.

Again I feel like beyond names of things it's all the same, but here are the tradeoffs as I see them

  • Forcing spaces implies that you either can have single "storage deal" tied to it, or there must be a way to disambiguate during invocation. Tag was supposed to disambiguate, but if not tag we need something else perhaps deal or store ?
  • If we force space per "storage deal" we are creating space for problems
    • If user makes a mistake and attempts to use space with other storage deal things won't work well
    • now user needs to jump between bunch of spaces
    • we need to sync spaces in keyring (or whatever else we'll have for switching). If I have added a new space on my laptop it's not yet on my phone, keyring needs to ask server what the new spaces have been added to let me obtain the access
    • in theory we could throw away keys for all those spaces, but then you can't revoke capabilities from space to lost agent or you need to introduce intermediary which is yet another hardle

@Gozala
Copy link
Contributor Author

Gozala commented Nov 17, 2022

📣 PLEASE DON'T FOCUS ON NAMES, THAT'S NOT IMPORTANT WE CAN FIX NAMES LATER

Personally I would much rather have something between two extremes, that is you get "storage contract" from the provider like nft.storage that is delegation of the capability

{
   can: 'contract/add',
   with: 'did:dns:nft.storage'
}

Which you can then enroll your space into, in other words invoke above delegated capability like

{
    can: 'contract/add',
    with: 'did:dns:nft.storage',
    nb: { target: 'did:key:zAlice' }
}

Once enrolled, did:key:zAlice space has a storage capacity funded by did:dns:nft.storage

Now store invocations can (optionally) signal which storage contract data is billed by (or in other words who to bill)

{
   can: 'store/add',
   with: 'did:key:zAlice',
   nb: { 
     link: carLink,
     contract: 'did:dns:nft.storage'
  }
}

If contract is not specified default contract is applied. E.g did:dns:free.web3.storage if it 's under free plan contract. If space has no storage contract, service is denied because there is no one to bill

@hugomrdias
Copy link
Contributor

In this scenario, is nft.storage creating the spaces and apply funds on behalf of the users? If yes it also needs to keep keypairs(maybe not?), delegations, recovery kits (invoke recovery for users) and probably other stuff. That may be ok for nft.storage but probably too much for other customers.

Example: A marketplace wants to handle/pay for user spaces but has a backend written in go, java, anything but js is it feasible that they need to write dag-ucan and probably more ucan code in golang ?

@alanshaw
Copy link
Member

@Gozala I like this proposal 👍

@Gozala
Copy link
Contributor Author

Gozala commented Nov 17, 2022

In this scenario, is nft.storage creating the spaces and apply funds on behalf of the users? If yes it also needs to keep keypairs(maybe not?), delegations, recovery kits (invoke recovery for users) and probably other stuff. That may be ok for nft.storage but probably too much for other customers.

No nft.storage does not create any spaces, it just gives out capability to tie whichever space to it's billing account basically. It won't have to store things and we'll probably provide some API to list all the spaces that were added to it's billing account

@Gozala Gozala changed the title Add tags to our capabilities Rebasing nft.storage on top of web3.storage Nov 17, 2022
@Gozala
Copy link
Contributor Author

Gozala commented Nov 17, 2022

I had a review session with @mikeal of the latest draft of the protocol that ties bunch of things together:

  1. It establishes general idea of a "contract" between two actors a "provider" and a "consumer".
  2. "consumer" (that is a user) can agree to terms of the contract by submitting whatever contract requires (e.g. for a free plan provide an email address, but other contracts may have other requirements) using UCAN invocation.
  3. "provider" in return can delegate back to "consumer" a contract certificate in form of "certificate/add" capability.
  4. when delegated "certificate/add" capability is invoked it essentially enrolls user "space" into the "contract", which in case of free plan manifests in adding "5GiB" storage to a "space" for which "provider" will be billed (in case of free plan that's web3.storage. With nft.storage it will be just different contract, but general idea is the same nft.storage get's billed).

More simply I think we want to proceed with the plan outlined in #167 (comment) with few caveats to reduce the scope further:

  1. We would want to reserve a field in the capabilities (that in the proposal was contract but probably a different name), but reject any invocations that set that field.
    • Because people can stick whatever they want in nb there is no other way for us to reserve a field, ppl can just stick arbitrary things and face problems later when we utilize them in some way.
    • While we recognize that there needs to be a way to communicate "who to bill", that is only relevant if your space has multiple storage contracts. In the MVP we will not support multiple contracts case, we'll do that post MVP.
  2. All our contracts (that is plans) will be mutually exclusive so you can have only one contract per space.
    • Our plans already kind of work that way so this fits well
    • Plan for nft.storage will be also be in MVP incompatible with other plans, so user would need to create a separate space to attach nft.storage contract. Again we can add support for multiple storage contracts post MVP and take time to design them well.
  3. Creating ways for "provider" to list enrolled "spaces" and / or their uploads is also post MVP, we're confident we could do them given the design.

It is also worth calling out that we considered how write pipeline would be affected by idea of having multiple (storage) contracts.

  • Right now we check if "space" can store data
  • In the future we would just change to if (spaceDID, contractDID) is active (which can continue to be a single key lookup)
  • billing and etc is post processing so optimizing it not as important

Concrete action items:

  1. Agree on names and terms (async)
  2. Merge protocol spec.
  3. Sync current voucher stuff with all the above, which is more or less what feat!: Update voucher API #163 doing except with "voucher" terminology (we don't have to update terminology, but I think it is worth it).
  4. Implement nb.contract field (or whatever we'll call it) so it fails to validate when included
  5. Implement use did:web for the services so we can rotate keys without having to redo delegations #182 because doing feat!: Update voucher API #163 is a lot easier with it and it addresses bunch of other readable label vs did:key constraints.

@Gozala
Copy link
Contributor Author

Gozala commented Nov 18, 2022

Ok I'm afraid I can no longer wave my hands around naming this thing. So I'll try to persuade you all that we should use term "provider" and try to explain why:

  1. When you create a space, you own it you can delegate capabilities to it, but you can not invoke those capabilities because you have no "provider" for them.
  2. There can be different kind of "capability providers" e.g. "storage provider" is the one that provides "store/*" capabilities so you can you know store things and check things that you've stored.
  3. If you invoke "store/add" but have no "store provider" in attached to your space, you are not able to store, makes sense right ?
  4. If you want to get can contract a "storage provider" provided by us and we offer different plans:
    • If you ask for a "free" storage provider and give us an email address, we'll give you one so you can add it to your space. Once you add storage provider you can store things with it.
    • If you want some "expert" level storage provider, well we've got you covered as well. You give us your billing info and we give you "expert storage provider" which you can add to your space.
  5. This expands to others as well nft.storage can create their own "nft store provider" that you can get from them. Although in reality nft.storage is just bradend variant of our "custom storage plan", in practice they lease storage provider from us and we charge them. It's their business however to decide who they let user their branded storage provider.

    We probably need to make "storage limits" part of this somehow, our plans have limits I imagine others may also would want to share their "branded" storage provider with some limits. This just room for thought not something we need to solve now.

  6. You know what we're not just limited to "storage providers", we can have a "name provider" as well that you can hire. It will provide w3name capabilities!
  7. We could also have "full stack" providers kind of like bundle deal! In fact our "expert" provider is not just store provider, it's also a "name provider" etc...
  8. When we have compute platform, we'll have "compute providers" as well that you'll be able to hire to provide some compute service!
  9. If you lost a "storage provider" what happens then ? Well you go and get another provider to keep your data around or you may loose it!

I hope I'll convinced you that "provider" is a good name for this! In fact it makes whole lot of sense that space on it's own is pretty useless until you fill it with some providers to do a job for you! It also allows to be not too generic with fields name e.g. instead of having something like:

{
   can: 'store/add',
   with: 'did:key:zAlice',
   nb: { 
     link: carLink,
     contract: 'did:dns:nft.storage'
  }
}

It turns into something like 🎉:

{
   can: 'store/add',
   with: 'did:key:zAlice',
   nb: { 
     link: carLink,
     store: 'did:dns:nft.storage'  <-- this is your storage provider
  }
}

For other things it could be called differently with domain specific term:

{
   can: 'worker/execute',
   with: 'did:key:zAlice',
   nb: { 
     worker: 'did:dns:vm.web3.storage' <-- this is your worker provider
     code:  codeCID,
     data: dataCID
  }
}

@jchris
Copy link
Contributor

jchris commented Nov 18, 2022

This makes sense to me. Do want to try for a correspondence between the prefix of can eg "compute" or "store" and the namespace we claim in nb? So maybe:

{
   can: 'compute/invoke',
   with: 'did:key:zAlice',
   nb: { 
     compute: {
       provider: 'did:dns:vm.web3.storage' 
       program:  codeCID,
       input: dataCID
     }
  }
}

@Gozala
Copy link
Contributor Author

Gozala commented Nov 18, 2022

This makes sense to me. Do want to try for a correspondence between the prefix of can eg "compute" or "store" and the namespace we claim in nb? So maybe

Yeah I was kind of going for it & probably in most case it would build up intuition. If I want to invoke "foo/*" capability I need to hire "foo" service provider.

{
can: 'compute/invoke',
with: 'did:key:zAlice',
nb: {
compute: {
provider: 'did:dns:vm.web3.storage'
program: codeCID,
input: dataCID
}
}
}

Yeah if we want reserve same name across all capabilities we could certainly generalize and call it "provider", but than again we could also always claim field name in nb which corresponds to first part of the can. So in store/* we claim store and in machine/* we claim machine.

@Gozala
Copy link
Contributor Author

Gozala commented Nov 18, 2022

Ok here is another cool piece that finally fits right into #167 (comment)

  1. We have this notion of upload/* list that you can add / remove / list dags in / from.
  2. Today @travis was just showing limitations of having a single upload list.
  3. I just realized how "capability provider" notion provides (see what I did here) an answer to this.
  4. With "free" plan includes one "list" provider (sorry have to call it list because "upload provider" makes no sense)
  5. But there could be multiple "list" providers and consequently multiple list of DAGs.
  6. In fact I could create my own list provider, just generate a keypair (well and tie to some billing which we don't have yet, but igrone that for the moment).
  7. Then I can install my custom list provider to my space.
  8. Now I have multiple lists that I can work with, in fact each app can have it's own list
  9. And you know what with did:dns we kind of already have named list associated with their brand!
  10. So here again well will be able to do something like { can: "upload/add", with: "did:key:zAlice", nb: { list: "did:dns:coolnotes.app" } }
  11. Not only it plugs nicely it also provides a very intuitive way to differentiate "app" specific data from each other.

Obviously just like stated before we don't have to support multiple providers in MVP, but it is cool that we can in the future and that it will address problems we're already finding with current limitations

@travis
Copy link
Member

travis commented Nov 18, 2022

this is cool!

With "free" plan includes one "list" provider (sorry have to call it list because "upload provider" makes no sense)

fwiw, "upload provider" makes sense to me as an app developer - the upload/* capabilities give me the ability to upload stuff "somewhere" and list/remove it later, and the provider "provides" that ability. Similarly, I like the idea of having an upload namespace in the caveats for upload/add because I could do something like

{  
  can: "upload/add", 
  with: "did:key:zAlice", 
  nb: { 
    upload: { 
      list: "did:dns:coolnotes.app", 
      contentType: "image/*", 
      capabilities: {... some capabilities that give some other DID access to the thing I upload ... } 
} } }

That is, I'd both like the ability to delegate parameterized upload capabilities to other folks AND would like to be able to do stuff like "specify a content type" or "set access control" during invocation (eg, "upload this note and give Irakli and Mikeal read and write access to it") - maybe this is the wrong way to do these specific things, but it seems like some sort of parameterization of the various upload/* capabilities makes sense?

Which is all to say that intuitively this choice of name makes sense to me!

@Gozala
Copy link
Contributor Author

Gozala commented Nov 19, 2022

fwiw, "upload provider" makes sense to me as an app developer - the upload/* capabilities give me the ability to upload stuff "somewhere" and list/remove it later, and the provider "provides" that ability.

Well it does not really let you upload though, you use store/add to do that, it mostly lets you maintain list of uploads or rather DAG roots.

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

No branches or pull requests

8 participants