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

feat!: switch decoder API to zod like schema API #108

Merged
merged 15 commits into from
Oct 16, 2022
Merged
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