flugrekorder 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,9 +6,14 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
6
6
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
7
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
8
 
9
- // source/flugrekorder.ts
10
- var _byId, _byProxy, _byTarget, _generator;
11
- var Graph = class {
9
+ // source/types.ts
10
+ function isProxiable(value) {
11
+ return value !== null && (typeof value === "object" || typeof value === "function");
12
+ }
13
+
14
+ // source/graph.ts
15
+ var _index, _all, _byId, _byProxy, _byTarget, _generator;
16
+ var _Graph = class _Graph {
12
17
  constructor(id) {
13
18
  __privateAdd(this, _byId, /* @__PURE__ */ new Map());
14
19
  __privateAdd(this, _byProxy, /* @__PURE__ */ new WeakMap());
@@ -17,9 +22,26 @@ var Graph = class {
17
22
  let counter = typeof id === "number" ? id : 0;
18
23
  __privateSet(this, _generator, typeof id === "function" ? id : () => `#${++counter}`);
19
24
  }
25
+ /** Returns the Graph that owns `pxy`, or `undefined` for non-proxies. */
26
+ static for(pxy) {
27
+ return __privateGet(_Graph, _index).get(pxy);
28
+ }
29
+ /** Returns `true` if `pxy` is a proxy created by this module. */
30
+ static isProxy(pxy) {
31
+ return __privateGet(_Graph, _all).has(pxy);
32
+ }
33
+ /** Marks `pxy` as a known proxy across all graphs (double-wrap guard). */
34
+ static track(pxy) {
35
+ __privateGet(_Graph, _all).add(pxy);
36
+ }
20
37
  nextId() {
21
38
  return __privateGet(this, _generator).call(this);
22
39
  }
40
+ /** Returns the underlying target if `value` is a proxy known to this graph, otherwise `value` unchanged. */
41
+ unwrap(value) {
42
+ if (!isProxiable(value)) return value;
43
+ return __privateGet(this, _byProxy).get(value)?.target ?? value;
44
+ }
23
45
  getByProxy(v) {
24
46
  return __privateGet(this, _byProxy).get(v);
25
47
  }
@@ -29,62 +51,89 @@ var Graph = class {
29
51
  getById(id) {
30
52
  return __privateGet(this, _byId).get(id);
31
53
  }
32
- register(proxy, target, origin, id) {
33
- const node = { id, proxy, target, origin };
54
+ register(proxy, target, origin2, id) {
55
+ const node = { id, proxy, target, origin: origin2 };
34
56
  __privateGet(this, _byId).set(id, node);
35
57
  __privateGet(this, _byProxy).set(proxy, node);
36
58
  __privateGet(this, _byTarget).set(target, node);
59
+ __privateGet(_Graph, _index).set(proxy, this);
37
60
  return node;
38
61
  }
39
62
  };
63
+ _index = new WeakMap();
64
+ _all = new WeakMap();
40
65
  _byId = new WeakMap();
41
66
  _byProxy = new WeakMap();
42
67
  _byTarget = new WeakMap();
43
68
  _generator = new WeakMap();
44
- var graphOf = /* @__PURE__ */ new WeakMap();
45
- var allProxies = /* @__PURE__ */ new WeakSet();
46
- var slotProtos = /* @__PURE__ */ new WeakMap();
47
- var bindCache = /* @__PURE__ */ new WeakMap();
48
- function isProxiable(value) {
49
- return value !== null && (typeof value === "object" || typeof value === "function");
69
+ __privateAdd(_Graph, _index, /* @__PURE__ */ new WeakMap());
70
+ __privateAdd(_Graph, _all, /* @__PURE__ */ new WeakSet());
71
+ var Graph = _Graph;
72
+
73
+ // source/serialize.ts
74
+ var defaults = {
75
+ depth: Infinity,
76
+ redactors: [],
77
+ truncate: Infinity
78
+ };
79
+ function redact(redactors, key, value, target) {
80
+ for (const redactor of redactors) {
81
+ const result = redactor(key, value, target);
82
+ if (result === false) continue;
83
+ return result === true ? "[redacted]" : result;
84
+ }
85
+ return false;
50
86
  }
51
- function serializeProxiable(v, graph, seen) {
52
- const node = graph.getByProxy(v) ?? graph.getByTarget(v);
53
- if (node !== void 0) return { $proxy: node.id };
54
- if (Array.isArray(v))
55
- return v.map((item) => serialize(item, graph, seen));
87
+ function proxiable(v, graph, seen, serial, depth) {
88
+ const proxyNode = graph.getByProxy(v);
89
+ if (proxyNode !== void 0) return { $proxy: proxyNode.id };
90
+ const targetNode = graph.getByTarget(v);
91
+ if (targetNode !== void 0) return { $unwrap: { $proxy: targetNode.id } };
92
+ if (depth >= serial.depth) return "[\u2026]";
93
+ if (Array.isArray(v)) {
94
+ return v.map(
95
+ (item) => serialize(item, graph, seen, serial, depth + 1)
96
+ );
97
+ }
56
98
  if (seen.has(v)) return { $proxy: "?" };
57
99
  seen.add(v);
58
- const result = Object.fromEntries(
59
- Object.entries(v).map(([k, val]) => [
60
- k,
61
- serialize(val, graph, seen)
62
- ])
63
- );
100
+ const entries = [];
101
+ for (const [k, val] of Object.entries(v)) {
102
+ if (serial.redactors.length > 0) {
103
+ const decision = redact(serial.redactors, k, val, v);
104
+ if (decision === null) continue;
105
+ if (decision !== false) {
106
+ entries.push([k, decision]);
107
+ continue;
108
+ }
109
+ }
110
+ entries.push([k, serialize(val, graph, seen, serial, depth + 1)]);
111
+ }
64
112
  seen.delete(v);
65
- return result;
113
+ return Object.fromEntries(entries);
66
114
  }
67
- var mappings = [
68
- { match: /number|boolean|bigint/, map: (v) => v },
69
- { match: /object|function/, map: serializeProxiable }
70
- ];
71
- function serialize(v, graph, seen = /* @__PURE__ */ new Set()) {
115
+ function serialize(v, graph, seen = /* @__PURE__ */ new Set(), serial = defaults, depth = 0) {
72
116
  if (v === null || v === void 0) return v;
73
- const { map = String } = mappings.find(({ match }) => match.test(typeof v)) ?? {};
74
- return map(v, graph, seen);
117
+ if (isProxiable(v)) return proxiable(v, graph, seen, serial, depth);
118
+ return typeof v === "string" ? v.length > serial.truncate ? `${v.slice(0, serial.truncate)}\u2026` : v : v;
75
119
  }
76
- function serializeOrigin(o) {
120
+ function origin(o) {
77
121
  if (!o) return null;
78
122
  if ("key" in o)
79
123
  return { trap: o.trap, parent: o.parent, key: String(o.key) };
80
124
  return o;
81
125
  }
82
- var slotError = /incompatible receiver|this is not/i;
126
+
127
+ // source/slots.ts
128
+ var slotProtos = /* @__PURE__ */ new WeakMap();
129
+ var bindCache = /* @__PURE__ */ new WeakMap();
130
+ var slotError = /incompatible receiver|this is not|illegal invocation/i;
83
131
  function hasInternalSlots(target) {
84
132
  if (typeof target !== "object" || target === null) return false;
85
133
  const direct = Object.getPrototypeOf(target);
86
134
  if (!direct) return false;
87
- if (slotProtos.has(direct)) return slotProtos.get(direct);
135
+ const cached = slotProtos.get(direct);
136
+ if (cached !== void 0) return cached;
88
137
  const probe = new Proxy(target, {
89
138
  set: () => true,
90
139
  defineProperty: () => true,
@@ -102,7 +151,8 @@ function hasInternalSlots(target) {
102
151
  try {
103
152
  fn.call(probe);
104
153
  } catch (e) {
105
- if (e instanceof TypeError && slotError.test(String(e))) slots = true;
154
+ if (e instanceof TypeError && slotError.test(String(e)))
155
+ slots = true;
106
156
  }
107
157
  slotProtos.set(direct, slots);
108
158
  return slots;
@@ -114,206 +164,401 @@ function hasInternalSlots(target) {
114
164
  return false;
115
165
  }
116
166
  function boundMethod(target, key, fn) {
117
- if (!bindCache.has(target)) bindCache.set(target, /* @__PURE__ */ new Map());
118
- const cache = bindCache.get(target);
119
- if (!cache.has(key)) cache.set(key, fn.bind(target));
120
- return cache.get(key);
167
+ let cache = bindCache.get(target);
168
+ if (!cache) {
169
+ cache = /* @__PURE__ */ new Map();
170
+ bindCache.set(target, cache);
171
+ }
172
+ const existing = cache.get(key);
173
+ if (existing) return existing;
174
+ const bound = fn.bind(target);
175
+ cache.set(key, bound);
176
+ return bound;
177
+ }
178
+
179
+ // source/specs.ts
180
+ var TypedArray = Object.getPrototypeOf(Int8Array);
181
+ var ecmaBuiltins = [
182
+ Promise,
183
+ Map,
184
+ Set,
185
+ WeakMap,
186
+ WeakSet,
187
+ Date,
188
+ RegExp,
189
+ ArrayBuffer,
190
+ TypedArray,
191
+ DataView
192
+ ];
193
+ function isECMABuiltin(v) {
194
+ return ecmaBuiltins.some((B) => v instanceof B);
195
+ }
196
+ function isUnsafeBinding(v) {
197
+ return isProxiable(v) && hasInternalSlots(v) && !isECMABuiltin(v);
121
198
  }
122
- var specs = {
123
- get: {
124
- // For targets with internal slots (Map, Set, WeakMap, WeakSet, Date …),
125
- // use the real target as the Reflect.get receiver so that getter-based
126
- // slot checks (e.g. Map.prototype.size) don't throw TypeError.
127
- pre: ([target, key, receiver], _wrap, _known) => [
128
- target,
129
- key,
130
- hasInternalSlots(target) ? target : receiver
131
- ],
132
- // For the same targets, bind method results to the real target before
133
- // wrapping so that apply-level slot checks (e.g. Map.prototype.get)
134
- // also pass. The bind cache ensures proxy stability.
135
- post: (result, [target, key], wrap) => {
136
- if (key === "prototype") return result;
137
- if (typeof result === "function" && hasInternalSlots(target)) {
138
- return wrap(boundMethod(target, key, result));
199
+ function makeSpecs(bind) {
200
+ return {
201
+ get: {
202
+ // For targets with internal slots (Map, Set, WeakMap, WeakSet, Date …)
203
+ // or when bind is true, use the real target as the Reflect.get
204
+ // receiver so that getter-based slot checks and #private field reads
205
+ // (e.g. `get value() { return this.#count; }`) don't throw TypeError.
206
+ pre: ([target, key, receiver], _wrap, _known) => [
207
+ target,
208
+ key,
209
+ hasInternalSlots(target) || bind ? target : receiver
210
+ ],
211
+ // For the same targets, bind method results to the real target before
212
+ // wrapping so that apply-level slot checks (e.g. Map.prototype.get)
213
+ // and #private field access inside methods also pass.
214
+ // The bind cache ensures proxy stability.
215
+ post: (result, [target, key], wrap) => {
216
+ if (key === "prototype") return result;
217
+ if (hasInternalSlots(target) || bind) {
218
+ if (typeof result === "function")
219
+ return wrap(
220
+ boundMethod(
221
+ target,
222
+ key,
223
+ result
224
+ )
225
+ );
226
+ }
227
+ if (isUnsafeBinding(result)) return result;
228
+ return wrap(result);
229
+ }
230
+ },
231
+ set: {
232
+ pre: ([target, key, value, receiver], wrap) => [
233
+ target,
234
+ key,
235
+ // Don't wrap when target has slots (Map/Set internals) or when the
236
+ // value is an unsafe C++ binding (TCP handles, etc.).
237
+ hasInternalSlots(target) || isUnsafeBinding(value) ? value : wrap(value),
238
+ receiver
239
+ ]
240
+ },
241
+ apply: {
242
+ // thisArg is wrapped normally (it's always a graph node).
243
+ // Call arguments are wrapped with known — only existing graph nodes
244
+ // get proxied; plain data passes through and is inlined by serialize().
245
+ pre: ([target, thisArg, callArgs], wrap, known) => [
246
+ target,
247
+ wrap(thisArg),
248
+ callArgs.map(known)
249
+ ],
250
+ post: (result, _args, wrap) => wrap(result)
251
+ },
252
+ construct: {
253
+ pre: ([target, callArgs, newTarget], wrap) => [
254
+ target,
255
+ callArgs.map(wrap),
256
+ newTarget
257
+ ],
258
+ post: (result, _args, wrap) => wrap(result)
259
+ },
260
+ defineProperty: {
261
+ pre: (args, wrap) => {
262
+ const [target, key, descriptor] = args;
263
+ const patch = {};
264
+ if (descriptor.value != null && !isUnsafeBinding(descriptor.value))
265
+ patch.value = wrap(descriptor.value);
266
+ if (typeof descriptor.get === "function")
267
+ patch.get = wrap(descriptor.get);
268
+ if (typeof descriptor.set === "function")
269
+ patch.set = wrap(descriptor.set);
270
+ return Object.keys(patch).length > 0 ? [target, key, { ...descriptor, ...patch }] : args;
271
+ }
272
+ },
273
+ getOwnPropertyDescriptor: {
274
+ post: (result, _args, wrap) => {
275
+ const desc = result;
276
+ if (!desc) return result;
277
+ const patch = {};
278
+ if (desc.value != null && !isUnsafeBinding(desc.value))
279
+ patch.value = wrap(desc.value);
280
+ if (typeof desc.get === "function")
281
+ patch.get = wrap(desc.get);
282
+ if (typeof desc.set === "function")
283
+ patch.set = wrap(desc.set);
284
+ return Object.keys(patch).length > 0 ? { ...desc, ...patch } : result;
139
285
  }
140
- return wrap(result);
286
+ }
287
+ };
288
+ }
289
+
290
+ // source/errors.ts
291
+ function isError(input) {
292
+ return input ? input instanceof Error : false;
293
+ }
294
+ function createErrorGuard(name, contains) {
295
+ const checks = [
296
+ isError,
297
+ (sub) => typeof sub === "object" && sub?.name === name
298
+ ];
299
+ if (contains instanceof RegExp) {
300
+ checks.push((v) => contains.test(String(v)));
301
+ }
302
+ return (input) => checks.every((predicate) => predicate(input));
303
+ }
304
+
305
+ // source/retry.ts
306
+ function unwrap(graph, value) {
307
+ return graph?.unwrap(value) ?? value;
308
+ }
309
+ var isDataCloneDOMException = createErrorGuard("DataCloneError");
310
+ var isTypeErrorPrivateMember = createErrorGuard("TypeError", /private member/i);
311
+ var isTypeErrorIllegalInvocation = createErrorGuard("TypeError", /illegal invocation/i);
312
+ var retryFlows = [
313
+ {
314
+ // Native methods (console.log, DOM APIs, http.Server) check the internal
315
+ // [[Receiver]] slot and throw "Illegal invocation" when called through a
316
+ // proxy. Unwrap the real target from the graph and retry as the receiver.
317
+ is: (trap, error) => trap === "apply" && isTypeErrorIllegalInvocation(error),
318
+ trap: "apply:native",
319
+ handle: (graph, fn, thisArg, argList) => {
320
+ const realThis = unwrap(graph, thisArg);
321
+ return {
322
+ args: [fn, realThis, argList],
323
+ result: Reflect.apply(fn, realThis, argList)
324
+ };
141
325
  }
142
326
  },
143
- set: {
144
- pre: ([target, key, value, receiver], wrap) => [
145
- target,
146
- key,
147
- wrap(value),
148
- receiver
149
- ]
150
- },
151
- apply: {
152
- // thisArg is wrapped normally (it's always a graph node).
153
- // Call arguments are wrapped with known — only existing graph nodes
154
- // get proxied; plain data passes through and is inlined by serialize().
155
- pre: ([target, thisArg, callArgs], wrap, known) => [
156
- target,
157
- wrap(thisArg),
158
- callArgs.map(known)
159
- ],
160
- post: (result, _args, wrap) => wrap(result)
161
- },
162
- construct: {
163
- pre: ([target, callArgs, newTarget], wrap) => [
164
- target,
165
- callArgs.map(wrap),
166
- newTarget
167
- ],
168
- post: (result, _args, wrap) => wrap(result)
327
+ {
328
+ // structuredClone and postMessage can't clone proxy objects — they throw a
329
+ // DataCloneError. Unwrap any proxy arguments to their real targets and retry.
330
+ is: (trap, error) => trap === "apply" && isDataCloneDOMException(error),
331
+ trap: "apply:structure",
332
+ handle: (graph, fn, thisArg, argList) => {
333
+ const unwrappedArgs = argList.map((arg) => unwrap(graph, arg));
334
+ return {
335
+ args: [fn, thisArg, unwrappedArgs],
336
+ result: Reflect.apply(fn, thisArg, unwrappedArgs)
337
+ };
338
+ }
169
339
  },
170
- defineProperty: {
171
- pre: (args, wrap) => {
172
- const [target, key, descriptor] = args;
173
- const patch = {};
174
- if (descriptor.value != null) patch.value = wrap(descriptor.value);
175
- if (typeof descriptor.get === "function")
176
- patch.get = wrap(descriptor.get);
177
- if (typeof descriptor.set === "function")
178
- patch.set = wrap(descriptor.set);
179
- return Object.keys(patch).length > 0 ? [target, key, { ...descriptor, ...patch }] : args;
340
+ {
341
+ // Private fields (#field) use brand checking — accessing #field on a proxy
342
+ // (rather than the original instance) throws "Cannot read private member".
343
+ // Unwrap the real instance from the graph and use it as the receiver.
344
+ is: (trap, error, bind) => bind !== false && trap === "apply" && isTypeErrorPrivateMember(error),
345
+ trap: "apply:private",
346
+ handle: (graph, fn, thisArg, argList) => {
347
+ const realThis = unwrap(graph, thisArg);
348
+ return {
349
+ args: [fn, realThis, argList],
350
+ result: Reflect.apply(fn, realThis, argList)
351
+ };
180
352
  }
181
353
  },
182
- getOwnPropertyDescriptor: {
183
- post: (result, _args, wrap) => {
184
- const desc = result;
185
- if (!desc) return result;
186
- const patch = {};
187
- if (desc.value != null) patch.value = wrap(desc.value);
188
- if (typeof desc.get === "function")
189
- patch.get = wrap(desc.get);
190
- if (typeof desc.set === "function")
191
- patch.set = wrap(desc.set);
192
- return Object.keys(patch).length > 0 ? { ...desc, ...patch } : result;
354
+ {
355
+ // A getter that reads a #private field hits the same brand check, but the
356
+ // apply retry doesn't apply here. Re-invoke Reflect.get with the real target
357
+ // as its own receiver so the brand check passes.
358
+ is: (trap, error, bind) => bind !== false && trap === "get" && isTypeErrorPrivateMember(error),
359
+ handle: (_graph, target, propertyKey) => ({
360
+ result: Reflect.get(target, propertyKey, target)
361
+ })
362
+ }
363
+ ];
364
+
365
+ // source/inspection.ts
366
+ function getTarget(pxy) {
367
+ return Graph.for(pxy)?.getByProxy(pxy)?.target ?? null;
368
+ }
369
+ function getProxyById(id, pxy) {
370
+ return Graph.for(pxy)?.getById(id)?.proxy;
371
+ }
372
+ function getOrigin(pxy) {
373
+ return Graph.for(pxy)?.getByProxy(pxy)?.origin ?? null;
374
+ }
375
+ function getAncestors(pxy) {
376
+ const graph = Graph.for(pxy);
377
+ if (!graph) return [];
378
+ const result = [];
379
+ let node = graph.getByProxy(pxy);
380
+ while (node) {
381
+ result.unshift({ proxy: node.proxy, origin: node.origin });
382
+ if (!node.origin) break;
383
+ const parentId = "parent" in node.origin ? node.origin.parent : node.origin.source;
384
+ node = graph.getById(parentId);
385
+ }
386
+ return result;
387
+ }
388
+ function getPath(pxy) {
389
+ const ancestors = getAncestors(pxy);
390
+ const parts = [];
391
+ for (const { origin: o } of ancestors) {
392
+ if (!o) continue;
393
+ if ("key" in o) {
394
+ parts.push(String(o.key));
395
+ } else {
396
+ if (parts.length > 0) {
397
+ parts[parts.length - 1] += "()";
398
+ } else {
399
+ parts.push("()");
400
+ }
193
401
  }
194
402
  }
195
- };
196
- function makeProxy(target, graph, config, origin) {
197
- if (allProxies.has(target)) return target;
403
+ return parts.join(".");
404
+ }
405
+
406
+ // source/format.ts
407
+ function resolve(id, proxy) {
408
+ if (!proxy) return id;
409
+ const p = getProxyById(id, proxy);
410
+ return p !== void 0 ? getPath(p) : id;
411
+ }
412
+ function display(v, proxy, limit = 80) {
413
+ if (v === null || v === void 0) return String(v);
414
+ if (typeof v !== "object") return String(v);
415
+ if (!Array.isArray(v) && "$proxy" in v)
416
+ return resolve(v.$proxy, proxy);
417
+ if (!Array.isArray(v) && "$unwrap" in v)
418
+ return `\u2193${resolve(v.$unwrap.$proxy, proxy)}`;
419
+ const raw = Array.isArray(v) ? `[${v.map((i) => display(i, proxy)).join(", ")}]` : JSON.stringify(v);
420
+ return raw.length > limit ? `${raw.slice(0, limit)}\u2026` : raw;
421
+ }
422
+ function format(rekording, proxy) {
423
+ const { id, trap, origin: origin2, args, result } = rekording;
424
+ if (origin2 && "parent" in origin2) {
425
+ const parent = resolve(origin2.parent, proxy);
426
+ const path = parent ? `${parent}.${origin2.key}` : String(origin2.key);
427
+ if (trap === "set") return `${path} = ${display(args[2], proxy)}`;
428
+ if (trap === "get") return `${path} \u2192 ${display(result, proxy)}`;
429
+ return `${trap} ${path}`;
430
+ }
431
+ if (origin2 && "source" in origin2) {
432
+ const path = resolve(origin2.source, proxy);
433
+ const callArgs = (Array.isArray(trap === "construct" ? args[1] : args[2]) ? trap === "construct" ? args[1] : args[2] : []).map((a) => display(a, proxy)).join(", ");
434
+ if (/^apply(:|$)/.test(trap))
435
+ return `${path}(${callArgs})`;
436
+ if (trap === "construct" || trap === "construct:native")
437
+ return `new ${path}(${callArgs})`;
438
+ }
439
+ return `${trap} on ${id}`;
440
+ }
441
+
442
+ // source/flugrekorder.ts
443
+ function makeProxy(target, graph, config, origin2) {
444
+ if (Graph.isProxy(target)) return target;
198
445
  const existing = graph.getByTarget(target);
199
446
  if (existing) return existing.proxy;
200
447
  if (target instanceof Promise) {
201
448
  const chained = target.then(
202
- (value) => isProxiable(value) ? makeProxy(value, graph, config, origin) : value
449
+ (value) => isProxiable(value) ? makeProxy(value, graph, config, origin2) : value
203
450
  );
204
451
  const id = graph.nextId();
205
- graph.register(chained, target, origin, id);
206
- graphOf.set(chained, graph);
452
+ graph.register(chained, target, origin2, id);
207
453
  return chained;
208
454
  }
209
455
  const proxyId = graph.nextId();
210
- let pxy;
211
456
  const traps = Object.getOwnPropertyNames(Reflect).filter((trap) => config.only === null || config.only.has(trap));
212
457
  const handler = Object.fromEntries(
213
458
  traps.map((trap) => [
214
459
  trap,
215
460
  (...rawArgs) => {
216
- const selfId = graph.getByProxy(pxy).id;
217
- const childOrigin = /get|set|defineProperty|getOwnPropertyDescriptor/.test(trap) ? {
461
+ const selfId = graph.getByTarget(target).id;
462
+ let childOrigin = /get|set|defineProperty|getOwnPropertyDescriptor/.test(trap) ? {
218
463
  trap,
219
464
  parent: selfId,
220
465
  key: rawArgs[1]
221
466
  } : /apply|construct/.test(trap) ? { trap, source: selfId } : null;
222
467
  const wrap = (v) => {
223
- if (!isProxiable(v) || allProxies.has(v))
468
+ if (!isProxiable(v) || Graph.isProxy(v))
224
469
  return v;
225
470
  if (!config.recursive) return v;
226
471
  return makeProxy(v, graph, config, childOrigin);
227
472
  };
228
473
  const known = (v) => {
229
474
  if (!isProxiable(v)) return v;
230
- if (allProxies.has(v)) return v;
475
+ if (Graph.isProxy(v)) return v;
231
476
  const existing2 = graph.getByTarget(v);
232
477
  if (existing2) return existing2.proxy;
233
478
  return v;
234
479
  };
235
- const spec = specs[trap] ?? {};
236
- const args = spec.pre ? spec.pre(rawArgs, wrap, known) : rawArgs;
237
- const result = Reflect[trap](...args);
238
- const output = spec.post ? spec.post(result, args, wrap) : result;
239
- config.write({
480
+ const spec = config.specs[trap] ?? {};
481
+ const preArgs = spec.pre ? spec.pre(rawArgs, wrap, known) : rawArgs;
482
+ let effectiveTrap = trap;
483
+ let effectiveArgs = preArgs;
484
+ let result;
485
+ try {
486
+ result = Reflect[trap](...preArgs);
487
+ } catch (e) {
488
+ const flow = retryFlows.find(
489
+ ({ is }) => is(trap, e, config.bind)
490
+ );
491
+ if (flow) {
492
+ const invoke = flow.handle;
493
+ const output2 = invoke(graph, ...preArgs);
494
+ if (flow.trap) {
495
+ effectiveTrap = flow.trap;
496
+ childOrigin = {
497
+ trap: flow.trap,
498
+ source: selfId
499
+ };
500
+ }
501
+ if (output2?.args) effectiveArgs = output2.args;
502
+ result = output2.result;
503
+ } else {
504
+ throw e;
505
+ }
506
+ }
507
+ const output = spec.post ? spec.post(result, effectiveArgs, wrap) : result;
508
+ const rekording = {
240
509
  id: graph.nextId(),
241
- trap,
242
- origin: serializeOrigin(childOrigin),
243
- args: args.map((arg) => serialize(arg, graph)),
244
- result: serialize(output, graph)
245
- });
510
+ trap: effectiveTrap,
511
+ origin: origin(childOrigin),
512
+ args: effectiveArgs.map(
513
+ (arg) => serialize(arg, graph, /* @__PURE__ */ new Set(), config.serial)
514
+ ),
515
+ result: serialize(output, graph, /* @__PURE__ */ new Set(), config.serial),
516
+ timestamp: Date.now()
517
+ };
518
+ if (!config.filter || config.filter(rekording))
519
+ config.write(rekording);
246
520
  return output;
247
521
  }
248
522
  ])
249
523
  );
250
- pxy = new Proxy(target, handler);
251
- graph.register(pxy, target, origin, proxyId);
252
- graphOf.set(pxy, graph);
253
- allProxies.add(pxy);
524
+ const pxy = new Proxy(target, handler);
525
+ graph.register(pxy, target, origin2, proxyId);
526
+ Graph.track(pxy);
254
527
  return pxy;
255
528
  }
256
529
  function create(target, options) {
257
- const { stream, callback } = options;
258
- const write = stream ? (r) => stream.write(`${JSON.stringify(r)}
259
- `) : (
260
- // biome-ignore lint/style/noNonNullAssertion: CreateOptions guarantees stream or callback is set — TypeScript cannot express this mutual exclusion
261
- callback
262
- );
530
+ const write = "stream" in options ? (r) => options.stream.write(`${JSON.stringify(r)}
531
+ `) : options.callback;
263
532
  const recursive = options.recursive !== false;
264
533
  const only = options.only ? new Set(options.only) : null;
534
+ const filter = options.filter ?? null;
535
+ const { redact: redact2 } = options;
536
+ const serial = {
537
+ depth: options.depth ?? Infinity,
538
+ redactors: redact2 ? Array.isArray(redact2) ? redact2 : [redact2] : [],
539
+ truncate: options.truncate ?? Infinity
540
+ };
265
541
  const graph = new Graph(options.id ?? 0);
266
- return makeProxy(target, graph, { write, recursive, only }, null);
542
+ const specs = makeSpecs(options.bind);
543
+ return makeProxy(
544
+ target,
545
+ graph,
546
+ { write, recursive, only, filter, serial, specs, bind: options.bind },
547
+ null
548
+ );
267
549
  }
268
550
  function isFlugrekorder(value) {
269
- return isProxiable(value) && allProxies.has(value);
270
- }
271
- function getTarget(pxy) {
272
- return graphOf.get(pxy)?.getByProxy(pxy)?.target ?? null;
273
- }
274
- function getProxyById(id, pxy) {
275
- return graphOf.get(pxy)?.getById(id)?.proxy;
276
- }
277
- function getOrigin(pxy) {
278
- return graphOf.get(pxy)?.getByProxy(pxy)?.origin ?? null;
279
- }
280
- function getAncestors(pxy) {
281
- const graph = graphOf.get(pxy);
282
- if (!graph) return [];
283
- const result = [];
284
- let node = graph.getByProxy(pxy);
285
- while (node) {
286
- result.unshift({ proxy: node.proxy, origin: node.origin });
287
- if (!node.origin) break;
288
- const parentId = "parent" in node.origin ? node.origin.parent : node.origin.source;
289
- node = graph.getById(parentId);
290
- }
291
- return result;
292
- }
293
- function getPath(pxy) {
294
- const ancestors = getAncestors(pxy);
295
- const parts = [];
296
- for (const { origin: o } of ancestors) {
297
- if (!o) continue;
298
- if ("key" in o) {
299
- parts.push(String(o.key));
300
- } else {
301
- if (parts.length > 0) {
302
- parts[parts.length - 1] += "()";
303
- } else {
304
- parts.push("()");
305
- }
306
- }
307
- }
308
- return parts.join(".");
551
+ return isProxiable(value) && Graph.isProxy(value);
309
552
  }
310
553
  export {
311
554
  create,
555
+ format,
312
556
  getAncestors,
313
557
  getOrigin,
314
558
  getPath,
315
559
  getProxyById,
316
560
  getTarget,
317
- isFlugrekorder
561
+ isFlugrekorder,
562
+ isProxiable
318
563
  };
319
564
  //# sourceMappingURL=flugrekorder.mjs.map