diff --git a/.changeset/dirty-bikes-glow.md b/.changeset/dirty-bikes-glow.md new file mode 100644 index 0000000..10c6e14 --- /dev/null +++ b/.changeset/dirty-bikes-glow.md @@ -0,0 +1,5 @@ +--- +"capnweb": minor +--- + +The package now exports the type `RpcCompatible` (previously called `Serializable`, but not exported), which is needed when writing generic functions on `RpcStub` / `RpcPromise`. diff --git a/src/index.ts b/src/index.ts index 6adb15d..1ff376e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,7 +5,7 @@ import { RpcTarget as RpcTargetImpl, RpcStub as RpcStubImpl, RpcPromise as RpcPromiseImpl } from "./core.js"; import { serialize, deserialize } from "./serialize.js"; import { RpcTransport, RpcSession as RpcSessionImpl, RpcSessionOptions } from "./rpc.js"; -import { RpcTargetBranded, Serializable, Stub, Stubify, __RPC_TARGET_BRAND } from "./types.js"; +import { RpcTargetBranded, RpcCompatible, Stub, Stubify, __RPC_TARGET_BRAND } from "./types.js"; import { newWebSocketRpcSession as newWebSocketRpcSessionImpl, newWorkersWebSocketRpcResponse } from "./websocket.js"; import { newHttpBatchRpcSession as newHttpBatchRpcSessionImpl, @@ -18,7 +18,7 @@ forceInitMap(); // Re-export public API types. export { serialize, deserialize, newWorkersWebSocketRpcResponse, newHttpBatchRpcResponse, nodeHttpBatchRpcResponse }; -export type { RpcTransport, RpcSessionOptions }; +export type { RpcTransport, RpcSessionOptions, RpcCompatible }; // Hack the type system to make RpcStub's types work nicely! /** @@ -31,9 +31,9 @@ export type { RpcTransport, RpcSessionOptions }; * such method exists on the remote object, an exception is thrown back. But the client does not * actually know, until that point, what methods exist. */ -export type RpcStub> = Stub; +export type RpcStub> = Stub; export const RpcStub: { - new >(value: T): RpcStub; + new >(value: T): RpcStub; } = RpcStubImpl; /** @@ -54,7 +54,7 @@ export const RpcStub: { * if you only intend to use the promise for pipelining and you never await it, then there's no * need to transmit the resolution! */ -export type RpcPromise> = Stub & Promise>; +export type RpcPromise> = Stub & Promise>; export const RpcPromise: { // Note: Cannot construct directly! } = RpcPromiseImpl; @@ -64,7 +64,7 @@ export const RpcPromise: { * * Most people won't use this. You only need it if you've implemented your own `RpcTransport`. */ -export interface RpcSession = undefined> { +export interface RpcSession = undefined> { getRemoteMain(): RpcStub; getStats(): {imports: number, exports: number}; @@ -73,7 +73,7 @@ export interface RpcSession = undefined> { drain(): Promise; } export const RpcSession: { - new = undefined>( + new = undefined>( transport: RpcTransport, localMain?: any, options?: RpcSessionOptions): RpcSession; } = RpcSessionImpl; @@ -106,7 +106,7 @@ interface Empty {} * @param localMain The main RPC interface to expose to the peer. Returns a stub for the main * interface exposed from the peer. */ -export let newWebSocketRpcSession: = Empty> +export let newWebSocketRpcSession: = Empty> (webSocket: WebSocket | string, localMain?: any, options?: RpcSessionOptions) => RpcStub = newWebSocketRpcSessionImpl; @@ -117,7 +117,7 @@ export let newWebSocketRpcSession: = Empty> * value is an RpcStub. You can customize anything about the request except for the method * (it will always be set to POST) and the body (which the RPC system will fill in). */ -export let newHttpBatchRpcSession:> +export let newHttpBatchRpcSession:> (urlOrRequest: string | Request, options?: RpcSessionOptions) => RpcStub = newHttpBatchRpcSessionImpl; @@ -126,7 +126,7 @@ export let newHttpBatchRpcSession:> * between an iframe and its parent frame in a browser context. Each side should call this function * on its own end of the MessageChannel. */ -export let newMessagePortRpcSession: = Empty> +export let newMessagePortRpcSession: = Empty> (port: MessagePort, localMain?: any, options?: RpcSessionOptions) => RpcStub = newMessagePortRpcSessionImpl; diff --git a/src/types.d.ts b/src/types.d.ts index 250d04e..75117cb 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -21,21 +21,21 @@ export type Stubable = RpcTargetBranded | ((...args: any[]) => any); // The reason for using a generic type here is to build a serializable subset of structured // cloneable composite types. This allows types defined with the "interface" keyword to pass the // serializable check as well. Otherwise, only types defined with the "type" keyword would pass. -export type Serializable = +export type RpcCompatible = // Structured cloneables | BaseType // Structured cloneable composites | Map< - T extends Map ? Serializable : never, - T extends Map ? Serializable : never + T extends Map ? RpcCompatible : never, + T extends Map ? RpcCompatible : never > - | Set ? Serializable : never> - | Array ? Serializable : never> - | ReadonlyArray ? Serializable : never> + | Set ? RpcCompatible : never> + | Array ? RpcCompatible : never> + | ReadonlyArray ? RpcCompatible : never> | { - [K in keyof T]: K extends number | string ? Serializable : never; + [K in keyof T]: K extends number | string ? RpcCompatible : never; } - | Promise ? Serializable : never> + | Promise ? RpcCompatible : never> // Special types | Stub // Serialized as stubs, see `Stubify` @@ -43,12 +43,12 @@ export type Serializable = // Base type for all RPC stubs, including common memory management methods. // `T` is used as a marker type for unwrapping `Stub`s later. -interface StubBase> extends Disposable { +interface StubBase> extends Disposable { [__RPC_STUB_BRAND]: T; dup(): this; onRpcBroken(callback: (error: any) => void): void; } -export type Stub> = +export type Stub> = T extends object ? Provider & StubBase : StubBase; type TypedArray = @@ -125,7 +125,7 @@ type MaybeDisposable = T extends object ? Disposable : unknown; // Type for method return or property on an RPC interface. // - Stubable types are replaced by stubs. -// - Serializable types are passed by value, with stubable types replaced by stubs +// - RpcCompatible types are passed by value, with stubable types replaced by stubs // and a top-level `Disposer`. // Everything else can't be passed over RPC. // Technically, we use custom thenables here, but they quack like `Promise`s. @@ -133,7 +133,7 @@ type MaybeDisposable = T extends object ? Disposable : unknown; // prettier-ignore type Result = R extends Stubable ? Promise> & Provider & StubBase - : R extends Serializable ? Promise & MaybeDisposable> & Provider & StubBase + : R extends RpcCompatible ? Promise & MaybeDisposable> & Provider & StubBase : never; // Type for method or property on an RPC interface.