@ucanto/server
Advanced tools
Comparing version 6.1.0 to 7.0.0
@@ -0,7 +1,23 @@ | ||
export * from './api.js' | ||
export * from './server.js' | ||
export { | ||
Failure, | ||
MalformedCapability, | ||
HandlerNotFound, | ||
Link, | ||
URI, | ||
} from './server.js' | ||
export * from '@ucanto/core' | ||
export { invoke } from '@ucanto/core' | ||
// @ts-ignore | ||
export * from './api.js' | ||
export { | ||
invoke, | ||
Invocation, | ||
Receipt, | ||
Delegation, | ||
DID, | ||
Signature, | ||
} from '@ucanto/core' | ||
export { access, claim, Schema } from '@ucanto/validator' | ||
export * from './handler.js' | ||
export * as API from './api.js' |
@@ -1,16 +0,8 @@ | ||
export function provide<A extends API.Ability, R extends API.URI<`${string}:`>, C extends API.Caveats, U extends unknown>(capability: API.CapabilityParser<API.Match<API.ParsedCapability<A, R, C>, API.UnknownMatch>>, handler: (input: API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<U>): API.ServiceMethod<API.Capability<A, R, C>, Exclude<U, { | ||
error: true; | ||
}>, Exclude<U, Exclude<U, { | ||
error: true; | ||
}>>>; | ||
export function provideAdvanced<A extends API.Ability, R extends API.URI<`${string}:`>, C extends API.Caveats, U extends unknown>({ capability, handler, audience }: { | ||
export function provide<A extends API.Ability, R extends API.URI<`${string}:`>, C extends API.Caveats, O extends {}, X extends {}>(capability: API.CapabilityParser<API.Match<API.ParsedCapability<A, R, C>, API.UnknownMatch>>, handler: (input: API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<API.Result<O, X>>): API.ServiceMethod<API.Capability<A, R, C>, O, X>; | ||
export function provideAdvanced<A extends API.Ability, R extends API.URI<`${string}:`>, C extends API.Caveats, O extends {}, X extends {}>({ capability, handler, audience }: { | ||
audience?: API.Reader<`did:${string}:${string}`, any, API.Failure> | undefined; | ||
capability: API.CapabilityParser<API.Match<API.ParsedCapability<A, R, C>, API.UnknownMatch>>; | ||
handler: (input: API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<U>; | ||
}): API.ServiceMethod<API.Capability<A, R, C>, Exclude<U, { | ||
error: true; | ||
}>, Exclude<U, Exclude<U, { | ||
error: true; | ||
}>>>; | ||
handler: (input: API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<API.Result<O, X>>; | ||
}): API.ServiceMethod<API.Capability<A, R, C>, O, X>; | ||
import * as API from "./api.js"; | ||
//# sourceMappingURL=handler.d.ts.map |
@@ -0,7 +1,9 @@ | ||
export * from "./api.js"; | ||
export * from "./server.js"; | ||
export * from "@ucanto/core"; | ||
export * from "./api.js"; | ||
export * from "./handler.js"; | ||
export { invoke } from "@ucanto/core"; | ||
export * as API from "./api.js"; | ||
export { Failure, MalformedCapability, HandlerNotFound, Link, URI } from "./server.js"; | ||
export { invoke, Invocation, Receipt, Delegation, DID, Signature } from "@ucanto/core"; | ||
export { access, claim, Schema } from "@ucanto/validator"; | ||
//# sourceMappingURL=lib.d.ts.map |
export function create<Service extends Record<string, any>>(options: API.Server<Service>): API.ServerView<Service>; | ||
export function handle<T extends Record<string, any>, C extends API.Capability<API.Ability, `${string}:${string}`, any>, I extends API.Transport.Tuple<API.ServiceInvocation<C, T>>>(server: API.ServerView<T>, request: API.HTTPRequest<I>): Promise<API.HTTPResponse<API.InferServiceInvocations<I, T>>>; | ||
export function execute<Service extends Record<string, any>, C extends API.Capability<API.Ability, `${string}:${string}`, any>, I extends API.Transport.Tuple<API.ServiceInvocation<C, Service>>>(invocations: API.InferInvocations<I>, server: API.ServerView<Service>): Promise<API.InferServiceInvocations<I, Service>>; | ||
export function invoke<Service extends Record<string, any>, C extends API.Capability<API.Ability, `${string}:${string}`, any>>(invocation: API.InferInvocation<API.ServiceInvocation<C, Service>>, server: API.ServerView<Service>): Promise<API.InferServiceInvocationReturn<C, Service>>; | ||
export function handle<S extends Record<string, any>, I extends API.Transport.Tuple<API.ServiceInvocation<API.Capability<API.Ability, `${string}:${string}`, any>, S>>>(server: API.ServerView<S>, request: API.HTTPRequest<API.AgentMessage<{ | ||
In: API.InferInvocations<I>; | ||
Out: API.Transport.Tuple<API.Receipt<any, any, API.Invocation<API.Capability<API.Ability, `${string}:${string}`, unknown>>, API.SigAlg>>; | ||
}>>): Promise<API.HTTPResponse<API.AgentMessage<{ | ||
Out: API.InferReceipts<I, S>; | ||
In: API.Transport.Tuple<API.Invocation<API.Capability<API.Ability, `${string}:${string}`, unknown>>>; | ||
}>> | { | ||
status: number; | ||
headers: Record<string, string>; | ||
body: Uint8Array; | ||
}>; | ||
export function execute<S extends Record<string, any>, I extends API.Transport.Tuple<unknown>>(input: API.AgentMessage<{ | ||
In: API.InferInvocations<I>; | ||
Out: API.Transport.Tuple<API.Receipt<any, any, API.Invocation<API.Capability<API.Ability, `${string}:${string}`, unknown>>, API.SigAlg>>; | ||
}>, server: API.ServerView<S>): Promise<API.AgentMessage<{ | ||
Out: API.InferReceipts<I, S>; | ||
In: API.Transport.Tuple<API.Invocation<API.Capability<API.Ability, `${string}:${string}`, unknown>>>; | ||
}>>; | ||
export function invoke<Service extends Record<string, any>, C extends API.Capability<API.Ability, `${string}:${string}`, any>>(invocation: API.Invocation<C>, server: API.ServerView<Service>): Promise<API.Receipt>; | ||
/** | ||
@@ -30,32 +46,46 @@ * @implements {API.HandlerNotFound} | ||
} | ||
import { ok } from "@ucanto/core/result"; | ||
import { fail } from "@ucanto/core/result"; | ||
import * as API from "@ucanto/interface"; | ||
/** | ||
* @template {Record<string, any>} Service | ||
* @implements {API.ServerView<Service>} | ||
* @template {Record<string, any>} S | ||
* @implements {API.ServerView<S>} | ||
*/ | ||
declare class Server<Service extends Record<string, any>> implements API.ServerView<Service> { | ||
declare class Server<S extends Record<string, any>> implements API.ServerView<S> { | ||
/** | ||
* @param {API.Server<Service>} options | ||
* @param {API.Server<S>} options | ||
*/ | ||
constructor({ id, service, encoder, decoder, principal, ...rest }: API.Server<Service>); | ||
constructor({ id, service, codec, principal, ...rest }: API.Server<S>); | ||
context: { | ||
canIssue?: ((capability: API.ParsedCapability<API.Ability, API.URI<`${string}:`>, {}>, issuer: `did:${string}:${string}`) => boolean) | undefined; | ||
resolve?: ((proof: API.UCANLink<API.Capabilities, API.MulticodecCode<number, string>, API.SigAlg>) => API.Await<API.Result<API.Delegation<API.Capabilities>, API.UnavailableProof>>) | undefined; | ||
id: API.Verifier<`did:${string}:${string}`, API.SigAlg>; | ||
id: API.Signer<`did:${string}:${string}`, API.SigAlg>; | ||
principal: API.PrincipalParser; | ||
}; | ||
service: Service; | ||
encoder: API.ResponseEncoder; | ||
decoder: API.RequestDecoder; | ||
service: S; | ||
codec: API.InboundCodec; | ||
catch: (err: API.HandlerExecutionError) => void; | ||
get id(): API.Verifier<`did:${string}:${string}`, API.SigAlg>; | ||
get id(): API.Signer<`did:${string}:${string}`, API.SigAlg>; | ||
/** | ||
* @template {API.Tuple<API.ServiceInvocation<API.Capability, S>>} I | ||
* @param {API.HTTPRequest<API.AgentMessage<{ In: API.InferInvocations<I>, Out: API.Tuple<API.Receipt> }>>} request | ||
* @returns {Promise<API.HTTPResponse<API.AgentMessage<{ Out: API.InferReceipts<I, S>, In: API.Tuple<API.Invocation> }>>>} | ||
*/ | ||
request<I extends API.Transport.Tuple<API.ServiceInvocation<API.Capability<API.Ability, `${string}:${string}`, any>, S>>>(request: API.HTTPRequest<API.AgentMessage<{ | ||
In: API.InferInvocations<I>; | ||
Out: API.Transport.Tuple<API.Receipt<any, any, API.Invocation<API.Capability<API.Ability, `${string}:${string}`, unknown>>, API.SigAlg>>; | ||
}>>): Promise<API.HTTPResponse<API.AgentMessage<{ | ||
Out: API.InferReceipts<I, S>; | ||
In: API.Transport.Tuple<API.Invocation<API.Capability<API.Ability, `${string}:${string}`, unknown>>>; | ||
}>>>; | ||
/** | ||
* @template {API.Capability} C | ||
* @template {API.Tuple<API.ServiceInvocation<C, Service>>} I | ||
* @param {API.HTTPRequest<I>} request | ||
* @returns {API.Await<API.HTTPResponse<API.InferServiceInvocations<I, Service>>>} | ||
* @param {API.ServiceInvocation<C, S>} invocation | ||
* @returns {Promise<API.InferReceipt<C, S>>} | ||
*/ | ||
request<C extends API.Capability<API.Ability, `${string}:${string}`, any>, I extends API.Transport.Tuple<API.ServiceInvocation<C, Service>>>(request: API.HTTPRequest<I>): API.Await<API.HTTPResponse<API.InferServiceInvocations<I, Service>>>; | ||
run<C extends API.Capability<API.Ability, `${string}:${string}`, any>>(invocation: API.ServiceInvocation<C, S>): Promise<API.InferReceipt<C, S>>; | ||
} | ||
import { Receipt } from "@ucanto/core"; | ||
export { ok, fail }; | ||
export { capability, URI, Link, Failure, MalformedCapability } from "@ucanto/validator"; | ||
//# sourceMappingURL=server.d.ts.map |
{ | ||
"name": "@ucanto/server", | ||
"description": "UCAN RPC Server", | ||
"version": "6.1.0", | ||
"version": "7.0.0", | ||
"types": "./dist/src/lib.d.ts", | ||
@@ -23,5 +23,5 @@ "main": "./src/lib.js", | ||
"dependencies": { | ||
"@ucanto/core": "^5.1.0", | ||
"@ucanto/interface": "^6.1.0", | ||
"@ucanto/validator": "^6.1.0" | ||
"@ucanto/core": "^7.0.0", | ||
"@ucanto/interface": "^7.0.0", | ||
"@ucanto/validator": "^7.0.0" | ||
}, | ||
@@ -38,9 +38,8 @@ "devDependencies": { | ||
"mocha": "^10.1.0", | ||
"multiformats": "^11.0.0", | ||
"nyc": "^15.1.0", | ||
"playwright-test": "^8.2.0", | ||
"typescript": "^4.9.5", | ||
"@ucanto/client": "^5.1.0", | ||
"@ucanto/principal": "^5.1.0", | ||
"@ucanto/transport": "^5.1.0" | ||
"@ucanto/client": "^7.0.0", | ||
"@ucanto/principal": "^7.0.0", | ||
"@ucanto/transport": "^7.0.0" | ||
}, | ||
@@ -62,3 +61,3 @@ "exports": { | ||
"test:node": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha test/**/*.spec.js", | ||
"test": "npm run test:node", | ||
"test": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha --bail test/**/*.spec.js", | ||
"coverage": "c8 --reporter=html mocha test/**/*.spec.js && npm_config_yes=true npx st -d coverage -p 8080", | ||
@@ -65,0 +64,0 @@ "check": "tsc --build", |
@@ -13,6 +13,7 @@ import * as API from './api.js' | ||
* @template {API.Caveats} C | ||
* @template {unknown} U | ||
* @template {{}} O | ||
* @template {{}} X | ||
* @param {API.CapabilityParser<API.Match<API.ParsedCapability<A, R, C>>>} capability | ||
* @param {(input:API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<U>} handler | ||
* @returns {API.ServiceMethod<API.Capability<A, R, C>, Exclude<U, {error:true}>, Exclude<U, Exclude<U, {error:true}>>>} | ||
* @param {(input:API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<API.Result<O, X>>} handler | ||
* @returns {API.ServiceMethod<API.Capability<A, R, C>, O, X>} | ||
*/ | ||
@@ -34,8 +35,9 @@ | ||
* @template {API.Caveats} C | ||
* @template {unknown} U | ||
* @template {{}} O | ||
* @template {{}} X | ||
* @param {object} input | ||
* @param {API.Reader<API.DID>} [input.audience] | ||
* @param {API.CapabilityParser<API.Match<API.ParsedCapability<A, R, C>>>} input.capability | ||
* @param {(input:API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<U>} input.handler | ||
* @returns {API.ServiceMethod<API.Capability<A, R, C>, Exclude<U, {error:true}>, Exclude<U, Exclude<U, {error:true}>>>} | ||
* @param {(input:API.ProviderInput<API.ParsedCapability<A, R, C>>) => API.Await<API.Result<O, X>>} input.handler | ||
* @returns {API.ServiceMethod<API.Capability<A, R, C>, O, X>} | ||
*/ | ||
@@ -56,3 +58,3 @@ | ||
if (result.error) { | ||
return new InvalidAudience({ cause: result }) | ||
return { error: new InvalidAudience({ cause: result.error }) } | ||
} | ||
@@ -68,9 +70,7 @@ | ||
} else { | ||
return /** @type {API.Result<Exclude<U, {error:true}>, {error:true} & Exclude<U, Exclude<U, {error:true}>>|API.InvocationError>} */ ( | ||
handler({ | ||
capability: authorization.capability, | ||
invocation, | ||
context: options, | ||
}) | ||
) | ||
return handler({ | ||
capability: authorization.ok.capability, | ||
invocation, | ||
context: options, | ||
}) | ||
} | ||
@@ -96,11 +96,2 @@ } | ||
} | ||
toJSON() { | ||
const { error, name, message, stack } = this | ||
return { | ||
error, | ||
name, | ||
message, | ||
stack, | ||
} | ||
} | ||
} |
@@ -0,7 +1,23 @@ | ||
export * from './api.js' | ||
export * from './server.js' | ||
export { | ||
Failure, | ||
MalformedCapability, | ||
HandlerNotFound, | ||
Link, | ||
URI, | ||
} from './server.js' | ||
export * from '@ucanto/core' | ||
export { invoke } from '@ucanto/core' | ||
// @ts-ignore | ||
export * from './api.js' | ||
export { | ||
invoke, | ||
Invocation, | ||
Receipt, | ||
Delegation, | ||
DID, | ||
Signature, | ||
} from '@ucanto/core' | ||
export { access, claim, Schema } from '@ucanto/validator' | ||
export * from './handler.js' | ||
export * as API from './api.js' |
@@ -10,2 +10,4 @@ import * as API from '@ucanto/interface' | ||
} from '@ucanto/validator' | ||
import { Receipt, ok, fail, Message, Failure } from '@ucanto/core' | ||
export { ok, fail } | ||
@@ -22,22 +24,14 @@ /** | ||
/** | ||
* @template {Record<string, any>} Service | ||
* @implements {API.ServerView<Service>} | ||
* @template {Record<string, any>} S | ||
* @implements {API.ServerView<S>} | ||
*/ | ||
class Server { | ||
/** | ||
* @param {API.Server<Service>} options | ||
* @param {API.Server<S>} options | ||
*/ | ||
constructor({ | ||
id, | ||
service, | ||
encoder, | ||
decoder, | ||
principal = Verifier, | ||
...rest | ||
}) { | ||
constructor({ id, service, codec, principal = Verifier, ...rest }) { | ||
const { catch: fail, ...context } = rest | ||
this.context = { id, principal, ...context } | ||
this.service = service | ||
this.encoder = encoder | ||
this.decoder = decoder | ||
this.codec = codec | ||
this.catch = fail || (() => {}) | ||
@@ -50,45 +44,62 @@ } | ||
/** | ||
* @template {API.Capability} C | ||
* @template {API.Tuple<API.ServiceInvocation<C, Service>>} I | ||
* @param {API.HTTPRequest<I>} request | ||
* @returns {API.Await<API.HTTPResponse<API.InferServiceInvocations<I, Service>>>} | ||
* @template {API.Tuple<API.ServiceInvocation<API.Capability, S>>} I | ||
* @param {API.HTTPRequest<API.AgentMessage<{ In: API.InferInvocations<I>, Out: API.Tuple<API.Receipt> }>>} request | ||
* @returns {Promise<API.HTTPResponse<API.AgentMessage<{ Out: API.InferReceipts<I, S>, In: API.Tuple<API.Invocation> }>>>} | ||
*/ | ||
request(request) { | ||
return handle(/** @type {API.ServerView<Service>} */ (this), request) | ||
return handle(this, request) | ||
} | ||
/** | ||
* @template {API.Capability} C | ||
* @param {API.ServiceInvocation<C, S>} invocation | ||
* @returns {Promise<API.InferReceipt<C, S>>} | ||
*/ | ||
async run(invocation) { | ||
const receipt = /** @type {API.InferReceipt<C, S>} */ ( | ||
await invoke(await invocation.buildIPLDView(), this) | ||
) | ||
return receipt | ||
} | ||
} | ||
/** | ||
* @template {Record<string, any>} T | ||
* @template {API.Capability} C | ||
* @template {API.Tuple<API.ServiceInvocation<C, T>>} I | ||
* @param {API.ServerView<T>} server | ||
* @param {API.HTTPRequest<I>} request | ||
* @returns {Promise<API.HTTPResponse<API.InferServiceInvocations<I, T>>>} | ||
* @template {Record<string, any>} S | ||
* @template {API.Tuple<API.ServiceInvocation<API.Capability, S>>} I | ||
* @param {API.ServerView<S>} server | ||
* @param {API.HTTPRequest<API.AgentMessage<{ In: API.InferInvocations<I>, Out: API.Tuple<API.Receipt> }>>} request | ||
*/ | ||
export const handle = async (server, request) => { | ||
const invocations = await server.decoder.decode(request) | ||
const result = await execute(invocations, server) | ||
return server.encoder.encode(result) | ||
const selection = server.codec.accept(request) | ||
if (selection.error) { | ||
const { status, headers = {}, message } = selection.error | ||
return { | ||
status, | ||
headers, | ||
body: new TextEncoder().encode(message), | ||
} | ||
} else { | ||
const { encoder, decoder } = selection.ok | ||
const message = await decoder.decode(request) | ||
const result = await execute(message, server) | ||
const response = await encoder.encode(result) | ||
return response | ||
} | ||
} | ||
/** | ||
* @template {Record<string, any>} Service | ||
* @template {API.Capability} C | ||
* @template {API.Tuple<API.ServiceInvocation<C, Service>>} I | ||
* @param {API.InferInvocations<I>} invocations | ||
* @param {API.ServerView<Service>} server | ||
* @returns {Promise<API.InferServiceInvocations<I, Service>>} | ||
* @template {Record<string, any>} S | ||
* @template {API.Tuple} I | ||
* @param {API.AgentMessage<{ In: API.InferInvocations<I>, Out: API.Tuple<API.Receipt> }>} input | ||
* @param {API.ServerView<S>} server | ||
* @returns {Promise<API.AgentMessage<{ Out: API.InferReceipts<I, S>, In: API.Tuple<API.Invocation> }>>} | ||
*/ | ||
export const execute = async (invocations, server) => { | ||
const results = [] | ||
const input = | ||
/** @type {API.InferInvocation<API.ServiceInvocation<C, Service>>[]} */ ( | ||
invocations | ||
) | ||
for (const invocation of input) { | ||
results.push(await invoke(invocation, server)) | ||
} | ||
export const execute = async (input, server) => { | ||
const promises = input.invocations.map($ => invoke($, server)) | ||
return /** @type {API.InferServiceInvocations<I, Service>} */ (results) | ||
const receipts = /** @type {API.InferReceipts<I, S>} */ ( | ||
await Promise.all(promises) | ||
) | ||
return Message.build({ receipts }) | ||
} | ||
@@ -99,5 +110,5 @@ | ||
* @template {API.Capability} C | ||
* @param {API.InferInvocation<API.ServiceInvocation<C, Service>>} invocation | ||
* @param {API.Invocation<C>} invocation | ||
* @param {API.ServerView<Service>} server | ||
* @returns {Promise<API.InferServiceInvocationReturn<C, Service>>} | ||
* @returns {Promise<API.Receipt>} | ||
*/ | ||
@@ -107,5 +118,9 @@ export const invoke = async (invocation, server) => { | ||
if (invocation.capabilities.length !== 1) { | ||
return /** @type {API.Result<any, InvocationCapabilityError>} */ ( | ||
new InvocationCapabilityError(invocation.capabilities) | ||
) | ||
return await Receipt.issue({ | ||
issuer: server.id, | ||
ran: invocation, | ||
result: { | ||
error: new InvocationCapabilityError(invocation.capabilities), | ||
}, | ||
}) | ||
} | ||
@@ -119,17 +134,32 @@ | ||
if (handler == null || typeof handler[method] !== 'function') { | ||
return /** @type {API.Result<any, API.HandlerNotFound>} */ ( | ||
new HandlerNotFound(capability) | ||
) | ||
return await Receipt.issue({ | ||
issuer: server.id, | ||
ran: invocation, | ||
result: { | ||
/** @type {API.HandlerNotFound} */ | ||
error: new HandlerNotFound(capability), | ||
}, | ||
}) | ||
} else { | ||
try { | ||
return await handler[method](invocation, server.context) | ||
} catch (error) { | ||
const err = new HandlerExecutionError( | ||
const result = await handler[method](invocation, server.context) | ||
return await Receipt.issue({ | ||
issuer: server.id, | ||
ran: invocation, | ||
result, | ||
}) | ||
} catch (cause) { | ||
/** @type {API.HandlerExecutionError} */ | ||
const error = new HandlerExecutionError( | ||
capability, | ||
/** @type {Error} */ (error) | ||
/** @type {Error} */ (cause) | ||
) | ||
server.catch(err) | ||
server.catch(error) | ||
return /** @type {API.Result<any, API.HandlerExecutionError>} */ (err) | ||
return await Receipt.issue({ | ||
issuer: server.id, | ||
ran: invocation, | ||
result: { error }, | ||
}) | ||
} | ||
@@ -173,5 +203,5 @@ } | ||
class HandlerExecutionError extends Error { | ||
class HandlerExecutionError extends Failure { | ||
/** | ||
* @param {API.ParsedCapability} capability | ||
* @param {API.Capability} capability | ||
* @param {Error} cause | ||
@@ -178,0 +208,0 @@ */ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
22578
15
539
+ Added@ucanto/core@7.1.1(transitive)
+ Added@ucanto/interface@7.1.0(transitive)
+ Added@ucanto/validator@7.0.0(transitive)
- Removed@ucanto/core@5.2.0(transitive)
- Removed@ucanto/interface@6.2.0(transitive)
- Removed@ucanto/validator@6.1.0(transitive)
Updated@ucanto/core@^7.0.0
Updated@ucanto/interface@^7.0.0
Updated@ucanto/validator@^7.0.0