Skip to content

Commit

Permalink
feat!: switch decoder API to zod like schema API (#108)
Browse files Browse the repository at this point in the history
* fix: optional caveats

backport #105 into 0.9

* stash: current status of schema code

* chore: increase coverage

* fix: get 100 coverage

* chore: optimize typings

* chore: rename decoder to schema

* feat: update decoders to new API

* feat: increase coverage to 100%

* fix: regressions in other packages

* fix: bundler issue

* Update packages/validator/src/schema/schema.js

* fix: fixes for #108 (#116)

* fix: coverage for Link.optional

Co-authored-by: Hugo Dias <hugomrdias@gmail.com>
  • Loading branch information
Gozala and hugomrdias committed Oct 16, 2022
1 parent 9397eb6 commit e2e03ff
Show file tree
Hide file tree
Showing 31 changed files with 3,989 additions and 384 deletions.
17 changes: 9 additions & 8 deletions packages/interface/src/capability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,17 @@ export interface MatchSelector<M extends Match>

export interface DirectMatch<T> extends Match<T, DirectMatch<T>> {}

export interface Decoder<
I extends unknown,
O extends unknown,
export interface Reader<
O = unknown,
I = unknown,
X extends { error: true } = Failure
> {
decode: (input: I) => Result<O, X>
read: (input: I) => Result<O, X>
}

export interface Caveats
extends Record<string, Decoder<unknown, unknown, Failure>> {}
export interface Caveats {
[key: string]: Reader<any, unknown>
}

export type MatchResult<M extends Match> = Result<M, InvalidCapability>

Expand Down Expand Up @@ -260,7 +261,7 @@ export type ParsedCapability<
: { can: Can; with: Resource; nb: C }

export type InferCaveats<C> = Optionalize<{
[K in keyof C]: C[K] extends Decoder<unknown, infer T, infer _> ? T : never
[K in keyof C]: C[K] extends Reader<infer T, unknown, infer _> ? T : never
}>

export interface Descriptor<
Expand All @@ -269,7 +270,7 @@ export interface Descriptor<
C extends Caveats
> {
can: A
with: Decoder<Resource, R, Failure>
with: Reader<R, Resource, Failure>

nb?: C

Expand Down
2 changes: 1 addition & 1 deletion packages/interface/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ export type ExecuteInvocation<
? Out
: never

export type Result<T, X extends { error: true }> =
export type Result<T extends unknown, X extends { error: true }> =
| (T extends null | undefined ? T : never)
| (T & { error?: never })
| X
Expand Down
8 changes: 6 additions & 2 deletions packages/principal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"types": "./dist/src/lib.d.ts",
"typesVersions": {
"*": {
"*": [
"dist/*"
".": [
"dist/src/lib.d.ts"
],
"ed25519": [
"dist/src/ed25519.d.ts"
Expand All @@ -60,6 +60,10 @@
}
},
"exports": {
".": {
"types": "./dist/src/lib.d.ts",
"import": "./src/lib.js"
},
"./ed25519": {
"types": "./dist/src/ed25519.d.ts",
"import": "./src/ed25519.js"
Expand Down
4 changes: 4 additions & 0 deletions packages/principal/src/ed25519/signer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const SIZE = PRIVATE_TAG_SIZE + KEY_SIZE + PUBLIC_TAG_SIZE + KEY_SIZE

export const PUB_KEY_OFFSET = PRIVATE_TAG_SIZE + KEY_SIZE

/**
* @typedef {API.EdSigner } EdSigner
*/

/**
* Generates new issuer by generating underlying ED25519 keypair.
* @returns {Promise<API.EdSigner>}
Expand Down
2 changes: 1 addition & 1 deletion packages/principal/src/ed25519/verifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const PUBLIC_TAG_SIZE = varint.encodingLength(code)
const SIZE = 32 + PUBLIC_TAG_SIZE

/**
* @typedef {API.Verifier<"key", Signature.EdDSA> & Uint8Array} Verifier
* @typedef {API.EdVerifier} EdVerifier
*/

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/server/test/server.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const storeAdd = Server.capability({
can: 'store/add',
with: Server.URI.match({ protocol: 'did:' }),
nb: {
link: Server.Link.optional(),
link: Server.Link.match().optional(),
},
derives: (claimed, delegated) => {
if (claimed.with !== delegated.with) {
Expand All @@ -35,7 +35,7 @@ const storeRemove = Server.capability({
can: 'store/remove',
with: Server.URI.match({ protocol: 'did:' }),
nb: {
link: Server.Link.optional(),
link: Server.Link.match().optional(),
},
derives: (claimed, delegated) => {
if (claimed.with !== delegated.with) {
Expand Down
4 changes: 2 additions & 2 deletions packages/server/test/service/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const addCapability = Server.capability({
can: 'store/add',
with: Server.URI.match({ protocol: 'did:' }),
nb: {
link: Server.Link.optional(),
link: Server.Link.match().optional(),
},
derives: (claimed, delegated) => {
if (claimed.with !== delegated.with) {
Expand All @@ -35,7 +35,7 @@ const removeCapability = Server.capability({
can: 'store/remove',
with: Server.URI.match({ protocol: 'did:' }),
nb: {
link: Server.Link.optional(),
link: Server.Link.match().optional(),
},
derives: (claimed, delegated) => {
if (claimed.with !== delegated.with) {
Expand Down
4 changes: 2 additions & 2 deletions packages/validator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
"homepage": "https://github.com/web3-storage/ucanto",
"scripts": {
"test:web": "playwright-test test/**/*.spec.js --cov && nyc report",
"test:node": "c8 --check-coverage --branches 96 --functions 85 --lines 93 mocha test/**/*.spec.js",
"test:node": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha test/**/*.spec.js",
"test": "npm run test:node",
"coverage": "c8 --reporter=html mocha test/**/*.spec.js && npm_config_yes=true npx st -d coverage -p 8080",
"coverage": "c8 --reporter=html mocha test/**/*.spec.js",
"typecheck": "tsc --build",
"build": "tsc --build"
},
Expand Down
36 changes: 22 additions & 14 deletions packages/validator/src/capability.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DelegationError as MatchError,
Failure,
} from './error.js'
import { invoke, delegate } from '@ucanto/core'
import { invoke } from '@ucanto/core'

/**
* @template {API.Ability} A
Expand Down Expand Up @@ -51,6 +51,7 @@ class View {
* @param {API.Source} source
* @returns {API.MatchResult<M>}
*/
/* c8 ignore next 3 */
match(source) {
return new UnknownCapability(source.capability)
}
Expand Down Expand Up @@ -121,7 +122,7 @@ class Capability extends Unit {
const decoders = descriptor.nb
const data = /** @type {API.InferCaveats<C>} */ (options.nb || {})

const resource = descriptor.with.decode(options.with)
const resource = descriptor.with.read(options.with)
if (resource.error) {
throw Object.assign(new Error(`Invalid 'with' - ${resource.message}`), {
cause: resource,
Expand All @@ -134,7 +135,7 @@ class Capability extends Unit {

for (const [name, decoder] of Object.entries(decoders || {})) {
const key = /** @type {keyof data & string} */ (name)
const value = decoder.decode(data[key])
const value = decoder.read(data[key])
if (value?.error) {
throw Object.assign(
new Error(`Invalid 'nb.${key}' - ${value.message}`),
Expand Down Expand Up @@ -209,7 +210,11 @@ class Or extends Unit {
if (left.error) {
const right = this.right.match(capability)
if (right.error) {
return right.name === 'MalformedCapability' ? right : left
return right.name === 'MalformedCapability'
? //
right
: //
left
} else {
return right
}
Expand Down Expand Up @@ -404,11 +409,11 @@ class Match {
return { matches, unknown, errors }
}
toString() {
const { nb } = this.value
return JSON.stringify({
can: this.descriptor.can,
with: this.value.with,
nb:
Object.keys(this.value.nb || {}).length > 0 ? this.value.nb : undefined,
nb: nb && Object.keys(nb).length > 0 ? nb : undefined,
})
}
}
Expand Down Expand Up @@ -552,7 +557,7 @@ class AndMatch {
proofs.push(delegation)
}

Object.defineProperties(this, { source: { value: proofs } })
Object.defineProperties(this, { proofs: { value: proofs } })
return proofs
}
/**
Expand Down Expand Up @@ -588,7 +593,7 @@ class AndMatch {
*/

const parse = (self, source) => {
const { can, with: withDecoder, nb: decoders } = self.descriptor
const { can, with: withReader, nb: readers } = self.descriptor
const { delegation } = source
const capability = /** @type {API.Capability<A, R, API.InferCaveats<C>>} */ (
source.capability
Expand All @@ -598,19 +603,19 @@ const parse = (self, source) => {
return new UnknownCapability(capability)
}

const uri = withDecoder.decode(capability.with)
const uri = withReader.read(capability.with)
if (uri.error) {
return new MalformedCapability(capability, uri)
}

const nb = /** @type {API.InferCaveats<C>} */ ({})

if (decoders) {
if (readers) {
/** @type {Partial<API.InferCaveats<C>>} */
const caveats = capability.nb || {}
for (const [name, decoder] of entries(decoders)) {
for (const [name, reader] of entries(readers)) {
const key = /** @type {keyof caveats & keyof nb} */ (name)
const result = decoder.decode(caveats[key])
const result = reader.read(caveats[key])
if (result?.error) {
return new MalformedCapability(capability, result)
} else if (result != null) {
Expand Down Expand Up @@ -697,7 +702,9 @@ const selectGroup = (self, capabilities) => {
const matches = combine(data).map(group => new AndMatch(group))

return {
unknown: unknown || [],
unknown:
/* c8 ignore next */
unknown || [],
errors,
matches,
}
Expand All @@ -720,10 +727,11 @@ const derives = (claimed, delegated) => {
}
} else if (delegated.with !== claimed.with) {
return new Failure(
`Resource ${claimed.with} does not contain ${delegated.with}`
`Resource ${claimed.with} is not contained by ${delegated.with}`
)
}

/* c8 ignore next 2 */
const caveats = delegated.nb || {}
const nb = claimed.nb || {}
const kv = entries(caveats)
Expand Down
48 changes: 0 additions & 48 deletions packages/validator/src/decoder/did.js

This file was deleted.

79 changes: 0 additions & 79 deletions packages/validator/src/decoder/link.js

This file was deleted.

Loading

0 comments on commit e2e03ff

Please sign in to comment.