import type { SynclinkTask } from "./task"; export const createEndpoint = Symbol("Synclink.endpoint"); export const releaseProxy = Symbol("Synclink.releaseProxy"); export const proxyMarker = Symbol("Synclink.proxy"); /** * Interface of values that were marked to be proxied with `synclink.proxy()`. * Can also be implemented by classes. */ export interface ProxyMarked { [proxyMarker]: true; } /** * Takes a type and wraps it in a Promise, if it not already is one. * This is to avoid `Promise>`. * * This is the inverse of `Unpromisify`. */ type Promisify = T extends Promise ? T : Promise; /** * Takes a type that may be Promise and unwraps the Promise type. * If `P` is not a Promise, it returns `P`. * * This is the inverse of `Promisify`. */ type Unpromisify

= P extends Promise ? T : P; /** * Takes the raw type of a remote property and returns the type that is visible to the local thread on the proxy. * * Note: This needs to be its own type alias, otherwise it will not distribute over unions. * See https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types */ type RemoteProperty = // If the value is a method, synclink will proxy it automatically. // Objects are only proxied if they are marked to be proxied. // Otherwise, the property is converted to a Promise that resolves the cloned value. T extends Function | ProxyMarked ? Remote : SynclinkTask; /** * Takes the raw type of a property as a remote thread would see it through a proxy (e.g. when passed in as a function * argument) and returns the type that the local thread has to supply. * * This is the inverse of `RemoteProperty`. * * Note: This needs to be its own type alias, otherwise it will not distribute over unions. See * https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types */ type LocalProperty = T extends Function | ProxyMarked ? Local : UnTask; /** * Proxies `T` if it is a `ProxyMarked`, clones it otherwise (as handled by structured cloning and transfer handlers). */ export type ProxyOrClone = T extends ProxyMarked ? Remote : T; /** * Inverse of `ProxyOrClone`. */ export type UnproxyOrClone = T extends RemoteObject ? Local : T; /** * Takes the raw type of a remote object in the other thread and returns the type as it is visible to the local thread * when proxied with `Synclink.proxy()`. * * This does not handle call signatures, which is handled by the more general `Remote` type. * * @template T The raw type of a remote object as seen in the other thread. */ export type RemoteObject = { [P in keyof T]: RemoteProperty }; /** * Takes the type of an object as a remote thread would see it through a proxy (e.g. when passed in as a function * argument) and returns the type that the local thread has to supply. * * This does not handle call signatures, which is handled by the more general `Local` type. * * This is the inverse of `RemoteObject`. * * @template T The type of a proxied object. */ export type LocalObject = { [P in keyof T]: LocalProperty }; /** * Additional special synclink methods available on each proxy returned by `Synclink.wrap()`. */ export interface ProxyMethods { [createEndpoint]: () => Promise; [releaseProxy]: () => SynclinkTask; } type UnTask = T extends SynclinkTask ? S : T; type MaybePromise = Promise | T; /** * Takes the raw type of a remote object, function or class in the other thread and returns the type as it is visible to * the local thread from the proxy return value of `Synclink.wrap()` or `Synclink.proxy()`. */ export type Remote = // Handle properties RemoteObject & // Handle call signature (if present) (T extends (...args: infer TArguments) => infer TReturn ? ( ...args: { [I in keyof TArguments]: UnproxyOrClone } ) => SynclinkTask>> : unknown) & // Handle construct signature (if present) // The return of construct signatures is always proxied (whether marked or not) (T extends { new (...args: infer TArguments): infer TInstance } ? { new ( ...args: { [I in keyof TArguments]: UnproxyOrClone; } ): SynclinkTask>; } : unknown) & // Include additional special synclink methods available on the proxy. ProxyMethods; /** * Takes the raw type of a remote object, function or class as a remote thread would see it through a proxy (e.g. when * passed in as a function argument) and returns the type the local thread has to supply. * * This is the inverse of `Remote`. It takes a `Remote` and returns its original input `T`. */ export type Local = // Omit the special proxy methods (they don't need to be supplied, synclink adds them) Omit, keyof ProxyMethods> & // Handle call signatures (if present) (T extends (...args: infer TArguments) => infer TReturn ? ( ...args: { [I in keyof TArguments]: ProxyOrClone } ) => // The raw function could either be sync or async, but is always proxied automatically MaybePromise>> : unknown) & // Handle construct signature (if present) // The return of construct signatures is always proxied (whether marked or not) (T extends { new (...args: infer TArguments): infer TInstance } ? { new ( ...args: { [I in keyof TArguments]: ProxyOrClone; } ): // The raw constructor could either be sync or async, but is always proxied automatically MaybePromise>>; } : unknown);