File size: 1,955 Bytes
aa89cb5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Internal execution plumbing. Never export provenance from the public facade
// or store it as a JSON/symbol property on a builder, entity or Context.
const origins = new WeakMap<object, object>();
const requestOwners = new WeakMap<object, object>();

/** Internal capability: never a field on query JSON, entities or Context. */
export function queryExecutionOwner(query: object): object | undefined { return requestOwners.get(query); }
export function retainQueryExecutionOwner(query: object, owner: object): void { requestOwners.set(query, owner); }

export function queryDiagnosticOrigin(query: object): object | undefined { return origins.get(query); }

export function retainQueryDiagnosticOrigin(source: object, target: object): void {
  origins.set(target, origins.get(source) ?? snapshotQuery(source));
}

/** Capture request-owned AST values while retaining opaque local capabilities.
 * Date/binary values keep their native types. Non-enumerable runtime policy and
 * Context handles are intentionally not traversed or serialized. */
export function snapshotQuery<T>(value: T, seen = new Map<object, unknown>()): T {
  if (!value || typeof value !== 'object') return value;
  if (seen.has(value)) return seen.get(value) as T;
  if (value instanceof Date) return new Date(value.getTime()) as T;
  if (value instanceof Uint8Array) return new Uint8Array(value) as T;
  const copy = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
  seen.set(value, copy);
  for (const key of Reflect.ownKeys(value)) {
    const descriptor = Object.getOwnPropertyDescriptor(value, key)!;
    if ('value' in descriptor && descriptor.enumerable) descriptor.value = snapshotQuery(descriptor.value, seen);
    Object.defineProperty(copy, key, descriptor);
  }
  const origin = origins.get(value);
  if (origin) origins.set(copy, origin);
  const owner = requestOwners.get(value);
  if (owner) requestOwners.set(copy, owner);
  return copy;
}