@braidlabs/studio 0.1.1

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.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @braidlabs/studio
2
+
3
+ Inspection tooling for version skew. Framework-free, no dependencies.
4
+
5
+ This package is being built incrementally alongside the web debugger
6
+ described in [`docs/skew-studio-plan.md`](../../docs/plans/skew-studio-plan.md).
7
+ What ships today is its most reusable piece.
8
+
9
+ ## `diffPayloads`
10
+
11
+ A structural diff of one payload against another, in the vocabulary the
12
+ migration itself uses.
13
+
14
+ ```ts
15
+ import { diffPayloads } from '@braidlabs/studio';
16
+
17
+ const result = FundSchemaV1.read(body); // or readResolving, or a store get
18
+
19
+ const { lines, stats } = diffPayloads(sentByServer, result.value, {
20
+ derivedPaths: result.derivedPaths, // values the migration guessed
21
+ lossyPaths: result.lossyPaths, // values the target shape cannot carry
22
+ });
23
+ ```
24
+
25
+ `lines` is a flat list of `{ kind, indent, text, path, tag? }` — render it
26
+ however you like; a `<pre>` and thirty lines of CSS is enough. `stats` gives
27
+ `{ added, removed, derived, lost }` for a header.
28
+
29
+ ### Why not a text diff
30
+
31
+ Running an LCS over two pretty-printed JSON strings produces plausible
32
+ garbage exactly when migrations are most interesting. A promotion — `nav`
33
+ going from `128450000` to `{ amount, asOf }`, or `cashPct` moving into
34
+ `liquidity.cashPct` — comes out as several unrelated line edits, and the one
35
+ change the reader needed to see has been dismantled. Pairing lines by key
36
+ path keeps a promotion legible as a promotion.
37
+
38
+ ### Why the tags matter
39
+
40
+ A generic diff can say a line was added. It cannot say the value was
41
+ *guessed*: that the writer never recorded it and the migration filled in the
42
+ best answer available from an older shape. That is the distinction
43
+ `derivedPaths` and `lossyPaths` exist to carry, and rendering them as
44
+ ordinary green and red throws it away.
45
+
46
+ - **`derived`** — the value is the migration's invention. It can appear on
47
+ either side: a migration *adds* a guessed field going up, and a
48
+ reconciliation against an authoritative record *removes* the guess it had
49
+ been carrying.
50
+ - **`lost`** — only ever on a removed line: the older shape has nowhere to
51
+ put this, so a downgrade drops it.
52
+
53
+ ### Path matching
54
+
55
+ Two vantage points always disagree, and both are handled:
56
+
57
+ - A read of a **list** reports paths against the list
58
+ (`[].liquidity.hqlaPct`) while a drill-down usually shows one element. The
59
+ leading hop is optional when matching.
60
+ - A result says "every holding loses its tier" (`holdings[].liquidityTier`)
61
+ while a line is about one holding (`holdings[3].liquidityTier`). Indices
62
+ collapse to `[]` on both sides.
63
+
64
+ Tags propagate **parent → child only**. A subtree that was dropped whole
65
+ marks every line inside it; a parent whose child alone was lost is *not*
66
+ marked, because saying `author` "cannot be carried" when it survives as a
67
+ bare string tells the reader the opposite of what happened.
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@braidlabs/studio",
3
+ "version": "0.1.1",
4
+ "description": "Inspection tooling for version skew: structural payload diffs that speak the migration's own vocabulary.",
5
+ "keywords": [
6
+ "version-skew",
7
+ "migration",
8
+ "devtools",
9
+ "diff"
10
+ ],
11
+ "license": "MIT",
12
+ "sideEffects": false,
13
+ "type": "module",
14
+ "main": "./src/index.js",
15
+ "types": "./src/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./src/index.d.ts",
19
+ "default": "./src/index.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/braidjs/braid.git",
29
+ "directory": "libs/studio"
30
+ },
31
+ "homepage": "https://github.com/braidjs/braid#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/braidjs/braid/issues"
34
+ },
35
+ "module": "./src/index.js"
36
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './lib/payload-diff.js';
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './lib/payload-diff.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/studio/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * A structural diff of one payload against another, in the vocabulary the
3
+ * migration itself uses.
4
+ *
5
+ * This is the engine behind the demo's payload view and behind Studio's
6
+ * drill-down: click a trace event, get the record it carried, before and
7
+ * after. It is deliberately pure and framework-free — the renderer is a
8
+ * dozen lines of template in whatever framework is asking, and every caller
9
+ * should agree about what a change *is*.
10
+ *
11
+ * Two decisions worth knowing, because both are wrong in the obvious
12
+ * implementation:
13
+ *
14
+ * **Structural, not textual.** Running an LCS over two pretty-printed JSON
15
+ * strings produces plausible garbage exactly when migrations are most
16
+ * interesting — a promotion (`author` from a string to `{ name, email }`, or
17
+ * `cashPct` moving into `liquidity.cashPct`) shows up as several unrelated
18
+ * line edits, and the one change the reader needs to see is the one the diff
19
+ * has dismantled. Walking both values by key path pairs each line with its
20
+ * genuine counterpart.
21
+ *
22
+ * **Lines carry migration semantics.** A generic diff can say a line was
23
+ * added. It cannot say the value was *guessed* — that the writer never
24
+ * recorded it and the migration filled in the best answer available from an
25
+ * older shape. That distinction is the whole reason `derivedPaths` and
26
+ * `lossyPaths` exist on a result, and a plain red/green diff erases it.
27
+ */
28
+ export type DiffLineKind = 'same' | 'add' | 'del';
29
+ /** Why a line is worth more than its `+`/`−`. */
30
+ export type DiffLineTag =
31
+ /** The migration invented this value; the writer never recorded it. */
32
+ 'derived'
33
+ /** The target version has nowhere to carry this, so a downgrade drops it. */
34
+ | 'lost';
35
+ export interface DiffLine {
36
+ readonly kind: DiffLineKind;
37
+ /** Nesting depth, for the renderer to indent by. */
38
+ readonly indent: number;
39
+ /** The line's JSON text, without indentation. */
40
+ readonly text: string;
41
+ /** Dot/bracket path of the value this line belongs to. */
42
+ readonly path: string;
43
+ readonly tag?: DiffLineTag;
44
+ }
45
+ export interface DiffStats {
46
+ readonly added: number;
47
+ readonly removed: number;
48
+ readonly derived: number;
49
+ readonly lost: number;
50
+ }
51
+ export interface PayloadDiff {
52
+ readonly lines: readonly DiffLine[];
53
+ readonly stats: DiffStats;
54
+ }
55
+ export interface DiffOptions {
56
+ /** `derivedPaths` from a read result: values the migration guessed. */
57
+ readonly derivedPaths?: readonly string[];
58
+ /** `lossyPaths` from a read result: values a downgrade discarded. */
59
+ readonly lossyPaths?: readonly string[];
60
+ }
61
+ /**
62
+ * Diffs two payloads.
63
+ *
64
+ * `before`/`after` are plain JSON values — pass the payload, not the
65
+ * envelope, so paths line up with the paths a result reports.
66
+ */
67
+ export declare function diffPayloads(before: unknown, after: unknown, options?: DiffOptions): PayloadDiff;
68
+ /**
69
+ * Array indices collapse to `[]` on both sides before matching, because the
70
+ * two sides count differently on purpose: a result says "every holding loses
71
+ * its liquidityTier" (`holdings[].liquidityTier`) while a diff line is about
72
+ * one specific holding (`holdings[3].liquidityTier`). Same claim, and only
73
+ * one of them can be written per element.
74
+ */
75
+ export declare function normalizePath(path: string): string;
@@ -0,0 +1,202 @@
1
+ /**
2
+ * A structural diff of one payload against another, in the vocabulary the
3
+ * migration itself uses.
4
+ *
5
+ * This is the engine behind the demo's payload view and behind Studio's
6
+ * drill-down: click a trace event, get the record it carried, before and
7
+ * after. It is deliberately pure and framework-free — the renderer is a
8
+ * dozen lines of template in whatever framework is asking, and every caller
9
+ * should agree about what a change *is*.
10
+ *
11
+ * Two decisions worth knowing, because both are wrong in the obvious
12
+ * implementation:
13
+ *
14
+ * **Structural, not textual.** Running an LCS over two pretty-printed JSON
15
+ * strings produces plausible garbage exactly when migrations are most
16
+ * interesting — a promotion (`author` from a string to `{ name, email }`, or
17
+ * `cashPct` moving into `liquidity.cashPct`) shows up as several unrelated
18
+ * line edits, and the one change the reader needs to see is the one the diff
19
+ * has dismantled. Walking both values by key path pairs each line with its
20
+ * genuine counterpart.
21
+ *
22
+ * **Lines carry migration semantics.** A generic diff can say a line was
23
+ * added. It cannot say the value was *guessed* — that the writer never
24
+ * recorded it and the migration filled in the best answer available from an
25
+ * older shape. That distinction is the whole reason `derivedPaths` and
26
+ * `lossyPaths` exist on a result, and a plain red/green diff erases it.
27
+ */
28
+ /**
29
+ * Diffs two payloads.
30
+ *
31
+ * `before`/`after` are plain JSON values — pass the payload, not the
32
+ * envelope, so paths line up with the paths a result reports.
33
+ */
34
+ export function diffPayloads(before, after, options = {}) {
35
+ var _a, _b;
36
+ const raw = [];
37
+ walk(null, before, after, '', 0, true, raw);
38
+ const derivedPaths = (_a = options.derivedPaths) !== null && _a !== void 0 ? _a : [];
39
+ const lossyPaths = (_b = options.lossyPaths) !== null && _b !== void 0 ? _b : [];
40
+ let added = 0;
41
+ let removed = 0;
42
+ let derived = 0;
43
+ let lost = 0;
44
+ const lines = raw.map((line) => {
45
+ // `lost` only ever describes something being removed. `derived` can land
46
+ // on either side, because "this value is a guess" is a claim about the
47
+ // value, not about the direction it is travelling: a migration adds a
48
+ // guessed field going up, and a reconciliation against an authoritative
49
+ // record *removes* the guessed one it had been carrying.
50
+ const tag = line.kind === 'del' && covers(lossyPaths, line.path)
51
+ ? 'lost'
52
+ : line.kind !== 'same' && covers(derivedPaths, line.path)
53
+ ? 'derived'
54
+ : undefined;
55
+ if (line.kind === 'add')
56
+ added++;
57
+ if (line.kind === 'del')
58
+ removed++;
59
+ if (tag === 'derived')
60
+ derived++;
61
+ if (tag === 'lost')
62
+ lost++;
63
+ return tag ? Object.assign(Object.assign({}, line), { tag }) : line;
64
+ });
65
+ return { lines, stats: { added, removed, derived, lost } };
66
+ }
67
+ /**
68
+ * True when `path` is one of the tagged paths, or sits inside one.
69
+ *
70
+ * Deliberately one-directional. Tagging a parent because one of its children
71
+ * is lossy reads as a lie: when `author` is promoted from `{ name, email }`
72
+ * to a bare string, `author.email` is genuinely lost but `author` itself
73
+ * survives — marking the whole object "cannot be carried" tells the reader
74
+ * the opposite of what happened. A subtree that really is dropped whole
75
+ * arrives with the parent path in the list, and every line under it is then
76
+ * tagged by the `startsWith` case.
77
+ */
78
+ function covers(paths, path) {
79
+ const line = normalizePath(path);
80
+ return paths.some((raw) => {
81
+ const tagged = normalizePath(raw);
82
+ // A read of a *list* reports paths against the list
83
+ // (`[].liquidity.hqlaPct`) while a diff often shows one element of it.
84
+ // Try the path as given and with that leading hop removed, so one result
85
+ // annotates either view without the caller rewriting its own paths.
86
+ const candidates = tagged.startsWith('[].')
87
+ ? [tagged, tagged.slice(3)]
88
+ : [tagged];
89
+ return candidates.some((p) => p === line || line.startsWith(`${p}.`));
90
+ });
91
+ }
92
+ /**
93
+ * Array indices collapse to `[]` on both sides before matching, because the
94
+ * two sides count differently on purpose: a result says "every holding loses
95
+ * its liquidityTier" (`holdings[].liquidityTier`) while a diff line is about
96
+ * one specific holding (`holdings[3].liquidityTier`). Same claim, and only
97
+ * one of them can be written per element.
98
+ */
99
+ export function normalizePath(path) {
100
+ return path.replace(/\[\d+\]/g, '[]');
101
+ }
102
+ // --- walking ---------------------------------------------------------------
103
+ function isPlainObject(v) {
104
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
105
+ }
106
+ function format(value) {
107
+ return typeof value === 'string' ? JSON.stringify(value) : String(value);
108
+ }
109
+ function label(key) {
110
+ return key === null ? '' : `${JSON.stringify(key)}: `;
111
+ }
112
+ function child(path, key) {
113
+ return path ? `${path}.${key}` : key;
114
+ }
115
+ /** Emits an entire value as one-sided lines — a wholly added or removed key. */
116
+ function emit(kind, key, value, path, indent, last, out) {
117
+ const comma = last ? '' : ',';
118
+ if (isPlainObject(value)) {
119
+ const keys = Object.keys(value);
120
+ out.push({ kind, indent, text: `${label(key)}{`, path });
121
+ keys.forEach((k, i) => emit(kind, k, value[k], child(path, k), indent + 1, i === keys.length - 1, out));
122
+ out.push({ kind, indent, text: `}${comma}`, path });
123
+ return;
124
+ }
125
+ if (Array.isArray(value)) {
126
+ out.push({ kind, indent, text: `${label(key)}[`, path });
127
+ value.forEach((v, i) => emit(kind, null, v, `${path}[${i}]`, indent + 1, i === value.length - 1, out));
128
+ out.push({ kind, indent, text: `]${comma}`, path });
129
+ return;
130
+ }
131
+ out.push({ kind, indent, text: `${label(key)}${format(value)}${comma}`, path });
132
+ }
133
+ function emitSame(key, value, path, indent, last, out) {
134
+ const comma = last ? '' : ',';
135
+ if (isPlainObject(value)) {
136
+ const keys = Object.keys(value);
137
+ out.push({ kind: 'same', indent, text: `${label(key)}{`, path });
138
+ keys.forEach((k, i) => emitSame(k, value[k], child(path, k), indent + 1, i === keys.length - 1, out));
139
+ out.push({ kind: 'same', indent, text: `}${comma}`, path });
140
+ return;
141
+ }
142
+ if (Array.isArray(value)) {
143
+ out.push({ kind: 'same', indent, text: `${label(key)}[`, path });
144
+ value.forEach((v, i) => emitSame(null, v, `${path}[${i}]`, indent + 1, i === value.length - 1, out));
145
+ out.push({ kind: 'same', indent, text: `]${comma}`, path });
146
+ return;
147
+ }
148
+ out.push({ kind: 'same', indent, text: `${label(key)}${format(value)}${comma}`, path });
149
+ }
150
+ /**
151
+ * Walks both values in parallel, pairing by key rather than by line number.
152
+ *
153
+ * `undefined` marks "absent on this side", which is safe because JSON has no
154
+ * undefined — a key that exists with an undefined value did not survive
155
+ * serialization in the first place.
156
+ */
157
+ function walk(key, before, after, path, indent, last, out) {
158
+ const comma = last ? '' : ',';
159
+ if (before === undefined && after === undefined)
160
+ return;
161
+ if (before === undefined) {
162
+ emit('add', key, after, path, indent, last, out);
163
+ return;
164
+ }
165
+ if (after === undefined) {
166
+ emit('del', key, before, path, indent, last, out);
167
+ return;
168
+ }
169
+ if (isPlainObject(before) && isPlainObject(after)) {
170
+ // Before's key order first, then keys only after has — an unchanged
171
+ // record reads in its original order, and additions land where they were
172
+ // introduced rather than being alphabetised into the middle of it.
173
+ const keys = [
174
+ ...Object.keys(before),
175
+ ...Object.keys(after).filter((k) => !(k in before)),
176
+ ];
177
+ out.push({ kind: 'same', indent, text: `${label(key)}{`, path });
178
+ keys.forEach((k, i) => walk(k, before[k], after[k], child(path, k), indent + 1, i === keys.length - 1, out));
179
+ out.push({ kind: 'same', indent, text: `}${comma}`, path });
180
+ return;
181
+ }
182
+ if (Array.isArray(before) && Array.isArray(after)) {
183
+ const length = Math.max(before.length, after.length);
184
+ out.push({ kind: 'same', indent, text: `${label(key)}[`, path });
185
+ for (let i = 0; i < length; i++) {
186
+ walk(null, before[i], after[i], `${path}[${i}]`, indent + 1, i === length - 1, out);
187
+ }
188
+ out.push({ kind: 'same', indent, text: `]${comma}`, path });
189
+ return;
190
+ }
191
+ if (JSON.stringify(before) === JSON.stringify(after)) {
192
+ // Unchanged, but possibly a whole subtree that moved wholesale, so print
193
+ // it rather than collapsing it to one line.
194
+ emitSame(key, after, path, indent, last, out);
195
+ return;
196
+ }
197
+ // Both sides describe the same key, so they share its position: a replaced
198
+ // final key must not sprout a trailing comma on the removed line only.
199
+ emit('del', key, before, path, indent, last, out);
200
+ emit('add', key, after, path, indent, last, out);
201
+ }
202
+ //# sourceMappingURL=payload-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-diff.js","sourceRoot":"","sources":["../../../../../libs/studio/src/lib/payload-diff.ts"],"names":[],"mappings":"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"}