@web3-storage/clock
Advanced tools
Comparing version 0.2.3 to 0.3.0
@@ -9,3 +9,3 @@ /** | ||
*/ | ||
export const clock: import("@ucanto/interface").TheCapabilityParser<import("@ucanto/interface").CapabilityMatch<"clock/*", import("@ucanto/interface").URI<"did:">, any>>; | ||
export const clock: import("@ucanto/interface").TheCapabilityParser<import("@ucanto/interface").CapabilityMatch<"clock/*", import("@ucanto/interface").URI<"did:">, {}>>; | ||
/** | ||
@@ -28,7 +28,7 @@ * Follow advances made by an agent to a clock. | ||
*/ | ||
export const following: import("@ucanto/interface").TheCapabilityParser<import("@ucanto/interface").CapabilityMatch<"clock/following", import("@ucanto/interface").URI<"did:">, any>>; | ||
export const following: import("@ucanto/interface").TheCapabilityParser<import("@ucanto/interface").CapabilityMatch<"clock/following", import("@ucanto/interface").URI<"did:">, {}>>; | ||
/** | ||
* List the CIDs of the events at the head of this clock. | ||
*/ | ||
export const head: import("@ucanto/interface").TheCapabilityParser<import("@ucanto/interface").CapabilityMatch<"clock/head", import("@ucanto/interface").URI<"did:">, any>>; | ||
export const head: import("@ucanto/interface").TheCapabilityParser<import("@ucanto/interface").CapabilityMatch<"clock/head", import("@ucanto/interface").URI<"did:">, {}>>; | ||
/** | ||
@@ -35,0 +35,0 @@ * Advance the clock by adding an event. |
@@ -1,2 +0,3 @@ | ||
import { Signer, Proof, DID, Principal, ConnectionView } from '@ucanto/interface'; | ||
import { Signer, Proof, DID, Principal, ConnectionView, Block } from '@ucanto/interface'; | ||
import { EventView } from '@alanshaw/pail/clock'; | ||
import { Service } from '../service'; | ||
@@ -30,8 +31,16 @@ export interface InvocationConfig { | ||
*/ | ||
issuer: DID; | ||
issuer?: DID; | ||
/** | ||
* Target clock. | ||
*/ | ||
with: DID; | ||
with?: DID; | ||
} | ||
export interface AdvanceOptions<T> extends RequestOptions<T> { | ||
/** | ||
* Event blocks that may help the service to advance the clock. This are | ||
* optional because event blocks _should_ be made available to fetch directly | ||
* from the IPFS network. | ||
*/ | ||
blocks?: Block<EventView<any>>[]; | ||
} | ||
//# sourceMappingURL=api.d.ts.map |
@@ -7,7 +7,7 @@ /** | ||
* @param {import('@alanshaw/pail/clock').EventLink<T>} event | ||
* @param {import('./api').RequestOptions<T>} [options] | ||
* @param {import('./api').AdvanceOptions<T>} [options] | ||
*/ | ||
export function advance<T>({ issuer, with: resource, proofs, audience }: import('./api').InvocationConfig, event: import("@ucanto/client").Link<import("@alanshaw/pail/clock").EventView<T>, number, number, 1>, options?: import("./api.js").RequestOptions<T> | undefined): Promise<import("@ucanto/client").Link<import("@alanshaw/pail/clock").EventView<T>, number, number, 1>[] & { | ||
error?: undefined; | ||
}>; | ||
export function advance<T>({ issuer, with: resource, proofs, audience }: import('./api').InvocationConfig, event: import("@ucanto/client").Link<import("@alanshaw/pail/clock").EventView<T>, number, number, 1>, options?: import("./api.js").AdvanceOptions<T> | undefined): Promise<import("@ucanto/interface").Receipt<{ | ||
head: import("@ucanto/client").Link<import("@alanshaw/pail/clock").EventView<T>, number, number, 1>[]; | ||
}, import("@ucanto/interface").HandlerExecutionError | import("@ucanto/interface").Failure | import("@ucanto/interface").HandlerNotFound | import("@ucanto/client").InvalidAudience | import("@ucanto/client").Unauthorized, import("@ucanto/interface").Invocation<import("@ucanto/client").Capability<import("@ucanto/client").Ability, `${string}:${string}`, unknown>>, import("@ucanto/client").SigAlg>>; | ||
/** | ||
@@ -20,5 +20,5 @@ * Retrieve the clock head. | ||
*/ | ||
export function head<T>({ issuer, with: resource, proofs, audience }: import('./api').InvocationConfig, options?: import("./api.js").RequestOptions<T> | undefined): Promise<import("@ucanto/client").Link<import("@alanshaw/pail/clock").EventView<T>, number, number, 1>[] & { | ||
error?: undefined; | ||
}>; | ||
export function head<T>({ issuer, with: resource, proofs, audience }: import('./api').InvocationConfig, options?: import("./api.js").RequestOptions<T> | undefined): Promise<import("@ucanto/interface").Receipt<{ | ||
head: import("@ucanto/client").Link<import("@alanshaw/pail/clock").EventView<T>, number, number, 1>[]; | ||
}, import("@ucanto/interface").HandlerExecutionError | import("@ucanto/interface").Failure | import("@ucanto/interface").HandlerNotFound | import("@ucanto/client").InvalidAudience | import("@ucanto/client").Unauthorized, import("@ucanto/interface").Invocation<import("@ucanto/client").Capability<import("@ucanto/client").Ability, `${string}:${string}`, unknown>>, import("@ucanto/client").SigAlg>>; | ||
/** | ||
@@ -25,0 +25,0 @@ * @template T |
/** | ||
* @template T | ||
* @param {Server.Verifier} signer | ||
* @param {import('@ucanto/interface').Signer} signer | ||
* @param {import('../service').Service<T>} service | ||
*/ | ||
export function createServer<T>(signer: Server.Verifier, service: import("../service").Service<T>): Server.ServerView<import("../service").Service<T>>; | ||
export function provide<A extends Server.API.Ability, R extends Server.API.URI<`${string}:`>, C extends Server.Caveats, U extends unknown>(capability: Server.CapabilityParser<Server.Match<Server.ParsedCapability<A, R, C>, Server.UnknownMatch>>, handler: (input: Server.ProviderInput<Server.ParsedCapability<A, R, C>>) => Server.Await<U>): Server.ServiceMethod<Server.API.Capability<A, R, C>, Exclude<U, { | ||
error: true; | ||
}>, Exclude<U, Exclude<U, { | ||
error: true; | ||
}>>>; | ||
export function createServer<T>(signer: import('@ucanto/interface').Signer, service: import("../service").Service<T>): Server.ServerView<import("../service").Service<T>>; | ||
export function provide<A extends Server.API.Ability, R extends Server.API.URI<`${string}:`>, C extends Server.Caveats, O extends {}, X extends Server.API.Failure, Result extends Server.Result<O, X>>(capability: Server.CapabilityParser<Server.Match<Server.ParsedCapability<A, R, C>, Server.UnknownMatch>>, handler: (input: Server.ProviderInput<Server.ParsedCapability<A, R, C>>) => Server.Await<Result>): Server.ServiceMethod<Server.API.Capability<A, R, C>, O & Result["ok"], X & Result["error"]>; | ||
import * as Server from '@ucanto/server'; | ||
import { Verifier } from '@ucanto/principal'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -12,5 +12,9 @@ import { Failure, ServiceMethod, DID } from '@ucanto/interface'; | ||
export interface ClockService<T> { | ||
advance: ServiceMethod<ClockAdvance, EventLink<T>[], Failure>; | ||
head: ServiceMethod<ClockHead, EventLink<T>[], Failure>; | ||
advance: ServiceMethod<ClockAdvance, { | ||
head: EventLink<T>[]; | ||
}, Failure>; | ||
head: ServiceMethod<ClockHead, { | ||
head: EventLink<T>[]; | ||
}, Failure>; | ||
} | ||
//# sourceMappingURL=service.d.ts.map |
{ | ||
"name": "@web3-storage/clock", | ||
"version": "0.2.3", | ||
"version": "0.3.0", | ||
"description": "UCAN based Merkle Clock as a service.", | ||
@@ -67,10 +67,12 @@ "type": "module", | ||
"@ipld/dag-cbor": "^9.0.0", | ||
"@ucanto/client": "^5.1.0", | ||
"@ucanto/interface": "^6.2.0", | ||
"@ucanto/principal": "^5.1.0", | ||
"@ucanto/server": "^6.1.0", | ||
"@ucanto/transport": "^5.1.1", | ||
"@ucanto/validator": "^6.1.0", | ||
"@ipld/dag-ucan": "^3.3.2", | ||
"@ucanto/client": "^7.0.1", | ||
"@ucanto/interface": "^7.1.0", | ||
"@ucanto/principal": "^7.0.0", | ||
"@ucanto/server": "^7.0.2", | ||
"@ucanto/transport": "^7.0.3", | ||
"@ucanto/validator": "^7.0.0", | ||
"hashlru": "^2.3.0", | ||
"multiformats": "^11.0.2" | ||
"multiformats": "^11.0.2", | ||
"p-retry": "^5.1.2" | ||
}, | ||
@@ -77,0 +79,0 @@ "devDependencies": { |
@@ -1,4 +0,9 @@ | ||
# w3clock | ||
<p> | ||
<div align="center"> | ||
<h1> | ||
<img src="https://bafybeiaqvsnz2lv4nhjx3hk6xfwko4virrlqze5ipg7irtfitrawwshkvm.ipfs.w3s.link/w3clock-circle-logo.png" width="160" /><br/> | ||
w3clock | ||
</h1> | ||
<p>UCAN based merkle clock implementation.</p> | ||
</div> | ||
<p align="center"> | ||
<a href="https://github.com/web3-storage/w3clock/actions/workflows/test.yml"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/web3-storage/w3clock/test.yml?branch=main&style=for-the-badge" /></a> | ||
@@ -10,5 +15,2 @@ <a href="https://standardjs.com"><img alt="StandardJS Code Style" src="https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=for-the-badge" /></a> | ||
UCAN based merkle clock implementation. | ||
## Background | ||
@@ -39,1 +41,5 @@ | ||
TBD --> | ||
## License | ||
Dual-licensed under [MIT + Apache 2.0](LICENSE.md) |
@@ -1,2 +0,2 @@ | ||
import { capability, URI, Link, Failure, Schema } from '@ucanto/validator' | ||
import { capability, URI, Link, Schema } from '@ucanto/validator' | ||
@@ -14,4 +14,3 @@ /** | ||
can: 'clock/*', | ||
with: URI.match({ protocol: 'did:' }), | ||
derives: equalWith | ||
with: URI.match({ protocol: 'did:' }) | ||
}) | ||
@@ -28,10 +27,3 @@ | ||
with: URI.match({ protocol: 'did:' }).optional() | ||
}), | ||
derives: (claim, proof) => { | ||
let result = equalCaveat('with', claim, proof) | ||
if (result !== true) return result | ||
result = equalCaveat('iss', claim, proof) | ||
if (result !== true) return result | ||
return equalWith(claim, proof) | ||
} | ||
}) | ||
}) | ||
@@ -48,10 +40,3 @@ | ||
with: URI.match({ protocol: 'did:' }).optional() | ||
}), | ||
derives: (claim, proof) => { | ||
let result = equalCaveat('with', claim, proof) | ||
if (result !== true) return result | ||
result = equalCaveat('iss', claim, proof) | ||
if (result !== true) return result | ||
return equalWith(claim, proof) | ||
} | ||
}) | ||
}) | ||
@@ -64,4 +49,3 @@ | ||
can: 'clock/following', | ||
with: URI.match({ protocol: 'did:' }), | ||
derives: equalWith | ||
with: URI.match({ protocol: 'did:' }) | ||
}) | ||
@@ -74,4 +58,3 @@ | ||
can: 'clock/head', | ||
with: URI.match({ protocol: 'did:' }), | ||
derives: equalWith | ||
with: URI.match({ protocol: 'did:' }) | ||
}) | ||
@@ -87,36 +70,3 @@ | ||
event: Link.match({ version: 1 }) | ||
}), | ||
derives: equalWith | ||
}) | ||
}) | ||
/** | ||
* Checks that `nb.<prop>` on claimed capability is the same as `nb.<prop>` | ||
* in delegated capability. | ||
* | ||
* @param {string} prop | ||
* @param {import('@ucanto/interface').ParsedCapability} claim | ||
* @param {import('@ucanto/interface').ParsedCapability} proof | ||
*/ | ||
function equalCaveat (prop, claim, proof) { | ||
if (proof.nb[prop] !== claim.nb[prop]) { | ||
if (proof.nb[prop] == null && claim.nb[prop] != null) { | ||
return new Failure(`missing nb.${prop} on delegated capability: ${claim.nb[prop]}`) | ||
} else if (proof.nb[prop] != null && claim.nb[prop] == null) { | ||
return new Failure(`missing nb.${prop} on claimed capability: ${proof.nb[prop]}`) | ||
} else { | ||
return new Failure(`mismatched nb.${prop}: ${claim.nb[prop]} != ${proof.nb[prop]}`) | ||
} | ||
} | ||
return true | ||
} | ||
/** | ||
* Checks that `with` on claimed capability is the same as `with` | ||
* in delegated capability. Note this will ignore `can` field. | ||
* | ||
* @param {import('@ucanto/interface').ParsedCapability} claim | ||
* @param {import('@ucanto/interface').ParsedCapability} proof | ||
*/ | ||
function equalWith (claim, proof) { | ||
return claim.with === proof.with || new Failure(`Can not derive ${claim.can} with ${claim.with} from ${proof.with}`) | ||
} |
@@ -1,2 +0,3 @@ | ||
import { Signer, Proof, DID, Principal, ConnectionView } from '@ucanto/interface' | ||
import { Signer, Proof, DID, Principal, ConnectionView, Block } from '@ucanto/interface' | ||
import { EventView } from '@alanshaw/pail/clock' | ||
import { Service } from '../service' | ||
@@ -33,7 +34,16 @@ | ||
*/ | ||
issuer: DID | ||
issuer?: DID | ||
/** | ||
* Target clock. | ||
*/ | ||
with: DID | ||
with?: DID | ||
} | ||
export interface AdvanceOptions<T> extends RequestOptions<T> { | ||
/** | ||
* Event blocks that may help the service to advance the clock. This are | ||
* optional because event blocks _should_ be made available to fetch directly | ||
* from the IPFS network. | ||
*/ | ||
blocks?: Block<EventView<any>>[] | ||
} |
import { connect as clientConnect } from '@ucanto/client' | ||
import { CAR, CBOR, HTTP } from '@ucanto/transport' | ||
import { CAR, HTTP } from '@ucanto/transport' | ||
import * as DID from '@ipld/dag-ucan/did' | ||
@@ -18,7 +18,8 @@ import * as ClockCaps from '../capabilities.js' | ||
* @param {import('@alanshaw/pail/clock').EventLink<T>} event | ||
* @param {import('./api').RequestOptions<T>} [options] | ||
* @param {import('./api').AdvanceOptions<T>} [options] | ||
*/ | ||
export async function advance ({ issuer, with: resource, proofs, audience }, event, options) { | ||
const conn = options?.connection ?? connect() | ||
const result = await ClockCaps.advance | ||
const facts = options?.blocks ? [Object.fromEntries(options.blocks.map(b => [b.cid.toString(), b.cid]))] : [] | ||
const invocation = ClockCaps.advance | ||
.invoke({ | ||
@@ -29,11 +30,11 @@ issuer, | ||
nb: { event }, | ||
proofs | ||
proofs, | ||
facts | ||
}) | ||
.execute(conn) | ||
if (result.error) { | ||
throw new Error(`failed ${ClockCaps.advance.can} invocation`, { cause: result }) | ||
for (const block of options?.blocks ?? []) { | ||
invocation.attach(block) | ||
} | ||
return result | ||
return invocation.execute(conn) | ||
} | ||
@@ -50,3 +51,3 @@ | ||
const conn = options?.connection ?? connect() | ||
const result = await ClockCaps.head | ||
return await ClockCaps.head | ||
.invoke({ | ||
@@ -56,12 +57,5 @@ issuer, | ||
with: resource, | ||
nb: {}, | ||
proofs | ||
}) | ||
.execute(conn) | ||
if (result.error) { | ||
throw new Error(`failed ${ClockCaps.head.can} invocation`, { cause: result }) | ||
} | ||
return result | ||
} | ||
@@ -107,11 +101,8 @@ | ||
export function connect (options) { | ||
const url = options?.serviceURL ?? new URL(SERVICE_URL) | ||
return clientConnect({ | ||
id: options?.servicePrincipal ?? DID.parse(SERVICE_PRINCIPAL), | ||
encoder: CAR, | ||
decoder: CBOR, | ||
channel: HTTP.open({ | ||
url: options?.serviceURL ?? new URL(SERVICE_URL), | ||
method: 'POST' | ||
}) | ||
codec: CAR.outbound, | ||
channel: HTTP.open({ url, method: 'POST' }) | ||
}) | ||
} |
import { Verifier } from '@ucanto/principal' | ||
import * as Server from '@ucanto/server' | ||
import * as CAR from '@ucanto/transport/car' | ||
import * as CBOR from '@ucanto/transport/cbor' | ||
import { access, Schema, Failure } from '@ucanto/validator' | ||
@@ -9,3 +8,3 @@ | ||
* @template T | ||
* @param {Server.Verifier} signer | ||
* @param {import('@ucanto/interface').Signer} signer | ||
* @param {import('../service').Service<T>} service | ||
@@ -16,4 +15,3 @@ */ | ||
id: signer, | ||
encoder: CBOR, | ||
decoder: CAR, | ||
codec: CAR.inbound, | ||
service, | ||
@@ -35,6 +33,8 @@ catch: err => console.error(err), | ||
* @template {import('@ucanto/interface').Caveats} C | ||
* @template {unknown} U | ||
* @template {{}} O | ||
* @template {import('@ucanto/interface').Failure} X | ||
* @template {import('@ucanto/interface').Result<O, X>} Result | ||
* @param {import('@ucanto/interface').CapabilityParser<import('@ucanto/interface').Match<import('@ucanto/interface').ParsedCapability<A, R, C>>>} capability | ||
* @param {(input:Server.ProviderInput<import('@ucanto/interface').ParsedCapability<A, R, C>>) => import('@ucanto/interface').Await<U>} handler | ||
* @returns {import('@ucanto/interface').ServiceMethod<import('@ucanto/interface').Capability<A, R, C>, Exclude<U, {error:true}>, Exclude<U, Exclude<U, {error:true}>>>} | ||
* @param {(input:import('@ucanto/server').ProviderInput<import('@ucanto/interface').ParsedCapability<A, R, C>>) => import('@ucanto/interface').Await<Result>} handler | ||
* @returns {import('@ucanto/interface').ServiceMethod<import('@ucanto/interface').Capability<A, R, C>, O & Result['ok'], X & Result['error']>} | ||
*/ | ||
@@ -47,6 +47,9 @@ export const provide = (capability, handler) => | ||
async (invocation, options) => { | ||
// If audience schema is not provided we expect the audience to match | ||
// the server id. Users could pass `schema.string()` if they want to accept | ||
// any audience. | ||
const audienceSchema = Schema.literal(options.id.did()) | ||
const result = audienceSchema.read(invocation.audience.did()) | ||
if (result.error) { | ||
return new InvalidAudience({ cause: result }) | ||
return { error: new InvalidAudience({ cause: result.error }) } | ||
} | ||
@@ -57,9 +60,7 @@ | ||
if (authorization.error) continue | ||
return /** @type {import('@ucanto/interface').Result<Exclude<U, {error:true}>, {error:true} & Exclude<U, Exclude<U, {error:true}>>|import('@ucanto/interface').InvocationError>} */ ( | ||
handler({ | ||
capability: authorization.capability, | ||
invocation, | ||
context: options | ||
}) | ||
) | ||
return handler({ | ||
capability: authorization.ok.capability, | ||
invocation, | ||
context: options | ||
}) | ||
} | ||
@@ -74,11 +75,8 @@ | ||
return authorization | ||
} else { | ||
return /** @type {import('@ucanto/interface').Result<Exclude<U, {error:true}>, {error:true} & Exclude<U, Exclude<U, {error:true}>>|import('@ucanto/interface').InvocationError>} */ ( | ||
handler({ | ||
capability: authorization.capability, | ||
invocation, | ||
context: options | ||
}) | ||
) | ||
} | ||
return handler({ | ||
capability: authorization.ok.capability, | ||
invocation, | ||
context: options | ||
}) | ||
} | ||
@@ -101,7 +99,2 @@ | ||
} | ||
toJSON () { | ||
const { error, name, message, stack } = this | ||
return { error, name, message, stack } | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
37161
44
12
436
+ Added@ipld/dag-ucan@^3.3.2
+ Addedp-retry@^5.1.2
+ Added@types/retry@0.12.1(transitive)
+ Added@ucanto/client@7.0.1(transitive)
+ Added@ucanto/core@7.1.1(transitive)
+ Added@ucanto/interface@7.1.0(transitive)
+ Added@ucanto/principal@7.0.0(transitive)
+ Added@ucanto/server@7.0.2(transitive)
+ Added@ucanto/transport@7.0.3(transitive)
+ Added@ucanto/validator@7.0.0(transitive)
+ Addedp-retry@5.1.2(transitive)
+ Addedretry@0.13.1(transitive)
- Removed@ucanto/client@5.1.0(transitive)
- Removed@ucanto/core@5.2.0(transitive)
- Removed@ucanto/interface@6.2.0(transitive)
- Removed@ucanto/principal@5.1.0(transitive)
- Removed@ucanto/server@6.1.0(transitive)
- Removed@ucanto/transport@5.1.1(transitive)
- Removed@ucanto/validator@6.1.0(transitive)
Updated@ucanto/client@^7.0.1
Updated@ucanto/interface@^7.1.0
Updated@ucanto/principal@^7.0.0
Updated@ucanto/server@^7.0.2
Updated@ucanto/transport@^7.0.3
Updated@ucanto/validator@^7.0.0