import { Observable } from 'rxjs'; import { RPCChannel } from './channel'; import { AnyConstructor, Constructor } from './internal'; import { Proxied, RemoteSubscription } from './proxied'; import { RemoteRef } from './remote-ref'; import { Request } from './request'; import { RPCLogger } from './logger'; export interface InFlightRequest { /** * It is important that we hold the request, because we must not garbage collect any objects referenced by * the request in the mean time. Normally this isn't possible because there's a hard reference within our * localObjectMap, but if a proxy for this object on the remote side is garbage collected in the mean time, * we may receive a finalizeProxy() request which will cause us to remove it. Holding the request will ensure * that it's not possible for the included remotables to be garbage collected as long as the request is in flight. */ request: Request; returnValue?: any; error?: any; responseHandler: (response: any) => void; } export type ServiceFactory = (session: RPCSession) => T; export interface IntrospectedEvent { name: string; simpleType?: SimpleIntrospectedType; description?: string; } export interface DiscoveredService { name: string; discoverable: boolean; introspectable: boolean; description: string; } export interface IntrospectedMethod { name: string; parameters?: IntrospectedParameter[]; description?: string; simpleReturnType?: SimpleIntrospectedType; } export type SimpleIntrospectedType = 'string' | 'number' | 'bigint' | 'boolean' | 'object' | 'array' | 'void' | 'undefined' | 'null' | 'unknown'; export interface IntrospectedParameter { name?: string; simpleType?: SimpleIntrospectedType; description?: string; } export interface IntrospectedService extends DiscoveredService { methods: IntrospectedMethod[]; events: IntrospectedEvent[]; } /** * Handles message passing, dispatch, resource management and other concerns for Conduit RPC sessions. Creating a * Session with a given communication channel will enable full remote procedure call functionality on that channel * without any further machination required. */ export declare class RPCSession { readonly channel: RPCChannel; constructor(channel: RPCChannel); /** * Whether discovery is allowed on this session. Set to false to globally disable discovery. Note that each * service can also opt out of discovery by using the `@Discovery(false)` decorator. */ enableDiscovery: boolean; /** * Whether introspection is allowed on this session. Set to false to globally disable introspection. Note that each * service can also opt out of introspection by using the `@Introspectable(false)` decorator. */ enableIntrospection: boolean; /** * When safe exceptions mode is enabled, Conduit will only allow exception information to be sent to the client if * the exception was thrown via the raise() function provided by the @/conduit package. Other exceptions will get * turned into RPCInternalError. */ safeExceptionsMode: boolean; /** * When true, stack traces are removed from errors before sending them over the wire. */ maskStackTraces: boolean; /** * When true, the client stack trace is added to the end of deserialized errors before they are thrown. */ addCallerStackTraces: boolean; /** * Cause the `fatalErrors` observable to emit the specified error. * @param error */ protected emitFatalError(error: Error): void; private _fatalErrors; /** * Receive notifications of fatal errors which cause the session to be ended. */ readonly fatalErrors: Observable; /** * Responsible for logging messages out. Default implementation is RPCConsoleLogger, which just uses console.* */ logger: RPCLogger; /** * Used by lock() and call() to allow delaying requests until some operation is complete. */ private waitChain; /** * Delay further requests on this session until the promise returned by the given function returns. * The callback will not execute until previous locks have been completed. * - When Zone.js is available, RPC calls made within the execution context of the callback will be automatically * *not* delayed by this lock or any others. * - If Zone.js is not available, it is important that you use ignoreLocks() to perform RPC calls when done from an * async completion handler. You do not need to use ignoreLocks() if your callback is synchronous. * * Returns a promise which resolves after all previous locks (and the one created with the given callback) * have been completed */ lock(callback: () => T): Promise; private _ignoreLocksSync; /** * Ignore the outstanding locks during the (synchronous) execution of the given callback. IMPORTANT: This property * does not extend to asynchronous operations performed by this function. If you need that, you need to load Zone.js * and use ignoreLocksAsync(). * @param callback */ ignoreLocks(callback: () => T): T; /** * Ignore the outstanding locks during the (asynchronous) execution of the given callback. This function requires * Zone.js, if you do not have Zone.js loaded, you must instead use ignoreLocks() at the synchronous moment that you * start an RPC call. * * @param callback */ ignoreLocksAsync(callback: () => T): T; /** * Connect via WebSocket to the given URL and create a new RPCSession using * the socket as the underlying channel. * @param url */ static connect(url: string): Promise; /** * NOTE: The Omit is here to avoid an infinite type recursion-- even though Proxied filters out all * non-async-function properties, it still causes TS to recur. Since we don't need the remote, and the remote * isn't available on the proxy anyway, we can work around the issue by omitting the recursion source. */ private _remote; /** * Retrieve the remote RPCSession for performing direct calls to it over Conduit. */ get remote(): import("./proxied").MethodsOf> & import("./proxied").EventsOf> & { metadata: Record; }; /** * Retrieve a proxy for a remote service according to the given service identity. * @param serviceIdentity A class which is annotated with `@conduit.Name()` * @throws when the remote cannot provide the given service */ getRemoteService(serviceClass: AnyConstructor): Promise>; /** * Retrieve a proxy for a remote service according to the given service identity * @param serviceIdentity The name of the service to retrieve. * @throws when the remote cannot provide the given service */ getRemoteService(serviceIdentity: string): Promise>; private rawSend; private encodeMessage; private decodeMessage; private _requestMap; tag: string; /** * Metadata to share with the remote side. This information is sent along whenever a new request occurs. Access * metadata sent by the remote using `remote.metadata` */ metadata: Record; call(receiver: any, method: string, parameters: any[], metadata?: Record): Promise; private errorTypes; private registerBuiltinErrors; /** * Registers a builtin error class. Usually this is not required, as Conduit registers all the standard builtin * types, but if your Javascript engine supports other nonstandard types, or if there are new types Conduit doesn't * handle, you can use this to get them registered. * * This is a convenience method that does the right thing (TM) compared to the options available on * registerErrorType(). In particular it ensures that the resulting error instances have the correct inspection * behavior in Node.js. * * @param type */ registerBuiltinErrorType(type: Constructor): void; /** * Register an error type so that errors coming over the wire can be reified into the types you are expecting. * Note that builtin errors (such as TypeError, ReferenceError etc) are already registered for you. * @param type The class constructor. May optionally support a serialize() method for constructing instances * @param factory A factory function for creating instances of this class. If unspecified, the static serialize() method * is used. If no serialize() method is available, the constructor itself is used, passing the message as * the only parameter. After construction, the rest of the properties of the raw error object are assigned * to the resulting instance. */ registerErrorType(type: Constructor & { deserialize?: (error: any) => T; }, factory?: (error: any) => T): void; /** * Prepare an error for being thrown after being received over the wire. * @param error * @returns */ protected deserializeError(error: { $constructorName: string; name: string; message: string; stack: string; }): any; /** * Prepare an error for going over the wire. Doing this properly is complicated. * @param error * @returns */ protected serializeError(error: any): any; protected performCall(request: Request): Promise; /** * Retrieve the RPCSession that is being served by the current remote method call. * This is only available when Zone.js is loaded. * @returns */ static current(): RPCSession; static currentRequest(): any; private onReceiveMessage; /** * Returns true if there are no outstanding requests or remotely held references. */ get idle(): boolean; /** * The number of in-flight requests */ get pendingRequestCount(): number; /** * The number of remotely held references */ get remoteReferenceCount(): number; private _becameIdle; private _becameIdle$; /** * Fired when the session has become idle (no pending requests or remote references). */ get becameIdle(): Observable; /** * Called when a request is finished processing. * @param request */ onRequestCompleted(request: InFlightRequest): void; /** * Close the related channel, if it supports such an operation. */ close(): void; private serviceRegistry; /** * Discover the services available on the remote side. * @returns */ discoverServices(): Promise; /** * Get the list of services that are discoverable on the local side. * @returns */ getDiscoverableServices(): Promise; /** * Introspect the given remote service, if possible. * @param name The name of the service * @returns */ introspectService(klass: Function): Promise; introspectService(name: string): Promise; /** * Return introspection information for the given local service. * @throws when the given service does not exist or is not introspectable. * @param name The name of the service * @returns */ getServiceIntrospection(name: string): Promise; /** * This map tracks individual objects which we've exported via RPC via object ID. */ private localObjectRegistry; /** * This map tracks individual *references* sent over the wire. Each time an object is sent over the wire, * a new hard reference is created for it on the sender side. Those references must be cleaned up by the remote side * using finalizeProxy. Think of each entry in this array as a distinct RPCProxy created on the remote side. * The keys here are `.`. */ private remoteRefRegistry; /** * Tracks the known RPCProxy objects allocated on this side of the connection for objects that exist on the remote * side. */ private proxyRegistry; /** * Used to track the lifetimes of remote object proxies for the purpose of releasing the corresponding remote object * (once all references have been finalized). */ private proxyFinalizer; /** * Determine how many local references are held to the remote object identified by `id`. * @param id * @returns */ countReferencesForObject(id: string): number; /** * How long to wait after an RPCProxy is finalized before notifying the other side * about it. If a new RPCProxy is created before the finalization delay timeout, then * the remote finalization will be cancelled. This helps to avoid a situation where the * old local proxy can go out of scope and be collected at the same time that a new request * is coming in which will revive it (via a new proxy). */ finalizationDelay: number; /** * Register the given proxy in the proxy and finalizer registries. This is required to ensure * we can identify the proxy by ID later, and that we are properly tracking when the finalization * of the given object occurs, so we can notify the remote side. * @param object */ private registerProxy; /** * Register a local object with the given ID (or one will be generated). This is required before * sending references to the local object to the remote side. * @param object * @param id */ private registerLocalObject; /** * Returns a RemoteRef for the given object. The object can be a Remotable object * or an RPCProxy object (representing an object remoted from the other side). * - If the object is local and remotable, a new reference will be created for the object, * which MUST be freed later (usually by the remote side). A new reference is *always* * created in this case. * - If the object is a remote proxy, we make sure we have registered the proxy, and return * an unallocated reference to the proxy. This is useful for the remote side to identify * and reassociate the objects it has sent us, when we send that object back to them. * @param object * @returns */ remoteRef(object: any): RemoteRef; /** * Retrieve the local object for the given RemoteRef. The RemoteRef may represent * a Remotable local object or an RPCProxy object for an object remoted from the other side. * @param ref * @returns */ getObjectByRemoteRef(ref: RemoteRef): any; debugLoggingEnabled: boolean; private debugLog; private debugLogObject; /** * Resolve the given ID to a local object, if a local object with that ID exists. * @param id * @returns The object if it was registered and not yet garbage collected. */ getLocalObjectById(id: string): any; /** * Register a new service on this session. * * When the remote side requests an instance of the service, the factory is called to create the instance. The * factory is passed the Session which is trying to create it, so that an instance of the service can be localized * per session, globally, or per call. * * @param klass The class implementing the service * @param factory A factory function which can create an instance of the given service. If no factory is provided, * a default factory is created which constructs the class with default parameters (this means each * session will have a separate instance of the service class). */ registerService(klass: Constructor): any; registerService(klass: AnyConstructor, factory: ServiceFactory): any; /** * Obtain an instance of the given service by it's identity. If the service has already been constructed, the * existing instance is used. Otherwise, the factory associated with the service registration will be called, * the new instance will be registered, and then returned. */ getLocalService(identity: string): Promise; /** * Obtain an instance of the given service by it's constructor. If the service has already been constructed, the * existing instance is used. Otherwise, the factory associated with the service registration will be called, * the new instance will be registered, and then returned. */ getLocalService(serviceClass: AnyConstructor): Promise; /** * Get the Conduit ID of the given object, if one has been assigned. * @param object Any object- can be a local object or a remote proxy object. * @returns */ getObjectId(object: any): any; getReferenceId(object: any): string; /** * Returns true if a local object with the given ID is (1) registered and (2) not garbage collected. * @param id * @returns */ isLocalObjectPresent(id: string): boolean; /** * Called by the remote when a proxy has been garbage collected. * @param id */ finalizeRef(refID: string): Promise; /** * Subscribe to an event (named `eventName`) on the given object (`eventSource`). This method is typically called * over Conduit by the remote side. It is not intended to be used on a local (non-proxied) instance of RPCSession. * * Constraints: * - The given `eventSource` must be remote from the caller's perspective (local from the perspective of the implementation). * - The given `eventReceiver` must be local from the caller's perspective (remote from the perspective of the implementation). * * The `eventSource` object should have an `eventName` property which contains an `Observable`. That observable will * be subscribed to, and the resulting emitted values will be passed to `eventReceiver` via it's `next()` method. * * @param eventSource * @param eventName * @param eventReceiver * @returns */ subscribeToEvent(eventSource: any, eventName: string, eventReceiver: { next(value: T): void; }): Promise; /** * This is used for testing. * @internal */ getRequestMap(): Map; /** * This is used for testing. * @internal */ finalizeProxy(proxy: any): void; }