@reticlehq/browser 2.13.1 → 3.1.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/dist/actions/actions-dom.d.ts +8 -20
- package/dist/actions/actions-dom.js +70 -69
- package/dist/actions/actions-press.d.ts +14 -0
- package/dist/actions/actions-press.js +123 -0
- package/dist/actions/actions.d.ts +1 -89
- package/dist/actions/actions.js +64 -365
- package/dist/actions/appeared-text.d.ts +0 -20
- package/dist/actions/appeared-text.js +6 -36
- package/dist/actions/danger-context.d.ts +3 -0
- package/dist/actions/danger-context.js +39 -0
- package/dist/actions/scroll.d.ts +8 -10
- package/dist/actions/scroll.js +28 -17
- package/dist/actions/synthetic/synthetic-input.d.ts +2 -0
- package/dist/actions/synthetic/synthetic-input.js +13 -0
- package/dist/actions/value-input.d.ts +0 -30
- package/dist/actions/value-input.js +0 -33
- package/dist/commands/commands.d.ts +0 -2
- package/dist/commands/commands.js +10 -70
- package/dist/connect-options.d.ts +2 -96
- package/dist/dom/a11y.d.ts +0 -29
- package/dist/dom/a11y.js +3 -90
- package/dist/dom/addressing/auto-anchor.d.ts +25 -0
- package/dist/dom/addressing/auto-anchor.js +41 -0
- package/dist/dom/addressing/refs.d.ts +14 -0
- package/dist/dom/addressing/refs.js +114 -0
- package/dist/dom/addressing/source.d.ts +9 -0
- package/dist/dom/addressing/source.js +29 -0
- package/dist/dom/chart.d.ts +0 -61
- package/dist/dom/chart.js +0 -60
- package/dist/dom/desktop-capture.d.ts +0 -30
- package/dist/dom/desktop-capture.js +1 -73
- package/dist/dom/dom-ignore.d.ts +0 -30
- package/dist/dom/dom-ignore.js +1 -48
- package/dist/dom/occlusion.d.ts +0 -7
- package/dist/dom/occlusion.js +31 -12
- package/dist/dom/paint-context.d.ts +6 -0
- package/dist/dom/paint-context.js +38 -0
- package/dist/dom/query.d.ts +0 -14
- package/dist/dom/query.js +50 -216
- package/dist/dom/realm.d.ts +0 -20
- package/dist/dom/realm.js +0 -28
- package/dist/dom/shadow-registry.d.ts +0 -33
- package/dist/dom/shadow-registry.js +2 -72
- package/dist/dom/snapshot.d.ts +2 -43
- package/dist/dom/snapshot.js +27 -152
- package/dist/dom/theme.d.ts +0 -37
- package/dist/dom/theme.js +2 -52
- package/dist/dom/virtualized.d.ts +0 -17
- package/dist/dom/virtualized.js +0 -27
- package/dist/edit-epoch.d.ts +1 -23
- package/dist/edit-epoch.js +1 -53
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -28
- package/dist/observers/animation.d.ts +0 -1
- package/dist/observers/animation.js +1 -4
- package/dist/observers/blind-spots.d.ts +0 -26
- package/dist/observers/blind-spots.js +3 -62
- package/dist/observers/console.d.ts +1 -2
- package/dist/observers/console.js +41 -30
- package/dist/observers/context-open.d.ts +1 -11
- package/dist/observers/context-open.js +10 -14
- package/dist/observers/departure.d.ts +3 -0
- package/dist/observers/departure.js +52 -0
- package/dist/observers/dialogs.d.ts +2 -0
- package/dist/observers/dialogs.js +39 -0
- package/dist/observers/dom.js +28 -52
- package/dist/observers/download.d.ts +1 -2
- package/dist/observers/download.js +39 -56
- package/dist/observers/focus.d.ts +0 -6
- package/dist/observers/focus.js +0 -7
- package/dist/observers/frames.d.ts +0 -9
- package/dist/observers/frames.js +1 -28
- package/dist/observers/health.d.ts +0 -5
- package/dist/observers/health.js +2 -34
- package/dist/observers/install-all.d.ts +2 -0
- package/dist/observers/install-all.js +26 -27
- package/dist/observers/ipc.d.ts +0 -25
- package/dist/observers/ipc.js +0 -65
- package/dist/observers/navigation.d.ts +2 -0
- package/dist/observers/navigation.js +33 -0
- package/dist/observers/net-detail/network-body.d.ts +12 -0
- package/dist/observers/net-detail/network-body.js +71 -0
- package/dist/observers/net-detail/network-redact.d.ts +1 -0
- package/dist/observers/net-detail/network-redact.js +1 -0
- package/dist/observers/network-stream.d.ts +0 -21
- package/dist/observers/network-stream.js +3 -46
- package/dist/observers/network.d.ts +3 -27
- package/dist/observers/network.js +178 -295
- package/dist/observers/perf.d.ts +0 -10
- package/dist/observers/perf.js +0 -16
- package/dist/observers/route.d.ts +1 -2
- package/dist/observers/route.js +13 -19
- package/dist/observers/scroll.d.ts +0 -1
- package/dist/observers/scroll.js +2 -11
- package/dist/observers/sdk-failure.d.ts +1 -9
- package/dist/observers/sdk-failure.js +1 -30
- package/dist/observers/state.d.ts +1 -11
- package/dist/observers/state.js +13 -41
- package/dist/observers/storage.d.ts +0 -14
- package/dist/observers/storage.js +10 -34
- package/dist/observers/types.d.ts +0 -15
- package/dist/observers/types.js +0 -14
- package/dist/patching/capture-method.d.ts +0 -24
- package/dist/patching/capture-method.js +0 -26
- package/dist/presenter/chrome/layers.d.ts +2 -0
- package/dist/presenter/chrome/layers.js +2 -0
- package/dist/presenter/chrome/log-kinds.d.ts +12 -0
- package/dist/presenter/chrome/log-kinds.js +7 -0
- package/dist/presenter/{overlay.d.ts → chrome/overlay.d.ts} +0 -1
- package/dist/presenter/{overlay.js → chrome/overlay.js} +0 -1
- package/dist/presenter/chrome/presenter-brand.d.ts +3 -0
- package/dist/presenter/{presenter-brand.js → chrome/presenter-brand.js} +0 -21
- package/dist/presenter/chrome/presenter-effects.d.ts +4 -0
- package/dist/presenter/{presenter-effects.js → chrome/presenter-effects.js} +1 -10
- package/dist/presenter/chrome/presenter-hud-chrome.d.ts +7 -0
- package/dist/presenter/{presenter-hud-chrome.js → chrome/presenter-hud-chrome.js} +0 -10
- package/dist/presenter/chrome/presenter-log.d.ts +17 -0
- package/dist/presenter/{presenter-log.js → chrome/presenter-log.js} +5 -54
- package/dist/presenter/chrome/presenter-report-copy.d.ts +51 -0
- package/dist/presenter/chrome/presenter-report-copy.js +95 -0
- package/dist/presenter/chrome/presenter-safe-html.d.ts +2 -0
- package/dist/presenter/chrome/presenter-safe-html.js +16 -0
- package/dist/presenter/{presenter-tally.d.ts → chrome/presenter-tally.d.ts} +0 -5
- package/dist/presenter/{presenter-tally.js → chrome/presenter-tally.js} +1 -5
- package/dist/presenter/{presenter-verbs.js → chrome/presenter-verbs.js} +0 -7
- package/dist/presenter/{presenter-heroicons-data.d.ts → icons/presenter-heroicons-data.d.ts} +1 -8
- package/dist/presenter/{presenter-heroicons-data.js → icons/presenter-heroicons-data.js} +1 -8
- package/dist/presenter/{presenter-icons.d.ts → icons/presenter-icons.d.ts} +1 -6
- package/dist/presenter/{presenter-icons.js → icons/presenter-icons.js} +1 -6
- package/dist/presenter/presenter-account-styles.d.ts +1 -0
- package/dist/presenter/presenter-account-styles.js +99 -0
- package/dist/presenter/presenter-account.d.ts +40 -0
- package/dist/presenter/presenter-account.js +178 -0
- package/dist/presenter/presenter-config.d.ts +10 -107
- package/dist/presenter/presenter-config.js +5 -92
- package/dist/presenter/presenter-controls.d.ts +1 -35
- package/dist/presenter/presenter-controls.js +10 -133
- package/dist/presenter/presenter-dock-layout.d.ts +0 -3
- package/dist/presenter/presenter-dock-layout.js +1 -5
- package/dist/presenter/presenter-drag.d.ts +2 -42
- package/dist/presenter/presenter-drag.js +3 -76
- package/dist/presenter/presenter-glow.d.ts +0 -21
- package/dist/presenter/presenter-glow.js +2 -28
- package/dist/presenter/presenter-hud-position.d.ts +18 -0
- package/dist/presenter/presenter-hud-position.js +50 -0
- package/dist/presenter/presenter-report-styles.d.ts +0 -6
- package/dist/presenter/presenter-report-styles.js +22 -7
- package/dist/presenter/presenter-report.d.ts +5 -7
- package/dist/presenter/presenter-report.js +44 -95
- package/dist/presenter/presenter-run-state.d.ts +1 -8
- package/dist/presenter/presenter-run-state.js +1 -6
- package/dist/presenter/presenter-settings-styles.d.ts +0 -1
- package/dist/presenter/presenter-settings-styles.js +2 -2
- package/dist/presenter/presenter-settings.d.ts +5 -23
- package/dist/presenter/presenter-settings.js +21 -33
- package/dist/presenter/presenter-shell-styles.js +23 -20
- package/dist/presenter/presenter-shell.d.ts +6 -18
- package/dist/presenter/presenter-shell.js +26 -77
- package/dist/presenter/presenter-styles.d.ts +2 -10
- package/dist/presenter/presenter-styles.js +6 -12
- package/dist/presenter/presenter-workspace.d.ts +4 -4
- package/dist/presenter/presenter-workspace.js +30 -10
- package/dist/presenter/presenter.d.ts +3 -63
- package/dist/presenter/presenter.js +29 -132
- package/dist/presenter/tour/tour-view.d.ts +33 -0
- package/dist/presenter/tour/tour-view.js +188 -0
- package/dist/presenter/tour/tour.d.ts +25 -0
- package/dist/presenter/tour/tour.js +245 -0
- package/dist/recorder/recorder-styles.d.ts +0 -6
- package/dist/recorder/recorder-styles.js +0 -6
- package/dist/recorder/recorder.d.ts +0 -34
- package/dist/recorder/recorder.js +6 -49
- package/dist/registry/auto-testids.d.ts +0 -19
- package/dist/registry/auto-testids.js +1 -21
- package/dist/registry/capabilities.d.ts +0 -31
- package/dist/registry/capabilities.js +1 -46
- package/dist/registry/commit-and-signal.d.ts +0 -6
- package/dist/registry/commit-and-signal.js +1 -7
- package/dist/registry/declared-channels.d.ts +2 -0
- package/dist/registry/declared-channels.js +14 -0
- package/dist/registry/declared-platform.d.ts +4 -0
- package/dist/registry/declared-platform.js +34 -0
- package/dist/registry/domains.d.ts +0 -8
- package/dist/registry/domains.js +0 -7
- package/dist/registry/emitter.d.ts +0 -14
- package/dist/registry/emitter.js +1 -11
- package/dist/registry/store-adapters.d.ts +0 -186
- package/dist/registry/store-adapters.js +1 -164
- package/dist/registry/{adapters.d.ts → stores/adapters.d.ts} +0 -10
- package/dist/registry/{adapters.js → stores/adapters.js} +0 -10
- package/dist/registry/stores.d.ts +0 -33
- package/dist/registry/stores.js +1 -60
- package/dist/reticle-presenter-helpers.d.ts +0 -13
- package/dist/reticle-presenter-helpers.js +10 -20
- package/dist/reticle-singleton.d.ts +2 -0
- package/dist/reticle-singleton.js +3 -0
- package/dist/reticle.d.ts +1 -52
- package/dist/reticle.js +115 -180
- package/dist/review/annotator-styles.js +1 -8
- package/dist/review/annotator.d.ts +2 -13
- package/dist/review/annotator.js +2 -42
- package/dist/review/mark-anchor.d.ts +0 -11
- package/dist/review/mark-anchor.js +3 -11
- package/dist/security/serialization.d.ts +0 -20
- package/dist/security/serialization.js +1 -66
- package/dist/session-continuity.d.ts +0 -16
- package/dist/session-continuity.js +1 -20
- package/dist/timers/clock.d.ts +1 -14
- package/dist/timers/clock.js +59 -60
- package/dist/timers/console/native-console.js +5 -0
- package/dist/timers/native/native-timers.d.ts +11 -0
- package/dist/timers/native/native-timers.js +48 -0
- package/dist/transport/transport.d.ts +0 -51
- package/dist/transport/transport.js +5 -131
- package/dist/transport/unreachable-message.d.ts +0 -17
- package/dist/transport/unreachable-message.js +0 -17
- package/dist/util/captured-method.d.ts +0 -35
- package/dist/util/captured-method.js +0 -35
- package/package.json +5 -4
- package/dist/actions/synthetic-input.d.ts +0 -9
- package/dist/actions/synthetic-input.js +0 -40
- package/dist/dom/auto-anchor.d.ts +0 -65
- package/dist/dom/auto-anchor.js +0 -74
- package/dist/dom/refs.d.ts +0 -90
- package/dist/dom/refs.js +0 -245
- package/dist/dom/source.d.ts +0 -53
- package/dist/dom/source.js +0 -74
- package/dist/observers/network-body.d.ts +0 -35
- package/dist/observers/network-body.js +0 -168
- package/dist/observers/network-redact.d.ts +0 -20
- package/dist/observers/network-redact.js +0 -80
- package/dist/presenter/presenter-brand.d.ts +0 -22
- package/dist/presenter/presenter-effects.d.ts +0 -13
- package/dist/presenter/presenter-hud-chrome.d.ts +0 -17
- package/dist/presenter/presenter-log.d.ts +0 -64
- package/dist/presenter/presenter-report-copy.d.ts +0 -112
- package/dist/presenter/presenter-report-copy.js +0 -156
- package/dist/presenter/presenter-test-helpers.d.ts +0 -16
- package/dist/presenter/presenter-test-helpers.js +0 -41
- package/dist/timers/native-console.js +0 -9
- package/dist/timers/native-timers.d.ts +0 -36
- package/dist/timers/native-timers.js +0 -78
- /package/dist/presenter/{presenter-verbs.d.ts → chrome/presenter-verbs.d.ts} +0 -0
- /package/dist/timers/{native-console.d.ts → console/native-console.d.ts} +0 -0
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import { nativeWarn } from '../timers/native-console.js';
|
|
1
|
+
import { nativeWarn } from '../timers/console/native-console.js';
|
|
2
2
|
import { markAdapterSource } from './stores.js';
|
|
3
|
-
/**
|
|
4
|
-
* Expose a TanStack Query cache as a Reticle store, keyed by query key.
|
|
5
|
-
*
|
|
6
|
-
* `isStale` / `fetchStatus` / `dataUpdatedAt` are carried deliberately: they are what let an agent
|
|
7
|
-
* assert the stronger property — not merely "the value rendered is X" but "the cache the UI rendered
|
|
8
|
-
* from was actually fresh". A screenshot cannot distinguish a correct number from a correct-looking
|
|
9
|
-
* stale one, and neither can a network log when the request never fired.
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* registerStore('queries', tanstackQueryStore(queryClient));
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
3
|
export function tanstackQueryStore(client) {
|
|
16
|
-
// Resolved per call, not captured once. A QueryClient can be rebuilt — React Strict Mode double
|
|
17
|
-
// effects, a provider remount, HMR — and an adapter holding the old cache would keep answering
|
|
18
|
-
// from a store the app no longer reads, which is a stale-data bug inside the tool whose job is
|
|
19
|
-
// catching stale data.
|
|
20
4
|
const store = {
|
|
21
5
|
getState: () => {
|
|
22
6
|
const out = {};
|
|
@@ -35,22 +19,9 @@ export function tanstackQueryStore(client) {
|
|
|
35
19
|
},
|
|
36
20
|
subscribe: (listener) => client.getQueryCache().subscribe(listener),
|
|
37
21
|
};
|
|
38
|
-
// Registering this adapter claims the CLIENT too, so fiber-tree discovery can tell that the app
|
|
39
|
-
// already wired this exact QueryClient and must not add a second entry for it.
|
|
40
22
|
markAdapterSource(store, client);
|
|
41
23
|
return store;
|
|
42
24
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Expose a chosen set of Jotai atoms as one Reticle store.
|
|
45
|
-
*
|
|
46
|
-
* The atom map is not an ergonomic shortcut, it is forced by the design: Jotai has no registry of live
|
|
47
|
-
* atoms to enumerate, so "the whole store" is not a thing that exists. Naming the atoms you care about
|
|
48
|
-
* is the only way to snapshot them, and it doubles as a declaration of what matters.
|
|
49
|
-
*
|
|
50
|
-
* ```ts
|
|
51
|
-
* registerStore('app', jotaiStore(getDefaultStore(), { cart: cartAtom, user: userAtom }));
|
|
52
|
-
* ```
|
|
53
|
-
*/
|
|
54
25
|
export function jotaiStore(store, atoms) {
|
|
55
26
|
return {
|
|
56
27
|
getState: () => {
|
|
@@ -68,10 +39,6 @@ export function jotaiStore(store, atoms) {
|
|
|
68
39
|
},
|
|
69
40
|
};
|
|
70
41
|
}
|
|
71
|
-
/**
|
|
72
|
-
* Expose an XState actor as a Reticle store. Its `subscribe` returns a subscription OBJECT rather than
|
|
73
|
-
* an unsubscribe function, which is the single reason it does not satisfy `StoreLike` already.
|
|
74
|
-
*/
|
|
75
42
|
export function xstateStore(actor) {
|
|
76
43
|
return {
|
|
77
44
|
getState: () => actor.getSnapshot(),
|
|
@@ -81,41 +48,18 @@ export function xstateStore(actor) {
|
|
|
81
48
|
},
|
|
82
49
|
};
|
|
83
50
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Expose a Valtio proxy as a Reticle store. Valtio ships `snapshot`/`subscribe` as free functions
|
|
86
|
-
* rather than methods, so the caller passes them in — importing them here would make every consumer
|
|
87
|
-
* of this file depend on valtio.
|
|
88
|
-
*
|
|
89
|
-
* ```ts
|
|
90
|
-
* import { snapshot, subscribe } from 'valtio/vanilla';
|
|
91
|
-
* registerStore('app', valtioStore(state, snapshot, subscribe));
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
51
|
export function valtioStore(proxy, snapshot, subscribe) {
|
|
95
52
|
return {
|
|
96
53
|
getState: () => snapshot(proxy),
|
|
97
54
|
subscribe: (listener) => subscribe(proxy, listener),
|
|
98
55
|
};
|
|
99
56
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Expose a MobX observable as a Reticle store. `toJS` and `reaction` are passed in for the same
|
|
102
|
-
* dependency reason as valtio above.
|
|
103
|
-
*
|
|
104
|
-
* ```ts
|
|
105
|
-
* import { reaction, toJS } from 'mobx';
|
|
106
|
-
* registerStore('app', mobxStore(store, toJS, reaction));
|
|
107
|
-
* ```
|
|
108
|
-
*/
|
|
109
57
|
export function mobxStore(observable, toJS, reaction) {
|
|
110
58
|
return {
|
|
111
59
|
getState: () => toJS(observable),
|
|
112
60
|
subscribe: (listener) => reaction(() => toJS(observable), () => listener()),
|
|
113
61
|
};
|
|
114
62
|
}
|
|
115
|
-
/**
|
|
116
|
-
* The load states a Recoil `Loadable` reports. Named because the projection below branches on them
|
|
117
|
-
* and a bare 'hasValue' in three places is exactly the free string the rules forbid.
|
|
118
|
-
*/
|
|
119
63
|
const RecoilLoadState = {
|
|
120
64
|
HAS_VALUE: 'hasValue',
|
|
121
65
|
LOADING: 'loading',
|
|
@@ -130,50 +74,13 @@ function projectLoadable(loadable) {
|
|
|
130
74
|
error: contents instanceof Error ? contents.message : String(contents),
|
|
131
75
|
};
|
|
132
76
|
}
|
|
133
|
-
// A LOADING loadable's `contents` is the pending promise. Sending it would serialize to `{}` and
|
|
134
|
-
// read as an empty value — so the value stays null and the status carries the truth.
|
|
135
77
|
if (loadable.state !== RecoilLoadState.HAS_VALUE) {
|
|
136
78
|
return { status: loadable.state, value: null, error: null };
|
|
137
79
|
}
|
|
138
80
|
return { status: loadable.state, value: loadable.contents, error: null };
|
|
139
81
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Expose a chosen set of Recoil atoms as one Reticle store.
|
|
142
|
-
*
|
|
143
|
-
* Three things about Recoil's API shape this adapter is built around, none of them optional:
|
|
144
|
-
*
|
|
145
|
-
* - **The atom map is forced, not an ergonomic choice.** Recoil has no enumerable registry of live
|
|
146
|
-
* atoms, so "the whole store" is not a thing that exists. Naming the atoms is the only way to
|
|
147
|
-
* snapshot them, and it doubles as a declaration of what matters — the same reason `jotaiStore`
|
|
148
|
-
* takes one.
|
|
149
|
-
* - **`.state`/`.contents`, never `.getValue()`.** On a pending async selector `getValue()` THROWS
|
|
150
|
-
* the pending promise, and on a failed one it throws the error. Either would take down the whole
|
|
151
|
-
* state read over one slow atom — so a loading atom reports `status: 'loading'` with a null value
|
|
152
|
-
* rather than silently becoming an empty object or an exception.
|
|
153
|
-
* - **One subscription, not one per atom.** Recoil exposes no per-atom subscription outside React
|
|
154
|
-
* (`jotaiStore` gets `store.sub(atom, …)`; there is no equivalent here). The transaction stream is
|
|
155
|
-
* the only public change signal, so the caller passes it in — the same "the library ships free
|
|
156
|
-
* functions, so hand them over" shape as `valtioStore` and `mobxStore`.
|
|
157
|
-
*
|
|
158
|
-
* Wire it from a bridge component, which is where `useRecoilTransactionObserver_UNSTABLE` lives:
|
|
159
|
-
*
|
|
160
|
-
* ```tsx
|
|
161
|
-
* const latest = useRef(snapshot_UNSTABLE());
|
|
162
|
-
* const listeners = useRef(new Set<() => void>()).current;
|
|
163
|
-
* useRecoilTransactionObserver_UNSTABLE(({ snapshot }) => {
|
|
164
|
-
* latest.current = snapshot;
|
|
165
|
-
* for (const l of listeners) l();
|
|
166
|
-
* });
|
|
167
|
-
* registerStore('recoil', recoilStore({ cart: cartAtom }, () => latest.current, (l) => {
|
|
168
|
-
* listeners.add(l);
|
|
169
|
-
* return () => listeners.delete(l);
|
|
170
|
-
* }));
|
|
171
|
-
* ```
|
|
172
|
-
*/
|
|
173
82
|
export function recoilStore(atoms, snapshot, subscribe) {
|
|
174
83
|
return {
|
|
175
|
-
// Resolved per call, not captured once: a Recoil snapshot is IMMUTABLE, so an adapter holding
|
|
176
|
-
// one would keep answering from the transaction it was built in and never see another write.
|
|
177
84
|
getState: () => {
|
|
178
85
|
const current = snapshot();
|
|
179
86
|
const out = {};
|
|
@@ -192,25 +99,6 @@ function stopSubscription(handle) {
|
|
|
192
99
|
}
|
|
193
100
|
handle.unsubscribe();
|
|
194
101
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Expose a Svelte store as a Reticle store.
|
|
197
|
-
*
|
|
198
|
-
* Structurally unlike every other adapter in this file: they all wrap something that can be PULLED
|
|
199
|
-
* (`getState`, `getSnapshot`, `snapshot(proxy)`, `toJS`). A Svelte store has no pull side at all —
|
|
200
|
-
* `{ subscribe }` is the entire contract. What makes a pull possible anyway is the part of that
|
|
201
|
-
* contract which says `subscribe` must call back **immediately and synchronously** with the current
|
|
202
|
-
* value: subscribe, catch the value, unsubscribe, return it. That is precisely how `svelte/store`'s
|
|
203
|
-
* own `get()` is implemented, so it is a blessed read rather than a trick.
|
|
204
|
-
*
|
|
205
|
-
* Doing it that way is what keeps this adapter free of the `dispose` the obvious implementation
|
|
206
|
-
* needs. Caching the latest value would mean holding a permanent subscription, which means a
|
|
207
|
-
* teardown the other five adapters don't have, which means a leak the moment a caller forgets it.
|
|
208
|
-
* A transient subscription per read owns nothing and leaks nothing.
|
|
209
|
-
*
|
|
210
|
-
* ```ts
|
|
211
|
-
* registerStore('cart', svelteStore(cartStore));
|
|
212
|
-
* ```
|
|
213
|
-
*/
|
|
214
102
|
export function svelteStore(readable, warn = nativeWarn) {
|
|
215
103
|
let warnedAboutLazyStore = false;
|
|
216
104
|
return {
|
|
@@ -221,10 +109,6 @@ export function svelteStore(readable, warn = nativeWarn) {
|
|
|
221
109
|
value = next;
|
|
222
110
|
called = true;
|
|
223
111
|
}));
|
|
224
|
-
// A store that did NOT call back synchronously (an RxJS Observable that is not a
|
|
225
|
-
// BehaviorSubject, a hand-rolled store that breaks the contract) leaves `value` undefined —
|
|
226
|
-
// indistinguishable from a store legitimately holding undefined. Reading empty when the answer
|
|
227
|
-
// is "unknown" is the false green this project exists to prevent, so say it once, out loud.
|
|
228
112
|
if (!called && !warnedAboutLazyStore) {
|
|
229
113
|
warnedAboutLazyStore = true;
|
|
230
114
|
warn('[reticle] a store passed to svelteStore did not call its subscriber synchronously, so ' +
|
|
@@ -235,17 +119,6 @@ export function svelteStore(readable, warn = nativeWarn) {
|
|
|
235
119
|
return value;
|
|
236
120
|
},
|
|
237
121
|
subscribe: (listener) => {
|
|
238
|
-
// Swallow whatever arrives DURING the subscribe call. Forwarding it would emit a STATE_CHANGE
|
|
239
|
-
// at REGISTRATION time for a change that never happened — a diff of nothing that shows up in
|
|
240
|
-
// causal summaries and that a {kind:'state'} predicate could satisfy without the app doing
|
|
241
|
-
// anything at all.
|
|
242
|
-
//
|
|
243
|
-
// The window is what makes this correct, rather than "swallow the first callback whenever it
|
|
244
|
-
// arrives". A store that does NOT call back synchronously (an RxJS Observable that is not a
|
|
245
|
-
// BehaviorSubject — the exact store `getState` warns about) has no registration callback to
|
|
246
|
-
// drop, so counting callbacks ate its first REAL change: no STATE_CHANGE, and a
|
|
247
|
-
// {kind:'state'} assertion with nothing to match. A silently missed state change is the false
|
|
248
|
-
// green this project exists to prevent, so the rule is positional, not ordinal.
|
|
249
122
|
let inSubscribeCall = true;
|
|
250
123
|
const handle = readable.subscribe(() => {
|
|
251
124
|
if (!inSubscribeCall)
|
|
@@ -256,49 +129,13 @@ export function svelteStore(readable, warn = nativeWarn) {
|
|
|
256
129
|
},
|
|
257
130
|
};
|
|
258
131
|
}
|
|
259
|
-
/** Pinia `$subscribe` options. `sync` and `detached` are library option values, not free strings. */
|
|
260
132
|
const PINIA_SUBSCRIBE_OPTIONS = { detached: true, flush: 'sync' };
|
|
261
|
-
/**
|
|
262
|
-
* Expose a Pinia store as a Reticle store. `$state` / `$subscribe` are close to `{getState,
|
|
263
|
-
* subscribe}` but not close enough for `registerStore`'s duck-type, which is the whole reason a Vue
|
|
264
|
-
* app currently connects and then reports no state at all.
|
|
265
|
-
*
|
|
266
|
-
* Both `$subscribe` options are load-bearing:
|
|
267
|
-
*
|
|
268
|
-
* - **`detached`** keeps the subscription alive past the component that happened to register the
|
|
269
|
-
* store. Without it Pinia tears the listener down on unmount, so a store registered from inside a
|
|
270
|
-
* component goes permanently silent after the first route change — readable, but never again
|
|
271
|
-
* emitting a STATE_CHANGE, which reads exactly like an app that stopped changing.
|
|
272
|
-
* - **`flush: 'sync'`** puts the notification inside the action's attribution window. The default
|
|
273
|
-
* (`'post'`) defers it past the Vue update tick, and a state change that lands after the window
|
|
274
|
-
* closed is no longer linked to the click that caused it in the causal summary.
|
|
275
|
-
*
|
|
276
|
-
* `$state` carries state, not getters — a Pinia getter is derived, so asserting on the state it
|
|
277
|
-
* derives from is the stronger assertion anyway.
|
|
278
|
-
*
|
|
279
|
-
* ```ts
|
|
280
|
-
* registerStore('cart', piniaStore(useCartStore()));
|
|
281
|
-
* ```
|
|
282
|
-
*/
|
|
283
133
|
export function piniaStore(store) {
|
|
284
134
|
return {
|
|
285
|
-
// `$state` is a live reactive proxy, so this reads through to the current value rather than
|
|
286
|
-
// snapshotting at registration. The transport serializer walks it like any object and guards
|
|
287
|
-
// each key, which is what keeps a throwing reactive trap from costing the whole read.
|
|
288
135
|
getState: () => store.$state,
|
|
289
136
|
subscribe: (listener) => store.$subscribe(() => listener(), { ...PINIA_SUBSCRIBE_OPTIONS }),
|
|
290
137
|
};
|
|
291
138
|
}
|
|
292
|
-
/**
|
|
293
|
-
* Build a store whose value is PUSHED in rather than pulled — for state that has no object to read.
|
|
294
|
-
*
|
|
295
|
-
* React Context and `useState`/`useReducer` keep their value inside the fiber tree; there is no store
|
|
296
|
-
* instance and no subscription point outside React, so no adapter over a public API is possible. The
|
|
297
|
-
* only way in is to invert the direction: the component holding the value tells Reticle when it
|
|
298
|
-
* changes. `@reticlehq/react`'s `useReticleStore` hook is the ergonomic wrapper over this.
|
|
299
|
-
*
|
|
300
|
-
* Returns the store plus the `push` that updates it, so the caller owns the write side.
|
|
301
|
-
*/
|
|
302
139
|
export function pushStore(initial) {
|
|
303
140
|
let current = initial;
|
|
304
141
|
const listeners = new Set();
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Framework adapter registry — enriches elements with component identity + source. */
|
|
2
1
|
export interface ComponentSource {
|
|
3
2
|
file: string;
|
|
4
3
|
line: number;
|
|
@@ -11,20 +10,11 @@ export interface ComponentInfo {
|
|
|
11
10
|
export interface ReticleAdapter {
|
|
12
11
|
name: string;
|
|
13
12
|
identify: (el: Element) => ComponentInfo | null;
|
|
14
|
-
/** Best-effort: read a component's hook state for a DOM element. */
|
|
15
13
|
readState?: (el: Element) => unknown;
|
|
16
|
-
/** Best-effort: does the element declare framework enter/leave handlers synthetic hover may not fire? */
|
|
17
14
|
hasHoverHandlers?: (el: Element) => boolean;
|
|
18
15
|
}
|
|
19
|
-
/** Called by @reticlehq/react (and future adapters) to register themselves. */
|
|
20
16
|
export declare function registerAdapter(adapter: ReticleAdapter): void;
|
|
21
|
-
/** First adapter that can identify the element wins. */
|
|
22
17
|
export declare function identifyComponent(el: Element): ComponentInfo | null;
|
|
23
|
-
/** First adapter that returns non-undefined component state for the element wins. */
|
|
24
18
|
export declare function readComponentState(el: Element): unknown;
|
|
25
|
-
/**
|
|
26
|
-
* True if any installed adapter reports framework enter/leave hover handlers on the element.
|
|
27
|
-
* No-op-safe: returns false when no adapter is installed or none implements the probe.
|
|
28
|
-
*/
|
|
29
19
|
export declare function elementHasHoverHandlers(el: Element): boolean;
|
|
30
20
|
export declare function adapterNames(): string[];
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
/** Framework adapter registry — enriches elements with component identity + source. */
|
|
2
|
-
// Persist on a global so the registry survives HMR module re-evaluation (otherwise the
|
|
3
|
-
// adapter silently drops after a hot reload and source mapping degrades). See feedback #7.
|
|
4
1
|
const globalStore = globalThis;
|
|
5
2
|
const adapters = (globalStore.__reticleAdapters ??= []);
|
|
6
|
-
/** Called by @reticlehq/react (and future adapters) to register themselves. */
|
|
7
3
|
export function registerAdapter(adapter) {
|
|
8
4
|
if (!adapters.some((a) => a.name === adapter.name))
|
|
9
5
|
adapters.push(adapter);
|
|
10
6
|
}
|
|
11
|
-
/** First adapter that can identify the element wins. */
|
|
12
7
|
export function identifyComponent(el) {
|
|
13
8
|
for (const adapter of adapters) {
|
|
14
9
|
const info = adapter.identify(el);
|
|
@@ -17,7 +12,6 @@ export function identifyComponent(el) {
|
|
|
17
12
|
}
|
|
18
13
|
return null;
|
|
19
14
|
}
|
|
20
|
-
/** First adapter that returns non-undefined component state for the element wins. */
|
|
21
15
|
export function readComponentState(el) {
|
|
22
16
|
for (const adapter of adapters) {
|
|
23
17
|
if (adapter.readState === undefined)
|
|
@@ -28,10 +22,6 @@ export function readComponentState(el) {
|
|
|
28
22
|
}
|
|
29
23
|
return undefined;
|
|
30
24
|
}
|
|
31
|
-
/**
|
|
32
|
-
* True if any installed adapter reports framework enter/leave hover handlers on the element.
|
|
33
|
-
* No-op-safe: returns false when no adapter is installed or none implements the probe.
|
|
34
|
-
*/
|
|
35
25
|
export function elementHasHoverHandlers(el) {
|
|
36
26
|
for (const adapter of adapters) {
|
|
37
27
|
if (adapter.hasHoverHandlers === undefined)
|
|
@@ -1,54 +1,21 @@
|
|
|
1
1
|
import { type TruncationReport } from '../security/serialization.js';
|
|
2
|
-
/** Store registry — lets the agent pull live framework/store state on demand. */
|
|
3
2
|
export type StoreGetter = () => unknown;
|
|
4
|
-
/** A store's subscribe method (Zustand/Redux shape): register a listener, get back an unsubscribe. */
|
|
5
3
|
export type StoreSubscribe = (listener: () => void) => () => void;
|
|
6
|
-
/** Notified when a SUBSCRIBABLE store is registered, so a late registration is still observed. */
|
|
7
4
|
export type StoreRegisteredListener = (entry: [string, StoreGetter, StoreSubscribe]) => void;
|
|
8
|
-
/**
|
|
9
|
-
* Observe FUTURE subscribable-store registrations. The SDK installs its observers during connect, but
|
|
10
|
-
* apps call registerStore afterwards — so enumerating once at install time subscribes to nothing and
|
|
11
|
-
* STATE_CHANGE never fires. Observers use this to pick up stores registered after they installed.
|
|
12
|
-
*/
|
|
13
5
|
export declare function onStoreRegistered(listener: StoreRegisteredListener): () => void;
|
|
14
|
-
/** A Zustand/Redux-shaped store: exposes both current state and a subscribe. */
|
|
15
6
|
export interface StoreLike {
|
|
16
7
|
getState: () => unknown;
|
|
17
8
|
subscribe: StoreSubscribe;
|
|
18
9
|
}
|
|
19
|
-
/**
|
|
20
|
-
* App calls this once per store. PREFER passing the store itself — `registerStore('app', useApp)` —
|
|
21
|
-
* which wires `getState` AND `subscribe`, so every mutation emits a STATE_CHANGE path diff automatically
|
|
22
|
-
* (the before→after the causal summary reports). Passing a bare getter still works for back-compat, but
|
|
23
|
-
* leaves the store on pull-only reads: no change events, and an empty `stateDiffs` in every act summary.
|
|
24
|
-
*/
|
|
25
10
|
export declare function registerStore(name: string, source: StoreGetter | StoreLike, subscribe?: StoreSubscribe): void;
|
|
26
11
|
export declare function unregisterStore(name: string): void;
|
|
27
12
|
export declare function storeNames(): string[];
|
|
28
|
-
/** Registered stores that exposed a subscribe method, as [name, getter, subscribe] tuples. */
|
|
29
13
|
export declare function subscribableStores(): Array<[string, StoreGetter, StoreSubscribe]>;
|
|
30
|
-
/**
|
|
31
|
-
* Read one store (by name) or all of them WITHOUT transport sanitization. For scoped reads that
|
|
32
|
-
* select a sub-tree first, so a deep/large path (e.g. row 250 of a 500-row array) isn't truncated
|
|
33
|
-
* before selection. Each getter is isolated: a throw becomes an error object.
|
|
34
|
-
*/
|
|
35
14
|
export declare function readStoresRaw(only?: string): Record<string, unknown>;
|
|
36
|
-
/** Read one store (by name) or all of them, each capped for transport. */
|
|
37
15
|
export declare function readStores(only?: string): Record<string, unknown>;
|
|
38
|
-
/**
|
|
39
|
-
* As `readStores`, plus which stores came back INCOMPLETE.
|
|
40
|
-
*
|
|
41
|
-
* The whole-store read is the one path where the transport caps could silently hand back a fraction
|
|
42
|
-
* of a large store — ~142 of 1,000 entities, with the remainder simply absent. A caller comparing
|
|
43
|
-
* that against expected data reads it as "the app lost the rest", which is a false failure; a caller
|
|
44
|
-
* asserting something is absent reads it as proof, which is a false green. Neither is recoverable
|
|
45
|
-
* from the payload, so the fact of truncation travels beside it.
|
|
46
|
-
*/
|
|
47
16
|
export declare function readStoresWithTruncation(only?: string): {
|
|
48
17
|
stores: Record<string, unknown>;
|
|
49
18
|
truncation?: Record<string, TruncationReport>;
|
|
50
19
|
};
|
|
51
|
-
/** Called by an adapter to record what it was built from. See `sourceOwner`. */
|
|
52
20
|
export declare function markAdapterSource(store: object, source: object): void;
|
|
53
|
-
/** The name this store source is registered under, or undefined if nothing has claimed it. */
|
|
54
21
|
export declare function sourceOwner(value: unknown): string | undefined;
|
package/dist/registry/stores.js
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import { RETICLE_RENDERS_STORE } from '@reticlehq/core';
|
|
2
|
-
import { nativeWarn } from '../timers/native-console.js';
|
|
2
|
+
import { nativeWarn } from '../timers/console/native-console.js';
|
|
3
3
|
import { sanitizeWithReport } from '../security/serialization.js';
|
|
4
4
|
const globalStore = globalThis;
|
|
5
5
|
const stores = (globalStore.__reticleStores ??= new Map());
|
|
6
|
-
// Parallel map: stores that also provided a subscribe method, for automatic STATE_CHANGE diffs.
|
|
7
6
|
const subscribers = (globalStore.__reticleStoreSubs ??= new Map());
|
|
8
7
|
const registrationListeners = (globalStore.__reticleStoreListeners ??=
|
|
9
8
|
new Set());
|
|
10
|
-
/**
|
|
11
|
-
* Observe FUTURE subscribable-store registrations. The SDK installs its observers during connect, but
|
|
12
|
-
* apps call registerStore afterwards — so enumerating once at install time subscribes to nothing and
|
|
13
|
-
* STATE_CHANGE never fires. Observers use this to pick up stores registered after they installed.
|
|
14
|
-
*/
|
|
15
9
|
export function onStoreRegistered(listener) {
|
|
16
10
|
registrationListeners.add(listener);
|
|
17
11
|
return () => registrationListeners.delete(listener);
|
|
18
12
|
}
|
|
19
13
|
function isStoreLike(source) {
|
|
20
|
-
// Zustand's `create` returns a CALLABLE hook that also carries getState/subscribe, so a store can be
|
|
21
|
-
// typeof 'function' as well as 'object'. What distinguishes it from a plain getter is those two members
|
|
22
|
-
// — never the typeof. (Checking only for 'object' left every Zustand app on pull-only reads.)
|
|
23
14
|
if (null === source)
|
|
24
15
|
return false;
|
|
25
16
|
if (typeof source !== 'object' && typeof source !== 'function')
|
|
@@ -27,12 +18,6 @@ function isStoreLike(source) {
|
|
|
27
18
|
const candidate = source;
|
|
28
19
|
return 'function' === typeof candidate.getState && 'function' === typeof candidate.subscribe;
|
|
29
20
|
}
|
|
30
|
-
/**
|
|
31
|
-
* App calls this once per store. PREFER passing the store itself — `registerStore('app', useApp)` —
|
|
32
|
-
* which wires `getState` AND `subscribe`, so every mutation emits a STATE_CHANGE path diff automatically
|
|
33
|
-
* (the before→after the causal summary reports). Passing a bare getter still works for back-compat, but
|
|
34
|
-
* leaves the store on pull-only reads: no change events, and an empty `stateDiffs` in every act summary.
|
|
35
|
-
*/
|
|
36
21
|
export function registerStore(name, source, subscribe) {
|
|
37
22
|
claimSource(name, source);
|
|
38
23
|
if (isStoreLike(source)) {
|
|
@@ -57,11 +42,6 @@ export function registerStore(name, source, subscribe) {
|
|
|
57
42
|
notifyRegistered(name, source, subscribe);
|
|
58
43
|
return;
|
|
59
44
|
}
|
|
60
|
-
// Readable but SILENT: reticle_state can read this store on demand, yet nothing will ever emit a
|
|
61
|
-
// STATE_CHANGE for it, so causal summaries show no state diff and a {kind:"state"} predicate can
|
|
62
|
-
// never observe it changing. That reads exactly like "the app did not change anything" — a false
|
|
63
|
-
// negative with no error attached. Say so once, at registration, where the developer can fix it by
|
|
64
|
-
// passing the store itself (or a subscribe function) instead of a bare getter.
|
|
65
45
|
warnSilentStoreOnce(name);
|
|
66
46
|
}
|
|
67
47
|
function notifyRegistered(name, getter, subscribe) {
|
|
@@ -70,7 +50,6 @@ function notifyRegistered(name, getter, subscribe) {
|
|
|
70
50
|
listener([name, getter, subscribe]);
|
|
71
51
|
}
|
|
72
52
|
catch {
|
|
73
|
-
// a broken observer must never break the app's registerStore call
|
|
74
53
|
}
|
|
75
54
|
}
|
|
76
55
|
}
|
|
@@ -81,7 +60,6 @@ export function unregisterStore(name) {
|
|
|
81
60
|
export function storeNames() {
|
|
82
61
|
return [...stores.keys()];
|
|
83
62
|
}
|
|
84
|
-
/** Registered stores that exposed a subscribe method, as [name, getter, subscribe] tuples. */
|
|
85
63
|
export function subscribableStores() {
|
|
86
64
|
const out = [];
|
|
87
65
|
for (const [name, subscribe] of subscribers) {
|
|
@@ -91,11 +69,6 @@ export function subscribableStores() {
|
|
|
91
69
|
}
|
|
92
70
|
return out;
|
|
93
71
|
}
|
|
94
|
-
/**
|
|
95
|
-
* Read one store (by name) or all of them WITHOUT transport sanitization. For scoped reads that
|
|
96
|
-
* select a sub-tree first, so a deep/large path (e.g. row 250 of a 500-row array) isn't truncated
|
|
97
|
-
* before selection. Each getter is isolated: a throw becomes an error object.
|
|
98
|
-
*/
|
|
99
72
|
export function readStoresRaw(only) {
|
|
100
73
|
const out = {};
|
|
101
74
|
for (const [name, getter] of stores) {
|
|
@@ -110,19 +83,9 @@ export function readStoresRaw(only) {
|
|
|
110
83
|
}
|
|
111
84
|
return out;
|
|
112
85
|
}
|
|
113
|
-
/** Read one store (by name) or all of them, each capped for transport. */
|
|
114
86
|
export function readStores(only) {
|
|
115
87
|
return readStoresWithTruncation(only).stores;
|
|
116
88
|
}
|
|
117
|
-
/**
|
|
118
|
-
* As `readStores`, plus which stores came back INCOMPLETE.
|
|
119
|
-
*
|
|
120
|
-
* The whole-store read is the one path where the transport caps could silently hand back a fraction
|
|
121
|
-
* of a large store — ~142 of 1,000 entities, with the remainder simply absent. A caller comparing
|
|
122
|
-
* that against expected data reads it as "the app lost the rest", which is a false failure; a caller
|
|
123
|
-
* asserting something is absent reads it as proof, which is a false green. Neither is recoverable
|
|
124
|
-
* from the payload, so the fact of truncation travels beside it.
|
|
125
|
-
*/
|
|
126
89
|
export function readStoresWithTruncation(only) {
|
|
127
90
|
const stores = {};
|
|
128
91
|
const truncation = {};
|
|
@@ -134,13 +97,7 @@ export function readStoresWithTruncation(only) {
|
|
|
134
97
|
}
|
|
135
98
|
return Object.keys(truncation).length > 0 ? { stores, truncation } : { stores };
|
|
136
99
|
}
|
|
137
|
-
/** Stores already warned about — a warning that repeats on every HMR cycle or remount becomes noise. */
|
|
138
100
|
const warnedSilent = new Set();
|
|
139
|
-
/**
|
|
140
|
-
* Reticle's OWN read-only stores. `@reticlehq/react` registers a render-stats getter that the app
|
|
141
|
-
* developer never wrote and cannot change, so warning about it would be Reticle telling the user to fix
|
|
142
|
-
* Reticle — the same self-contradiction as a tool description naming a tool the profile does not expose.
|
|
143
|
-
*/
|
|
144
101
|
const RETICLE_OWNED_STORES = new Set([RETICLE_RENDERS_STORE]);
|
|
145
102
|
function warnSilentStoreOnce(name) {
|
|
146
103
|
if (RETICLE_OWNED_STORES.has(name) || warnedSilent.has(name))
|
|
@@ -150,23 +107,8 @@ function warnSilentStoreOnce(name) {
|
|
|
150
107
|
`changes are invisible: no STATE_CHANGE events, no state diffs in causal summaries, and a state ` +
|
|
151
108
|
`predicate will never see it update. Pass the store object (or a subscribe callback) to fix.`);
|
|
152
109
|
}
|
|
153
|
-
/**
|
|
154
|
-
* Who owns a given store SOURCE — the object the app (or an adapter) was built from.
|
|
155
|
-
*
|
|
156
|
-
* Registration is keyed by name, which cannot answer "is this same store already readable?". The
|
|
157
|
-
* question matters because the React adapter discovers stores from the fiber tree, and an app that
|
|
158
|
-
* has already registered the very same store by hand must not get a second entry for it under a
|
|
159
|
-
* second name. Comparing the READ VALUE cannot answer it either: `tanstackQueryStore` builds a fresh
|
|
160
|
-
* snapshot object on every `getState`, so identity never matches. Measured on bench-app, which
|
|
161
|
-
* registers `queries` itself and got an auto-discovered `query` beside it — one cache, listed twice,
|
|
162
|
-
* in every state read.
|
|
163
|
-
*
|
|
164
|
-
* A WeakMap so nothing here keeps an app's store alive.
|
|
165
|
-
*/
|
|
166
110
|
const sourceOwners = new WeakMap();
|
|
167
|
-
/** Adapter instance → the object it wraps, so registering an adapter also claims its source. */
|
|
168
111
|
const adapterSources = new WeakMap();
|
|
169
|
-
/** Called by an adapter to record what it was built from. See `sourceOwner`. */
|
|
170
112
|
export function markAdapterSource(store, source) {
|
|
171
113
|
adapterSources.set(store, source);
|
|
172
114
|
}
|
|
@@ -178,7 +120,6 @@ function claimSource(name, source) {
|
|
|
178
120
|
if (wrapped !== undefined)
|
|
179
121
|
sourceOwners.set(wrapped, name);
|
|
180
122
|
}
|
|
181
|
-
/** The name this store source is registered under, or undefined if nothing has claimed it. */
|
|
182
123
|
export function sourceOwner(value) {
|
|
183
124
|
if (null === value || ('object' !== typeof value && 'function' !== typeof value))
|
|
184
125
|
return undefined;
|
|
@@ -1,18 +1,5 @@
|
|
|
1
1
|
import { PresenterMode } from '@reticlehq/core';
|
|
2
|
-
/** Coerce an unknown arg to a string, falling back to `fallback` (default empty) when it isn't one. */
|
|
3
2
|
export declare function str(value: unknown, fallback?: string): string;
|
|
4
|
-
/** A short human label for a ref ("button \"Save\"") for the presenter HUD. */
|
|
5
3
|
export declare function refLabel(refId: string): string;
|
|
6
|
-
/**
|
|
7
|
-
* Classify a browser command into the presenter intent the human watcher sees. Exhaustive
|
|
8
|
-
* over the ReticleCommand names that actually reach the browser. CLOCK/NARRATE are control/meta
|
|
9
|
-
* (neither a page read nor an act) -> IDLE so they don't paint a misleading chip. NARRATE never
|
|
10
|
-
* reaches #presentBefore anyway (it returns early in #handleCommand) and must not clear the mode.
|
|
11
|
-
*/
|
|
12
4
|
export declare function modeForCommand(commandName: string): PresenterMode;
|
|
13
|
-
/**
|
|
14
|
-
* Human-legible status for a read command — now WITH the target (which testid/value/ref/store), so
|
|
15
|
-
* the watcher sees "Finding [testid=row-3700]" instead of a meaningless repeating "Finding an
|
|
16
|
-
* element". Falls back to the bare verb when no target is in the args.
|
|
17
|
-
*/
|
|
18
5
|
export declare function presentStatus(commandName: string, args?: Record<string, unknown>): string;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ReticleCommand, PresenterMode, QueryBy } from '@reticlehq/core';
|
|
2
|
-
import { refs } from './dom/refs.js';
|
|
2
|
+
import { refs } from './dom/addressing/refs.js';
|
|
3
3
|
import { describe } from './dom/a11y.js';
|
|
4
|
-
/** Coerce an unknown arg to a string, falling back to `fallback` (default empty) when it isn't one. */
|
|
5
4
|
export function str(value, fallback = '') {
|
|
6
5
|
return 'string' === typeof value ? value : fallback;
|
|
7
6
|
}
|
|
8
|
-
|
|
7
|
+
function text(value) {
|
|
8
|
+
const asString = str(value);
|
|
9
|
+
return '' === asString ? undefined : asString;
|
|
10
|
+
}
|
|
9
11
|
export function refLabel(refId) {
|
|
10
12
|
const el = refs.resolve(refId);
|
|
11
13
|
if (!(el instanceof Element))
|
|
@@ -13,12 +15,6 @@ export function refLabel(refId) {
|
|
|
13
15
|
const d = describe(el);
|
|
14
16
|
return d.name.length > 0 ? `${d.role} "${d.name}"` : `${d.role} (${refId})`;
|
|
15
17
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Classify a browser command into the presenter intent the human watcher sees. Exhaustive
|
|
18
|
-
* over the ReticleCommand names that actually reach the browser. CLOCK/NARRATE are control/meta
|
|
19
|
-
* (neither a page read nor an act) -> IDLE so they don't paint a misleading chip. NARRATE never
|
|
20
|
-
* reaches #presentBefore anyway (it returns early in #handleCommand) and must not clear the mode.
|
|
21
|
-
*/
|
|
22
18
|
export function modeForCommand(commandName) {
|
|
23
19
|
switch (commandName) {
|
|
24
20
|
case ReticleCommand.ACT:
|
|
@@ -36,11 +32,6 @@ export function modeForCommand(commandName) {
|
|
|
36
32
|
return PresenterMode.IDLE;
|
|
37
33
|
}
|
|
38
34
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Human-legible status for a read command — now WITH the target (which testid/value/ref/store), so
|
|
41
|
-
* the watcher sees "Finding [testid=row-3700]" instead of a meaningless repeating "Finding an
|
|
42
|
-
* element". Falls back to the bare verb when no target is in the args.
|
|
43
|
-
*/
|
|
44
35
|
export function presentStatus(commandName, args = {}) {
|
|
45
36
|
switch (commandName) {
|
|
46
37
|
case ReticleCommand.SNAPSHOT:
|
|
@@ -52,13 +43,13 @@ export function presentStatus(commandName, args = {}) {
|
|
|
52
43
|
return target !== undefined ? `Finding ${target}` : 'Finding an element';
|
|
53
44
|
}
|
|
54
45
|
case ReticleCommand.INSPECT: {
|
|
55
|
-
const ref =
|
|
46
|
+
const ref = text(args['ref']);
|
|
56
47
|
return ref !== undefined ? `Inspecting ${refLabel(ref)}` : 'Inspecting an element';
|
|
57
48
|
}
|
|
58
49
|
case ReticleCommand.ANIMATIONS:
|
|
59
50
|
return 'Reading animations';
|
|
60
51
|
case ReticleCommand.STATE_READ: {
|
|
61
|
-
const store =
|
|
52
|
+
const store = text(args['store']);
|
|
62
53
|
return store !== undefined ? `Reading state: ${store}` : 'Reading state';
|
|
63
54
|
}
|
|
64
55
|
case ReticleCommand.CAPABILITIES:
|
|
@@ -67,13 +58,12 @@ export function presentStatus(commandName, args = {}) {
|
|
|
67
58
|
return commandName;
|
|
68
59
|
}
|
|
69
60
|
}
|
|
70
|
-
/** Compact "what we're looking for" from a query's args (testid/value/name/role/text/label). */
|
|
71
61
|
function queryTarget(q) {
|
|
72
|
-
const testid =
|
|
62
|
+
const testid = text(q['testid']) ?? (QueryBy.TESTID === str(q['by']) ? text(q['value']) : undefined);
|
|
73
63
|
if (testid !== undefined)
|
|
74
64
|
return `[testid=${testid}]`;
|
|
75
|
-
const name =
|
|
76
|
-
const value =
|
|
65
|
+
const name = text(q['name']);
|
|
66
|
+
const value = text(q['value']) ?? text(q['text']) ?? text(q['label']) ?? text(q['role']);
|
|
77
67
|
if (value !== undefined)
|
|
78
68
|
return name !== undefined ? `"${value}" (${name})` : `"${value}"`;
|
|
79
69
|
return name !== undefined ? `"${name}"` : undefined;
|