1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-02 01:33:22 +00:00

feat: add functions and some special commands/props

This commit is contained in:
Andreas Coroiu
2025-10-31 14:16:53 +01:00
parent 42905ed83a
commit 1ce283f833
3 changed files with 95 additions and 10 deletions

View File

@@ -42,6 +42,73 @@ describe("Batching proxies", () => {
{ method: "get", propertyName: "someProperty" },
]);
});
// it("accumulates commands when accessing multiple properties", async () => {
// const reference = { referenceId: 1, objectType: "TestObject" };
// const proxy = RpcObjectReference(channel, reference) as any;
// const pending = proxy.firstProperty.secondProperty.thirdProperty;
// expect(pending[ProxyInfo].proxyType).toBe("RpcPendingObjectReference");
// expect(pending[ProxyInfo].commands).toEqual([
// { method: "get", propertyName: "firstProperty" },
// { method: "get", propertyName: "secondProperty" },
// { method: "get", propertyName: "thirdProperty" },
// ]);
// });
it("returns a pending object reference proxy when calling a function", async () => {
const reference = { referenceId: 1, objectType: "TestObject" };
const proxy = RpcObjectReference(channel, reference) as any;
const args = [1, 2, 3];
const someMethod = proxy.someMethod(...args);
expect(someMethod[ProxyInfo].proxyType).toBe("RpcPendingObjectReference");
expect(someMethod[ProxyInfo].commands).toEqual([
{ method: "get", propertyName: "someMethod" },
{ method: "apply", args },
]);
});
it("returns a pending object reference proxy when awaiting", async () => {
const reference = { referenceId: 1, objectType: "TestObject" };
const proxy = RpcObjectReference(channel, reference) as any;
const someMethod = proxy.await;
expect(someMethod[ProxyInfo].proxyType).toBe("RpcPendingObjectReference");
expect(someMethod[ProxyInfo].commands).toEqual([{ method: "await" }]);
});
it("returns a pending object reference proxy when requesting value", async () => {
const reference = { referenceId: 1, objectType: "TestObject" };
const proxy = RpcObjectReference(channel, reference) as any;
const someMethod = proxy.transfer;
expect(someMethod[ProxyInfo].proxyType).toBe("RpcPendingObjectReference");
expect(someMethod[ProxyInfo].commands).toEqual([{ method: "transfer" }]);
});
it("returns all commands when accessing multiple props and functions", async () => {
const reference = { referenceId: 1, objectType: "TestObject" };
const proxy = RpcObjectReference(channel, reference) as any;
const someMethod = proxy.propOne.await.functionOne(9001).await.propTwo.await.transfer;
expect(someMethod[ProxyInfo].proxyType).toBe("RpcPendingObjectReference");
expect(someMethod[ProxyInfo].commands).toEqual([
{ method: "get", propertyName: "propOne" },
{ method: "await" },
{ method: "get", propertyName: "functionOne" },
{ method: "apply", args: [9001] },
{ method: "await" },
{ method: "get", propertyName: "propTwo" },
{ method: "await" },
{ method: "transfer" },
]);
});
});
class RpcChannel implements RpcRequestChannel {

View File

@@ -70,6 +70,20 @@ function proxyHandler(
return undefined;
}
if (property === "await") {
return RpcPendingObjectReference(channel, {
reference,
commands: [...commands, { method: "await" }],
});
}
if (property === "transfer") {
return RpcPendingObjectReference(channel, {
reference,
commands: [...commands, { method: "transfer" }],
});
}
return RpcPendingObjectReference(channel, {
reference,
commands:
@@ -78,7 +92,14 @@ function proxyHandler(
: [...commands, { method: "get", propertySymbol: serializeSymbol(property) }],
});
},
};
apply(_target: any, _thisArg: any, argArray?: any): any {
return RpcPendingObjectReference(channel, {
reference,
commands: [...commands, { method: "apply", args: argArray }],
});
},
} satisfies ProxyHandler<any>;
}
function commandsToString(commands: BatchCommand[]): string {
@@ -86,10 +107,10 @@ function commandsToString(commands: BatchCommand[]): string {
.map((cmd) => {
if (cmd.method === "get") {
const prop = (cmd as any).propertyName ?? (cmd as any).propertySymbol;
return `get(${String(prop)})`;
} else if (cmd.method === "call") {
return `${String(prop)}`;
} else if (cmd.method === "apply") {
const prop = (cmd as any).propertyName ?? (cmd as any).propertySymbol;
return `call(${String(prop)})`;
return `${String(prop)}()`;
}
return "???";

View File

@@ -6,12 +6,9 @@ export type SerializedPropertySymbol = (typeof PropertySymbolMap)[keyof typeof P
export type BatchCommand =
| { method: "get"; propertyName: string }
| { method: "get"; propertySymbol: SerializedPropertySymbol }
| { method: "call"; propertyName: string; args: unknown[] }
| {
method: "call";
propertySymbol: SerializedPropertySymbol;
args: unknown[];
};
| { method: "apply"; args: unknown[] }
| { method: "await" }
| { method: "transfer" };
export type Command =
| { method: "get"; referenceId: ReferenceId; propertyName: string }