@reticlehq/browser 2.13.0 → 2.14.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 +0 -20
- package/dist/actions/actions-dom.js +0 -66
- package/dist/actions/actions-press.d.ts +10 -0
- package/dist/actions/actions-press.js +77 -0
- package/dist/actions/actions.d.ts +0 -89
- package/dist/actions/actions.js +24 -358
- package/dist/actions/appeared-text.d.ts +0 -20
- package/dist/actions/appeared-text.js +0 -36
- package/dist/actions/danger-context.d.ts +3 -0
- package/dist/actions/danger-context.js +39 -0
- package/dist/actions/scroll.d.ts +0 -9
- package/dist/actions/scroll.js +0 -7
- package/dist/actions/synthetic-input.d.ts +0 -7
- package/dist/actions/synthetic-input.js +0 -27
- 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 +0 -67
- package/dist/connect-options.d.ts +2 -96
- package/dist/dom/a11y.d.ts +0 -29
- package/dist/dom/a11y.js +1 -88
- package/dist/dom/auto-anchor.d.ts +0 -40
- package/dist/dom/auto-anchor.js +0 -33
- 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 +0 -72
- package/dist/dom/dom-ignore.d.ts +0 -30
- package/dist/dom/dom-ignore.js +0 -47
- package/dist/dom/occlusion.d.ts +0 -7
- package/dist/dom/occlusion.js +0 -7
- package/dist/dom/query.d.ts +0 -14
- package/dist/dom/query.js +48 -214
- package/dist/dom/realm.d.ts +0 -20
- package/dist/dom/realm.js +0 -28
- package/dist/dom/refs.d.ts +0 -76
- package/dist/dom/refs.js +2 -133
- 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 +26 -151
- package/dist/dom/source.d.ts +0 -44
- package/dist/dom/source.js +0 -45
- 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 +0 -22
- package/dist/edit-epoch.js +0 -52
- package/dist/index.js +1 -23
- package/dist/observers/animation.d.ts +0 -1
- package/dist/observers/animation.js +0 -3
- package/dist/observers/blind-spots.d.ts +0 -26
- package/dist/observers/blind-spots.js +2 -61
- 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 +0 -44
- package/dist/observers/download.d.ts +1 -2
- package/dist/observers/download.js +38 -55
- 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 +1 -33
- 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/network-body.d.ts +5 -28
- package/dist/observers/network-body.js +11 -108
- package/dist/observers/network-redact.d.ts +1 -20
- package/dist/observers/network-redact.js +1 -80
- package/dist/observers/network-stream.d.ts +0 -21
- package/dist/observers/network-stream.js +1 -44
- package/dist/observers/network.d.ts +2 -26
- package/dist/observers/network.js +177 -294
- 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 +0 -9
- 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/overlay.d.ts +0 -1
- package/dist/presenter/overlay.js +0 -1
- package/dist/presenter/presenter-brand.d.ts +0 -19
- package/dist/presenter/presenter-brand.js +0 -21
- package/dist/presenter/presenter-config.d.ts +1 -105
- package/dist/presenter/presenter-config.js +2 -91
- package/dist/presenter/presenter-controls.d.ts +0 -29
- package/dist/presenter/presenter-controls.js +3 -131
- package/dist/presenter/presenter-dock-layout.d.ts +0 -3
- package/dist/presenter/presenter-dock-layout.js +0 -4
- package/dist/presenter/presenter-drag.d.ts +2 -24
- package/dist/presenter/presenter-drag.js +0 -26
- package/dist/presenter/presenter-effects.d.ts +0 -9
- package/dist/presenter/presenter-effects.js +0 -9
- package/dist/presenter/presenter-glow.d.ts +0 -21
- package/dist/presenter/presenter-glow.js +1 -27
- package/dist/presenter/presenter-heroicons-data.d.ts +0 -8
- package/dist/presenter/presenter-heroicons-data.js +0 -8
- package/dist/presenter/presenter-hud-chrome.d.ts +0 -10
- package/dist/presenter/presenter-hud-chrome.js +0 -10
- package/dist/presenter/presenter-icons.d.ts +0 -6
- package/dist/presenter/presenter-icons.js +0 -6
- package/dist/presenter/presenter-log.d.ts +0 -38
- package/dist/presenter/presenter-log.js +1 -45
- package/dist/presenter/presenter-report-copy.d.ts +5 -66
- package/dist/presenter/presenter-report-copy.js +5 -66
- package/dist/presenter/presenter-report-styles.d.ts +0 -6
- package/dist/presenter/presenter-report-styles.js +6 -6
- package/dist/presenter/presenter-report.d.ts +4 -7
- package/dist/presenter/presenter-report.js +18 -76
- package/dist/presenter/presenter-run-state.d.ts +0 -7
- package/dist/presenter/presenter-run-state.js +0 -5
- package/dist/presenter/presenter-settings-styles.d.ts +0 -1
- package/dist/presenter/presenter-settings-styles.js +0 -1
- package/dist/presenter/presenter-settings.d.ts +1 -23
- package/dist/presenter/presenter-settings.js +1 -31
- package/dist/presenter/presenter-shell-styles.js +2 -5
- package/dist/presenter/presenter-shell.d.ts +2 -18
- package/dist/presenter/presenter-shell.js +1 -73
- package/dist/presenter/presenter-styles.d.ts +0 -9
- package/dist/presenter/presenter-styles.js +0 -9
- package/dist/presenter/presenter-tally.d.ts +0 -5
- package/dist/presenter/presenter-tally.js +0 -4
- package/dist/presenter/presenter-test-helpers.d.ts +0 -2
- package/dist/presenter/presenter-test-helpers.js +0 -2
- package/dist/presenter/presenter-verbs.js +0 -7
- package/dist/presenter/presenter-workspace.d.ts +0 -4
- package/dist/presenter/presenter-workspace.js +1 -8
- package/dist/presenter/presenter.d.ts +0 -60
- package/dist/presenter/presenter.js +4 -118
- 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 +0 -49
- package/dist/registry/adapters.d.ts +0 -10
- package/dist/registry/adapters.js +0 -10
- 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/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 +0 -10
- package/dist/registry/store-adapters.d.ts +0 -186
- package/dist/registry/store-adapters.js +0 -163
- package/dist/registry/stores.d.ts +0 -33
- package/dist/registry/stores.js +0 -59
- package/dist/reticle-presenter-helpers.d.ts +0 -13
- package/dist/reticle-presenter-helpers.js +0 -14
- package/dist/reticle.d.ts +1 -52
- package/dist/reticle.js +20 -145
- package/dist/review/annotator-styles.js +0 -7
- package/dist/review/annotator.d.ts +2 -13
- package/dist/review/annotator.js +0 -40
- package/dist/review/mark-anchor.d.ts +0 -11
- package/dist/review/mark-anchor.js +0 -8
- 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/native-console.js +0 -4
- package/dist/timers/native-timers.d.ts +0 -25
- package/dist/timers/native-timers.js +3 -33
- package/dist/transport/transport.d.ts +0 -51
- package/dist/transport/transport.js +3 -129
- 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 +2 -2
|
@@ -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,21 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The testids the page is actually showing, read from the live DOM.
|
|
3
|
-
*
|
|
4
|
-
* `registerCapabilities({ testids: [...] })` used to be the only source, and `init` filled it by
|
|
5
|
-
* grepping the source at install time. That list is a snapshot of the codebase on the day `init` ran:
|
|
6
|
-
* it goes stale on the next commit that renames an element, it is empty for every app whose testids
|
|
7
|
-
* arrive with a lazy route, and finishing it was homework handed to whoever ran the install.
|
|
8
|
-
*
|
|
9
|
-
* The attribute in the DOM is the same declaration, read fresh, so nothing has to be copied into a
|
|
10
|
-
* config file to be true. Reticle's own presenter markup is excluded — advertising our own controls
|
|
11
|
-
* as the app's testable surface would be the tool describing itself.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Ceiling on the reported list.
|
|
15
|
-
*
|
|
16
|
-
* A virtualized 500-row grid stamps a testid per cell, and the capabilities payload rides in every
|
|
17
|
-
* announce — an uncapped read turns one long table into a permanently expensive message. The cap is
|
|
18
|
-
* on the REPORT, not on what can be driven: a testid past it is still findable by query.
|
|
19
|
-
*/
|
|
20
1
|
export declare const MAX_AUTO_TESTIDS = 200;
|
|
21
2
|
export declare function domTestids(doc: Document): string[];
|
|
@@ -1,26 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The testids the page is actually showing, read from the live DOM.
|
|
3
|
-
*
|
|
4
|
-
* `registerCapabilities({ testids: [...] })` used to be the only source, and `init` filled it by
|
|
5
|
-
* grepping the source at install time. That list is a snapshot of the codebase on the day `init` ran:
|
|
6
|
-
* it goes stale on the next commit that renames an element, it is empty for every app whose testids
|
|
7
|
-
* arrive with a lazy route, and finishing it was homework handed to whoever ran the install.
|
|
8
|
-
*
|
|
9
|
-
* The attribute in the DOM is the same declaration, read fresh, so nothing has to be copied into a
|
|
10
|
-
* config file to be true. Reticle's own presenter markup is excluded — advertising our own controls
|
|
11
|
-
* as the app's testable surface would be the tool describing itself.
|
|
12
|
-
*/
|
|
13
1
|
const TESTID_ATTR = 'data-testid';
|
|
14
2
|
const TESTID_SELECTOR = `[${TESTID_ATTR}]`;
|
|
15
|
-
/**
|
|
16
|
-
* Ceiling on the reported list.
|
|
17
|
-
*
|
|
18
|
-
* A virtualized 500-row grid stamps a testid per cell, and the capabilities payload rides in every
|
|
19
|
-
* announce — an uncapped read turns one long table into a permanently expensive message. The cap is
|
|
20
|
-
* on the REPORT, not on what can be driven: a testid past it is still findable by query.
|
|
21
|
-
*/
|
|
22
3
|
export const MAX_AUTO_TESTIDS = 200;
|
|
23
|
-
/** Reticle's own UI carries testids; they are not the host app's surface. */
|
|
24
4
|
const RETICLE_OWN_PREFIX = 'reticle-';
|
|
25
5
|
export function domTestids(doc) {
|
|
26
6
|
const out = [];
|
|
@@ -30,7 +10,7 @@ export function domTestids(doc) {
|
|
|
30
10
|
nodes = doc.querySelectorAll(TESTID_SELECTOR);
|
|
31
11
|
}
|
|
32
12
|
catch {
|
|
33
|
-
return out;
|
|
13
|
+
return out;
|
|
34
14
|
}
|
|
35
15
|
for (let i = 0; i < nodes.length && out.length < MAX_AUTO_TESTIDS; i += 1) {
|
|
36
16
|
const value = nodes[i]?.getAttribute(TESTID_ATTR);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Self-describing capability registry — the testable surface the app advertises. */
|
|
2
1
|
export interface CapabilityFlow {
|
|
3
2
|
name: string;
|
|
4
3
|
steps: string[];
|
|
@@ -8,46 +7,16 @@ export interface Capabilities {
|
|
|
8
7
|
signals: string[];
|
|
9
8
|
stores: string[];
|
|
10
9
|
flows: CapabilityFlow[];
|
|
11
|
-
/**
|
|
12
|
-
* True when Reticle's OWN presenter is visible to snapshots and queries.
|
|
13
|
-
*
|
|
14
|
-
* Present only when the hatch is open, and reported here rather than left implicit, because a
|
|
15
|
-
* verdict drawn against Reticle's own interface is not an ordinary verdict: an agent that can see
|
|
16
|
-
* the impact panel can also assert against it. Anybody reading a result should be able to tell
|
|
17
|
-
* which kind they are holding without going to look at a build config.
|
|
18
|
-
*/
|
|
19
10
|
presenterExposed?: boolean;
|
|
20
11
|
}
|
|
21
|
-
/** What the host app passes to reticle.describe; all fields optional. */
|
|
22
12
|
export interface CapabilitiesInput {
|
|
23
13
|
testids?: string[];
|
|
24
14
|
signals?: string[];
|
|
25
15
|
stores?: string[];
|
|
26
16
|
flows?: CapabilityFlow[];
|
|
27
17
|
}
|
|
28
|
-
/** Set by the SDK at connect. Idempotent; the last connect wins. */
|
|
29
18
|
export declare function setCapabilitiesListener(cb: (() => void) | undefined): void;
|
|
30
|
-
/** Called by the host app via reticle.describe. Merges (idempotent), never replaces wholesale. */
|
|
31
19
|
export declare function registerCapabilities(input: CapabilitiesInput): void;
|
|
32
|
-
/** Snapshot copy of the registered capabilities (defensive — never hand out the live arrays). */
|
|
33
20
|
export declare function getCapabilities(): Capabilities;
|
|
34
|
-
/**
|
|
35
|
-
* Testids the app DECLARED, without the ones merely observed in the DOM.
|
|
36
|
-
*
|
|
37
|
-
* The difference carries meaning the merged list cannot. `knownEmptyState` asks "did the app NAME
|
|
38
|
-
* this element as part of its testable surface?", which is how a zero-match query against
|
|
39
|
-
* `cart-empty-region` is told apart from a broken selector. Every testid on the page is observed, so
|
|
40
|
-
* answering that over the merged list makes it true whenever the page has any testid at all — the
|
|
41
|
-
* same as not asking.
|
|
42
|
-
*/
|
|
43
21
|
export declare function declaredTestids(): string[];
|
|
44
|
-
/**
|
|
45
|
-
* Whether the app has a testable surface at all (used in the HELLO flag).
|
|
46
|
-
*
|
|
47
|
-
* Answered over the OBSERVED surface as well as the declared one. It used to be answerable only by
|
|
48
|
-
* declaration, so an app with two hundred testids in its DOM and a live Redux store reported
|
|
49
|
-
* `hasCapabilities: false` until somebody typed those facts into a config file — and the agent
|
|
50
|
-
* reading that flag concluded, correctly by the flag and wrongly in fact, that there was nothing to
|
|
51
|
-
* drive.
|
|
52
|
-
*/
|
|
53
22
|
export declare function hasCapabilities(): boolean;
|
|
@@ -1,23 +1,12 @@
|
|
|
1
|
-
/** Self-describing capability registry — the testable surface the app advertises. */
|
|
2
1
|
import { RETICLE_RENDERS_STORE } from '@reticlehq/core';
|
|
3
2
|
import { isPresenterVisible } from '../dom/dom-ignore.js';
|
|
4
3
|
import { domTestids } from './auto-testids.js';
|
|
5
4
|
import { storeNames } from './stores.js';
|
|
6
|
-
/**
|
|
7
|
-
* The two halves of the capability report the app no longer has to write down.
|
|
8
|
-
*
|
|
9
|
-
* `testids` and `stores` used to be *declarations* — strings copied into a generated file by `init`
|
|
10
|
-
* and then expected to stay true. Both are now read from the thing they describe: the testids from
|
|
11
|
-
* the DOM, the store names from the registry (which the React adapter fills by discovery). What the
|
|
12
|
-
* app declares is still merged in and still wins nothing away: `signals` and `flows` cannot be
|
|
13
|
-
* observed and remain the app's to state.
|
|
14
|
-
*/
|
|
15
5
|
function liveTestids() {
|
|
16
6
|
if ('undefined' === typeof document)
|
|
17
7
|
return [];
|
|
18
8
|
return domTestids(document);
|
|
19
9
|
}
|
|
20
|
-
/** Registered stores, minus the ones Reticle registered on the app's behalf. */
|
|
21
10
|
function liveStores() {
|
|
22
11
|
return storeNames().filter((name) => RETICLE_RENDERS_STORE !== name);
|
|
23
12
|
}
|
|
@@ -28,7 +17,6 @@ function union(declared, observed) {
|
|
|
28
17
|
out.push(value);
|
|
29
18
|
return out;
|
|
30
19
|
}
|
|
31
|
-
// Persist on a global so the registry survives HMR module re-evaluation (matches __reticleAdapters).
|
|
32
20
|
const globalStore = globalThis;
|
|
33
21
|
function empty() {
|
|
34
22
|
return { testids: [], signals: [], stores: [], flows: [] };
|
|
@@ -41,22 +29,10 @@ function mergeUnique(into, add) {
|
|
|
41
29
|
if (!into.includes(v))
|
|
42
30
|
into.push(v);
|
|
43
31
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Notified whenever capabilities change, so the SDK can re-announce them to the bridge.
|
|
46
|
-
*
|
|
47
|
-
* `hasCapabilities` rides in the HELLO, which goes out at connect() — and registering deliberately
|
|
48
|
-
* happens AFTER connect, because `registerStore` needs a live SDK to subscribe through. Without a
|
|
49
|
-
* notification, an app that declared its whole testable surface still appeared to the agent as
|
|
50
|
-
* having none, permanently. The hook lives HERE rather than on `reticle.describe` because the
|
|
51
|
-
* documented entry point is this bare function; only wiring `describe` would have fixed the path
|
|
52
|
-
* almost nobody uses.
|
|
53
|
-
*/
|
|
54
32
|
let onChanged;
|
|
55
|
-
/** Set by the SDK at connect. Idempotent; the last connect wins. */
|
|
56
33
|
export function setCapabilitiesListener(cb) {
|
|
57
34
|
onChanged = cb;
|
|
58
35
|
}
|
|
59
|
-
/** Called by the host app via reticle.describe. Merges (idempotent), never replaces wholesale. */
|
|
60
36
|
export function registerCapabilities(input) {
|
|
61
37
|
mergeUnique(capabilities.testids, input.testids);
|
|
62
38
|
mergeUnique(capabilities.signals, input.signals);
|
|
@@ -68,45 +44,24 @@ export function registerCapabilities(input) {
|
|
|
68
44
|
capabilities.flows.push({ name: flow.name, steps: [...flow.steps] });
|
|
69
45
|
}
|
|
70
46
|
else {
|
|
71
|
-
existing.steps = [...flow.steps];
|
|
47
|
+
existing.steps = [...flow.steps];
|
|
72
48
|
}
|
|
73
49
|
}
|
|
74
50
|
}
|
|
75
51
|
onChanged?.();
|
|
76
52
|
}
|
|
77
|
-
/** Snapshot copy of the registered capabilities (defensive — never hand out the live arrays). */
|
|
78
53
|
export function getCapabilities() {
|
|
79
54
|
return {
|
|
80
55
|
testids: union(capabilities.testids, liveTestids()),
|
|
81
56
|
signals: [...capabilities.signals],
|
|
82
57
|
stores: union(capabilities.stores, liveStores()),
|
|
83
58
|
flows: capabilities.flows.map((f) => ({ name: f.name, steps: [...f.steps] })),
|
|
84
|
-
// Only when open — an absent field is the ordinary case and should not cost a line in every
|
|
85
|
-
// capabilities payload ever sent.
|
|
86
59
|
...(isPresenterVisible() ? { presenterExposed: true } : {}),
|
|
87
60
|
};
|
|
88
61
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Testids the app DECLARED, without the ones merely observed in the DOM.
|
|
91
|
-
*
|
|
92
|
-
* The difference carries meaning the merged list cannot. `knownEmptyState` asks "did the app NAME
|
|
93
|
-
* this element as part of its testable surface?", which is how a zero-match query against
|
|
94
|
-
* `cart-empty-region` is told apart from a broken selector. Every testid on the page is observed, so
|
|
95
|
-
* answering that over the merged list makes it true whenever the page has any testid at all — the
|
|
96
|
-
* same as not asking.
|
|
97
|
-
*/
|
|
98
62
|
export function declaredTestids() {
|
|
99
63
|
return [...capabilities.testids];
|
|
100
64
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Whether the app has a testable surface at all (used in the HELLO flag).
|
|
103
|
-
*
|
|
104
|
-
* Answered over the OBSERVED surface as well as the declared one. It used to be answerable only by
|
|
105
|
-
* declaration, so an app with two hundred testids in its DOM and a live Redux store reported
|
|
106
|
-
* `hasCapabilities: false` until somebody typed those facts into a config file — and the agent
|
|
107
|
-
* reading that flag concluded, correctly by the flag and wrongly in fact, that there was nothing to
|
|
108
|
-
* drive.
|
|
109
|
-
*/
|
|
110
65
|
export function hasCapabilities() {
|
|
111
66
|
return (capabilities.signals.length > 0 ||
|
|
112
67
|
capabilities.flows.length > 0 ||
|
|
@@ -1,8 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* P5b — pair a mutation with its signal so the two can't drift. The lighter alternative to a
|
|
3
|
-
* Zustand middleware: one call runs the mutation, then emits the signal exactly once, and returns
|
|
4
|
-
* the mutation's value. If `mutate` throws, the mutation never happened — so the signal is NOT
|
|
5
|
-
* emitted and the error propagates unchanged (no try/finally, which would wrongly emit on throw).
|
|
6
|
-
*/
|
|
7
1
|
import type { ReticleEmitter } from './emitter.js';
|
|
8
2
|
export declare function commitAndSignal<T>(emitter: ReticleEmitter, mutate: () => T, name: string, data?: Record<string, unknown>): T;
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* P5b — pair a mutation with its signal so the two can't drift. The lighter alternative to a
|
|
3
|
-
* Zustand middleware: one call runs the mutation, then emits the signal exactly once, and returns
|
|
4
|
-
* the mutation's value. If `mutate` throws, the mutation never happened — so the signal is NOT
|
|
5
|
-
* emitted and the error propagates unchanged (no try/finally, which would wrongly emit on throw).
|
|
6
|
-
*/
|
|
7
1
|
export function commitAndSignal(emitter, mutate, name, data) {
|
|
8
|
-
const result = mutate();
|
|
2
|
+
const result = mutate();
|
|
9
3
|
emitter.signal(name, data);
|
|
10
4
|
return result;
|
|
11
5
|
}
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* P5c — self-registering domains. Instead of one hand-maintained flat-map of the whole testable
|
|
3
|
-
* surface, each app domain co-locates its `{ testids, signals, stores }` and calls
|
|
4
|
-
* `registerReticleDomain...)`; the capability registry assembles itself from every domain. Thin
|
|
5
|
-
* adapter over `registerCapabilities`, so merge/dedupe (and HMR persistence) are reused, not
|
|
6
|
-
* reinvented — later calls accumulate as a union, empty domains are a no-op.
|
|
7
|
-
*/
|
|
8
|
-
/** A co-located domain bundle (one `reticle.ts` per app domain). */
|
|
9
1
|
export interface ReticleDomain {
|
|
10
2
|
testids?: readonly string[];
|
|
11
3
|
signals?: readonly string[];
|
package/dist/registry/domains.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* P5c — self-registering domains. Instead of one hand-maintained flat-map of the whole testable
|
|
3
|
-
* surface, each app domain co-locates its `{ testids, signals, stores }` and calls
|
|
4
|
-
* `registerReticleDomain...)`; the capability registry assembles itself from every domain. Thin
|
|
5
|
-
* adapter over `registerCapabilities`, so merge/dedupe (and HMR persistence) are reused, not
|
|
6
|
-
* reinvented — later calls accumulate as a union, empty domains are a no-op.
|
|
7
|
-
*/
|
|
8
1
|
import { registerCapabilities } from './capabilities.js';
|
|
9
2
|
export function registerReticleDomain(domain) {
|
|
10
3
|
const input = {};
|
|
@@ -1,27 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The injected-emitter pattern (P5a): host-app components depend on a tiny structural interface
|
|
3
|
-
* instead of importing the SDK directly. The real emitter proxies to the connected `reticle`
|
|
4
|
-
* singleton; when Reticle isn't connected (or isn't loaded) every call is a SAFE NO-OP — so nothing
|
|
5
|
-
* breaks in production or before `reticle.connect`, and `@reticlehq/browser` stays out of the prod bundle.
|
|
6
|
-
*/
|
|
7
|
-
/** Structural emitter the host app's components depend on. */
|
|
8
1
|
export interface ReticleEmitter {
|
|
9
2
|
signal: (name: string, data?: Record<string, unknown>) => void;
|
|
10
3
|
state: (name: string, value: unknown) => void;
|
|
11
4
|
}
|
|
12
|
-
/** The subset of the reticle singleton an emitter proxies to (lets tests inject a fake). */
|
|
13
5
|
export interface EmitterTarget {
|
|
14
6
|
signal(name: string, data?: Record<string, unknown>): void;
|
|
15
7
|
state(name: string, value: unknown): void;
|
|
16
|
-
/** Discriminator the emitter reads per call to decide forward-vs-no-op. */
|
|
17
8
|
readonly connected: boolean;
|
|
18
9
|
}
|
|
19
10
|
export interface CreateReticleEmitterOptions {
|
|
20
|
-
/** Override the proxy target (tests / advanced embedding). Defaults to the reticle singleton. */
|
|
21
11
|
target?: EmitterTarget;
|
|
22
12
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Create an emitter. Reads `target.connected` on EVERY call (not at creation) so an emitter
|
|
25
|
-
* made at module load — before `reticle.connect` — starts working the moment Reticle connects.
|
|
26
|
-
*/
|
|
27
13
|
export declare function createReticleEmitter(options?: CreateReticleEmitterOptions): ReticleEmitter;
|
package/dist/registry/emitter.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The injected-emitter pattern (P5a): host-app components depend on a tiny structural interface
|
|
3
|
-
* instead of importing the SDK directly. The real emitter proxies to the connected `reticle`
|
|
4
|
-
* singleton; when Reticle isn't connected (or isn't loaded) every call is a SAFE NO-OP — so nothing
|
|
5
|
-
* breaks in production or before `reticle.connect`, and `@reticlehq/browser` stays out of the prod bundle.
|
|
6
|
-
*/
|
|
7
1
|
import { reticle } from '../index.js';
|
|
8
|
-
/**
|
|
9
|
-
* Create an emitter. Reads `target.connected` on EVERY call (not at creation) so an emitter
|
|
10
|
-
* made at module load — before `reticle.connect` — starts working the moment Reticle connects.
|
|
11
|
-
*/
|
|
12
2
|
export function createReticleEmitter(options = {}) {
|
|
13
3
|
const target = options.target ?? reticle;
|
|
14
4
|
return {
|
|
@@ -1,23 +1,4 @@
|
|
|
1
1
|
import { type StoreLike, type StoreSubscribe } from './stores.js';
|
|
2
|
-
/**
|
|
3
|
-
* Adapters that give non-`{getState, subscribe}` state libraries the shape `registerStore` wants.
|
|
4
|
-
*
|
|
5
|
-
* `registerStore` duck-types on `{getState, subscribe}`, which zustand and Redux satisfy natively — so
|
|
6
|
-
* those two needed nothing and got support for free. Everything else was unserved, and the gap was not
|
|
7
|
-
* evenly distributed: by weekly npm downloads TanStack Query (~64M) is larger than zustand (~46M) and
|
|
8
|
-
* redux (~39M), and it holds the state most likely to be WRONG in a way nothing else can see.
|
|
9
|
-
*
|
|
10
|
-
* That last point is the reason this file exists rather than a docs page. A stale-cache bug — the UI
|
|
11
|
-
* rendering data the server has since changed, a mutation that never invalidated its query, an
|
|
12
|
-
* optimistic update that was never rolled back — fires NO network request. An outside-in tool watching
|
|
13
|
-
* the network sees silence and calls it healthy; the DOM shows a plausible number. The only witness is
|
|
14
|
-
* the cache itself, and until now Reticle could not read it either.
|
|
15
|
-
*
|
|
16
|
-
* Every adapter here is a pure function returning `{getState, subscribe}`. None of them import their
|
|
17
|
-
* library — they take an already-constructed client/store/proxy and use structural types, so this file
|
|
18
|
-
* adds no dependency and no bundle weight for an app that uses none of them.
|
|
19
|
-
*/
|
|
20
|
-
/** The minimum of TanStack Query's `QueryClient` that this adapter touches. */
|
|
21
2
|
interface QueryLike {
|
|
22
3
|
queryKey: readonly unknown[];
|
|
23
4
|
state: {
|
|
@@ -38,7 +19,6 @@ interface QueryCacheLike {
|
|
|
38
19
|
interface QueryClientLike {
|
|
39
20
|
getQueryCache: () => QueryCacheLike;
|
|
40
21
|
}
|
|
41
|
-
/** How a single cached query is projected into readable state. */
|
|
42
22
|
export interface QuerySnapshot {
|
|
43
23
|
status: string;
|
|
44
24
|
fetchStatus: string | undefined;
|
|
@@ -47,174 +27,40 @@ export interface QuerySnapshot {
|
|
|
47
27
|
error: string | null;
|
|
48
28
|
data: unknown;
|
|
49
29
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Expose a TanStack Query cache as a Reticle store, keyed by query key.
|
|
52
|
-
*
|
|
53
|
-
* `isStale` / `fetchStatus` / `dataUpdatedAt` are carried deliberately: they are what let an agent
|
|
54
|
-
* assert the stronger property — not merely "the value rendered is X" but "the cache the UI rendered
|
|
55
|
-
* from was actually fresh". A screenshot cannot distinguish a correct number from a correct-looking
|
|
56
|
-
* stale one, and neither can a network log when the request never fired.
|
|
57
|
-
*
|
|
58
|
-
* ```ts
|
|
59
|
-
* registerStore('queries', tanstackQueryStore(queryClient));
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
30
|
export declare function tanstackQueryStore(client: QueryClientLike): StoreLike;
|
|
63
|
-
/**
|
|
64
|
-
* The minimum of a Jotai vanilla store this adapter touches, generic in the ATOM type.
|
|
65
|
-
*
|
|
66
|
-
* `atom: object` was rejected by TypeScript for a real store and the reason is contravariance, not
|
|
67
|
-
* pedantry: Jotai's `get` is `<Value>(atom: Atom<Value>) => Value`, and a function that requires an
|
|
68
|
-
* `Atom` cannot stand in for one that accepts any `object`. So `jotaiStore(createStore(), …)` did
|
|
69
|
-
* not compile — the adapter was advertised, shipped, and unusable from TypeScript without a cast,
|
|
70
|
-
* which the shape-matched fake in the sibling test could never reveal because the fake was written
|
|
71
|
-
* to the same belief the adapter was.
|
|
72
|
-
*/
|
|
73
31
|
interface JotaiStoreLike<A> {
|
|
74
32
|
get: (atom: A) => unknown;
|
|
75
33
|
sub: (atom: A, listener: () => void) => () => void;
|
|
76
34
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Expose a chosen set of Jotai atoms as one Reticle store.
|
|
79
|
-
*
|
|
80
|
-
* The atom map is not an ergonomic shortcut, it is forced by the design: Jotai has no registry of live
|
|
81
|
-
* atoms to enumerate, so "the whole store" is not a thing that exists. Naming the atoms you care about
|
|
82
|
-
* is the only way to snapshot them, and it doubles as a declaration of what matters.
|
|
83
|
-
*
|
|
84
|
-
* ```ts
|
|
85
|
-
* registerStore('app', jotaiStore(getDefaultStore(), { cart: cartAtom, user: userAtom }));
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
35
|
export declare function jotaiStore<A>(store: JotaiStoreLike<A>, atoms: Record<string, A>): StoreLike;
|
|
89
|
-
/** The minimum of an XState actor this adapter touches. */
|
|
90
36
|
interface ActorLike {
|
|
91
37
|
getSnapshot: () => unknown;
|
|
92
38
|
subscribe: (listener: () => void) => {
|
|
93
39
|
unsubscribe: () => void;
|
|
94
40
|
};
|
|
95
41
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Expose an XState actor as a Reticle store. Its `subscribe` returns a subscription OBJECT rather than
|
|
98
|
-
* an unsubscribe function, which is the single reason it does not satisfy `StoreLike` already.
|
|
99
|
-
*/
|
|
100
42
|
export declare function xstateStore(actor: ActorLike): StoreLike;
|
|
101
|
-
/**
|
|
102
|
-
* Expose a Valtio proxy as a Reticle store. Valtio ships `snapshot`/`subscribe` as free functions
|
|
103
|
-
* rather than methods, so the caller passes them in — importing them here would make every consumer
|
|
104
|
-
* of this file depend on valtio.
|
|
105
|
-
*
|
|
106
|
-
* ```ts
|
|
107
|
-
* import { snapshot, subscribe } from 'valtio/vanilla';
|
|
108
|
-
* registerStore('app', valtioStore(state, snapshot, subscribe));
|
|
109
|
-
* ```
|
|
110
|
-
*/
|
|
111
43
|
export declare function valtioStore<T extends object>(proxy: T, snapshot: (p: T) => unknown, subscribe: (p: T, listener: () => void) => () => void): StoreLike;
|
|
112
|
-
/**
|
|
113
|
-
* Expose a MobX observable as a Reticle store. `toJS` and `reaction` are passed in for the same
|
|
114
|
-
* dependency reason as valtio above.
|
|
115
|
-
*
|
|
116
|
-
* ```ts
|
|
117
|
-
* import { reaction, toJS } from 'mobx';
|
|
118
|
-
* registerStore('app', mobxStore(store, toJS, reaction));
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
44
|
export declare function mobxStore<T>(observable: T, toJS: (value: T) => unknown, reaction: (track: () => unknown, effect: () => void) => () => void): StoreLike;
|
|
122
|
-
/** The minimum of a Recoil `Loadable` this adapter touches. */
|
|
123
45
|
interface RecoilLoadableLike {
|
|
124
|
-
/** 'hasValue' | 'loading' | 'hasError'. Widened to string: it arrives from outside this package. */
|
|
125
46
|
state: string;
|
|
126
|
-
/** The value, the pending promise, or the thrown error — which one depends on `state`. */
|
|
127
47
|
contents: unknown;
|
|
128
48
|
}
|
|
129
|
-
/** The minimum of a Recoil `Snapshot` this adapter touches, generic in the ATOM type. */
|
|
130
49
|
interface RecoilSnapshotLike<A> {
|
|
131
50
|
getLoadable: (atom: A) => RecoilLoadableLike;
|
|
132
51
|
}
|
|
133
|
-
/** How one Recoil atom is projected: the value never travels without the load state beside it. */
|
|
134
52
|
export interface RecoilAtomSnapshot {
|
|
135
53
|
status: string;
|
|
136
54
|
value: unknown;
|
|
137
55
|
error: string | null;
|
|
138
56
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Expose a chosen set of Recoil atoms as one Reticle store.
|
|
141
|
-
*
|
|
142
|
-
* Three things about Recoil's API shape this adapter is built around, none of them optional:
|
|
143
|
-
*
|
|
144
|
-
* - **The atom map is forced, not an ergonomic choice.** Recoil has no enumerable registry of live
|
|
145
|
-
* atoms, so "the whole store" is not a thing that exists. Naming the atoms is the only way to
|
|
146
|
-
* snapshot them, and it doubles as a declaration of what matters — the same reason `jotaiStore`
|
|
147
|
-
* takes one.
|
|
148
|
-
* - **`.state`/`.contents`, never `.getValue()`.** On a pending async selector `getValue()` THROWS
|
|
149
|
-
* the pending promise, and on a failed one it throws the error. Either would take down the whole
|
|
150
|
-
* state read over one slow atom — so a loading atom reports `status: 'loading'` with a null value
|
|
151
|
-
* rather than silently becoming an empty object or an exception.
|
|
152
|
-
* - **One subscription, not one per atom.** Recoil exposes no per-atom subscription outside React
|
|
153
|
-
* (`jotaiStore` gets `store.sub(atom, …)`; there is no equivalent here). The transaction stream is
|
|
154
|
-
* the only public change signal, so the caller passes it in — the same "the library ships free
|
|
155
|
-
* functions, so hand them over" shape as `valtioStore` and `mobxStore`.
|
|
156
|
-
*
|
|
157
|
-
* Wire it from a bridge component, which is where `useRecoilTransactionObserver_UNSTABLE` lives:
|
|
158
|
-
*
|
|
159
|
-
* ```tsx
|
|
160
|
-
* const latest = useRef(snapshot_UNSTABLE());
|
|
161
|
-
* const listeners = useRef(new Set<() => void>()).current;
|
|
162
|
-
* useRecoilTransactionObserver_UNSTABLE(({ snapshot }) => {
|
|
163
|
-
* latest.current = snapshot;
|
|
164
|
-
* for (const l of listeners) l();
|
|
165
|
-
* });
|
|
166
|
-
* registerStore('recoil', recoilStore({ cart: cartAtom }, () => latest.current, (l) => {
|
|
167
|
-
* listeners.add(l);
|
|
168
|
-
* return () => listeners.delete(l);
|
|
169
|
-
* }));
|
|
170
|
-
* ```
|
|
171
|
-
*/
|
|
172
57
|
export declare function recoilStore<A>(atoms: Record<string, A>, snapshot: () => RecoilSnapshotLike<A>, subscribe: StoreSubscribe): StoreLike;
|
|
173
|
-
/**
|
|
174
|
-
* The minimum of a Svelte store this adapter touches.
|
|
175
|
-
*
|
|
176
|
-
* `subscribe` may return either the unsubscribe function or an object carrying one — the store
|
|
177
|
-
* contract permits both, and an RxJS-shaped source returns the object form.
|
|
178
|
-
*/
|
|
179
58
|
interface SvelteReadable {
|
|
180
59
|
subscribe: (run: (value: unknown) => void) => (() => void) | {
|
|
181
60
|
unsubscribe: () => void;
|
|
182
61
|
};
|
|
183
62
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Expose a Svelte store as a Reticle store.
|
|
186
|
-
*
|
|
187
|
-
* Structurally unlike every other adapter in this file: they all wrap something that can be PULLED
|
|
188
|
-
* (`getState`, `getSnapshot`, `snapshot(proxy)`, `toJS`). A Svelte store has no pull side at all —
|
|
189
|
-
* `{ subscribe }` is the entire contract. What makes a pull possible anyway is the part of that
|
|
190
|
-
* contract which says `subscribe` must call back **immediately and synchronously** with the current
|
|
191
|
-
* value: subscribe, catch the value, unsubscribe, return it. That is precisely how `svelte/store`'s
|
|
192
|
-
* own `get()` is implemented, so it is a blessed read rather than a trick.
|
|
193
|
-
*
|
|
194
|
-
* Doing it that way is what keeps this adapter free of the `dispose` the obvious implementation
|
|
195
|
-
* needs. Caching the latest value would mean holding a permanent subscription, which means a
|
|
196
|
-
* teardown the other five adapters don't have, which means a leak the moment a caller forgets it.
|
|
197
|
-
* A transient subscription per read owns nothing and leaks nothing.
|
|
198
|
-
*
|
|
199
|
-
* ```ts
|
|
200
|
-
* registerStore('cart', svelteStore(cartStore));
|
|
201
|
-
* ```
|
|
202
|
-
*/
|
|
203
63
|
export declare function svelteStore(readable: SvelteReadable, warn?: (message: string) => void): StoreLike;
|
|
204
|
-
/**
|
|
205
|
-
* The minimum of a Pinia store this adapter touches.
|
|
206
|
-
*
|
|
207
|
-
* Two things here look over-specified and are not, both found by compiling against the real library
|
|
208
|
-
* rather than against a fake written to the same belief as the adapter:
|
|
209
|
-
*
|
|
210
|
-
* - **`$state: object`, not `Record<string, unknown>`.** A Pinia store's `$state` is a concrete
|
|
211
|
-
* object type with named keys and no index signature, and TypeScript rejects those for a
|
|
212
|
-
* `Record<string, unknown>` parameter. `piniaStore(useCartStore())` did not compile — the same
|
|
213
|
-
* shape of failure as the Jotai contravariance note above, and equally invisible to a fake.
|
|
214
|
-
* - **`flush` as the literal union**, not `string`. The option object is checked contravariantly, so
|
|
215
|
-
* a widened `string` here makes the real `$subscribe` unassignable to this shape and the whole
|
|
216
|
-
* store stops matching.
|
|
217
|
-
*/
|
|
218
64
|
interface PiniaStoreLike {
|
|
219
65
|
$state: object;
|
|
220
66
|
$subscribe: (callback: (mutation: unknown, state: unknown) => void, options?: {
|
|
@@ -222,39 +68,7 @@ interface PiniaStoreLike {
|
|
|
222
68
|
flush?: 'pre' | 'post' | 'sync';
|
|
223
69
|
}) => () => void;
|
|
224
70
|
}
|
|
225
|
-
/**
|
|
226
|
-
* Expose a Pinia store as a Reticle store. `$state` / `$subscribe` are close to `{getState,
|
|
227
|
-
* subscribe}` but not close enough for `registerStore`'s duck-type, which is the whole reason a Vue
|
|
228
|
-
* app currently connects and then reports no state at all.
|
|
229
|
-
*
|
|
230
|
-
* Both `$subscribe` options are load-bearing:
|
|
231
|
-
*
|
|
232
|
-
* - **`detached`** keeps the subscription alive past the component that happened to register the
|
|
233
|
-
* store. Without it Pinia tears the listener down on unmount, so a store registered from inside a
|
|
234
|
-
* component goes permanently silent after the first route change — readable, but never again
|
|
235
|
-
* emitting a STATE_CHANGE, which reads exactly like an app that stopped changing.
|
|
236
|
-
* - **`flush: 'sync'`** puts the notification inside the action's attribution window. The default
|
|
237
|
-
* (`'post'`) defers it past the Vue update tick, and a state change that lands after the window
|
|
238
|
-
* closed is no longer linked to the click that caused it in the causal summary.
|
|
239
|
-
*
|
|
240
|
-
* `$state` carries state, not getters — a Pinia getter is derived, so asserting on the state it
|
|
241
|
-
* derives from is the stronger assertion anyway.
|
|
242
|
-
*
|
|
243
|
-
* ```ts
|
|
244
|
-
* registerStore('cart', piniaStore(useCartStore()));
|
|
245
|
-
* ```
|
|
246
|
-
*/
|
|
247
71
|
export declare function piniaStore(store: PiniaStoreLike): StoreLike;
|
|
248
|
-
/**
|
|
249
|
-
* Build a store whose value is PUSHED in rather than pulled — for state that has no object to read.
|
|
250
|
-
*
|
|
251
|
-
* React Context and `useState`/`useReducer` keep their value inside the fiber tree; there is no store
|
|
252
|
-
* instance and no subscription point outside React, so no adapter over a public API is possible. The
|
|
253
|
-
* only way in is to invert the direction: the component holding the value tells Reticle when it
|
|
254
|
-
* changes. `@reticlehq/react`'s `useReticleStore` hook is the ergonomic wrapper over this.
|
|
255
|
-
*
|
|
256
|
-
* Returns the store plus the `push` that updates it, so the caller owns the write side.
|
|
257
|
-
*/
|
|
258
72
|
export declare function pushStore(initial: unknown): {
|
|
259
73
|
store: StoreLike;
|
|
260
74
|
push: (value: unknown) => void;
|