cyborg-hunter 0.7.4 → 0.8.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/CITATION.cff +2 -2
  3. package/README.md +21 -6
  4. package/dist/cyborg-hunter-replay.js +3 -3
  5. package/dist/cyborg-hunter.esm.js +3 -2
  6. package/dist/cyborg-hunter.min.js +3 -3
  7. package/dist/extension-cyborg-hunter.js +1 -1
  8. package/dist/extension-guard-friction.js +5 -5
  9. package/package.json +10 -2
  10. package/src/cli/ingest.js +311 -57
  11. package/src/cli/renderers/html-index-core.js +66 -12
  12. package/src/cli/renderers/html-index.js +7 -5
  13. package/src/cli/renderers/replay-assets.js +61 -7
  14. package/src/cli/renderers/replay-client-source.js +102 -0
  15. package/src/cli/renderers/replay-viewer.client.js +1750 -595
  16. package/src/cli/report.js +6 -0
  17. package/src/core/monitor.js +12 -13
  18. package/src/jspsych/extension-cyborg-hunter-replay.js +64 -3
  19. package/src/jspsych/extension-cyborg-hunter.js +1 -1
  20. package/src/jspsych/extension-guard-friction.js +59 -1
  21. package/src/replay/capture-dom.js +470 -458
  22. package/src/replay/capture-trace.js +688 -271
  23. package/src/replay/delivery.js +82 -0
  24. package/src/replay/dom-instantiate.js +779 -0
  25. package/src/replay/index.js +88 -5
  26. package/src/replay/initial-state.js +295 -0
  27. package/src/replay/mutations.js +668 -0
  28. package/src/replay/node-registry.js +116 -0
  29. package/src/replay/persistence.js +19 -6
  30. package/src/replay/recorder.js +342 -73
  31. package/src/replay/redaction.js +165 -0
  32. package/src/replay/serializer.js +148 -43
  33. package/src/replay/snapshot.js +409 -0
  34. package/src/replay/span.js +55 -0
  35. package/src/replay/viewer-model.js +293 -102
  36. package/src/shared/constants.js +1 -1
  37. package/src/shared/inline-safe.js +80 -0
  38. package/src/shared/schema-v2-validator.js +595 -0
  39. package/tools/convert/jspsych-v1-to-v2.mjs +432 -0
@@ -0,0 +1,82 @@
1
+ // src/replay/delivery.js
2
+ // What the FILE currently contains: which nodes a player reading this
3
+ // recording holds, and under which parent.
4
+ //
5
+ // Every mutation question that matters turns out to be this one question.
6
+ // Should a removal be emitted? Only if the player holds that node under that
7
+ // parent. May a `before` name this sibling? Only if the player holds it. Does
8
+ // an insertion need its old copy removed first? Only if the player holds it
9
+ // somewhere else. Two review rounds fixed those one at a time by reasoning
10
+ // about the live DOM — the batch's own composition, detached parents, purged
11
+ // ancestors — and a differential fuzz kept finding compositions the reasoning
12
+ // missed, because the live DOM is not the question. It is the DESTINATION.
13
+ //
14
+ // Lifetime is the keyframe span, the same as node ids — which is why the two
15
+ // are handed out together (span.js) rather than left to be reset in step by
16
+ // convention. Nothing here is shared or ambient: a serialization that is not
17
+ // going into the file gets its own span, so it cannot tell a live recording
18
+ // that the player already holds what it has never been sent.
19
+ //
20
+ // Identity-keyed WeakMaps: nothing here holds a node alive, and two recorders
21
+ // on one page never see each other's nodes.
22
+
23
+ /**
24
+ * @returns {{deliver, purge, holds, parentOf, childrenOf, reset}}
25
+ */
26
+ export function createDelivery() {
27
+ var parents = new WeakMap(); // node → the parent it sits under in the file
28
+ var children = new WeakMap(); // node → Set of its delivered children
29
+
30
+ function detach(node) {
31
+ var parent = parents.get(node);
32
+ if (parent) {
33
+ var siblings = children.get(parent);
34
+ if (siblings) siblings.delete(node);
35
+ }
36
+ }
37
+
38
+ function purgeNode(node) {
39
+ var kids = children.get(node);
40
+ if (kids) {
41
+ kids.forEach(function (child) { purgeNode(child); });
42
+ children.delete(node);
43
+ }
44
+ parents.delete(node);
45
+ }
46
+
47
+ return {
48
+ // The file now carries `node` under `parent` (null for a keyframe root).
49
+ // A node delivered somewhere else first leaves that place, which is what
50
+ // makes a move a single fact rather than two.
51
+ deliver: function (node, parent) {
52
+ if (parents.has(node)) detach(node);
53
+ parents.set(node, parent || null);
54
+ if (parent) {
55
+ var siblings = children.get(parent);
56
+ if (!siblings) { siblings = new Set(); children.set(parent, siblings); }
57
+ siblings.add(node);
58
+ }
59
+ },
60
+
61
+ // The file no longer carries `node`, and a player removing it takes the
62
+ // subtree with it — so its delivered descendants go too.
63
+ purge: function (node) {
64
+ detach(node);
65
+ purgeNode(node);
66
+ },
67
+
68
+ holds: function (node) { return parents.has(node); },
69
+ parentOf: function (node) {
70
+ var parent = parents.get(node);
71
+ return parent === undefined ? null : parent;
72
+ },
73
+ // Delivery order, not document order: callers use this to take children
74
+ // away, where order does not matter.
75
+ childrenOf: function (node) {
76
+ var kids = children.get(node);
77
+ return kids ? Array.from(kids) : [];
78
+ },
79
+
80
+ reset: function () { parents = new WeakMap(); children = new WeakMap(); },
81
+ };
82
+ }