|
1 | | -import { type ExecutionContext } from '@cloudflare/workers-types'; |
| 1 | +import { type DurableObjectState, type ExecutionContext } from '@cloudflare/workers-types'; |
2 | 2 |
|
3 | 3 | const kBound = Symbol.for('kBound'); |
4 | 4 |
|
| 5 | +const defaultPropertyOptions: PropertyDescriptor = { |
| 6 | + enumerable: true, |
| 7 | + configurable: true, |
| 8 | + writable: true, |
| 9 | +}; |
| 10 | + |
5 | 11 | /** |
6 | 12 | * Clones the given execution context by creating a shallow copy while ensuring the binding of specific methods. |
7 | 13 | * |
8 | | - * @param {ExecutionContext|void} ctx - The execution context to clone. Can be void. |
9 | | - * @return {ExecutionContext|void} A cloned execution context with bound methods, or the original void value if no context was provided. |
| 14 | + * @param {ExecutionContext|DurableObjectState|void} ctx - The execution context to clone. Can be void. |
| 15 | + * @return {ExecutionContext|DurableObjectState|void} A cloned execution context with bound methods, or the original void value if no context was provided. |
10 | 16 | */ |
11 | | -export function copyExecutionContext<T extends ExecutionContext | void>(ctx: T): T { |
| 17 | +export function copyExecutionContext<T extends ExecutionContext | DurableObjectState>(ctx: T): T { |
12 | 18 | if (!ctx) return ctx; |
13 | | - return Object.assign({}, ctx, { |
14 | | - ...('waitUntil' in ctx && { waitUntil: copyBound(ctx, 'waitUntil') }), |
15 | | - ...('passThroughOnException' in ctx && { passThroughOnException: copyBound(ctx, 'passThroughOnException') }), |
| 19 | + return Object.create(ctx, { |
| 20 | + waitUntil: { ...defaultPropertyOptions, value: copyBound(ctx, 'waitUntil') }, |
| 21 | + ...('passThroughOnException' in ctx && { |
| 22 | + passThroughOnException: { ...defaultPropertyOptions, value: copyBound(ctx, 'passThroughOnException') }, |
| 23 | + }), |
16 | 24 | }); |
17 | 25 | } |
18 | 26 |
|
19 | | -function copyBound<T extends object, K extends keyof T>(obj: T, method: K): T[K] { |
| 27 | +function copyBound<T, K extends keyof T>(obj: T, method: K): T[K] { |
20 | 28 | const method_impl = obj[method]; |
21 | 29 | if (typeof method_impl !== 'function') return method_impl; |
22 | 30 | if ((method_impl as T[K] & { [kBound]?: boolean })[kBound]) return method_impl; |
23 | 31 |
|
24 | | - const bound = method_impl.bind(obj); |
25 | | - return Object.defineProperty(bound, kBound, { value: true, enumerable: false }); |
| 32 | + return new Proxy(method_impl.bind(obj), { |
| 33 | + get: (target, key, receiver) => { |
| 34 | + if ('bind' === key) { |
| 35 | + return () => receiver; |
| 36 | + } else if (kBound === key) { |
| 37 | + return true; |
| 38 | + } |
| 39 | + return Reflect.get(target, key, receiver); |
| 40 | + }, |
| 41 | + }); |
26 | 42 | } |
0 commit comments