@reticlehq/browser 3.6.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/action-report.d.ts +64 -0
- package/dist/actions/action-report.js +87 -0
- package/dist/actions/actions-dom.d.ts +5 -0
- package/dist/actions/actions-dom.js +32 -4
- package/dist/actions/actions-press.d.ts +1 -0
- package/dist/actions/actions-press.js +25 -1
- package/dist/actions/actions.d.ts +2 -37
- package/dist/actions/actions.js +56 -80
- package/dist/actions/appeared-text.js +5 -2
- package/dist/actions/click-target.d.ts +1 -0
- package/dist/actions/click-target.js +14 -0
- package/dist/actions/danger-context.d.ts +4 -1
- package/dist/actions/danger-context.js +45 -4
- package/dist/actions/value-input.d.ts +1 -0
- package/dist/actions/value-input.js +11 -0
- package/dist/activate.d.ts +14 -0
- package/dist/activate.js +43 -0
- package/dist/busy.d.ts +3 -0
- package/dist/busy.js +42 -0
- package/dist/commands/commands.js +49 -17
- package/dist/connect-options.d.ts +12 -1
- package/dist/connect-options.js +18 -1
- package/dist/dom/a11y.d.ts +2 -0
- package/dist/dom/a11y.js +353 -80
- package/dist/dom/addressing/coverage-markers.d.ts +6 -0
- package/dist/dom/addressing/coverage-markers.js +13 -0
- package/dist/dom/chart.d.ts +3 -2
- package/dist/dom/chart.js +3 -2
- package/dist/dom/dom-ignore.d.ts +8 -0
- package/dist/dom/dom-ignore.js +57 -2
- package/dist/dom/layout-audit.d.ts +15 -0
- package/dist/dom/layout-audit.js +208 -0
- package/dist/dom/paint-context.d.ts +15 -0
- package/dist/dom/paint-context.js +78 -0
- package/dist/dom/query.d.ts +2 -1
- package/dist/dom/query.js +163 -38
- package/dist/dom/render-page.d.ts +12 -0
- package/dist/dom/render-page.js +135 -0
- package/dist/dom/shadow-registry.d.ts +1 -0
- package/dist/dom/shadow-registry.js +27 -0
- package/dist/dom/snapshot.d.ts +5 -0
- package/dist/dom/snapshot.js +135 -36
- package/dist/dom/stable-selector.d.ts +1 -0
- package/dist/dom/stable-selector.js +19 -0
- package/dist/dom/text-match.d.ts +12 -0
- package/dist/dom/text-match.js +115 -0
- package/dist/dom/theme.d.ts +1 -0
- package/dist/dom/theme.js +21 -9
- package/dist/dom/virtualized.js +5 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -0
- package/dist/observers/blind-spots.js +3 -2
- package/dist/observers/canvas.d.ts +18 -0
- package/dist/observers/canvas.js +76 -0
- package/dist/observers/dom.js +96 -32
- package/dist/observers/field.d.ts +11 -0
- package/dist/observers/field.js +116 -30
- package/dist/observers/install-all.js +4 -0
- package/dist/observers/media.d.ts +2 -0
- package/dist/observers/media.js +32 -0
- package/dist/observers/net-detail/network-body.d.ts +2 -0
- package/dist/observers/net-detail/network-body.js +8 -1
- package/dist/observers/network.js +82 -13
- package/dist/observers/perf.js +53 -1
- package/dist/observers/route.d.ts +2 -0
- package/dist/observers/route.js +39 -9
- package/dist/presenter/carousel/carousel.js +2 -7
- package/dist/presenter/carousel/panel-slides.d.ts +2 -4
- package/dist/presenter/carousel/panel-slides.js +17 -15
- package/dist/presenter/chrome/log-memory.d.ts +1 -0
- package/dist/presenter/chrome/presenter-log.d.ts +7 -0
- package/dist/presenter/chrome/presenter-log.js +48 -8
- package/dist/presenter/chrome/presenter-morph.d.ts +1 -0
- package/dist/presenter/chrome/presenter-morph.js +34 -0
- package/dist/presenter/chrome/presenter-report-copy.d.ts +12 -4
- package/dist/presenter/chrome/presenter-report-copy.js +12 -4
- package/dist/presenter/hud-telemetry.js +55 -4
- package/dist/presenter/presenter-account-styles.js +3 -3
- package/dist/presenter/presenter-account.d.ts +27 -5
- package/dist/presenter/presenter-account.js +83 -6
- package/dist/presenter/presenter-agent-link.d.ts +9 -0
- package/dist/presenter/presenter-agent-link.js +62 -0
- package/dist/presenter/presenter-chat-views.d.ts +25 -4
- package/dist/presenter/presenter-chat-views.js +339 -72
- package/dist/presenter/presenter-config.d.ts +3 -0
- package/dist/presenter/presenter-config.js +2 -0
- package/dist/presenter/presenter-controls.d.ts +0 -1
- package/dist/presenter/presenter-controls.js +13 -91
- package/dist/presenter/presenter-design-tokens.js +1 -1
- package/dist/presenter/presenter-frame.d.ts +3 -2
- package/dist/presenter/presenter-frame.js +31 -24
- package/dist/presenter/presenter-harness-row.d.ts +56 -0
- package/dist/presenter/presenter-harness-row.js +170 -0
- package/dist/presenter/presenter-personas.d.ts +35 -0
- package/dist/presenter/presenter-personas.js +95 -0
- package/dist/presenter/presenter-plan.js +25 -24
- package/dist/presenter/presenter-report-styles.js +23 -22
- package/dist/presenter/presenter-report.js +29 -13
- package/dist/presenter/presenter-run-state.js +2 -1
- package/dist/presenter/presenter-settings-styles.js +8 -4
- package/dist/presenter/presenter-settings.d.ts +4 -4
- package/dist/presenter/presenter-settings.js +66 -28
- package/dist/presenter/presenter-shell-styles.js +12 -3
- package/dist/presenter/presenter-shell.d.ts +11 -3
- package/dist/presenter/presenter-shell.js +60 -22
- package/dist/presenter/presenter-styles.js +0 -2
- package/dist/presenter/presenter-workspace.js +10 -3
- package/dist/presenter/presenter.d.ts +3 -2
- package/dist/presenter/presenter.js +107 -25
- package/dist/registry/declared-platform.js +2 -0
- package/dist/registry/store-adapters.d.ts +5 -2
- package/dist/registry/store-adapters.js +40 -10
- package/dist/reticle-inject.js +771 -703
- package/dist/reticle.d.ts +4 -2
- package/dist/reticle.js +72 -8
- package/dist/security/page-location.d.ts +2 -0
- package/dist/security/page-location.js +7 -0
- package/dist/security/serialization.js +1 -1
- package/dist/storage-keys.d.ts +4 -2
- package/dist/storage-keys.js +8 -3
- package/dist/timers/native/native-timers.d.ts +1 -0
- package/dist/timers/native/native-timers.js +5 -0
- package/dist/transport/transport.d.ts +1 -0
- package/dist/transport/transport.js +23 -3
- package/dist/transport/unreachable-message.d.ts +1 -1
- package/dist/transport/unreachable-message.js +3 -5
- package/package.json +6 -2
- package/dist/presenter/carousel/offer-card.d.ts +0 -21
- package/dist/presenter/carousel/offer-card.js +0 -56
package/dist/reticle.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EventType, RETICLE_URL_PARAM, HudVisibility, type ReticleEvent } from '@reticlehq/core';
|
|
2
2
|
import { type CapabilitiesInput } from './registry/capabilities.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type ReticleConnectOptions } from './connect-options.js';
|
|
4
|
+
export { helloMode, shouldBlockProduction } from './connect-options.js';
|
|
4
5
|
export type { ReticleConnectOptions };
|
|
5
|
-
export declare function shouldBlockProduction(nodeEnv: string | undefined, allowInProduction: boolean): boolean;
|
|
6
6
|
export declare function withBridgePath(bridgeUrl: string): {
|
|
7
7
|
url: string;
|
|
8
8
|
adjusted: boolean;
|
|
@@ -43,7 +43,9 @@ export declare class Reticle {
|
|
|
43
43
|
#private;
|
|
44
44
|
connect(options?: ReticleConnectOptions): void;
|
|
45
45
|
get connected(): boolean;
|
|
46
|
+
routes(patterns: readonly string[]): void;
|
|
46
47
|
signal(name: string, data?: Record<string, unknown>): void;
|
|
48
|
+
busy<T>(work: Promise<T>): Promise<T>;
|
|
47
49
|
state(name: string, value: unknown): void;
|
|
48
50
|
renderCommit(commits: number): void;
|
|
49
51
|
describe(input: CapabilitiesInput): void;
|
package/dist/reticle.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { setPresenterVisible } from './dom/dom-ignore.js';
|
|
1
|
+
import { setPresenterViewer, setPresenterVisible } from './dom/dom-ignore.js';
|
|
2
|
+
import { trackBusy } from './busy.js';
|
|
3
|
+
import { declareRoutes } from './observers/route.js';
|
|
4
|
+
import { setOutwardPolicy } from './actions/danger-context.js';
|
|
5
|
+
import { coverageMarkers, notApplicableFor } from './dom/addressing/coverage-markers.js';
|
|
2
6
|
import { EventType, RETICLE_DEFAULT_PORT, RETICLE_PROTOCOL_VERSION, RETICLE_URL_PARAM, RETICLE_WS_PATH, bridgeWsUrl, ReticleCommand, MessageKind, SESSION_AUTO, SessionState, TRANSPORT_LIMITS, buildRedactionPolicy, isLoopbackHostname, isLocalPage, setActiveRedactionPolicy, wireRedactionKeys, RETICLE_ROOT_GLOBAL, RETICLE_SDK_VERSION_GLOBAL, CONTRACT_FINGERPRINT, CONTRACT_PARTS, newDocumentId, NO_EDITS_OBSERVED, PresenterMode, CommandActor, HudCorner, HudVisibility, } from '@reticlehq/core';
|
|
3
7
|
import { rememberSessionLabel } from './session-continuity.js';
|
|
4
8
|
import { editEpoch } from './edit-epoch.js';
|
|
@@ -12,6 +16,8 @@ import { registerCapabilities, setCapabilitiesListener, hasCapabilities, } from
|
|
|
12
16
|
import { installAllObservers, runTeardowns } from './observers/install-all.js';
|
|
13
17
|
import { setTestIdAttr } from './dom/addressing/testid-attr.js';
|
|
14
18
|
import { setNetworkBodyMaxChars } from './observers/net-detail/network-body.js';
|
|
19
|
+
import { pageHref } from './security/page-location.js';
|
|
20
|
+
import { scrubKnownSecrets } from './security/serialization.js';
|
|
15
21
|
import { installOverlay } from './presenter/chrome/overlay.js';
|
|
16
22
|
import { LOG_ACTOR, LOG_KIND, LOG_RESULT } from './presenter/chrome/log-kinds.js';
|
|
17
23
|
import { actionVerb } from './presenter/chrome/presenter-verbs.js';
|
|
@@ -20,9 +26,8 @@ import { resetClock } from './timers/clock.js';
|
|
|
20
26
|
import { nativeWarn } from './timers/console/native-console.js';
|
|
21
27
|
import { installRecorder } from './recorder/recorder.js';
|
|
22
28
|
import { Annotator } from './review/annotator.js';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
29
|
+
import { helloMode, leaseToken, shouldBlockProduction, } from './connect-options.js';
|
|
30
|
+
export { helloMode, shouldBlockProduction } from './connect-options.js';
|
|
26
31
|
export function withBridgePath(bridgeUrl) {
|
|
27
32
|
let parsed;
|
|
28
33
|
try {
|
|
@@ -73,6 +78,7 @@ export function connectionPolicy(pageHostname, bridgeUrl, allowNonLocalhost, tok
|
|
|
73
78
|
}
|
|
74
79
|
return { allowed: true };
|
|
75
80
|
}
|
|
81
|
+
const MAX_PENDING_NARRATIONS = 20;
|
|
76
82
|
const KILLED_MESSAGE = '[Reticle] killed for this page. Restart your dev server or reload the page to bring it back.';
|
|
77
83
|
const BRIDGE_LOST_SUMMARY = 'Session ended - lost connection to Reticle (the agent is no longer running).';
|
|
78
84
|
export function resolveSessionLabel(option, gen) {
|
|
@@ -141,6 +147,7 @@ export class Reticle {
|
|
|
141
147
|
#overlay;
|
|
142
148
|
#presenter;
|
|
143
149
|
#pendingPushes = new Map();
|
|
150
|
+
#pendingNarrations = [];
|
|
144
151
|
#pendingHud;
|
|
145
152
|
#readPanelSettings;
|
|
146
153
|
#panelRequested = false;
|
|
@@ -149,6 +156,7 @@ export class Reticle {
|
|
|
149
156
|
#annotator;
|
|
150
157
|
#eventCount = 0;
|
|
151
158
|
#token;
|
|
159
|
+
#mode = {};
|
|
152
160
|
#sdkVersion;
|
|
153
161
|
#captureBodies = false;
|
|
154
162
|
#sourceMapping = undefined;
|
|
@@ -156,8 +164,15 @@ export class Reticle {
|
|
|
156
164
|
#redactKeys = [];
|
|
157
165
|
#actHandle;
|
|
158
166
|
connect(options = {}) {
|
|
159
|
-
if (this.#connected)
|
|
167
|
+
if (this.#connected) {
|
|
168
|
+
const leased = leaseToken(options, this.#token);
|
|
169
|
+
if (leased !== undefined) {
|
|
170
|
+
this.#token = leased;
|
|
171
|
+
this.#transport?.redialAfterRefusal();
|
|
172
|
+
}
|
|
173
|
+
this.#adoptLateProjectId(options);
|
|
160
174
|
return;
|
|
175
|
+
}
|
|
161
176
|
if ('undefined' === typeof window || 'undefined' === typeof document)
|
|
162
177
|
return;
|
|
163
178
|
const proc = globalThis.process;
|
|
@@ -194,6 +209,7 @@ export class Reticle {
|
|
|
194
209
|
this.#token =
|
|
195
210
|
options.token !== undefined && options.token.length > 0 ? options.token : undefined;
|
|
196
211
|
this.#projectId = identity.projectId;
|
|
212
|
+
this.#mode = helloMode(options);
|
|
197
213
|
this.#applyRedaction(options.redact);
|
|
198
214
|
this.#start = performance.now();
|
|
199
215
|
this.#registry = createCommandRegistry();
|
|
@@ -281,6 +297,8 @@ export class Reticle {
|
|
|
281
297
|
if (options.idleEndMs !== undefined)
|
|
282
298
|
panelOptions.idleEndMs = options.idleEndMs;
|
|
283
299
|
panelOptions.sessionId = this.#session;
|
|
300
|
+
if (this.#projectId !== undefined)
|
|
301
|
+
panelOptions.projectId = this.#projectId;
|
|
284
302
|
panelOptions.onControl = (intent) => this.#emit(EventType.HUMAN_CONTROL, intent.text !== undefined
|
|
285
303
|
? { kind: intent.kind, text: intent.text }
|
|
286
304
|
: { kind: intent.kind });
|
|
@@ -292,9 +310,14 @@ export class Reticle {
|
|
|
292
310
|
const panel = new Presenter(panelOptions);
|
|
293
311
|
this.#presenter = panel;
|
|
294
312
|
panel.mount();
|
|
313
|
+
panel.showSdkVersion(this.#sdkVersion);
|
|
295
314
|
for (const buffered of this.#pendingPushes.values())
|
|
296
315
|
panel.handlePush(buffered);
|
|
297
316
|
this.#pendingPushes.clear();
|
|
317
|
+
if (0 < this.#pendingNarrations.length)
|
|
318
|
+
panel.sessionStart();
|
|
319
|
+
for (const early of this.#pendingNarrations.splice(0))
|
|
320
|
+
panel.narrate(early.text, early.level, early.actor, early.summary);
|
|
298
321
|
if (this.#pendingHud !== undefined)
|
|
299
322
|
panel.placeHud(this.#pendingHud, undefined);
|
|
300
323
|
this.#pendingHud = undefined;
|
|
@@ -333,9 +356,17 @@ export class Reticle {
|
|
|
333
356
|
get connected() {
|
|
334
357
|
return this.#connected;
|
|
335
358
|
}
|
|
359
|
+
routes(patterns) {
|
|
360
|
+
declareRoutes(patterns);
|
|
361
|
+
}
|
|
336
362
|
signal(name, data = {}) {
|
|
337
363
|
this.#emit(EventType.SIGNAL, { name, data });
|
|
338
364
|
}
|
|
365
|
+
busy(work) {
|
|
366
|
+
return trackBusy(work, (name, data) => {
|
|
367
|
+
this.signal(name, data);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
339
370
|
state(name, value) {
|
|
340
371
|
this.#emit(EventType.STATE_CHANGE, { name, value });
|
|
341
372
|
}
|
|
@@ -396,16 +427,26 @@ export class Reticle {
|
|
|
396
427
|
setActiveRedactionPolicy(buildRedactionPolicy(config, nativeWarn));
|
|
397
428
|
this.#redactKeys = wireRedactionKeys(config);
|
|
398
429
|
}
|
|
430
|
+
#adoptLateProjectId(options) {
|
|
431
|
+
if (this.#projectId !== undefined)
|
|
432
|
+
return;
|
|
433
|
+
const late = resolveConnectIdentity(options, window.location.search).projectId;
|
|
434
|
+
if (late === undefined)
|
|
435
|
+
return;
|
|
436
|
+
this.#projectId = late;
|
|
437
|
+
this.#transport?.reannounce();
|
|
438
|
+
}
|
|
399
439
|
#hello() {
|
|
400
440
|
return {
|
|
401
441
|
kind: MessageKind.HELLO,
|
|
402
442
|
protocolVersion: RETICLE_PROTOCOL_VERSION,
|
|
403
443
|
sessionId: this.#session,
|
|
404
444
|
...(this.#projectId === undefined ? {} : { projectId: this.#projectId }),
|
|
405
|
-
url:
|
|
406
|
-
title: document.title,
|
|
445
|
+
url: pageHref(),
|
|
446
|
+
title: scrubKnownSecrets(document.title),
|
|
407
447
|
adapters: adapterNames(),
|
|
408
448
|
...(this.#token === undefined ? {} : { token: this.#token }),
|
|
449
|
+
...this.#mode,
|
|
409
450
|
hasCapabilities: hasCapabilities(),
|
|
410
451
|
channels: declaredChannels(),
|
|
411
452
|
platform: declaredPlatform(),
|
|
@@ -423,9 +464,25 @@ export class Reticle {
|
|
|
423
464
|
};
|
|
424
465
|
}
|
|
425
466
|
async #handleCommand(command) {
|
|
467
|
+
if (command.name === ReticleCommand.MARKERS) {
|
|
468
|
+
const markers = coverageMarkers(document);
|
|
469
|
+
const buildPlugin = this.#sdkVersion !== undefined || this.#sourceMapping !== undefined;
|
|
470
|
+
const na = notApplicableFor({ buildPlugin, adapters: adapterNames(), markers });
|
|
471
|
+
return { ok: true, result: { markers, ...(0 === na.length ? {} : { notApplicable: na }) } };
|
|
472
|
+
}
|
|
426
473
|
if (command.name === ReticleCommand.NARRATE) {
|
|
474
|
+
if (this.#presenter === undefined && this.#panelRequested) {
|
|
475
|
+
if (this.#pendingNarrations.length < MAX_PENDING_NARRATIONS)
|
|
476
|
+
this.#pendingNarrations.push({
|
|
477
|
+
text: str(command.args['text']),
|
|
478
|
+
level: str(command.args['level'], 'info'),
|
|
479
|
+
actor: narrationActor(command.args),
|
|
480
|
+
summary: true === command.args['summary'],
|
|
481
|
+
});
|
|
482
|
+
return { ok: true, result: { shown: false, buffered: true } };
|
|
483
|
+
}
|
|
427
484
|
this.#presenter?.sessionStart();
|
|
428
|
-
this.#presenter?.narrate(str(command.args['text']), str(command.args['level'], 'info'));
|
|
485
|
+
this.#presenter?.narrate(str(command.args['text']), str(command.args['level'], 'info'), narrationActor(command.args), true === command.args['summary']);
|
|
429
486
|
return { ok: true, result: { shown: this.#presenter !== undefined } };
|
|
430
487
|
}
|
|
431
488
|
if (command.name === ReticleCommand.SESSION_CONFIG) {
|
|
@@ -471,6 +528,8 @@ export class Reticle {
|
|
|
471
528
|
}
|
|
472
529
|
this.#presenter?.sessionStart();
|
|
473
530
|
await this.#presentBefore(command);
|
|
531
|
+
setPresenterViewer(CommandActor.HARNESS === command.by);
|
|
532
|
+
setOutwardPolicy(command.outward?.allowed);
|
|
474
533
|
try {
|
|
475
534
|
const result = await handler(command.args);
|
|
476
535
|
this.#actHandle?.result(LOG_RESULT.PASS);
|
|
@@ -481,6 +540,8 @@ export class Reticle {
|
|
|
481
540
|
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
482
541
|
}
|
|
483
542
|
finally {
|
|
543
|
+
setPresenterViewer(false);
|
|
544
|
+
setOutwardPolicy(undefined);
|
|
484
545
|
this.#actHandle = undefined;
|
|
485
546
|
this.#presenter?.scheduleIdle();
|
|
486
547
|
}
|
|
@@ -515,6 +576,9 @@ export class Reticle {
|
|
|
515
576
|
}
|
|
516
577
|
}
|
|
517
578
|
}
|
|
579
|
+
function narrationActor(args) {
|
|
580
|
+
return CommandActor.HARNESS === args['actor'] ? LOG_ACTOR.HARNESS : LOG_ACTOR.AGENT;
|
|
581
|
+
}
|
|
518
582
|
function oneOf(values, raw) {
|
|
519
583
|
return Object.values(values).includes(raw) ? raw : undefined;
|
|
520
584
|
}
|
|
@@ -29,7 +29,7 @@ function sanitize(value, state, depth, key) {
|
|
|
29
29
|
if (null === value || 'boolean' === typeof value)
|
|
30
30
|
return value;
|
|
31
31
|
if ('string' === typeof value) {
|
|
32
|
-
return boundedString(value, state, 'error' === key?.toLowerCase()
|
|
32
|
+
return boundedString(scrubKnownSecrets(value), state, 'error' === key?.toLowerCase()
|
|
33
33
|
? TRANSPORT_LIMITS.MAX_ERROR_LENGTH
|
|
34
34
|
: TRANSPORT_LIMITS.MAX_STRING_LENGTH);
|
|
35
35
|
}
|
package/dist/storage-keys.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ export declare const ReticleStorageKey: {
|
|
|
5
5
|
readonly PRESENTER_LOG_OWNER: "reticle-presenter-log-owner";
|
|
6
6
|
readonly PRESENTER_SETTINGS: "reticle-presenter-settings";
|
|
7
7
|
readonly PRESENTER_MINIMISED: "reticle-presenter-minimised";
|
|
8
|
+
readonly PRESENTER_OPEN: "reticle-presenter-open";
|
|
9
|
+
readonly PRESENTER_VIEW: "reticle-presenter-view";
|
|
8
10
|
readonly CAROUSEL_DISMISSED: "reticle.carousel.dismissed";
|
|
9
|
-
readonly HARNESS_OFFER_DISMISSED: "reticle.harnessOffer.dismissed";
|
|
10
11
|
readonly ANNOTATION_HISTORY: "reticle.annotations.history.v1";
|
|
11
|
-
readonly RECENT_PLAYS: "reticle.flow.recent.v1";
|
|
12
12
|
};
|
|
13
13
|
export declare const TOUR_SEEN_KEY_PREFIX = "reticle.tour.seen.";
|
|
14
|
+
export declare const PERSONA_KEY_PREFIX = "reticle.harness.persona.";
|
|
15
|
+
export declare const IMPACT_SEEN_KEY_PREFIX = "reticle.impact.seen.";
|
|
14
16
|
export declare function isReticleStorageKey(key: string): boolean;
|
package/dist/storage-keys.js
CHANGED
|
@@ -5,13 +5,18 @@ export const ReticleStorageKey = {
|
|
|
5
5
|
PRESENTER_LOG_OWNER: 'reticle-presenter-log-owner',
|
|
6
6
|
PRESENTER_SETTINGS: 'reticle-presenter-settings',
|
|
7
7
|
PRESENTER_MINIMISED: 'reticle-presenter-minimised',
|
|
8
|
+
PRESENTER_OPEN: 'reticle-presenter-open',
|
|
9
|
+
PRESENTER_VIEW: 'reticle-presenter-view',
|
|
8
10
|
CAROUSEL_DISMISSED: 'reticle.carousel.dismissed',
|
|
9
|
-
HARNESS_OFFER_DISMISSED: 'reticle.harnessOffer.dismissed',
|
|
10
11
|
ANNOTATION_HISTORY: 'reticle.annotations.history.v1',
|
|
11
|
-
RECENT_PLAYS: 'reticle.flow.recent.v1',
|
|
12
12
|
};
|
|
13
13
|
export const TOUR_SEEN_KEY_PREFIX = 'reticle.tour.seen.';
|
|
14
|
+
export const PERSONA_KEY_PREFIX = 'reticle.harness.persona.';
|
|
15
|
+
export const IMPACT_SEEN_KEY_PREFIX = 'reticle.impact.seen.';
|
|
14
16
|
const OWN_KEYS = new Set(Object.values(ReticleStorageKey));
|
|
15
17
|
export function isReticleStorageKey(key) {
|
|
16
|
-
return OWN_KEYS.has(key) ||
|
|
18
|
+
return (OWN_KEYS.has(key) ||
|
|
19
|
+
key.startsWith(TOUR_SEEN_KEY_PREFIX) ||
|
|
20
|
+
key.startsWith(PERSONA_KEY_PREFIX) ||
|
|
21
|
+
key.startsWith(IMPACT_SEEN_KEY_PREFIX));
|
|
17
22
|
}
|
|
@@ -8,4 +8,5 @@ interface FrameOutcome {
|
|
|
8
8
|
export declare const boundedFrame: (budgetMs?: number) => Promise<FrameOutcome>;
|
|
9
9
|
export declare const nativeFrame: () => Promise<void>;
|
|
10
10
|
export declare const settle: (budgetMs?: number) => Promise<FrameOutcome>;
|
|
11
|
+
export declare function asSettleBudget(raw: unknown): number | undefined;
|
|
11
12
|
export {};
|
|
@@ -46,3 +46,8 @@ export const settle = async (budgetMs = FRAME_BUDGET_MS) => {
|
|
|
46
46
|
await Promise.resolve();
|
|
47
47
|
return boundedFrame(budgetMs);
|
|
48
48
|
};
|
|
49
|
+
export function asSettleBudget(raw) {
|
|
50
|
+
if ('number' !== typeof raw || !Number.isFinite(raw))
|
|
51
|
+
return undefined;
|
|
52
|
+
return Math.max(0, Math.min(raw, FRAME_BUDGET_MS));
|
|
53
|
+
}
|
|
@@ -26,6 +26,8 @@ export class Transport {
|
|
|
26
26
|
#signalQueue = [];
|
|
27
27
|
#insertOrder = 0;
|
|
28
28
|
#closed = false;
|
|
29
|
+
#refused = false;
|
|
30
|
+
#redialOnRefusal = false;
|
|
29
31
|
#disconnectedSince;
|
|
30
32
|
#reconnectDelay = RECONNECT_DELAY_MS;
|
|
31
33
|
#lost = false;
|
|
@@ -55,6 +57,7 @@ export class Transport {
|
|
|
55
57
|
this.#reconnectDelay = RECONNECT_DELAY_MS;
|
|
56
58
|
if (this.#ws !== undefined)
|
|
57
59
|
return;
|
|
60
|
+
this.#refused = false;
|
|
58
61
|
this.#open();
|
|
59
62
|
}
|
|
60
63
|
#open() {
|
|
@@ -92,9 +95,14 @@ export class Transport {
|
|
|
92
95
|
ws.onclose = (event) => {
|
|
93
96
|
this.#ws = undefined;
|
|
94
97
|
if (event.code === WS_POLICY_VIOLATION) {
|
|
95
|
-
this.#closed
|
|
98
|
+
if (this.#redialOnRefusal && !this.#closed) {
|
|
99
|
+
this.#redialOnRefusal = false;
|
|
100
|
+
this.#open();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.#refused = true;
|
|
96
104
|
const reason = event.reason.length > 0 ? event.reason : 'policy violation';
|
|
97
|
-
nativeWarn(`[reticle] bridge refused the connection: ${reason} — not retrying.`);
|
|
105
|
+
nativeWarn(`[reticle] bridge refused the connection: ${reason} — not retrying until you come back to this tab.`);
|
|
98
106
|
this.#deps.onConnectionLost?.();
|
|
99
107
|
return;
|
|
100
108
|
}
|
|
@@ -107,7 +115,7 @@ export class Transport {
|
|
|
107
115
|
};
|
|
108
116
|
}
|
|
109
117
|
#scheduleReopen() {
|
|
110
|
-
if (this.#closed)
|
|
118
|
+
if (this.#closed || this.#refused)
|
|
111
119
|
return;
|
|
112
120
|
const delay = this.#reconnectDelay;
|
|
113
121
|
this.#reconnectDelay = nextReconnectDelay(delay);
|
|
@@ -195,6 +203,18 @@ export class Transport {
|
|
|
195
203
|
type: event.type,
|
|
196
204
|
});
|
|
197
205
|
}
|
|
206
|
+
redialAfterRefusal() {
|
|
207
|
+
if (this.#closed) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (this.#refused && this.#ws === undefined) {
|
|
211
|
+
this.#refused = false;
|
|
212
|
+
this.#reconnectDelay = RECONNECT_DELAY_MS;
|
|
213
|
+
this.#open();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.#redialOnRefusal = true;
|
|
217
|
+
}
|
|
198
218
|
reannounce() {
|
|
199
219
|
if (this.#ws === undefined || this.#ws.readyState !== WebSocket.OPEN)
|
|
200
220
|
return;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare function unreachableMessage(url: string, attempts: number): string;
|
|
2
|
-
export declare
|
|
2
|
+
export declare const UNREACHABLE_HEADLINE = "Can't reach Reticle from this page. Run reticle status to check, or reticle serve to start it.";
|
|
@@ -5,9 +5,7 @@ export function unreachableMessage(url, attempts) {
|
|
|
5
5
|
`that is not there from one it is not allowed to reach, so this is not evidence about the ` +
|
|
6
6
|
`daemon. What answers it: run \`npx @reticlehq/server status\` to see whether one is listening ` +
|
|
7
7
|
`and on which port. If your app runs in a container, devcontainer or WSL, the daemon is on a ` +
|
|
8
|
-
`different host, so
|
|
9
|
-
`reticle.connect({ url })
|
|
10
|
-
}
|
|
11
|
-
export function unreachableStripText(url, attempts) {
|
|
12
|
-
return `no bridge at ${url} — ${String(attempts)} attempt${1 === attempts ? '' : 's'}`;
|
|
8
|
+
`different host, so point the page at it: RETICLE_PORT or reticle({ port }) with the Vite ` +
|
|
9
|
+
`plugin, reticle.connect({ url }) by hand. An https page cannot open a ws:// socket. Still retrying…`);
|
|
13
10
|
}
|
|
11
|
+
export const UNREACHABLE_HEADLINE = "Can't reach Reticle from this page. Run reticle status to check, or reticle serve to start it.";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reticlehq/browser",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.0",
|
|
4
4
|
"description": "Reticle browser SDK — installs observers, builds semantic snapshots, executes actions, talks to the bridge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,10 +15,14 @@
|
|
|
15
15
|
"./inject": {
|
|
16
16
|
"types": "./dist/reticle-inject.d.ts",
|
|
17
17
|
"default": "./dist/reticle-inject.js"
|
|
18
|
+
},
|
|
19
|
+
"./activate": {
|
|
20
|
+
"types": "./dist/activate.d.ts",
|
|
21
|
+
"default": "./dist/activate.js"
|
|
18
22
|
}
|
|
19
23
|
},
|
|
20
24
|
"dependencies": {
|
|
21
|
-
"@reticlehq/core": "3.
|
|
25
|
+
"@reticlehq/core": "3.8.0"
|
|
22
26
|
},
|
|
23
27
|
"devDependencies": {
|
|
24
28
|
"@iconify-json/heroicons-outline": "^1.2.1",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export declare const OFFER_ATTR = "data-reticle-offer";
|
|
2
|
-
export declare const OFFER_CLAIM_ATTR = "data-reticle-offer-claim";
|
|
3
|
-
export declare const OFFER_DISMISSED_KEY: "reticle.harnessOffer.dismissed";
|
|
4
|
-
export declare const OFFER_TEXT: {
|
|
5
|
-
readonly HEADLINE: "Get Harness free for 3 months";
|
|
6
|
-
readonly BODY: "Explores your app and saves every journey as a free replay.";
|
|
7
|
-
readonly CLAIM: "Claim now";
|
|
8
|
-
readonly DISMISS: "Not now";
|
|
9
|
-
readonly claimed: (days: number) => string;
|
|
10
|
-
readonly ending: (days: number) => string;
|
|
11
|
-
};
|
|
12
|
-
export declare function offerDismissed(storage: Pick<Storage, 'getItem'> | undefined): boolean;
|
|
13
|
-
export interface OfferState {
|
|
14
|
-
claimed: boolean;
|
|
15
|
-
daysRemaining?: number | undefined;
|
|
16
|
-
claimUrl?: string | undefined;
|
|
17
|
-
eligible?: boolean | undefined;
|
|
18
|
-
drivable?: boolean | undefined;
|
|
19
|
-
}
|
|
20
|
-
export declare function offerHtml(offer: OfferState | undefined, dismissed: boolean): string;
|
|
21
|
-
export declare const OFFER_CSS: string;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { ReticleStorageKey } from '../../storage-keys.js';
|
|
2
|
-
export const OFFER_ATTR = 'data-reticle-offer';
|
|
3
|
-
export const OFFER_CLAIM_ATTR = 'data-reticle-offer-claim';
|
|
4
|
-
export const OFFER_DISMISSED_KEY = ReticleStorageKey.HARNESS_OFFER_DISMISSED;
|
|
5
|
-
export const OFFER_TEXT = {
|
|
6
|
-
HEADLINE: 'Get Harness free for 3 months',
|
|
7
|
-
BODY: 'Explores your app and saves every journey as a free replay.',
|
|
8
|
-
CLAIM: 'Claim now',
|
|
9
|
-
DISMISS: 'Not now',
|
|
10
|
-
claimed: (days) => `Harness active — ${String(days)} days left`,
|
|
11
|
-
ending: (days) => 1 >= days
|
|
12
|
-
? 'Harness free period ends today'
|
|
13
|
-
: `Harness free period ends in ${String(days)} days`,
|
|
14
|
-
};
|
|
15
|
-
const ENDING_SOON_DAYS = 14;
|
|
16
|
-
export function offerDismissed(storage) {
|
|
17
|
-
try {
|
|
18
|
-
return '1' === storage?.getItem(OFFER_DISMISSED_KEY);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
const escape = (text) => text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
25
|
-
export function offerHtml(offer, dismissed) {
|
|
26
|
-
if (offer === undefined)
|
|
27
|
-
return '';
|
|
28
|
-
if (offer.claimed) {
|
|
29
|
-
const days = offer.daysRemaining;
|
|
30
|
-
if (days === undefined || 0 > days)
|
|
31
|
-
return '';
|
|
32
|
-
const text = ENDING_SOON_DAYS >= days ? OFFER_TEXT.ending(days) : OFFER_TEXT.claimed(days);
|
|
33
|
-
return `<div ${OFFER_ATTR} class="reticle-offer reticle-offer-claimed">${escape(text)}</div>`;
|
|
34
|
-
}
|
|
35
|
-
if (false === offer.eligible)
|
|
36
|
-
return '';
|
|
37
|
-
if (false === offer.drivable)
|
|
38
|
-
return '';
|
|
39
|
-
if (dismissed)
|
|
40
|
-
return '';
|
|
41
|
-
const url = offer.claimUrl;
|
|
42
|
-
if (url === undefined || 0 === url.length)
|
|
43
|
-
return '';
|
|
44
|
-
return `<div ${OFFER_ATTR} class="reticle-offer" role="note">
|
|
45
|
-
<span class="reticle-offer-title">${escape(OFFER_TEXT.HEADLINE)}</span>
|
|
46
|
-
<p class="reticle-offer-body">${escape(OFFER_TEXT.BODY)}</p>
|
|
47
|
-
<a ${OFFER_CLAIM_ATTR} class="reticle-offer-claim" href="${escape(url)}" target="_blank" rel="noopener noreferrer">${escape(OFFER_TEXT.CLAIM)}</a>
|
|
48
|
-
</div>`;
|
|
49
|
-
}
|
|
50
|
-
export const OFFER_CSS = `
|
|
51
|
-
.reticle-offer{margin:8px 10px;padding:10px 12px;border:1px solid var(--reticle-line,#2a2f3a);border-radius:10px;background:var(--reticle-surface-inset,rgba(255,255,255,.03));}
|
|
52
|
-
.reticle-offer-title{display:block;font-weight:600;font-size:12px;padding-right:18px;}
|
|
53
|
-
.reticle-offer-body{margin:6px 0 8px;font-size:11px;line-height:1.45;opacity:.8;}
|
|
54
|
-
.reticle-offer-claim{display:inline-block;font-size:11px;font-weight:600;padding:4px 10px;border-radius:6px;background:var(--reticle-accent,#4f7cff);color:#fff;text-decoration:none;}
|
|
55
|
-
.reticle-offer-claimed{margin:6px 10px;font-size:10px;opacity:.6;}
|
|
56
|
-
`;
|