@reactra/devtools 0.1.0-alpha.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.
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/dist/ValueTree.d.ts +38 -0
- package/dist/ValueTree.d.ts.map +1 -0
- package/dist/ValueTree.js +178 -0
- package/dist/ValueTree.js.map +1 -0
- package/dist/helpers.d.ts +59 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +110 -0
- package/dist/helpers.js.map +1 -0
- package/dist/hookRecorder.d.ts +72 -0
- package/dist/hookRecorder.d.ts.map +1 -0
- package/dist/hookRecorder.js +142 -0
- package/dist/hookRecorder.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/invoke.d.ts +35 -0
- package/dist/invoke.d.ts.map +1 -0
- package/dist/invoke.js +67 -0
- package/dist/invoke.js.map +1 -0
- package/dist/model.d.ts +99 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +160 -0
- package/dist/model.js.map +1 -0
- package/dist/panel.d.ts +17 -0
- package/dist/panel.d.ts.map +1 -0
- package/dist/panel.js +438 -0
- package/dist/panel.js.map +1 -0
- package/dist/routerWatcher.d.ts +47 -0
- package/dist/routerWatcher.d.ts.map +1 -0
- package/dist/routerWatcher.js +51 -0
- package/dist/routerWatcher.js.map +1 -0
- package/dist/serialize.d.ts +38 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +217 -0
- package/dist/serialize.js.map +1 -0
- package/dist/storeRecorder.d.ts +25 -0
- package/dist/storeRecorder.d.ts.map +1 -0
- package/dist/storeRecorder.js +94 -0
- package/dist/storeRecorder.js.map +1 -0
- package/dist/storeWatcher.d.ts +26 -0
- package/dist/storeWatcher.d.ts.map +1 -0
- package/dist/storeWatcher.js +24 -0
- package/dist/storeWatcher.js.map +1 -0
- package/dist/styles.d.ts +5 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +288 -0
- package/dist/styles.js.map +1 -0
- package/dist/tabs/router.d.ts +10 -0
- package/dist/tabs/router.d.ts.map +1 -0
- package/dist/tabs/router.js +48 -0
- package/dist/tabs/router.js.map +1 -0
- package/dist/tabs/stores.d.ts +14 -0
- package/dist/tabs/stores.d.ts.map +1 -0
- package/dist/tabs/stores.js +167 -0
- package/dist/tabs/stores.js.map +1 -0
- package/dist/tabs/timeTravel.d.ts +46 -0
- package/dist/tabs/timeTravel.d.ts.map +1 -0
- package/dist/tabs/timeTravel.js +322 -0
- package/dist/tabs/timeTravel.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// @reactra/devtools — shared value serializer.
|
|
2
|
+
//
|
|
3
|
+
// Owner: reactra-devtools-spec.md §7 (binding-card data layer). Replaces
|
|
4
|
+
// the unbounded JSON.parse(JSON.stringify(...)) round-trip in `dataBindings`
|
|
5
|
+
// with a depth-limited, size-capped walk that also handles resource handles
|
|
6
|
+
// (DVT-LIM-04 resolution: status projection instead of "[unserializable]").
|
|
7
|
+
//
|
|
8
|
+
// Rules:
|
|
9
|
+
// - Functions are dropped (never serialized — the action-invoke path
|
|
10
|
+
// handles them separately via callableNames).
|
|
11
|
+
// - Cyclic values become the sentinel (no throw).
|
|
12
|
+
// - Objects/arrays past `maxDepth` become summary placeholders.
|
|
13
|
+
// - Objects/arrays with more than `maxKeys` entries are truncated.
|
|
14
|
+
// - A resource handle (object with a `status` string property equal to
|
|
15
|
+
// "pending", "resolved", or "error") emits { status, value? } — the
|
|
16
|
+
// resource-status projection (DVT-LIM-04).
|
|
17
|
+
/** Sentinel for values that can't be serialized cleanly. */
|
|
18
|
+
export const SENTINEL = "[unserializable]";
|
|
19
|
+
const RESOURCE_STATUSES = new Set(["pending", "resolved", "error"]);
|
|
20
|
+
/**
|
|
21
|
+
* Detect a genuine Reactra resource handle (DVT-LIM-04 resource projection).
|
|
22
|
+
*
|
|
23
|
+
* Tightened from the old duck-typed `status`-only check: any plain data object
|
|
24
|
+
* with a `status: "error"` field (e.g. `{status:"error", message, code}`) was
|
|
25
|
+
* silently reduced to `{status}`, dropping all extra fields. The fix: only
|
|
26
|
+
* apply the projection when the object positively identifies as a
|
|
27
|
+
* `ResourceHandle<T>` — it must carry the `promise` field (a Promise), which
|
|
28
|
+
* is structurally unique to the resource handle returned by `useResource`. A
|
|
29
|
+
* plain state object may have a `status` string but will never carry a live
|
|
30
|
+
* Promise on its `promise` field. This avoids false-positives while keeping
|
|
31
|
+
* the DVT-LIM-04 projection for real handles.
|
|
32
|
+
*
|
|
33
|
+
* References: Resource v1 §2 (`ResourceHandle<T>` surface — `data`, `error`,
|
|
34
|
+
* `isPending`, `refetch`, `promise`).
|
|
35
|
+
*/
|
|
36
|
+
const isResourceHandle = (v) => {
|
|
37
|
+
const rec = v;
|
|
38
|
+
const s = rec.status;
|
|
39
|
+
if (typeof s !== "string" || !RESOURCE_STATUSES.has(s))
|
|
40
|
+
return false;
|
|
41
|
+
// Require a `promise` property that is a Promise — the structural differentiator
|
|
42
|
+
// between a ResourceHandle and an ordinary data object with a status field.
|
|
43
|
+
const p = rec.promise;
|
|
44
|
+
return p !== null && p !== undefined && typeof p.then === "function";
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Serialize a single value to a depth/size-capped representation.
|
|
48
|
+
* Functions are dropped from objects; cyclic references become `SENTINEL`.
|
|
49
|
+
*
|
|
50
|
+
* @param value - The value to serialize.
|
|
51
|
+
* @param caps - Optional depth/size caps (defaults: depth=5, keys=50).
|
|
52
|
+
* @returns A plain JSON-compatible representation, or `SENTINEL`/summary.
|
|
53
|
+
*/
|
|
54
|
+
export const serialize = (value, caps) => {
|
|
55
|
+
const maxDepth = caps?.maxDepth ?? 5;
|
|
56
|
+
const maxKeys = caps?.maxKeys ?? 50;
|
|
57
|
+
// Cycle detection — tracks object identity through the recursion stack.
|
|
58
|
+
const seen = new Set();
|
|
59
|
+
const walk = (v, depth) => {
|
|
60
|
+
if (v === null)
|
|
61
|
+
return null;
|
|
62
|
+
if (v === undefined)
|
|
63
|
+
return undefined;
|
|
64
|
+
if (typeof v === "boolean" || typeof v === "number" || typeof v === "string")
|
|
65
|
+
return v;
|
|
66
|
+
if (typeof v === "function")
|
|
67
|
+
return undefined; // dropped
|
|
68
|
+
if (typeof v === "bigint")
|
|
69
|
+
return String(v) + "n";
|
|
70
|
+
if (typeof v === "symbol")
|
|
71
|
+
return String(v);
|
|
72
|
+
if (typeof v === "object") {
|
|
73
|
+
if (seen.has(v))
|
|
74
|
+
return SENTINEL; // cyclic
|
|
75
|
+
seen.add(v);
|
|
76
|
+
try {
|
|
77
|
+
// Resource-status projection (DVT-LIM-04): only genuine handles
|
|
78
|
+
// (those that carry a `promise` Promise field) are projected.
|
|
79
|
+
if (isResourceHandle(v)) {
|
|
80
|
+
const r = v;
|
|
81
|
+
const proj = { status: r.status };
|
|
82
|
+
if (r.status === "resolved" && "value" in r) {
|
|
83
|
+
proj.value = walk(r.value, depth + 1) ?? null;
|
|
84
|
+
}
|
|
85
|
+
return proj;
|
|
86
|
+
}
|
|
87
|
+
// Fix 2 — explicit branches for built-in types that Object.entries
|
|
88
|
+
// renders as `{}` (empty or numeric-index keys), making them look like
|
|
89
|
+
// empty objects in the panel.
|
|
90
|
+
if (v instanceof Date) {
|
|
91
|
+
return v.toISOString();
|
|
92
|
+
}
|
|
93
|
+
if (v instanceof Error) {
|
|
94
|
+
return { name: v.name, message: v.message };
|
|
95
|
+
}
|
|
96
|
+
if (v instanceof Map) {
|
|
97
|
+
if (depth >= maxDepth)
|
|
98
|
+
return `Map(${v.size})`;
|
|
99
|
+
const entries = [];
|
|
100
|
+
let count = 0;
|
|
101
|
+
for (const [mk, mv] of v) {
|
|
102
|
+
if (count >= maxKeys) {
|
|
103
|
+
entries.push(`…${v.size - maxKeys} more`);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
entries.push([walk(mk, depth + 1) ?? null, walk(mv, depth + 1) ?? null]);
|
|
107
|
+
count++;
|
|
108
|
+
}
|
|
109
|
+
return entries;
|
|
110
|
+
}
|
|
111
|
+
if (v instanceof Set) {
|
|
112
|
+
if (depth >= maxDepth)
|
|
113
|
+
return `Set(${v.size})`;
|
|
114
|
+
const items = [];
|
|
115
|
+
let count = 0;
|
|
116
|
+
for (const sv of v) {
|
|
117
|
+
if (count >= maxKeys) {
|
|
118
|
+
items.push(`…${v.size - maxKeys} more`);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
items.push(walk(sv, depth + 1) ?? null);
|
|
122
|
+
count++;
|
|
123
|
+
}
|
|
124
|
+
return items;
|
|
125
|
+
}
|
|
126
|
+
// TypedArray detection: ArrayBuffer views like Uint8Array, Float32Array, etc.
|
|
127
|
+
if (ArrayBuffer.isView(v) && !(v instanceof DataView)) {
|
|
128
|
+
const ta = v;
|
|
129
|
+
if (depth >= maxDepth)
|
|
130
|
+
return `TypedArray(${ta.length})`;
|
|
131
|
+
const truncated = ta.length > maxKeys;
|
|
132
|
+
const items = [];
|
|
133
|
+
const len = truncated ? maxKeys : ta.length;
|
|
134
|
+
for (let i = 0; i < len; i++)
|
|
135
|
+
items.push(ta[i]);
|
|
136
|
+
if (truncated)
|
|
137
|
+
items.push(`…${ta.length - maxKeys} more`);
|
|
138
|
+
return items;
|
|
139
|
+
}
|
|
140
|
+
if (depth >= maxDepth) {
|
|
141
|
+
// Summarize rather than truncate to avoid misleading data.
|
|
142
|
+
if (Array.isArray(v))
|
|
143
|
+
return `[…${v.length} items]`;
|
|
144
|
+
return `{…${Object.keys(v).length} keys}`;
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(v)) {
|
|
147
|
+
const truncated = v.length > maxKeys;
|
|
148
|
+
const items = v.slice(0, maxKeys);
|
|
149
|
+
const out = items.map((item) => walk(item, depth + 1) ?? null);
|
|
150
|
+
if (truncated)
|
|
151
|
+
out.push(`…${v.length - maxKeys} more`);
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
// Plain object — enumerate entries with per-key getter guard so a
|
|
155
|
+
// single throwing accessor only sentinels that key, not the whole object.
|
|
156
|
+
const keys = Object.keys(v);
|
|
157
|
+
const truncated = keys.length > maxKeys;
|
|
158
|
+
const kept = truncated ? keys.slice(0, maxKeys) : keys;
|
|
159
|
+
const out = {};
|
|
160
|
+
for (const k of kept) {
|
|
161
|
+
let val;
|
|
162
|
+
try {
|
|
163
|
+
val = v[k];
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// Throwing getter — sentinel THIS key only, don't abort the object.
|
|
167
|
+
out[k] = SENTINEL;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (typeof val === "function")
|
|
171
|
+
continue; // drop functions
|
|
172
|
+
const serialized = walk(val, depth + 1);
|
|
173
|
+
if (serialized !== undefined)
|
|
174
|
+
out[k] = serialized;
|
|
175
|
+
}
|
|
176
|
+
if (truncated) {
|
|
177
|
+
out["…"] = `${keys.length - maxKeys} more keys`;
|
|
178
|
+
}
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
seen.delete(v);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Unknown type — stringify as best effort, never throw.
|
|
186
|
+
try {
|
|
187
|
+
return String(v);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return SENTINEL;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
try {
|
|
194
|
+
return walk(value, 0);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return SENTINEL;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Serialize a bindings object for display: functions are dropped, values
|
|
202
|
+
* are depth/size-capped, unserializable values become `SENTINEL`.
|
|
203
|
+
* Mirrors the old `dataBindings` contract but with proper caps and resource
|
|
204
|
+
* projection (DVT-LIM-04 resolution). Exposed for use by helpers.ts.
|
|
205
|
+
*/
|
|
206
|
+
export const serializeBindings = (bindings, caps) => {
|
|
207
|
+
const out = {};
|
|
208
|
+
for (const [k, v] of Object.entries(bindings)) {
|
|
209
|
+
if (typeof v === "function")
|
|
210
|
+
continue;
|
|
211
|
+
const s = serialize(v, caps);
|
|
212
|
+
// Keep undefined-valued keys (they render as undefined in the panel).
|
|
213
|
+
out[k] = s ?? SENTINEL;
|
|
214
|
+
}
|
|
215
|
+
return out;
|
|
216
|
+
};
|
|
217
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { HookRecorder } from "./hookRecorder.ts";
|
|
2
|
+
export interface AttachStoreRecorderOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Re-enumeration interval in ms — catches stores instantiated after attach
|
|
5
|
+
* (a session store registered late, or a route store promoted; v1 only
|
|
6
|
+
* export/session subscribe). Mirrors the panel ticker cadence (default 700).
|
|
7
|
+
* Tests pass a tiny value or drive `refresh()` directly.
|
|
8
|
+
*/
|
|
9
|
+
refreshIntervalMs?: number;
|
|
10
|
+
}
|
|
11
|
+
/** Handle returned by `attachStoreRecorder`. */
|
|
12
|
+
export interface StoreRecorderHandle {
|
|
13
|
+
/** Re-enumerate stores now and subscribe to any newly-instantiated ones. */
|
|
14
|
+
refresh(): void;
|
|
15
|
+
/** Unsubscribe from every store and stop the re-enumeration interval. */
|
|
16
|
+
dispose(): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Subscribe every instantiated export/session store and fold its snapshots into
|
|
20
|
+
* the recorder's passive ring. Returns a handle whose `dispose()` unsubscribes
|
|
21
|
+
* all + stops the re-enumeration interval. Folding is gated by
|
|
22
|
+
* `recorder.recording()` — frozen/replay-mode is a full no-op.
|
|
23
|
+
*/
|
|
24
|
+
export declare const attachStoreRecorder: (recorder: HookRecorder, opts?: AttachStoreRecorderOptions) => StoreRecorderHandle;
|
|
25
|
+
//# sourceMappingURL=storeRecorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storeRecorder.d.ts","sourceRoot":"","sources":["../src/storeRecorder.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,OAAO,IAAI,IAAI,CAAA;IACf,yEAAyE;IACzE,OAAO,IAAI,IAAI,CAAA;CAChB;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,YAAY,EACtB,OAAM,0BAA+B,KACpC,mBA2DF,CAAA"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// @reactra/devtools — the store recorder: folds export/session store snapshots
|
|
2
|
+
// into the passive time-travel ring (Devtools spec §7; plan store-time-travel
|
|
3
|
+
// §3.2; architect C6).
|
|
4
|
+
//
|
|
5
|
+
// Subscribes every instantiated export/session store via the Stores-tab data
|
|
6
|
+
// layer and, on each change, folds a `store:<name>#1` full-state snapshot into
|
|
7
|
+
// the same `HookRecorder` ring the component commits + Route snapshots use.
|
|
8
|
+
// Gated by `recorder.recording()` — a full no-op while frozen/replaying (the
|
|
9
|
+
// ring must not grow during scrub). The snapshot runs through `recordSnapshot`,
|
|
10
|
+
// which serializes via `dataBindings` — the SAME depth/size-cap serializer as
|
|
11
|
+
// component commits (C6: shared serialization path, not a PII redactor — neither
|
|
12
|
+
// store nor component snapshots redact by field name). Re-drive uses the recorder's
|
|
13
|
+
// RAW store stash (not this serialized copy) so a `Map`/`Date`/large value
|
|
14
|
+
// round-trips losslessly.
|
|
15
|
+
//
|
|
16
|
+
// All store kinds record (route stores included — DVT-LIM-05 narrowed). A route
|
|
17
|
+
// store re-drives once its route re-instantiates it (driveAt re-drives the URL
|
|
18
|
+
// FIRST, which fires onEnter → StoreRegistry.instantiate synchronously on the
|
|
19
|
+
// fast path); on a middleware-gated / not-yet-loaded route the instance is async,
|
|
20
|
+
// so the snapshot degrades to a `view` card (replayStoreState returns 0). Subs to
|
|
21
|
+
// disposed route stores are dropped on route exit. Browser globals: none at module
|
|
22
|
+
// level (setInterval lives inside `attach`, started only when called).
|
|
23
|
+
import { listStores, storeInstanceToken, storeSnapshot, subscribeStore } from "./storeWatcher.js";
|
|
24
|
+
/** The id a store folds under in the ring (`store:` + name + the `#1` singleton suffix). */
|
|
25
|
+
const storeId = (name) => `store:${name}#1`;
|
|
26
|
+
/**
|
|
27
|
+
* Subscribe every instantiated export/session store and fold its snapshots into
|
|
28
|
+
* the recorder's passive ring. Returns a handle whose `dispose()` unsubscribes
|
|
29
|
+
* all + stops the re-enumeration interval. Folding is gated by
|
|
30
|
+
* `recorder.recording()` — frozen/replay-mode is a full no-op.
|
|
31
|
+
*/
|
|
32
|
+
export const attachStoreRecorder = (recorder, opts = {}) => {
|
|
33
|
+
const refreshIntervalMs = opts.refreshIntervalMs ?? 700;
|
|
34
|
+
// name → { unsubscribe, instance-identity }. The instance token lets refresh
|
|
35
|
+
// detect an HMR `replace` swap and re-subscribe — a subscription made before
|
|
36
|
+
// the swap is bound to the dead instance and would silently stop folding.
|
|
37
|
+
const subs = new Map();
|
|
38
|
+
const fold = (name) => {
|
|
39
|
+
// recordSnapshot itself no-ops when recording is off (C6 + freeze gate),
|
|
40
|
+
// but check here too so we never read a snapshot we won't use.
|
|
41
|
+
if (!recorder.recording())
|
|
42
|
+
return;
|
|
43
|
+
const snap = storeSnapshot(name);
|
|
44
|
+
if (snap === undefined)
|
|
45
|
+
return;
|
|
46
|
+
recorder.recordSnapshot(storeId(name), snap);
|
|
47
|
+
};
|
|
48
|
+
const refresh = () => {
|
|
49
|
+
// All store kinds now record (route stores incl. — DVT-LIM-05 narrowed). A
|
|
50
|
+
// route store re-drives once its route re-instantiates it (driveAt Pass A);
|
|
51
|
+
// until then its snapshot is a `view` card.
|
|
52
|
+
const liveNames = new Set();
|
|
53
|
+
for (const row of listStores()) {
|
|
54
|
+
if (!row.instantiated)
|
|
55
|
+
continue;
|
|
56
|
+
liveNames.add(row.name);
|
|
57
|
+
const inst = storeInstanceToken(row.name);
|
|
58
|
+
const existing = subs.get(row.name);
|
|
59
|
+
// Already subscribed to the SAME instance → nothing to do. After an HMR
|
|
60
|
+
// `replace` (or a route-store re-enter) the token differs → drop the dead
|
|
61
|
+
// subscription + re-subscribe to the new instance.
|
|
62
|
+
if (existing && existing.inst === inst)
|
|
63
|
+
continue;
|
|
64
|
+
if (existing)
|
|
65
|
+
existing.off();
|
|
66
|
+
const off = subscribeStore(row.name, () => fold(row.name));
|
|
67
|
+
subs.set(row.name, { off, inst });
|
|
68
|
+
// Fold the current value immediately so the store has a baseline in the
|
|
69
|
+
// ring (mirrors the panel's mount-time Route#1 fold).
|
|
70
|
+
fold(row.name);
|
|
71
|
+
}
|
|
72
|
+
// C5 — drop subscriptions to stores no longer instantiated (a route store
|
|
73
|
+
// disposed on route exit). The recorded snapshots stay in the ring; we just
|
|
74
|
+
// stop holding a dead subscription. A re-enter re-subscribes above.
|
|
75
|
+
for (const name of [...subs.keys()]) {
|
|
76
|
+
if (!liveNames.has(name)) {
|
|
77
|
+
subs.get(name).off();
|
|
78
|
+
subs.delete(name);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
refresh();
|
|
83
|
+
const intervalId = setInterval(refresh, refreshIntervalMs);
|
|
84
|
+
return {
|
|
85
|
+
refresh,
|
|
86
|
+
dispose: () => {
|
|
87
|
+
clearInterval(intervalId);
|
|
88
|
+
for (const { off } of subs.values())
|
|
89
|
+
off();
|
|
90
|
+
subs.clear();
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=storeRecorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storeRecorder.js","sourceRoot":"","sources":["../src/storeRecorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** One Stores-tab row (Devtools §5). */
|
|
2
|
+
export interface StoreRow {
|
|
3
|
+
name: string;
|
|
4
|
+
kind: "export" | "session" | "route";
|
|
5
|
+
instantiated: boolean;
|
|
6
|
+
preservedFields: readonly string[];
|
|
7
|
+
subtreePath?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Snapshot of every registered binding (fresh read — call per render tick). */
|
|
10
|
+
export declare const listStores: () => readonly StoreRow[];
|
|
11
|
+
/** A live store's current snapshot; `undefined` when not instantiated. */
|
|
12
|
+
export declare const storeSnapshot: (name: string) => Record<string, unknown> | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Subscribe to one live store's changes. No-op unsubscriber when the store
|
|
15
|
+
* isn't instantiated (route store before entry) — the panel re-lists on its
|
|
16
|
+
* own cadence and re-subscribes when the instance appears.
|
|
17
|
+
*/
|
|
18
|
+
export declare const subscribeStore: (name: string, onChange: () => void) => (() => void);
|
|
19
|
+
/**
|
|
20
|
+
* An identity token for a store's CURRENT instance (or undefined when not
|
|
21
|
+
* instantiated). HMR `StoreRegistry.replace` swaps the instance object, so a
|
|
22
|
+
* watcher can compare this token to detect the swap and re-subscribe — without
|
|
23
|
+
* it, a subscription made before the swap stays bound to the dead instance.
|
|
24
|
+
*/
|
|
25
|
+
export declare const storeInstanceToken: (name: string) => object | undefined;
|
|
26
|
+
//# sourceMappingURL=storeWatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storeWatcher.d.ts","sourceRoot":"","sources":["../src/storeWatcher.ts"],"names":[],"mappings":"AAQA,wCAAwC;AACxC,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAA;IACpC,YAAY,EAAE,OAAO,CAAA;IACrB,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,gFAAgF;AAChF,eAAO,MAAM,UAAU,QAAO,SAAS,QAAQ,EAA2B,CAAA;AAE1E,0EAA0E;AAC1E,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SACM,CAAA;AAE7E;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,UAAU,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CACG,CAAA;AAElF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAAM,GAAG,SAC2B,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// @reactra/devtools — the Stores-tab data layer.
|
|
2
|
+
//
|
|
3
|
+
// Owner: reactra-devtools-spec.md §5. Thin reads over `@reactra/store`'s
|
|
4
|
+
// registry: the internal `__listStoreBindings` enumeration (Runtime §1
|
|
5
|
+
// internal tier — diagnostics) + per-instance subscribe/getSnapshot.
|
|
6
|
+
import { StoreRegistry, __listStoreBindings } from "@reactra/store";
|
|
7
|
+
/** Snapshot of every registered binding (fresh read — call per render tick). */
|
|
8
|
+
export const listStores = () => __listStoreBindings();
|
|
9
|
+
/** A live store's current snapshot; `undefined` when not instantiated. */
|
|
10
|
+
export const storeSnapshot = (name) => StoreRegistry.has(name) ? StoreRegistry.get(name).getSnapshot() : undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Subscribe to one live store's changes. No-op unsubscriber when the store
|
|
13
|
+
* isn't instantiated (route store before entry) — the panel re-lists on its
|
|
14
|
+
* own cadence and re-subscribes when the instance appears.
|
|
15
|
+
*/
|
|
16
|
+
export const subscribeStore = (name, onChange) => StoreRegistry.has(name) ? StoreRegistry.get(name).subscribe(onChange) : () => { };
|
|
17
|
+
/**
|
|
18
|
+
* An identity token for a store's CURRENT instance (or undefined when not
|
|
19
|
+
* instantiated). HMR `StoreRegistry.replace` swaps the instance object, so a
|
|
20
|
+
* watcher can compare this token to detect the swap and re-subscribe — without
|
|
21
|
+
* it, a subscription made before the swap stays bound to the dead instance.
|
|
22
|
+
*/
|
|
23
|
+
export const storeInstanceToken = (name) => StoreRegistry.has(name) ? StoreRegistry.get(name) : undefined;
|
|
24
|
+
//# sourceMappingURL=storeWatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storeWatcher.js","sourceRoot":"","sources":["../src/storeWatcher.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,yEAAyE;AACzE,uEAAuE;AACvE,qEAAqE;AAErE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAWnE,gFAAgF;AAChF,MAAM,CAAC,MAAM,UAAU,GAAG,GAAwB,EAAE,CAAC,mBAAmB,EAAE,CAAA;AAE1E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAuC,EAAE,CACjF,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;AAE7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAE,QAAoB,EAAgB,EAAE,CACjF,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;AAElF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAsB,EAAE,CACrE,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,aAAa,CAAC,GAAG,CAAC,IAAI,CAAuB,CAAC,CAAC,CAAC,SAAS,CAAA"}
|
package/dist/styles.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Append the devtools stylesheet once per document. No-op outside a browser. */
|
|
2
|
+
export declare const ensureStyles: (target?: Document) => void;
|
|
3
|
+
/** Test hook: lets unit tests assert single-injection semantics. */
|
|
4
|
+
export declare const __resetStylesForTest: () => void;
|
|
5
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAkBA,iFAAiF;AACjF,eAAO,MAAM,YAAY,GAAI,SAAS,QAAQ,KAAG,IAUhD,CAAA;AAED,oEAAoE;AACpE,eAAO,MAAM,oBAAoB,QAAO,IAEvC,CAAA"}
|