@expressive/inspect 0.1.1 → 0.3.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.
@@ -1,4 +1,6 @@
1
- import { Context, State } from "@expressive/mvc";
1
+ import { i as unsettled, n as tick, r as unreached, t as bracket } from "./bracket-BYmLIpQH.js";
2
+ import { Caught, Context, State } from "@expressive/mvc";
3
+ import { listener } from "@expressive/mvc/observable";
2
4
  import { isElement } from "@expressive/mvc/runtime";
3
5
 
4
6
  //#region src/serialize.ts
@@ -24,7 +26,7 @@ function walk(value, path) {
24
26
  let cur = value;
25
27
  for (const part of path.split(".")) {
26
28
  if (cur == null || typeof cur !== "object") return void 0;
27
- if (cur instanceof State) cur = entries(cur).get(part);
29
+ if (cur instanceof State) cur = part[0] == "_" ? Object.getOwnPropertyDescriptor(cur, part)?.get?.() : entries(cur).get(part);
28
30
  else if (cur instanceof Map) cur = cur.get(part);
29
31
  else cur = cur[part];
30
32
  }
@@ -36,6 +38,19 @@ function ref(state) {
36
38
  $type: state.constructor.name
37
39
  };
38
40
  }
41
+ /** Only the selected keys, read in one synchronous pass - a consistent snapshot. States keep their `$ref`. */
42
+ function project(value, select) {
43
+ if (select === true || value == null || typeof value !== "object") return serialize(value);
44
+ const items = value instanceof State ? void 0 : list(value);
45
+ if (items) {
46
+ const out = items.slice(0, MAX_ARRAY).map((row) => project(row, select));
47
+ if (items.length > MAX_ARRAY) out.push(`…+${items.length - MAX_ARRAY}`);
48
+ return out;
49
+ }
50
+ const out = value instanceof State ? ref(value) : {};
51
+ for (const key in select) out[key] = project(walk(value, key), select[key]);
52
+ return out;
53
+ }
39
54
  /** JSON-safe, size-capped view. Nested States collapse to `$ref`. */
40
55
  function serialize(value, depth = 2) {
41
56
  if (value instanceof State) {
@@ -193,6 +208,45 @@ const journal = {
193
208
  ...event
194
209
  }))).join("\n");
195
210
  },
211
+ summary(query = {}) {
212
+ const by = /* @__PURE__ */ new Map();
213
+ for (const frame of journal.frames(query)) for (const event of frame.events) {
214
+ if (!event.id) continue;
215
+ let entry = by.get(event.id);
216
+ if (!entry) by.set(event.id, entry = {
217
+ id: event.id,
218
+ type: event.type,
219
+ last: 0,
220
+ keys: {},
221
+ calls: {},
222
+ caught: 0,
223
+ hot: 0,
224
+ destroyed: false
225
+ });
226
+ entry.last = frame.seq;
227
+ if (event.kind === "destroy") entry.destroyed = true;
228
+ else if (event.kind === "call") entry.calls[event.key] = (entry.calls[event.key] || 0) + 1;
229
+ else if (event.kind === "caught") entry.caught++;
230
+ else if (event.kind === "hot") entry.hot++;
231
+ else {
232
+ const key = entry.keys[event.key] ||= { count: 0 };
233
+ key.count++;
234
+ if ("value" in event) key.value = event.value;
235
+ }
236
+ }
237
+ return [...by.values()].sort((a, b) => b.last - a.last);
238
+ },
239
+ hot(key, value) {
240
+ if (config.level === "off") return;
241
+ const event = {
242
+ id: "",
243
+ type: "vite",
244
+ key,
245
+ kind: "hot"
246
+ };
247
+ if (value !== void 0) event.value = value;
248
+ push(event);
249
+ },
196
250
  clear() {
197
251
  frames.length = 0;
198
252
  open = void 0;
@@ -236,19 +290,6 @@ function wants(state, key) {
236
290
  function recordsCalls() {
237
291
  return config.calls && config.level !== "off";
238
292
  }
239
- /** Run `work` with recording forced on; returns the frames it produced. */
240
- async function act(work) {
241
- const level = config.level;
242
- const start = seq;
243
- if (level === "off") config.level = "values";
244
- try {
245
- await work();
246
- await new Promise((resolve) => setTimeout(resolve, 0));
247
- } finally {
248
- config.level = level;
249
- }
250
- return journal.frames({ since: start });
251
- }
252
293
  function note(state, key, store) {
253
294
  const name = String(key);
254
295
  if (!wants(state, name)) return;
@@ -272,6 +313,32 @@ function noteCall(state, key, args) {
272
313
  if (config.level === "values") event.args = args.map((arg) => serialize(arg, 1));
273
314
  push(event);
274
315
  }
316
+ function noteCaught(error, name) {
317
+ const { state, key } = error;
318
+ if (!wants(state, key)) return;
319
+ const value = {
320
+ case: name,
321
+ message: error.message,
322
+ stack: error.stack,
323
+ handled: true
324
+ };
325
+ push({
326
+ id: String(state),
327
+ type: labelOf(state.constructor),
328
+ key: key ?? "",
329
+ kind: "caught",
330
+ value
331
+ });
332
+ return value;
333
+ }
334
+ function notePatch(state) {
335
+ if (wants(state)) push({
336
+ id: String(state),
337
+ type: labelOf(state.constructor),
338
+ key: "patch",
339
+ kind: "hot"
340
+ });
341
+ }
275
342
  function noteDestroy(state) {
276
343
  if (!wants(state)) return;
277
344
  push({
@@ -312,13 +379,69 @@ const Reaper = typeof FinalizationRegistry === "function" ? FinalizationRegistry
312
379
  const weak = (state) => typeof WeakRef === "function" ? new WeakRef(state) : { deref: () => state };
313
380
  const live = /* @__PURE__ */ new Map();
314
381
  const hooks = /* @__PURE__ */ new Map();
315
- const wrapped = /* @__PURE__ */ new WeakSet();
382
+ const CASES = [
383
+ "Destroyed",
384
+ "Inactive",
385
+ "Getter",
386
+ "Init",
387
+ "Effect"
388
+ ];
389
+ const COPIES = Symbol.for("@expressive/mvc");
390
+ const wrapped = /* @__PURE__ */ new WeakMap();
391
+ const REFRESH = Symbol.for("@expressive/mvc.refresh");
316
392
  const wrappers = /* @__PURE__ */ new WeakMap();
317
393
  const spans = /* @__PURE__ */ new WeakMap();
318
394
  const reaper = new Reaper(collected);
319
395
  let version = 0;
320
396
  let cached;
321
397
  let lost = 0;
398
+ let tally = counts();
399
+ let copies = 1;
400
+ let unwatch;
401
+ function counts() {
402
+ return {
403
+ Destroyed: 0,
404
+ Inactive: 0,
405
+ Getter: 0,
406
+ Init: 0,
407
+ Effect: 0
408
+ };
409
+ }
410
+ const noted = /* @__PURE__ */ new WeakMap();
411
+ function observe(error) {
412
+ const name = CASES.find((type) => error instanceof Caught[type]);
413
+ if (name) tally[name]++;
414
+ noted.set(error, noteCaught(error, name || "Caught"));
415
+ return error;
416
+ }
417
+ function unhandled(error) {
418
+ if (!noted.has(error)) observe(error);
419
+ const event = noted.get(error);
420
+ if (event) event.handled = false;
421
+ return error;
422
+ }
423
+ function clearCaught() {
424
+ tally = counts();
425
+ }
426
+ /** Count loaded copies of mvc from the list each one joins on first construction; warn once on a second. */
427
+ function watchCopies() {
428
+ const list = globalThis[COPIES] ||= [];
429
+ const { push } = list;
430
+ const check = () => {
431
+ const was = copies;
432
+ copies = new Set([State, ...list]).size;
433
+ if (copies > 1 && was === 1) console.warn(`${copies} copies of @expressive/mvc are loaded - inspect sees only the one it imports.`);
434
+ };
435
+ list.push = (...items) => {
436
+ const length = push.apply(list, items);
437
+ check();
438
+ return length;
439
+ };
440
+ check();
441
+ unwatch = () => {
442
+ list.push = push;
443
+ };
444
+ }
322
445
  /** Registered instances still reachable, claimed or not. */
323
446
  function registered() {
324
447
  return [...live.values()].map((row) => row.held ?? row.ref.deref()).filter((state) => !!state);
@@ -424,15 +547,16 @@ var Instance = class Instance {
424
547
  if (deep) return deep;
425
548
  }
426
549
  }
427
- get(path) {
428
- return serialize(walk(this.state, path));
550
+ get(path, select) {
551
+ const value = walk(this.state, path);
552
+ return select ? project(value, select) : serialize(value);
429
553
  }
430
554
  model() {
431
555
  return describe(this.state, ownership());
432
556
  }
433
557
  /** Run `work`, settle, and return the frames it produced. */
434
- act(work) {
435
- return act(() => work(this.state));
558
+ act(work, options) {
559
+ return act(() => work(this.state), options);
436
560
  }
437
561
  /** Call `fn` on each update, and with `null` on destroy; `keys` narrows updates. Returns unsubscribe. */
438
562
  watch(fn, keys) {
@@ -453,38 +577,56 @@ var Instance = class Instance {
453
577
  }
454
578
  };
455
579
  function attach(Type = State) {
456
- if (!hooks.has(Type)) hooks.set(Type, Type.on(function() {
457
- const self = this.is;
458
- const id = String(self);
459
- const span = {
460
- since: Date.now(),
461
- claimed: false,
462
- settled: false
463
- };
464
- seen(self.constructor);
465
- live.set(id, { ref: weak(self) });
466
- spans.set(self, span);
467
- reaper.register(self, id, self);
468
- setTimeout(() => {
469
- span.settled = true;
470
- }, 0);
471
- version++;
472
- if (recordsCalls()) wrap(self);
473
- mounts(self);
474
- const stop = self.set((key) => {
475
- const store = entries(self);
476
- if (typeof key === "string" && typeof store.get(key) === "object") version++;
477
- note(self, key, store);
478
- });
479
- return () => {
480
- stop();
481
- live.delete(id);
482
- reaper.unregister(self);
483
- span.until = Date.now();
580
+ if (!unwatch) watchCopies();
581
+ if (!hooks.has(Type)) {
582
+ const observed = /* @__PURE__ */ new Map();
583
+ const stopCatch = Type.on({ catch: unhandled });
584
+ const stopSetup = Type.on(function() {
585
+ const self = this.is;
586
+ const T = self.constructor;
587
+ const id = String(self);
588
+ const span = {
589
+ since: Date.now(),
590
+ claimed: false,
591
+ settled: false
592
+ };
593
+ if (!observed.has(T)) observed.set(T, T.on({ catch: observe }));
594
+ seen(T);
595
+ live.set(id, { ref: weak(self) });
596
+ spans.set(self, span);
597
+ reaper.register(self, id, self);
598
+ setTimeout(() => {
599
+ span.settled = true;
600
+ }, 0);
484
601
  version++;
485
- noteDestroy(self);
486
- };
487
- }));
602
+ if (recordsCalls()) wrap(self);
603
+ mounts(self);
604
+ const unpatch = listener(self, () => {
605
+ unwrap(self);
606
+ if (recordsCalls()) wrap(self);
607
+ notePatch(self);
608
+ }, REFRESH);
609
+ const stop = self.set((key) => {
610
+ const store = entries(self);
611
+ if (typeof key === "string" && typeof store.get(key) === "object") version++;
612
+ note(self, key, store);
613
+ });
614
+ return () => {
615
+ stop();
616
+ unpatch();
617
+ live.delete(id);
618
+ reaper.unregister(self);
619
+ span.until = Date.now();
620
+ version++;
621
+ noteDestroy(self);
622
+ };
623
+ });
624
+ hooks.set(Type, () => {
625
+ for (const stop of observed.values()) stop();
626
+ stopCatch();
627
+ stopSetup();
628
+ });
629
+ }
488
630
  return () => {
489
631
  hooks.get(Type)?.();
490
632
  hooks.delete(Type);
@@ -496,6 +638,10 @@ function detach() {
496
638
  live.clear();
497
639
  cached = void 0;
498
640
  lost = 0;
641
+ tally = counts();
642
+ copies = 1;
643
+ unwatch?.();
644
+ unwatch = void 0;
499
645
  journal.reset();
500
646
  forget();
501
647
  }
@@ -504,7 +650,17 @@ function find(target) {
504
650
  const byId = live.get(target);
505
651
  const held = byId && (byId.held ?? byId.ref.deref());
506
652
  if (held) return Instance.of(held);
507
- for (const pool of [mainline(), abandoned()]) for (const state of pool) if (seen(state.constructor).type === target) return Instance.of(state);
653
+ const types = /* @__PURE__ */ new Map();
654
+ let first;
655
+ for (const pool of [mainline(), abandoned()]) for (const state of pool) {
656
+ const Type = state.constructor;
657
+ const info = seen(Type);
658
+ if (info.type !== target) continue;
659
+ first ??= state;
660
+ types.set(Type, info.typeId);
661
+ }
662
+ if (types.size > 1) throw new Error(`${target} matches ${types.size} classes (${[...types.values()].join(", ")}) - address by instance id or owner path, or label() one. models() lists their construction sites.`);
663
+ return first && Instance.of(first);
508
664
  }
509
665
  function instances() {
510
666
  return [...mainline()].map(Instance.of);
@@ -517,11 +673,13 @@ function* abandoned() {
517
673
  const parents = ownership();
518
674
  for (const state of registered()) if (orphaned(state, parents)) yield state;
519
675
  }
520
- /** Counts worth a look: live orphans, and unclaimed instances the collector already reaped. */
521
- function warnings() {
676
+ /** Counts worth a look before trusting what inspect shows. */
677
+ function health() {
522
678
  return {
523
679
  orphans: orphans().length,
524
- collected: lost
680
+ collected: lost,
681
+ copies,
682
+ caught: { ...tally }
525
683
  };
526
684
  }
527
685
  function roots() {
@@ -549,10 +707,20 @@ function tree() {
549
707
  }
550
708
  return out;
551
709
  }
552
- function get(address) {
710
+ /** Run `work` recording values; returns the frames it produced once `until` holds and activity goes quiet. */
711
+ async function act(work, options = {}) {
712
+ const { frames, settled, pending, missing, timeout } = await bracket({
713
+ ...journal,
714
+ get
715
+ }, work, tick, options, true);
716
+ if (pending.length) throw unreached(timeout, pending, missing, frames);
717
+ if (!settled) unsettled(timeout);
718
+ return frames;
719
+ }
720
+ function get(address, select) {
553
721
  if (!address) return models();
554
722
  const { target, path } = parsePath(address);
555
- return find(target)?.get(path);
723
+ return find(target)?.get(path, select);
556
724
  }
557
725
  function set(address, value) {
558
726
  const { target, path } = parsePath(address);
@@ -602,20 +770,34 @@ function describe(state, parents) {
602
770
  return model;
603
771
  }
604
772
  function wrap(state) {
605
- if (wrapped.has(state)) return;
606
- wrapped.add(state);
773
+ let keys = wrapped.get(state);
774
+ if (!keys) wrapped.set(state, keys = new Set(["render"]));
607
775
  const target = state;
608
- const seenKeys = new Set(["render"]);
609
776
  for (let proto = Object.getPrototypeOf(state); proto !== State.prototype; proto = Object.getPrototypeOf(proto)) for (const [key, desc] of Object.entries(Object.getOwnPropertyDescriptors(proto))) {
610
- if (seenKeys.has(key) || typeof desc.get !== "function" || desc.get !== desc.set) continue;
611
- seenKeys.add(key);
612
- const original = target[key];
777
+ if (keys.has(key) || typeof desc.get !== "function" || desc.get !== desc.set) continue;
778
+ keys.add(key);
613
779
  target[key] = function(...args) {
614
780
  noteCall(state, key, args);
615
- return original.apply(this, args);
781
+ return latest(state, key).apply(this, args);
616
782
  };
617
783
  }
618
784
  }
785
+ /** Drop wrappers of methods a hot patch removed. */
786
+ function unwrap(state) {
787
+ const keys = wrapped.get(state);
788
+ if (keys) {
789
+ for (const key of keys) if (key != "render" && !(key in Object.getPrototypeOf(state))) {
790
+ delete state[key];
791
+ keys.delete(key);
792
+ }
793
+ }
794
+ }
795
+ /** A method's current implementation - through its accessor, so a hot patch is followed. */
796
+ function latest(state, key) {
797
+ let proto = Object.getPrototypeOf(state);
798
+ while (!Object.prototype.hasOwnProperty.call(proto, key)) proto = Object.getPrototypeOf(proto);
799
+ return Object.getOwnPropertyDescriptor(proto, key).get.call(state);
800
+ }
619
801
  function ownership() {
620
802
  if (cached?.version !== version) {
621
803
  const parents = /* @__PURE__ */ new Map();
@@ -637,5 +819,5 @@ function own(parents, owner, value) {
637
819
  }
638
820
 
639
821
  //#endregion
640
- export { label as _, find as a, serialize as b, models as c, set as d, tree as f, journal as g, act as h, detach as i, orphans as l, wrapAll as m, attach as n, get as o, warnings as p, call as r, instances as s, Instance as t, roots as u, resolve as v, parsePath as y };
641
- //# sourceMappingURL=inspect-D4NC5Mx5.js.map
822
+ export { journal as _, clearCaught as a, parsePath as b, get as c, models as d, orphans as f, wrapAll as g, tree as h, call as i, health as l, set as m, act as n, detach as o, roots as p, attach as r, find as s, Instance as t, instances as u, label as v, serialize as x, resolve as y };
823
+ //# sourceMappingURL=inspect-DXj1Vvhi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect-DXj1Vvhi.js","names":[],"sources":["../src/serialize.ts","../src/types.ts","../src/journal.ts","../src/inspect.ts"],"sourcesContent":["import { State } from '@expressive/mvc';\n\nconst MAX_STRING = 240;\nconst MAX_ARRAY = 24;\nconst MAX_KEYS = 40;\n\nexport type Address = { target: string; path?: string };\n\nexport function parsePath(raw: string): Address {\n const trimmed = raw.trim();\n const dot = trimmed.indexOf('.');\n if (dot <= 0) return { target: trimmed };\n return { target: trimmed.slice(0, dot), path: trimmed.slice(dot + 1) };\n}\n\n/** Raw stored entries of a State - never reads through accessors. */\nexport function entries(state: State): Map<string, unknown> {\n return new Map(state);\n}\n\n/** Walk `path` without triggering getters, factories, or suspense. */\nexport function walk(value: unknown, path?: string): unknown {\n if (!path) return value;\n let cur: unknown = value;\n for (const part of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return undefined;\n if (cur instanceof State)\n cur = part[0] == '_' ? Object.getOwnPropertyDescriptor(cur, part)?.get?.() : entries(cur).get(part);\n else if (cur instanceof Map) cur = cur.get(part);\n else cur = (cur as Record<string, unknown>)[part];\n }\n return cur;\n}\n\nexport function ref(state: State) {\n return { $ref: String(state), $type: state.constructor.name };\n}\n\n/** `true` takes a value as `serialize` would; an object picks keys and descends, applying to each element of a list. */\nexport type Select = true | { [key: string]: Select };\n\n/** Only the selected keys, read in one synchronous pass - a consistent snapshot. States keep their `$ref`. */\nexport function project(value: unknown, select: Select): unknown {\n if (select === true || value == null || typeof value !== 'object') return serialize(value);\n\n const items = value instanceof State ? undefined : list(value);\n\n if (items) {\n const out = items.slice(0, MAX_ARRAY).map((row) => project(row, select));\n if (items.length > MAX_ARRAY) out.push(`…+${items.length - MAX_ARRAY}`);\n return out;\n }\n\n const out: Record<string, unknown> = value instanceof State ? ref(value) : {};\n for (const key in select) out[key] = project(walk(value, key), select[key]);\n return out;\n}\n\n/** JSON-safe, size-capped view. Nested States collapse to `$ref`. */\nexport function serialize(value: unknown, depth = 2): unknown {\n if (value instanceof State) {\n const out: Record<string, unknown> = ref(value);\n for (const [key, child] of [...entries(value)].slice(0, MAX_KEYS))\n out[key] = write(child, depth - 1);\n return out;\n }\n return write(value, depth);\n}\n\nfunction write(value: unknown, depth: number): unknown {\n if (value == null || typeof value === 'boolean') return value;\n if (typeof value === 'number') return Number.isFinite(value) ? value : String(value);\n if (typeof value === 'string')\n return value.length > MAX_STRING ? `${value.slice(0, MAX_STRING - 1)}…` : value;\n if (typeof value === 'bigint') return `${value}n`;\n if (typeof value !== 'object') return undefined;\n if (value instanceof State) return ref(value);\n if (value instanceof Date) return value.toISOString();\n if (value instanceof Error) return { name: value.name, message: value.message };\n if (typeof (value as PromiseLike<unknown>).then === 'function') return '(pending)';\n\n const items = list(value);\n\n if (items) {\n if (depth <= 0) return `[${items.length}]`;\n const out = items.slice(0, MAX_ARRAY).map((row) => write(row, depth - 1));\n if (items.length > MAX_ARRAY) out.push(`…+${items.length - MAX_ARRAY}`);\n return out;\n }\n\n const pairs = value instanceof Map\n ? [...value].map(([k, v]) => [String(k), v] as const)\n : Object.entries(value);\n\n if (depth <= 0) return `{${pairs.length}}`;\n\n const out: Record<string, unknown> = {};\n for (const [key, child] of pairs.slice(0, MAX_KEYS)) {\n if (key === 'is') continue;\n const next = write(child, depth - 1);\n if (next !== undefined) out[key] = next;\n }\n if (pairs.length > MAX_KEYS) out['…'] = pairs.length - MAX_KEYS;\n return out;\n}\n\nfunction list(value: object): unknown[] | undefined {\n if (Array.isArray(value)) return value;\n if (value instanceof Map) return undefined;\n if (typeof (value as Iterable<unknown>)[Symbol.iterator] === 'function')\n return [...(value as Iterable<unknown>)];\n return undefined;\n}\n","import { State } from '@expressive/mvc';\n\nexport interface TypeInfo {\n /** Opaque, stable for the life of the process. */\n typeId: string;\n /** Resolved display name - see `label`. */\n type: string;\n /** Construction stack captured at first sight, for a source-map resolver. */\n site: string;\n}\n\nconst info = new Map<typeof State, TypeInfo>();\nconst labels = new Map<typeof State, string>();\nconst names = new Map<string, string>();\nlet count = 0;\n\nfunction register(Type: typeof State): TypeInfo {\n let row = info.get(Type);\n if (!row) {\n const site = String(new Error().stack).split('\\n').slice(1, 16).join('\\n');\n info.set(Type, (row = { typeId: `T${++count}`, type: '', site }));\n }\n return row;\n}\n\nexport function seen(Type: typeof State): TypeInfo {\n const row = register(Type);\n row.type = labelOf(Type);\n return { ...row };\n}\n\nexport function labelOf(Type: typeof State): string {\n const row = register(Type);\n const explicit = labels.get(Type) ?? (Type as { displayName?: string }).displayName;\n if (explicit) return explicit;\n const named = names.get(row.typeId) ?? names.get(row.site);\n if (named) return named;\n return Type.name.length > 2 ? Type.name : row.typeId;\n}\n\nexport function label(Type: typeof State, name: string): void {\n labels.set(Type, name);\n}\n\n/** Supply resolved names keyed by `typeId` or `site`, e.g. from a source-map pass. */\nexport function resolve(table: Record<string, string>): void {\n for (const [key, name] of Object.entries(table)) names.set(key, name);\n}\n\nexport function forget(): void {\n info.clear();\n labels.clear();\n names.clear();\n count = 0;\n}\n","import { Caught, State } from '@expressive/mvc';\n\nimport { parsePath, serialize } from './serialize';\nimport { labelOf, seen } from './types';\n\nexport type Level = 'off' | 'keys' | 'values';\n\nexport interface Options {\n level?: Level;\n /** Labels to record. */\n types?: string[];\n /** `Type.key` addresses to record - label, `typeId`, or instance id on the left, property on the right. */\n paths?: string[];\n /** Property names to record on any type. */\n keys?: string[];\n /** Also record method calls (wraps instance methods except `render`). */\n calls?: boolean;\n}\n\nexport interface Event {\n id: string;\n type: string;\n key: string;\n kind: 'update' | 'event' | 'call' | 'destroy' | 'caught' | 'hot';\n value?: unknown;\n args?: unknown[];\n}\n\nexport interface Frame {\n seq: number;\n at: number;\n /** Frame whose flush scheduled the work that opened this one. */\n cause?: number;\n events: Event[];\n}\n\nexport interface Summary {\n id: string;\n type: string;\n /** Seq of the last frame touching this instance. */\n last: number;\n /** Updates and events per key, with the last recorded value at `values` level. */\n keys: Record<string, { count: number; value?: unknown }>;\n calls: Record<string, number>;\n /** `caught` reports. */\n caught: number;\n /** Hot patches applied to it. */\n hot: number;\n destroyed: boolean;\n}\n\nexport interface Query {\n since?: number;\n type?: string;\n id?: string;\n key?: string;\n cause?: number;\n}\n\nconst FRAME_CAP = 500;\n\nconst frames: Frame[] = [];\nconst config: Required<Options> = { level: 'off', types: [], paths: [], keys: [], calls: false };\nlet seq = 0;\nlet open: Frame | undefined;\nlet cause: number | undefined;\n\nexport const journal = {\n record(options: Options = {}): Required<Options> {\n Object.assign(config, options);\n if (!options.level && options.calls && config.level === 'off') config.level = 'keys';\n return { ...config, types: [...config.types], paths: [...config.paths], keys: [...config.keys] };\n },\n\n frames(query: Query = {}): Frame[] {\n const out: Frame[] = [];\n for (const frame of frames) {\n if (query.since !== undefined && frame.seq <= query.since) continue;\n if (query.cause !== undefined && frame.cause !== query.cause) continue;\n const events = frame.events.filter((e) => matches(e, query));\n if (events.length) out.push({ ...frame, events });\n }\n return out;\n },\n\n history(query: Query): Array<{ seq: number; at: number; event: Event }> {\n const out = [];\n for (const frame of journal.frames(query))\n for (const event of frame.events) out.push({ seq: frame.seq, at: frame.at, event });\n return out;\n },\n\n /** Frames reachable from `seq` through `cause` links, in order. */\n downstream(from: number): Frame[] {\n const roots = new Set([from]);\n return frames.filter((frame) => {\n if (frame.cause === undefined || !roots.has(frame.cause)) return false;\n roots.add(frame.seq);\n return true;\n });\n },\n\n /** Current sequence - pass as `since` to read only what follows. */\n seq(): number {\n return seq;\n },\n\n /** One event per line, for bulk export to a sidecar. */\n export(query: Query = {}): string {\n return journal\n .frames(query)\n .flatMap((frame) =>\n frame.events.map((event) =>\n JSON.stringify({ seq: frame.seq, at: frame.at, cause: frame.cause, ...event })\n )\n )\n .join('\\n');\n },\n\n /** Per-instance digest of recorded frames, most recently active first. */\n summary(query: Query = {}): Summary[] {\n const by = new Map<string, Summary>();\n\n for (const frame of journal.frames(query))\n for (const event of frame.events) {\n if (!event.id) continue;\n\n let entry = by.get(event.id);\n\n if (!entry) by.set(event.id, (entry = { id: event.id, type: event.type, last: 0, keys: {}, calls: {}, caught: 0, hot: 0, destroyed: false }));\n\n entry.last = frame.seq;\n\n if (event.kind === 'destroy') entry.destroyed = true;\n else if (event.kind === 'call') entry.calls[event.key] = (entry.calls[event.key] || 0) + 1;\n else if (event.kind === 'caught') entry.caught++;\n else if (event.kind === 'hot') entry.hot++;\n else {\n const key = (entry.keys[event.key] ||= { count: 0 });\n key.count++;\n if ('value' in event) key.value = event.value;\n }\n }\n\n return [...by.values()].sort((a, b) => b.last - a.last);\n },\n\n /**\n * Record a page-level hot update: `key` names it (`update`, `reload`), `value`\n * its detail. Recorded unfiltered while the journal is on.\n */\n hot(key: string, value?: unknown): void {\n if (config.level === 'off') return;\n\n const event: Event = { id: '', type: 'vite', key, kind: 'hot' };\n if (value !== undefined) event.value = value;\n push(event);\n },\n\n clear(): void {\n frames.length = 0;\n open = undefined;\n cause = undefined;\n seq = 0;\n },\n\n reset(): void {\n journal.clear();\n Object.assign(config, { level: 'off', types: [], paths: [], keys: [], calls: false });\n }\n};\n\nfunction matches(event: Event, query: Query) {\n return (\n (!query.type || event.type === query.type) &&\n (!query.id || event.id === query.id) &&\n (!query.key || event.key === query.key)\n );\n}\n\n/** Filters OR together; none set records everything. Without a key only type-level filters apply. */\nexport function wants(state: State, key?: string): boolean {\n if (config.level === 'off') return false;\n\n const { types, paths, keys } = config;\n if (!types.length && !paths.length && !keys.length) return true;\n\n const Type = state.constructor as typeof State;\n const label = labelOf(Type);\n if (types.includes(label)) return true;\n if (key !== undefined && keys.includes(key)) return true;\n\n const targets = [label, seen(Type).typeId, String(state)];\n for (const address of paths) {\n const { target, path } = parsePath(address);\n if (targets.includes(target) && (key === undefined || path === key)) return true;\n }\n return false;\n}\n\nexport function recordsCalls(): boolean {\n return config.calls && config.level !== 'off';\n}\n\n\nexport function note(state: State, key: unknown, store: Map<string, unknown>): void {\n const name = String(key);\n if (!wants(state, name)) return;\n\n const event: Event = {\n id: String(state),\n type: labelOf(state.constructor as typeof State),\n key: name,\n kind: typeof key === 'string' && store.has(key) ? 'update' : 'event'\n };\n\n if (config.level === 'values' && event.kind === 'update')\n event.value = serialize(store.get(name), 1);\n\n push(event);\n}\n\nexport function noteCall(state: State, key: string, args: unknown[]): void {\n if (!recordsCalls() || !wants(state, key)) return;\n\n const event: Event = { id: String(state), type: labelOf(state.constructor as typeof State), key, kind: 'call' };\n if (config.level === 'values') event.args = args.map((arg) => serialize(arg, 1));\n push(event);\n}\n\nexport function noteCaught(error: Caught, name: string): { handled: boolean } | undefined {\n const { state, key } = error;\n if (!wants(state, key)) return;\n const value = { case: name, message: error.message, stack: error.stack, handled: true };\n push({ id: String(state), type: labelOf(state.constructor as typeof State), key: key ?? '', kind: 'caught', value });\n return value;\n}\n\nexport function notePatch(state: State): void {\n if (wants(state)) push({ id: String(state), type: labelOf(state.constructor as typeof State), key: 'patch', kind: 'hot' });\n}\n\nexport function noteDestroy(state: State): void {\n if (!wants(state)) return;\n push({ id: String(state), type: labelOf(state.constructor as typeof State), key: '', kind: 'destroy' });\n}\n\nfunction push(event: Event) {\n if (!open) {\n const frame: Frame = { seq: ++seq, at: Date.now(), events: [] };\n if (cause !== undefined) frame.cause = cause;\n open = frame;\n frames.push(frame);\n if (frames.length > FRAME_CAP) frames.splice(0, frames.length - FRAME_CAP);\n queueMicrotask(() => {\n open = undefined;\n cause = frame.seq;\n queueMicrotask(() => {\n if (seq === frame.seq) cause = undefined;\n });\n });\n }\n open.events.push(event);\n}\n","import { Caught, Context, State } from '@expressive/mvc';\nimport { listener } from '@expressive/mvc/observable';\nimport { isElement } from '@expressive/mvc/runtime';\n\nimport { journal, note, noteCall, noteCaught, noteDestroy, notePatch, recordsCalls, type Frame, type Query } from './journal';\nimport { entries, parsePath, project, serialize, walk, type Select } from './serialize';\nimport { bracket } from './bracket';\nimport { tick, unreached, unsettled, type Act } from './settle';\nimport { forget, seen, type TypeInfo } from './types';\n\nexport interface Model extends TypeInfo {\n id: string;\n parent?: string;\n /** Keys with a stored value. */\n keys: string[];\n /** Declared keys with no stored value yet - lazy, pending, or uncomputed. */\n absent: string[];\n}\n\nexport interface Node {\n id: string;\n type: string;\n children: Node[];\n}\n\ninterface Span {\n since: number;\n until?: number;\n claimed: boolean;\n settled: boolean;\n}\n\ninterface Row {\n ref: { deref(): State | undefined };\n held?: State;\n}\n\nconst Reaper: typeof FinalizationRegistry =\n typeof FinalizationRegistry === 'function'\n ? FinalizationRegistry\n : (class {\n register() {}\n unregister() {}\n } as unknown as typeof FinalizationRegistry);\n\nconst weak = (state: State): Row['ref'] =>\n typeof WeakRef === 'function' ? new WeakRef(state) : { deref: () => state };\n\nconst live = new Map<string, Row>();\nconst hooks = new Map<typeof State, () => void>();\n\nconst CASES = ['Destroyed', 'Inactive', 'Getter', 'Init', 'Effect'] as const;\nconst COPIES = Symbol.for('@expressive/mvc');\n\ntype Case = (typeof CASES)[number];\nconst wrapped = new WeakMap<State, Set<string>>();\nconst REFRESH = Symbol.for('@expressive/mvc.refresh');\nconst wrappers = new WeakMap<State, Instance>();\nconst spans = new WeakMap<State, Span>();\nconst reaper = new Reaper<string>(collected);\n\nlet version = 0;\nlet cached: { version: number; parents: Map<State, State> } | undefined;\nlet lost = 0;\nlet tally = counts();\nlet copies = 1;\nlet unwatch: (() => void) | undefined;\n\nfunction counts(): Record<Case, number> {\n return { Destroyed: 0, Inactive: 0, Getter: 0, Init: 0, Effect: 0 };\n}\n\nconst noted = new WeakMap<Caught, { handled: boolean } | undefined>();\n\nfunction observe(error: Caught) {\n const name = CASES.find((type) => error instanceof Caught[type]);\n if (name) tally[name]++;\n noted.set(error, noteCaught(error, name || 'Caught'));\n return error;\n}\n\nfunction unhandled(error: Caught) {\n if (!noted.has(error)) observe(error);\n const event = noted.get(error);\n if (event) event.handled = false;\n return error;\n}\n\nexport function clearCaught(): void {\n tally = counts();\n}\n\n/** Count loaded copies of mvc from the list each one joins on first construction; warn once on a second. */\nfunction watchCopies() {\n const list = ((globalThis as { [COPIES]?: unknown[] })[COPIES] ||= []);\n const { push } = list;\n const check = () => {\n const was = copies;\n copies = new Set([State, ...list]).size;\n if (copies > 1 && was === 1)\n console.warn(`${copies} copies of @expressive/mvc are loaded - inspect sees only the one it imports.`);\n };\n\n list.push = (...items) => {\n const length = push.apply(list, items);\n check();\n return length;\n };\n\n check();\n unwatch = () => {\n list.push = push;\n };\n}\n\n/** Registered instances still reachable, claimed or not. */\nfunction registered(): State[] {\n return [...live.values()]\n .map((row) => row.held ?? row.ref.deref())\n .filter((state): state is State => !!state);\n}\n\n/** Instances on the mainline: claimed, or too young to judge, or every one when no host renders. */\nfunction* mainline(): Generator<State> {\n const parents = ownership();\n for (const state of registered()) if (!orphaned(state, parents)) yield state;\n}\n\nfunction orphaned(state: State, parents: Map<State, State>, seen = new Set<State>()): boolean {\n const span = spans.get(state)!;\n if (span.claimed || !span.settled || !hosted()) return false;\n if (provided(state)) {\n claim(state);\n return false;\n }\n const owner = parents.get(state);\n if (!owner || seen.has(owner)) return true;\n seen.add(state);\n if (orphaned(owner, parents, seen)) return true;\n if (spans.get(owner)!.claimed) claim(state);\n return false;\n}\n\nfunction claim(state: State) {\n const span = spans.get(state)!;\n if (span.claimed) return;\n span.claimed = true;\n const row = live.get(String(state));\n if (row) {\n row.held = state;\n reaper.unregister(state);\n }\n version++;\n}\n\n/** A `static global` instance currently holding its slot in the root context. */\nfunction provided(state: State): boolean {\n const type = state.constructor as typeof State;\n const global = typeof type.global === 'function' ? type.global(state) : type.global;\n if (!global) return false;\n for (const set of Context.root.provide.values())\n if (set) for (const [member] of set) if (member === state) return true;\n return false;\n}\n\nfunction hosted(): boolean {\n try {\n isElement(null);\n return true;\n } catch {\n return false;\n }\n}\n\n/** A registered, unclaimed instance was garbage collected - it was abandoned. */\nexport function collected(id: string): void {\n if (!live.delete(id)) return;\n lost++;\n version++;\n}\n\n/** Navigable view of one instance - identity, ownership, reads, observation. One per state; outlives it. */\nexport class Instance {\n private constructor(readonly state: State) {}\n\n static of(state: State): Instance {\n let instance = wrappers.get(state);\n if (!instance) wrappers.set(state, (instance = new Instance(state)));\n return instance;\n }\n\n get id() {\n return String(this.state);\n }\n\n get type() {\n return seen(this.state.constructor as typeof State).type;\n }\n\n get alive() {\n return live.has(this.id);\n }\n\n /** Reached by a host commit (`mount`), a claimed owner, or `static global`. Always true without a host. */\n get claimed() {\n return !orphaned(this.state, ownership());\n }\n\n /** Registration time (ms). */\n get since() {\n return spans.get(this.state)!.since;\n }\n\n /** Destruction time (ms), once destroyed. */\n get until() {\n return spans.get(this.state)!.until;\n }\n\n get parent(): Instance | undefined {\n const owner = ownership().get(this.state);\n return owner && Instance.of(owner);\n }\n\n get children(): Instance[] {\n const parents = ownership();\n return [...registered()]\n .filter((state) => parents.get(state) === this.state)\n .map(Instance.of);\n }\n\n /** First instance in this subtree, depth-first, matching `where` (a label or predicate). */\n find(where: string | ((instance: Instance) => boolean)): Instance | undefined {\n const test = typeof where === 'string' ? (h: Instance) => h.type === where : where;\n for (const child of this.children) {\n if (test(child)) return child;\n const deep = child.find(test);\n if (deep) return deep;\n }\n return undefined;\n }\n\n get(path?: string, select?: Select): unknown {\n const value = walk(this.state, path);\n return select ? project(value, select) : serialize(value);\n }\n\n model(): Model {\n return describe(this.state, ownership());\n }\n\n /** Run `work`, settle, and return the frames it produced. */\n act(work: (state: State) => unknown, options?: Act): Promise<Frame[]> {\n return act(() => work(this.state), options);\n }\n\n /** Call `fn` on each update, and with `null` on destroy; `keys` narrows updates. Returns unsubscribe. */\n watch(fn: (key: string | null) => void, keys?: string[]): () => void {\n const updates = this.state.set((key) => {\n if (typeof key === 'string' && (!keys || keys.includes(key))) fn(key);\n });\n const destroy = this.state.get(null, () => fn(null));\n return () => {\n updates();\n destroy();\n };\n }\n\n frames(query: Query = {}): Frame[] {\n return journal.frames({ ...query, id: this.id });\n }\n}\n\nexport function attach(Type: typeof State = State): () => void {\n if (!unwatch) watchCopies();\n\n if (!hooks.has(Type)) {\n const observed = new Map<typeof State, () => void>();\n const stopCatch = Type.on({ catch: unhandled });\n const stopSetup = Type.on(function (this: State) {\n const self = this.is;\n const T = self.constructor as typeof State;\n const id = String(self);\n const span: Span = { since: Date.now(), claimed: false, settled: false };\n if (!observed.has(T)) observed.set(T, T.on({ catch: observe }));\n seen(T);\n live.set(id, { ref: weak(self) });\n spans.set(self, span);\n reaper.register(self, id, self);\n setTimeout(() => {\n span.settled = true;\n }, 0);\n version++;\n if (recordsCalls()) wrap(self);\n mounts(self);\n const unpatch = listener(self, () => {\n unwrap(self);\n if (recordsCalls()) wrap(self);\n notePatch(self);\n }, REFRESH);\n const stop = self.set((key) => {\n const store = entries(self);\n if (typeof key === 'string' && typeof store.get(key) === 'object') version++;\n note(self, key, store);\n });\n return () => {\n stop();\n unpatch();\n live.delete(id);\n reaper.unregister(self);\n span.until = Date.now();\n version++;\n noteDestroy(self);\n };\n });\n\n hooks.set(Type, () => {\n for (const stop of observed.values()) stop();\n stopCatch();\n stopSetup();\n });\n }\n\n return () => {\n hooks.get(Type)?.();\n hooks.delete(Type);\n };\n}\n\nexport function detach(): void {\n for (const stop of hooks.values()) stop();\n hooks.clear();\n live.clear();\n cached = undefined;\n lost = 0;\n tally = counts();\n copies = 1;\n unwatch?.();\n unwatch = undefined;\n journal.reset();\n forget();\n}\n\n/** Resolve an id or label to an instance - mainline first, then orphans. */\nexport function find(target: string): Instance | undefined {\n const byId = live.get(target);\n const held = byId && (byId.held ?? byId.ref.deref());\n if (held) return Instance.of(held);\n\n const types = new Map<typeof State, string>();\n let first: State | undefined;\n\n for (const pool of [mainline(), abandoned()])\n for (const state of pool) {\n const Type = state.constructor as typeof State;\n const info = seen(Type);\n if (info.type !== target) continue;\n first ??= state;\n types.set(Type, info.typeId);\n }\n\n if (types.size > 1)\n throw new Error(\n `${target} matches ${types.size} classes (${[...types.values()].join(', ')}) - address by instance id or owner path, or label() one. models() lists their construction sites.`\n );\n\n return first && Instance.of(first);\n}\n\nexport function instances(): Instance[] {\n return [...mainline()].map(Instance.of);\n}\n\n/** Registered and settled, but never claimed by a host commit, an owner, or root context. */\nexport function orphans(): Instance[] {\n return [...abandoned()].map(Instance.of);\n}\n\nfunction* abandoned(): Generator<State> {\n const parents = ownership();\n for (const state of registered()) if (orphaned(state, parents)) yield state;\n}\n\nexport interface Health {\n /** Live instances no host, owner, or root slot claimed. */\n orphans: number;\n /** Unclaimed instances the collector already reaped. */\n collected: number;\n /** Loaded copies of `@expressive/mvc` - more than 1 means inspect cannot see every State. */\n copies: number;\n /** `Caught` reports by case, including ones an app handler went on to handle; zeroed by `journal.clear()`. */\n caught: Record<Case, number>;\n}\n\n/** Counts worth a look before trusting what inspect shows. */\nexport function health(): Health {\n return { orphans: orphans().length, collected: lost, copies, caught: { ...tally } };\n}\n\nexport function roots(): Instance[] {\n const parents = ownership();\n return instances().filter((instance) => !parents.has(instance.state));\n}\n\nexport function models(): Model[] {\n const parents = ownership();\n return [...mainline()].map((state) => describe(state, parents));\n}\n\nexport function tree(): Node[] {\n const parents = ownership();\n const nodes = new Map<State, Node>();\n const out: Node[] = [];\n\n for (const state of mainline())\n nodes.set(state, { id: String(state), type: seen(state.constructor as typeof State).type, children: [] });\n\n for (const [state, node] of nodes) {\n const parent = parents.get(state);\n const owner = parent && nodes.get(parent);\n if (owner) owner.children.push(node);\n else out.push(node);\n }\n\n return out;\n}\n\n/** Run `work` recording values; returns the frames it produced once `until` holds and activity goes quiet. */\nexport async function act(work: () => unknown, options: Act = {}): Promise<Frame[]> {\n const { frames, settled, pending, missing, timeout } = await bracket({ ...journal, get }, work, tick, options, true);\n if (pending.length) throw unreached(timeout, pending, missing, frames);\n if (!settled) unsettled(timeout);\n return frames;\n}\n\nexport function get(address?: string, select?: Select): unknown {\n if (!address) return models();\n const { target, path } = parsePath(address);\n return find(target)?.get(path, select);\n}\n\nexport function set(address: string, value: unknown): void {\n const { target, path } = parsePath(address);\n const instance = find(target);\n if (!instance || !path) throw new Error(`No model at ${address}.`);\n\n const dot = path.lastIndexOf('.');\n const key = path.slice(dot + 1);\n const owner = dot < 0 ? instance.state : walk(instance.state, path.slice(0, dot));\n\n if (owner == null || typeof owner !== 'object') throw new Error(`No model at ${address}.`);\n\n if (owner instanceof Map) owner.set(key, value);\n else (owner as Record<string, unknown>)[key] = value;\n}\n\nexport async function call(address: string, ...args: unknown[]): Promise<unknown> {\n const { target, path } = parsePath(address);\n const state = find(target)?.state;\n const method = state && path && (state as unknown as Record<string, unknown>)[path];\n\n if (typeof method !== 'function') throw new Error(`No method at ${address}.`);\n\n return serialize(await method.apply(state, args));\n}\n\nexport function wrapAll(): void {\n for (const state of registered()) wrap(state);\n}\n\n/** Observe the host commit: adapters call `mount?.()` once an instance is placed. */\nfunction mounts(state: State) {\n const target = state as State & { mount?: (...args: unknown[]) => unknown };\n const original = target.mount;\n\n Object.defineProperty(target, 'mount', {\n configurable: true,\n writable: true,\n value(this: unknown, ...args: unknown[]) {\n claim(state);\n return typeof original === 'function' ? original.apply(this, args) : undefined;\n }\n });\n}\n\nfunction describe(state: State, parents: Map<State, State>): Model {\n const stored = entries(state);\n const declared = Object.entries(Object.getOwnPropertyDescriptors(state))\n .filter(([, desc]) => typeof desc.get === 'function')\n .map(([key]) => key);\n const model: Model = {\n id: String(state),\n ...seen(state.constructor as typeof State),\n keys: [...stored.keys()],\n absent: declared.filter((key) => !stored.has(key))\n };\n const parent = parents.get(state);\n if (parent) model.parent = String(parent);\n return model;\n}\n\nfunction wrap(state: State) {\n let keys = wrapped.get(state);\n if (!keys) wrapped.set(state, (keys = new Set(['render'])));\n\n const target = state as unknown as Record<string, Function>;\n\n for (let proto = Object.getPrototypeOf(state); proto !== State.prototype; proto = Object.getPrototypeOf(proto))\n for (const [key, desc] of Object.entries(Object.getOwnPropertyDescriptors(proto))) {\n if (keys.has(key) || typeof desc.get !== 'function' || desc.get !== desc.set) continue;\n\n keys.add(key);\n\n target[key] = function (this: unknown, ...args: unknown[]) {\n noteCall(state, key, args);\n return latest(state, key).apply(this, args);\n };\n }\n}\n\n/** Drop wrappers of methods a hot patch removed. */\nfunction unwrap(state: State) {\n const keys = wrapped.get(state);\n\n if (keys)\n for (const key of keys)\n if (key != 'render' && !(key in Object.getPrototypeOf(state))) {\n delete (state as unknown as Record<string, unknown>)[key];\n keys.delete(key);\n }\n}\n\n/** A method's current implementation - through its accessor, so a hot patch is followed. */\nfunction latest(state: State, key: string): Function {\n let proto = Object.getPrototypeOf(state);\n\n while (!Object.prototype.hasOwnProperty.call(proto, key)) proto = Object.getPrototypeOf(proto);\n\n return Object.getOwnPropertyDescriptor(proto, key)!.get!.call(state);\n}\n\nfunction ownership(): Map<State, State> {\n if (cached?.version !== version) {\n const parents = new Map<State, State>();\n\n for (const owner of registered())\n for (const [key, value] of entries(owner)) {\n const field = Object.getOwnPropertyDescriptor(owner, key)?.enumerable;\n if (field || !(value instanceof State)) own(parents, owner, value);\n }\n\n cached = { version, parents };\n }\n\n return cached.parents;\n}\n\nfunction own(parents: Map<State, State>, owner: State, value: unknown) {\n if (value instanceof State) {\n if (!parents.has(value) && value !== owner) parents.set(value, owner);\n } else if (value && typeof value === 'object' && Symbol.iterator in value) {\n const items = value instanceof Map ? value.values() : (value as Iterable<unknown>);\n for (const item of items) if (item instanceof State) own(parents, owner, item);\n }\n}\n"],"mappings":"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"}
package/dist/install.js CHANGED
@@ -1,8 +1,10 @@
1
- import { n as attach } from "./inspect-D4NC5Mx5.js";
2
- import inspect from "./index.js";
1
+ import { r as attach } from "./inspect-DXj1Vvhi.js";
2
+ import inspect, { journal } from "./index.js";
3
3
 
4
4
  //#region src/install.ts
5
+ const preset = globalThis.__EXPRESSIVE_INSPECT__;
5
6
  attach();
7
+ if (preset?.record) journal.record(preset.record);
6
8
  globalThis.__EXPRESSIVE_INSPECT__ = inspect;
7
9
 
8
10
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","names":[],"sources":["../src/install.ts"],"sourcesContent":["import { attach, inspect } from './index';\n\nattach();\n\nglobalThis.__EXPRESSIVE_INSPECT__ = inspect;\n"],"mappings":";;;;AAEA,QAAQ;AAER,WAAW,yBAAyB"}
1
+ {"version":3,"file":"install.js","names":[],"sources":["../src/install.ts"],"sourcesContent":["import { attach, inspect, journal, type Options } from './index';\n\nconst preset = globalThis.__EXPRESSIVE_INSPECT__ as { record?: Options } | undefined;\n\nattach();\n\nif (preset?.record) journal.record(preset.record);\n\nglobalThis.__EXPRESSIVE_INSPECT__ = inspect;\n"],"mappings":";;;;AAEA,MAAM,SAAS,WAAW;AAE1B,QAAQ;AAER,IAAI,QAAQ,OAAQ,SAAQ,OAAO,OAAO,OAAO;AAEjD,WAAW,yBAAyB"}
@@ -0,0 +1,16 @@
1
+ //#region src/dispatch.d.ts
2
+ type Call = [path: string[], args: unknown[]];
3
+ //#endregion
4
+ //#region src/vite/client.d.ts
5
+ interface Hot {
6
+ on(event: string, listener: (data: any) => unknown): void;
7
+ send(event: string, data?: unknown): void;
8
+ }
9
+ interface Ask {
10
+ rid: number;
11
+ call?: Call;
12
+ }
13
+ declare function connect(hot: Hot): void;
14
+ //#endregion
15
+ export { Ask, Hot, connect };
16
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,76 @@
1
+ import { n as tick, t as bracket } from "../bracket-BYmLIpQH.js";
2
+ import { t as dispatch } from "../dispatch-Dnd88-J9.js";
3
+
4
+ //#region src/vite/client.ts
5
+ const journal = (method, ...args) => dispatch([["journal", method], args]);
6
+ async function act(step, options) {
7
+ if (!Array.isArray(step) || typeof step[0] != "string") throw new Error("act takes one call: [\"act\", [method, ...args], options?].");
8
+ const { value, frames, settled, pending, missing } = await bracket({
9
+ record: (...options) => journal("record", ...options),
10
+ seq: () => journal("seq"),
11
+ frames: (query) => journal("frames", query),
12
+ get: (address) => dispatch([["get"], [address]])
13
+ }, () => dispatch([step[0].split("."), step.slice(1)]), tick, options, true);
14
+ return {
15
+ value: value ?? null,
16
+ frames,
17
+ settled,
18
+ pending,
19
+ missing
20
+ };
21
+ }
22
+ const RELOAD = "@expressive/inspect.reload";
23
+ /** Keep a reload's reason past the reload, for the next page's journal. */
24
+ function remember(reason) {
25
+ try {
26
+ sessionStorage.setItem(RELOAD, JSON.stringify(reason));
27
+ } catch {}
28
+ }
29
+ function recall() {
30
+ try {
31
+ const reason = sessionStorage.getItem(RELOAD);
32
+ if (reason === null) return;
33
+ sessionStorage.removeItem(RELOAD);
34
+ return JSON.parse(reason);
35
+ } catch {}
36
+ }
37
+ function connect(hot) {
38
+ const id = Math.random().toString(36).slice(2, 8);
39
+ if (journal("record").level === "off") journal("record", { level: "keys" });
40
+ const reloaded = recall();
41
+ if (reloaded) journal("hot", "reload", reloaded);
42
+ hot.on("vite:beforeUpdate", ({ updates }) => {
43
+ journal("hot", "update", updates.map((update) => update.path));
44
+ });
45
+ hot.on("vite:beforeFullReload", ({ path, triggeredBy } = {}) => {
46
+ remember({
47
+ path,
48
+ triggeredBy
49
+ });
50
+ });
51
+ globalThis.addEventListener?.("expressive:reload", (event) => remember(event.detail));
52
+ hot.on("expressive-inspect:ask", async ({ rid, call }) => {
53
+ try {
54
+ const value = !call ? {
55
+ id,
56
+ url: location.href,
57
+ title: document.title,
58
+ top: window.self === window.top
59
+ } : call[0].join(".") == "act" ? await act(call[1][0], call[1][1]) : await dispatch(call);
60
+ hot.send("expressive-inspect:answer", {
61
+ rid,
62
+ value: JSON.parse(JSON.stringify(value) ?? "null")
63
+ });
64
+ } catch (error) {
65
+ hot.send("expressive-inspect:answer", {
66
+ rid,
67
+ error: error instanceof Error ? error.message : String(error)
68
+ });
69
+ }
70
+ });
71
+ hot.send("expressive-inspect:hello", { id });
72
+ }
73
+
74
+ //#endregion
75
+ export { connect };
76
+ //# sourceMappingURL=client.js.map