mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-03-01 16:20:25 +00:00
Support object references and deep proxying
Introduce remote object references (refId) and deep proxy support across client, server, serializer and types. Key changes: - Add refId propagation in client proxies so child proxies inherit and include refId on RPC requests. - Extend serializer to handle a new SerializedValueType.OBJECT_REF, add refResolver and pass refId to proxyCreator. - Server: store object references in a Map with generated ref IDs, resolve paths with optional refId, serialize results to OBJECT_REF when shouldProxyResult returns true, and release cleans up references. Add defaultShouldProxyResult heuristic to decide which return values should remain proxied (class instances and objects with methods). - Types: add refId fields and ObjectRef shape, expose shouldProxyResult option on RpcServerOptions, and include refId in ProxyMeta and serialized values. - Tests updated across the suite to expect proxied return values (arrays/objects/class instances) and to await property access or method calls; add comprehensive tests for deep return value proxying, chained calls, callbacks, constructors on returned proxies, and lifecycle of remote object proxies. These changes enable returning live/proxied remote objects (including class instances and objects with methods) from RPC calls, preserving remote behavior and allowing subsequent operations to target the same server-side object.
This commit is contained in:
@@ -28,6 +28,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
const {
|
||||
transport,
|
||||
rootPath = [],
|
||||
refId: rootRefId,
|
||||
// callbackTimeout 可供未来扩展使用
|
||||
} = options;
|
||||
void options.callbackTimeout;
|
||||
@@ -47,7 +48,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
if (!cb) throw new Error(`Nested callback not found: ${id}`);
|
||||
return cb;
|
||||
},
|
||||
proxyCreator: (path) => createProxyAtPath(path),
|
||||
proxyCreator: (path, proxyRefId) => createProxyAtPath(path, proxyRefId),
|
||||
}));
|
||||
const result = await callback(...args);
|
||||
return serialize(result, { callbackRegistry });
|
||||
@@ -57,10 +58,11 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
/**
|
||||
* 在指定路径创建代理
|
||||
*/
|
||||
function createProxyAtPath (path: PropertyKey[]): unknown {
|
||||
function createProxyAtPath (path: PropertyKey[], refId?: string): unknown {
|
||||
const proxyMeta: ProxyMeta = {
|
||||
path: [...path],
|
||||
isProxy: true,
|
||||
refId,
|
||||
};
|
||||
|
||||
// 创建一个函数目标,以支持 apply 和 construct
|
||||
@@ -78,8 +80,8 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 返回新的子路径代理
|
||||
return createProxyAtPath([...path, prop]);
|
||||
// 返回新的子路径代理(继承 refId)
|
||||
return createProxyAtPath([...path, prop], refId);
|
||||
},
|
||||
|
||||
set (_target, prop, value) {
|
||||
@@ -88,6 +90,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
type: RpcOperationType.SET,
|
||||
path: [...path, prop],
|
||||
args: [serialize(value, { callbackRegistry })],
|
||||
refId,
|
||||
};
|
||||
|
||||
// 同步返回,但实际是异步操作
|
||||
@@ -105,6 +108,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
path,
|
||||
args: serializedArgs,
|
||||
callbackIds: Object.keys(callbackIds).length > 0 ? callbackIds : undefined,
|
||||
refId,
|
||||
};
|
||||
|
||||
return createAsyncResultProxy(request);
|
||||
@@ -120,6 +124,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
path,
|
||||
args: serializedArgs,
|
||||
callbackIds: Object.keys(callbackIds).length > 0 ? callbackIds : undefined,
|
||||
refId,
|
||||
};
|
||||
|
||||
return createAsyncResultProxy(request) as object;
|
||||
@@ -152,6 +157,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
id: generateRequestId(),
|
||||
type: RpcOperationType.DELETE,
|
||||
path: [...path, prop],
|
||||
refId,
|
||||
};
|
||||
|
||||
transport.send(request).catch(() => { /* ignore */ });
|
||||
@@ -197,7 +203,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
if (!cb) throw new Error(`Callback not found: ${id}`);
|
||||
return cb;
|
||||
},
|
||||
proxyCreator: (proxyPath) => createProxyAtPath(proxyPath),
|
||||
proxyCreator: (proxyPath, proxyRefId) => createProxyAtPath(proxyPath, proxyRefId),
|
||||
});
|
||||
return deserialized;
|
||||
}
|
||||
@@ -208,7 +214,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
if (!cb) throw new Error(`Callback not found: ${id}`);
|
||||
return cb;
|
||||
},
|
||||
proxyCreator: (proxyPath) => createProxyAtPath(proxyPath),
|
||||
proxyCreator: (proxyPath, proxyRefId) => createProxyAtPath(proxyPath, proxyRefId),
|
||||
});
|
||||
})();
|
||||
}
|
||||
@@ -323,7 +329,7 @@ export function createDeepProxy<T = unknown> (options: DeepProxyOptions): T {
|
||||
});
|
||||
}
|
||||
|
||||
return createProxyAtPath(rootPath) as T;
|
||||
return createProxyAtPath(rootPath, rootRefId) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,9 @@ export interface DeserializeContext {
|
||||
/** 回调解析器 */
|
||||
callbackResolver?: (id: string) => Function;
|
||||
/** 代理创建器 */
|
||||
proxyCreator?: (path: PropertyKey[]) => unknown;
|
||||
proxyCreator?: (path: PropertyKey[], refId?: string) => unknown;
|
||||
/** 对象引用解析器 */
|
||||
refResolver?: (refId: string) => unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,7 +265,7 @@ export function serialize (value: unknown, context: SerializeContext = {}): Seri
|
||||
* 将序列化数据还原为值
|
||||
*/
|
||||
export function deserialize (data: SerializedValue, context: DeserializeContext = {}): unknown {
|
||||
const { callbackResolver, proxyCreator } = context;
|
||||
const { callbackResolver, proxyCreator, refResolver } = context;
|
||||
|
||||
switch (data.type) {
|
||||
case SerializedValueType.UNDEFINED:
|
||||
@@ -357,6 +359,20 @@ export function deserialize (data: SerializedValue, context: DeserializeContext
|
||||
}
|
||||
return {};
|
||||
|
||||
case SerializedValueType.OBJECT_REF:
|
||||
// 对象引用:在客户端创建代理,在服务端解析为实际对象
|
||||
if (data.refId) {
|
||||
// 优先使用 refResolver(服务端场景)
|
||||
if (refResolver) {
|
||||
return refResolver(data.refId);
|
||||
}
|
||||
// 否则创建代理(客户端场景)
|
||||
if (proxyCreator) {
|
||||
return proxyCreator([], data.refId);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
||||
case SerializedValueType.OBJECT: {
|
||||
const obj: Record<string, unknown> = {};
|
||||
if (data.properties) {
|
||||
|
||||
@@ -4,9 +4,58 @@ import {
|
||||
type RpcServerOptions,
|
||||
type SerializedValue,
|
||||
RpcOperationType,
|
||||
SerializedValueType,
|
||||
} from './types.js';
|
||||
import { serialize, deserialize, SimpleCallbackRegistry } from './serializer.js';
|
||||
|
||||
/**
|
||||
* 生成唯一引用 ID
|
||||
*/
|
||||
function generateRefId (): string {
|
||||
return `ref_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的代理判断函数
|
||||
* 判断返回值是否应该保持代理引用(而非完全序列化)
|
||||
* 策略:class 实例和有方法的对象保持代理,普通对象直接序列化
|
||||
*/
|
||||
function defaultShouldProxyResult (value: unknown): boolean {
|
||||
if (value === null || value === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (typeof value !== 'object' && typeof value !== 'function') {
|
||||
return false;
|
||||
}
|
||||
// 函数保持代理
|
||||
if (typeof value === 'function') {
|
||||
return true;
|
||||
}
|
||||
// 可安全序列化的内置类型不代理
|
||||
if (value instanceof Date || value instanceof RegExp || value instanceof Error) {
|
||||
return false;
|
||||
}
|
||||
if (value instanceof Map || value instanceof Set) {
|
||||
return false;
|
||||
}
|
||||
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
||||
return false;
|
||||
}
|
||||
// 数组不代理
|
||||
if (Array.isArray(value)) {
|
||||
return false;
|
||||
}
|
||||
// 检查对象原型是否为 Object.prototype(普通对象)
|
||||
const proto = Object.getPrototypeOf(value);
|
||||
if (proto === Object.prototype || proto === null) {
|
||||
// 普通对象检查是否有方法
|
||||
const hasMethod = Object.values(value as object).some(v => typeof v === 'function');
|
||||
return hasMethod;
|
||||
}
|
||||
// 非普通对象(class 实例)- 保持代理
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* RPC 服务端
|
||||
*
|
||||
@@ -16,10 +65,15 @@ export class RpcServer {
|
||||
private target: unknown;
|
||||
private callbackInvoker?: (callbackId: string, args: unknown[]) => Promise<unknown>;
|
||||
private localCallbacks = new SimpleCallbackRegistry();
|
||||
/** 对象引用存储 */
|
||||
private objectRefs = new Map<string, unknown>();
|
||||
/** 代理判断函数 */
|
||||
private shouldProxyResult: (value: unknown) => boolean;
|
||||
|
||||
constructor (options: RpcServerOptions) {
|
||||
this.target = options.target;
|
||||
this.callbackInvoker = options.callbackInvoker;
|
||||
this.shouldProxyResult = options.shouldProxyResult ?? defaultShouldProxyResult;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,10 +125,16 @@ export class RpcServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析路径获取目标值
|
||||
* 解析路径获取目标值,支持 refId
|
||||
*/
|
||||
private resolvePath (path: PropertyKey[]): { parent: unknown; key: PropertyKey | undefined; value: unknown; } {
|
||||
let current = this.target;
|
||||
private resolvePath (path: PropertyKey[], refId?: string): { parent: unknown; key: PropertyKey | undefined; value: unknown; } {
|
||||
// 如果有 refId,从引用存储中获取根对象
|
||||
let current = refId ? this.objectRefs.get(refId) : this.target;
|
||||
|
||||
if (refId && current === undefined) {
|
||||
throw new Error(`Object reference not found: ${refId}`);
|
||||
}
|
||||
|
||||
let parent: unknown = null;
|
||||
let key: PropertyKey | undefined;
|
||||
|
||||
@@ -93,18 +153,54 @@ export class RpcServer {
|
||||
return { parent, key, value: current };
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储对象引用并返回序列化的引用
|
||||
*/
|
||||
private storeObjectRef (value: unknown): SerializedValue {
|
||||
const refId = generateRefId();
|
||||
this.objectRefs.set(refId, value);
|
||||
const className = value?.constructor?.name;
|
||||
return {
|
||||
type: SerializedValueType.OBJECT_REF,
|
||||
refId,
|
||||
className: className !== 'Object' ? className : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化结果值,如果需要代理则存储引用
|
||||
*/
|
||||
private serializeResult (value: unknown): { result: SerializedValue; isProxyable: boolean; refId?: string; } {
|
||||
const shouldProxy = this.shouldProxyResult(value);
|
||||
|
||||
if (shouldProxy) {
|
||||
const ref = this.storeObjectRef(value);
|
||||
return {
|
||||
result: ref,
|
||||
isProxyable: true,
|
||||
refId: ref.refId,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
result: serialize(value, { callbackRegistry: this.localCallbacks }),
|
||||
isProxyable: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 GET 操作
|
||||
*/
|
||||
private handleGet (request: RpcRequest): RpcResponse {
|
||||
const { value } = this.resolvePath(request.path);
|
||||
const isProxyable = this.isProxyable(value);
|
||||
const { value } = this.resolvePath(request.path, request.refId);
|
||||
const { result, isProxyable, refId } = this.serializeResult(value);
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
success: true,
|
||||
result: serialize(value, { callbackRegistry: this.localCallbacks }),
|
||||
result,
|
||||
isProxyable,
|
||||
refId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -113,13 +209,13 @@ export class RpcServer {
|
||||
*/
|
||||
private handleSet (request: RpcRequest): RpcResponse {
|
||||
const path = request.path;
|
||||
if (path.length === 0) {
|
||||
if (path.length === 0 && !request.refId) {
|
||||
throw new Error('Cannot set root object');
|
||||
}
|
||||
|
||||
const parentPath = path.slice(0, -1);
|
||||
const key = path[path.length - 1]!;
|
||||
const { value: parent } = this.resolvePath(parentPath);
|
||||
const { value: parent } = this.resolvePath(parentPath, request.refId);
|
||||
|
||||
if (parent === null || parent === undefined) {
|
||||
throw new Error(`Cannot set property '${String(key)}' of ${parent}`);
|
||||
@@ -128,6 +224,7 @@ export class RpcServer {
|
||||
const newValue = request.args?.[0]
|
||||
? deserialize(request.args[0], {
|
||||
callbackResolver: this.createCallbackResolver(request),
|
||||
refResolver: (refId) => this.objectRefs.get(refId),
|
||||
})
|
||||
: undefined;
|
||||
|
||||
@@ -144,13 +241,43 @@ export class RpcServer {
|
||||
*/
|
||||
private async handleApply (request: RpcRequest): Promise<RpcResponse> {
|
||||
const path = request.path;
|
||||
|
||||
// 如果有 refId 且 path 为空,说明引用对象本身是函数
|
||||
if (path.length === 0 && request.refId) {
|
||||
const func = this.objectRefs.get(request.refId);
|
||||
if (typeof func !== 'function') {
|
||||
throw new Error('Referenced object is not callable');
|
||||
}
|
||||
|
||||
const args = (request.args ?? []).map(arg =>
|
||||
deserialize(arg, {
|
||||
callbackResolver: this.createCallbackResolver(request),
|
||||
refResolver: (refId) => this.objectRefs.get(refId),
|
||||
})
|
||||
);
|
||||
|
||||
let result = func(...args);
|
||||
if (result instanceof Promise) {
|
||||
result = await result;
|
||||
}
|
||||
|
||||
const { result: serializedResult, isProxyable, refId } = this.serializeResult(result);
|
||||
return {
|
||||
id: request.id,
|
||||
success: true,
|
||||
result: serializedResult,
|
||||
isProxyable,
|
||||
refId,
|
||||
};
|
||||
}
|
||||
|
||||
if (path.length === 0) {
|
||||
throw new Error('Cannot call root object');
|
||||
}
|
||||
|
||||
const methodPath = path.slice(0, -1);
|
||||
const methodName = path[path.length - 1]!;
|
||||
const { value: parent } = this.resolvePath(methodPath);
|
||||
const { value: parent } = this.resolvePath(methodPath, request.refId);
|
||||
|
||||
if (parent === null || parent === undefined) {
|
||||
throw new Error(`Cannot call method on ${parent}`);
|
||||
@@ -164,6 +291,7 @@ export class RpcServer {
|
||||
const args = (request.args ?? []).map(arg =>
|
||||
deserialize(arg, {
|
||||
callbackResolver: this.createCallbackResolver(request),
|
||||
refResolver: (refId) => this.objectRefs.get(refId),
|
||||
})
|
||||
);
|
||||
|
||||
@@ -174,13 +302,14 @@ export class RpcServer {
|
||||
result = await result;
|
||||
}
|
||||
|
||||
const isProxyable = this.isProxyable(result);
|
||||
const { result: serializedResult, isProxyable, refId } = this.serializeResult(result);
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
success: true,
|
||||
result: serialize(result, { callbackRegistry: this.localCallbacks }),
|
||||
result: serializedResult,
|
||||
isProxyable,
|
||||
refId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -188,7 +317,7 @@ export class RpcServer {
|
||||
* 处理 CONSTRUCT 操作
|
||||
*/
|
||||
private async handleConstruct (request: RpcRequest): Promise<RpcResponse> {
|
||||
const { value: Constructor } = this.resolvePath(request.path);
|
||||
const { value: Constructor } = this.resolvePath(request.path, request.refId);
|
||||
|
||||
if (typeof Constructor !== 'function') {
|
||||
throw new Error('Target is not a constructor');
|
||||
@@ -197,17 +326,19 @@ export class RpcServer {
|
||||
const args = (request.args ?? []).map(arg =>
|
||||
deserialize(arg, {
|
||||
callbackResolver: this.createCallbackResolver(request),
|
||||
refResolver: (refId) => this.objectRefs.get(refId),
|
||||
})
|
||||
);
|
||||
|
||||
const instance = new (Constructor as new (...args: unknown[]) => unknown)(...args);
|
||||
const isProxyable = this.isProxyable(instance);
|
||||
const { result, isProxyable, refId } = this.serializeResult(instance);
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
success: true,
|
||||
result: serialize(instance, { callbackRegistry: this.localCallbacks }),
|
||||
result,
|
||||
isProxyable,
|
||||
refId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -226,7 +357,7 @@ export class RpcServer {
|
||||
|
||||
const parentPath = path.slice(0, -1);
|
||||
const key = path[path.length - 1]!;
|
||||
const { value: parent } = this.resolvePath(parentPath);
|
||||
const { value: parent } = this.resolvePath(parentPath, request.refId);
|
||||
|
||||
const has = parent !== null && parent !== undefined && key in (parent as object);
|
||||
|
||||
@@ -241,7 +372,7 @@ export class RpcServer {
|
||||
* 处理 OWNKEYS 操作
|
||||
*/
|
||||
private handleOwnKeys (request: RpcRequest): RpcResponse {
|
||||
const { value } = this.resolvePath(request.path);
|
||||
const { value } = this.resolvePath(request.path, request.refId);
|
||||
|
||||
if (value === null || value === undefined) {
|
||||
return {
|
||||
@@ -265,13 +396,13 @@ export class RpcServer {
|
||||
*/
|
||||
private handleDelete (request: RpcRequest): RpcResponse {
|
||||
const path = request.path;
|
||||
if (path.length === 0) {
|
||||
if (path.length === 0 && !request.refId) {
|
||||
throw new Error('Cannot delete root object');
|
||||
}
|
||||
|
||||
const parentPath = path.slice(0, -1);
|
||||
const key = path[path.length - 1]!;
|
||||
const { value: parent } = this.resolvePath(parentPath);
|
||||
const { value: parent } = this.resolvePath(parentPath, request.refId);
|
||||
|
||||
if (parent === null || parent === undefined) {
|
||||
throw new Error(`Cannot delete property from ${parent}`);
|
||||
@@ -301,7 +432,7 @@ export class RpcServer {
|
||||
|
||||
const parentPath = path.slice(0, -1);
|
||||
const key = path[path.length - 1]!;
|
||||
const { value: parent } = this.resolvePath(parentPath);
|
||||
const { value: parent } = this.resolvePath(parentPath, request.refId);
|
||||
|
||||
if (parent === null || parent === undefined) {
|
||||
return {
|
||||
@@ -337,7 +468,7 @@ export class RpcServer {
|
||||
* 处理 GET_PROTOTYPE 操作
|
||||
*/
|
||||
private handleGetPrototype (request: RpcRequest): RpcResponse {
|
||||
const { value } = this.resolvePath(request.path);
|
||||
const { value } = this.resolvePath(request.path, request.refId);
|
||||
|
||||
if (value === null || value === undefined) {
|
||||
return {
|
||||
@@ -361,7 +492,10 @@ export class RpcServer {
|
||||
* 处理 RELEASE 操作
|
||||
*/
|
||||
private handleRelease (request: RpcRequest): RpcResponse {
|
||||
// 清理与该路径相关的资源(如果有)
|
||||
// 如果有 refId,释放该引用
|
||||
if (request.refId) {
|
||||
this.objectRefs.delete(request.refId);
|
||||
}
|
||||
return {
|
||||
id: request.id,
|
||||
success: true,
|
||||
@@ -383,17 +517,6 @@ export class RpcServer {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断值是否应该返回代理引用
|
||||
*/
|
||||
private isProxyable (value: unknown): boolean {
|
||||
if (value === null || value === undefined) {
|
||||
return false;
|
||||
}
|
||||
const type = typeof value;
|
||||
return type === 'object' || type === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建错误响应
|
||||
*/
|
||||
|
||||
@@ -40,6 +40,8 @@ export interface RpcRequest {
|
||||
args?: SerializedValue[];
|
||||
/** 回调 ID 映射 (参数索引 -> 回调 ID) */
|
||||
callbackIds?: Record<number, string>;
|
||||
/** 远程对象引用 ID(用于对引用对象的操作) */
|
||||
refId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,6 +60,8 @@ export interface RpcResponse {
|
||||
stack?: string;
|
||||
/** 结果是否为可代理对象 */
|
||||
isProxyable?: boolean;
|
||||
/** 远程对象引用 ID(用于深层对象代理) */
|
||||
refId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,6 +82,8 @@ export interface SerializedValue {
|
||||
properties?: Record<string, SerializedValue>;
|
||||
/** 数组元素 */
|
||||
elements?: SerializedValue[];
|
||||
/** 远程对象引用 ID(用于保持代理能力) */
|
||||
refId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,6 +108,18 @@ export enum SerializedValueType {
|
||||
BUFFER = 'buffer',
|
||||
MAP = 'map',
|
||||
SET = 'set',
|
||||
/** 远程对象引用 - 保持代理能力 */
|
||||
OBJECT_REF = 'objectRef',
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象引用信息
|
||||
*/
|
||||
export interface ObjectRef {
|
||||
/** 引用 ID */
|
||||
refId: string;
|
||||
/** 对象类型名称 */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,6 +156,8 @@ export interface DeepProxyOptions {
|
||||
cacheProperties?: boolean;
|
||||
/** 回调超时时间 (ms) */
|
||||
callbackTimeout?: number;
|
||||
/** 远程对象引用 ID(用于引用对象的代理) */
|
||||
refId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,6 +168,11 @@ export interface RpcServerOptions {
|
||||
target: unknown;
|
||||
/** 回调调用器 */
|
||||
callbackInvoker?: (callbackId: string, args: unknown[]) => Promise<unknown>;
|
||||
/**
|
||||
* 判断返回值是否应保持代理引用(而非完全序列化)
|
||||
* 默认对 class 实例和包含方法的对象返回 true
|
||||
*/
|
||||
shouldProxyResult?: (value: unknown) => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,4 +188,6 @@ export interface ProxyMeta {
|
||||
path: PropertyKey[];
|
||||
/** 是否为代理 */
|
||||
isProxy: true;
|
||||
/** 远程对象引用 ID */
|
||||
refId?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user