@storystick/preview 0.0.0-stage → 0.2.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +112 -0
- package/PUBLIC-API.md +55 -0
- package/README.md +42 -2
- package/dist/.source-hash +1 -0
- package/dist/authoring/runtime-contract.d.ts +89 -0
- package/dist/authoring/runtime-contract.js +28 -0
- package/dist/channel-taxonomy.d.ts +17 -0
- package/dist/channel-taxonomy.js +46 -0
- package/dist/context-command.d.ts +18 -0
- package/dist/context-command.js +38 -0
- package/dist/dev/suspicious-codeword-detector.d.ts +15 -0
- package/dist/dev/suspicious-codeword-detector.js +220 -0
- package/dist/dev/suspicious-codeword-detector.noop.d.ts +3 -0
- package/dist/dev/suspicious-codeword-detector.noop.js +4 -0
- package/dist/framework/browser-context.d.ts +2 -0
- package/dist/framework/browser-context.js +2 -0
- package/dist/framework/generation-refresh.d.ts +23 -0
- package/dist/framework/generation-refresh.js +82 -0
- package/dist/framework/generation-signal.d.ts +8 -0
- package/dist/framework/generation-signal.js +17 -0
- package/dist/framework/projection-generation-watch.d.ts +5 -0
- package/dist/framework/projection-generation-watch.js +53 -0
- package/dist/framework/render-receipt.d.ts +8 -0
- package/dist/framework/render-receipt.js +10 -0
- package/dist/framework/runtime-adapter-store.d.ts +30 -0
- package/dist/framework/runtime-adapter-store.js +81 -0
- package/dist/grant-coordinator.d.ts +53 -0
- package/dist/grant-coordinator.js +329 -0
- package/dist/grant-lifecycle.d.ts +52 -0
- package/dist/grant-lifecycle.js +74 -0
- package/dist/identity/__test-adapter.d.ts +34 -0
- package/dist/identity/__test-adapter.js +59 -0
- package/dist/identity/browser-context-gate.d.ts +4 -0
- package/dist/identity/browser-context-gate.js +22 -0
- package/dist/identity/browser-context.d.ts +13 -0
- package/dist/identity/browser-context.js +22 -0
- package/dist/identity/carriers/postmessage.d.ts +84 -0
- package/dist/identity/carriers/postmessage.js +177 -0
- package/dist/identity/carriers/storage-state.d.ts +41 -0
- package/dist/identity/carriers/storage-state.js +99 -0
- package/dist/identity/carriers/storage.d.ts +39 -0
- package/dist/identity/carriers/storage.js +182 -0
- package/dist/identity/carriers/url.d.ts +19 -0
- package/dist/identity/carriers/url.js +38 -0
- package/dist/identity/identity-state-machine.d.ts +70 -0
- package/dist/identity/identity-state-machine.js +244 -0
- package/dist/identity/identity-types.d.ts +192 -0
- package/dist/identity/identity-types.js +22 -0
- package/dist/identity/index.d.ts +18 -0
- package/dist/identity/index.js +16 -0
- package/dist/identity/preview-cookie.d.ts +9 -0
- package/dist/identity/preview-cookie.js +12 -0
- package/dist/identity/preview-draft.d.ts +6 -0
- package/dist/identity/preview-draft.js +25 -0
- package/dist/identity/preview-identity.d.ts +28 -0
- package/dist/identity/preview-identity.js +84 -0
- package/dist/identity/preview-scope.d.ts +28 -0
- package/dist/identity/preview-scope.js +47 -0
- package/dist/identity/resolver.d.ts +110 -0
- package/dist/identity/resolver.js +334 -0
- package/dist/identity/session-query.d.ts +4 -0
- package/dist/identity/session-query.js +19 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +788 -0
- package/dist/interaction-mode.d.ts +58 -0
- package/dist/interaction-mode.js +93 -0
- package/dist/nav-handler.d.ts +95 -0
- package/dist/nav-handler.js +84 -0
- package/dist/overlay-label.d.ts +79 -0
- package/dist/overlay-label.js +73 -0
- package/dist/provenance/anchor-map.d.ts +95 -0
- package/dist/provenance/anchor-map.js +177 -0
- package/dist/provenance/carrier-plan.d.ts +51 -0
- package/dist/provenance/carrier-plan.js +90 -0
- package/dist/provenance/coded-text.d.ts +20 -0
- package/dist/provenance/coded-text.js +302 -0
- package/dist/provenance/direct-edit-locator.d.ts +29 -0
- package/dist/provenance/direct-edit-locator.js +218 -0
- package/dist/provenance/editable-leaf.d.ts +134 -0
- package/dist/provenance/editable-leaf.js +483 -0
- package/dist/provenance/editor-target.d.ts +29 -0
- package/dist/provenance/editor-target.js +46 -0
- package/dist/provenance/field-leaf-walker.d.ts +21 -0
- package/dist/provenance/field-leaf-walker.js +98 -0
- package/dist/provenance/frame-dependencies.d.ts +212 -0
- package/dist/provenance/frame-dependencies.js +550 -0
- package/dist/provenance/index.d.ts +26 -0
- package/dist/provenance/index.js +26 -0
- package/dist/provenance/local-events.d.ts +1 -0
- package/dist/provenance/local-events.js +1 -0
- package/dist/provenance/markers.d.ts +21 -0
- package/dist/provenance/markers.js +70 -0
- package/dist/provenance/multi-frame-anchor-map.d.ts +54 -0
- package/dist/provenance/multi-frame-anchor-map.js +109 -0
- package/dist/provenance/normalize.d.ts +2 -0
- package/dist/provenance/normalize.js +19 -0
- package/dist/provenance/overlay-focus-echo.d.ts +17 -0
- package/dist/provenance/overlay-focus-echo.js +16 -0
- package/dist/provenance/overlay-projection.d.ts +65 -0
- package/dist/provenance/overlay-projection.js +201 -0
- package/dist/provenance/owner-map.d.ts +55 -0
- package/dist/provenance/owner-map.js +239 -0
- package/dist/provenance/read-carrier.d.ts +22 -0
- package/dist/provenance/read-carrier.js +92 -0
- package/dist/provenance/recorder.d.ts +38 -0
- package/dist/provenance/recorder.js +82 -0
- package/dist/provenance/render-context.d.ts +106 -0
- package/dist/provenance/render-context.js +338 -0
- package/dist/provenance/reveal-contract.d.ts +44 -0
- package/dist/provenance/reveal-contract.js +1 -0
- package/dist/provenance/richtext-slice-embed-address.d.ts +20 -0
- package/dist/provenance/richtext-slice-embed-address.js +35 -0
- package/dist/provenance/runtime-script.d.ts +1 -0
- package/dist/provenance/runtime-script.js +2217 -0
- package/dist/provenance/sidecar-store.d.ts +63 -0
- package/dist/provenance/sidecar-store.js +151 -0
- package/dist/provenance/sidecar.d.ts +34 -0
- package/dist/provenance/sidecar.js +227 -0
- package/dist/provenance/slice-model.d.ts +28 -0
- package/dist/provenance/slice-model.js +86 -0
- package/dist/provenance/source-identity.d.ts +3 -0
- package/dist/provenance/source-identity.js +7 -0
- package/dist/provenance/source-map-materializer.d.ts +76 -0
- package/dist/provenance/source-map-materializer.js +286 -0
- package/dist/provenance/source-registry.d.ts +103 -0
- package/dist/provenance/source-registry.js +562 -0
- package/dist/provenance/transformed-output-gate.d.ts +161 -0
- package/dist/provenance/transformed-output-gate.js +171 -0
- package/dist/provenance/types.d.ts +102 -0
- package/dist/provenance/types.js +1 -0
- package/dist/refresh-policy.d.ts +11 -0
- package/dist/refresh-policy.js +14 -0
- package/dist/reveal-target.d.ts +8 -0
- package/dist/reveal-target.js +47 -0
- package/dist/route-paths.d.ts +11 -0
- package/dist/route-paths.js +14 -0
- package/dist/router-subscriber.d.ts +92 -0
- package/dist/router-subscriber.js +44 -0
- package/dist/runtime/anchor-types.d.ts +5 -0
- package/dist/runtime/anchor-types.js +1 -0
- package/dist/runtime/authority-store.d.ts +31 -0
- package/dist/runtime/authority-store.js +56 -0
- package/dist/runtime/boot.d.ts +52 -0
- package/dist/runtime/boot.js +379 -0
- package/dist/runtime/content-refresh.d.ts +30 -0
- package/dist/runtime/content-refresh.js +68 -0
- package/dist/runtime/emit-runtime-error.d.ts +51 -0
- package/dist/runtime/emit-runtime-error.js +64 -0
- package/dist/runtime/field-proxy.d.ts +112 -0
- package/dist/runtime/field-proxy.js +471 -0
- package/dist/runtime/form-contract-reporter.d.ts +99 -0
- package/dist/runtime/form-contract-reporter.js +391 -0
- package/dist/runtime/invalidation-adapter.d.ts +17 -0
- package/dist/runtime/invalidation-adapter.js +42 -0
- package/dist/runtime/live-query-overlay.d.ts +39 -0
- package/dist/runtime/live-query-overlay.js +345 -0
- package/dist/runtime/momentary-navigate.d.ts +16 -0
- package/dist/runtime/momentary-navigate.js +106 -0
- package/dist/runtime/observation-scheduler.d.ts +15 -0
- package/dist/runtime/observation-scheduler.js +42 -0
- package/dist/runtime/perf-metrics.d.ts +28 -0
- package/dist/runtime/perf-metrics.js +90 -0
- package/dist/runtime/preview-interaction-policy.d.ts +1 -0
- package/dist/runtime/preview-interaction-policy.js +103 -0
- package/dist/runtime/preview-overlay-painter.d.ts +27 -0
- package/dist/runtime/preview-overlay-painter.js +1732 -0
- package/dist/runtime/preview-overlay-sidecar.d.ts +26 -0
- package/dist/runtime/preview-overlay-sidecar.js +45 -0
- package/dist/runtime/preview-perspective-alignment.d.ts +15 -0
- package/dist/runtime/preview-perspective-alignment.js +40 -0
- package/dist/runtime/preview-perspective-intent-state.d.ts +23 -0
- package/dist/runtime/preview-perspective-intent-state.js +5 -0
- package/dist/runtime/preview-transition-state.d.ts +142 -0
- package/dist/runtime/preview-transition-state.js +257 -0
- package/dist/runtime/render-mode-state.d.ts +51 -0
- package/dist/runtime/render-mode-state.js +76 -0
- package/dist/runtime/request-id.d.ts +4 -0
- package/dist/runtime/request-id.js +8 -0
- package/dist/runtime/resolve-schema-field.d.ts +99 -0
- package/dist/runtime/resolve-schema-field.js +356 -0
- package/dist/runtime/runtime-error-dispatch.d.ts +23 -0
- package/dist/runtime/runtime-error-dispatch.js +75 -0
- package/dist/runtime/schema-store.d.ts +121 -0
- package/dist/runtime/schema-store.js +667 -0
- package/dist/runtime/snapshot-assembly.d.ts +104 -0
- package/dist/runtime/snapshot-assembly.js +553 -0
- package/dist/runtime/snapshot-reporter.d.ts +55 -0
- package/dist/runtime/snapshot-reporter.js +375 -0
- package/dist/runtime/standalone-overlay-controller.d.ts +33 -0
- package/dist/runtime/standalone-overlay-controller.js +281 -0
- package/dist/runtime/store.d.ts +307 -0
- package/dist/runtime/store.js +1026 -0
- package/dist/runtime/windowed-minimap-projection.d.ts +28 -0
- package/dist/runtime/windowed-minimap-projection.js +189 -0
- package/dist/runtime/workspace-shortcuts.d.ts +30 -0
- package/dist/runtime/workspace-shortcuts.js +188 -0
- package/dist/sdk-error-copy.d.ts +48 -0
- package/dist/sdk-error-copy.js +182 -0
- package/dist/select-cursor.d.ts +2 -0
- package/dist/select-cursor.js +23 -0
- package/dist/server/admission-cookie.d.ts +38 -0
- package/dist/server/admission-cookie.js +122 -0
- package/dist/server/control-client.d.ts +29 -0
- package/dist/server/control-client.js +22 -0
- package/dist/server/control-errors.d.ts +22 -0
- package/dist/server/control-errors.js +165 -0
- package/dist/server/draft-route.d.ts +12 -0
- package/dist/server/draft-route.js +45 -0
- package/dist/server/extract-token.d.ts +30 -0
- package/dist/server/extract-token.js +98 -0
- package/dist/server/grant.d.ts +128 -0
- package/dist/server/grant.js +395 -0
- package/dist/server/ordinary-read-provenance.d.ts +11 -0
- package/dist/server/ordinary-read-provenance.js +124 -0
- package/dist/server/preview-read-metadata.d.ts +10 -0
- package/dist/server/preview-read-metadata.js +27 -0
- package/dist/server/provenance-frame-builder.d.ts +53 -0
- package/dist/server/provenance-frame-builder.js +102 -0
- package/dist/server/provenance-runtime.d.ts +70 -0
- package/dist/server/provenance-runtime.js +46 -0
- package/dist/server/read-context-command.d.ts +11 -0
- package/dist/server/read-context-command.js +53 -0
- package/dist/server/read-identity.d.ts +3 -0
- package/dist/server/read-identity.js +63 -0
- package/dist/server/read-lifecycle.d.ts +17 -0
- package/dist/server/read-lifecycle.js +52 -0
- package/dist/server/render-frame-provenance.d.ts +133 -0
- package/dist/server/render-frame-provenance.js +676 -0
- package/dist/server/render-id.d.ts +15 -0
- package/dist/server/render-id.js +22 -0
- package/dist/server/route-document-provenance.d.ts +77 -0
- package/dist/server/route-document-provenance.js +1327 -0
- package/dist/server/route-session-cookie.d.ts +33 -0
- package/dist/server/route-session-cookie.js +54 -0
- package/dist/session-projections.d.ts +33 -0
- package/dist/session-projections.js +43 -0
- package/dist/session-subscriber.d.ts +124 -0
- package/dist/session-subscriber.js +79 -0
- package/dist/sha256-fallback.d.ts +30 -0
- package/dist/sha256-fallback.js +126 -0
- package/dist/types.d.ts +446 -0
- package/dist/types.js +85 -0
- package/dist/validators.d.ts +61 -0
- package/dist/validators.js +110 -0
- package/package.json +206 -3
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const NOOP = () => {
|
|
2
|
+
/* default — no adapter registered */
|
|
3
|
+
};
|
|
4
|
+
function subscriberCell() {
|
|
5
|
+
const existing = globalThis.__storystick_preview_router_subscriber__;
|
|
6
|
+
if (existing)
|
|
7
|
+
return existing;
|
|
8
|
+
const created = { subscriber: null };
|
|
9
|
+
globalThis.__storystick_preview_router_subscriber__ = created;
|
|
10
|
+
return created;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Register the router subscriber. Replaces any previously registered
|
|
14
|
+
* subscriber. Pass `null` to reset to the default no-op.
|
|
15
|
+
*/
|
|
16
|
+
export function setRouterSubscriber(fn) {
|
|
17
|
+
subscriberCell().subscriber = fn;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read the currently-registered subscriber. Returns `null` before any
|
|
21
|
+
* adapter has called `setRouterSubscriber`. Consumers gate their
|
|
22
|
+
* invocation on the non-null return.
|
|
23
|
+
*/
|
|
24
|
+
export function getRouterSubscriber() {
|
|
25
|
+
return subscriberCell().subscriber;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convenience for `activate()`'s router-transition path: invoke the
|
|
29
|
+
* currently-registered subscriber if any, no-op otherwise. Centralises
|
|
30
|
+
* the null-check so callers don't repeat it.
|
|
31
|
+
*/
|
|
32
|
+
export function notifyRouterTransition(transition) {
|
|
33
|
+
if (typeof window !== 'undefined')
|
|
34
|
+
window.dispatchEvent(new CustomEvent('storystick.preview.location-committed', { detail: transition }));
|
|
35
|
+
const fn = subscriberCell().subscriber ?? NOOP;
|
|
36
|
+
fn(transition);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Test-only reset. Vitest isolates modules per file but multiple
|
|
40
|
+
* cases inside one file would otherwise share state.
|
|
41
|
+
*/
|
|
42
|
+
export function _resetRouterSubscriberForTests() {
|
|
43
|
+
subscriberCell().subscriber = null;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Client } from "@storystick/client";
|
|
2
|
+
import type { ConvexReactClient } from "convex/react";
|
|
3
|
+
import type { PreviewReadContext } from "@storystick/types/preview-query-targeting";
|
|
4
|
+
/**
|
|
5
|
+
* The narrow Preview authority projection consumed by query runtimes.
|
|
6
|
+
*
|
|
7
|
+
* Keep this module value-import free: production query hooks can depend on it
|
|
8
|
+
* without pulling the Preview overlay, identity resolver, or grant coordinator
|
|
9
|
+
* into their bundle.
|
|
10
|
+
*/
|
|
11
|
+
export interface PreviewAuthoritySnapshot {
|
|
12
|
+
readonly client: ConvexReactClient | null;
|
|
13
|
+
readonly httpClient: Client | null;
|
|
14
|
+
readonly sessionId: string | null;
|
|
15
|
+
readonly previewToken: string | null;
|
|
16
|
+
readonly variantId: string | null;
|
|
17
|
+
readonly releaseId: string | null;
|
|
18
|
+
readonly readContext: PreviewReadContext | null;
|
|
19
|
+
}
|
|
20
|
+
interface PreviewAuthorityCell {
|
|
21
|
+
snapshot: PreviewAuthoritySnapshot;
|
|
22
|
+
listeners: Set<() => void>;
|
|
23
|
+
}
|
|
24
|
+
declare global {
|
|
25
|
+
var __storystick_preview_authority__: PreviewAuthorityCell | undefined;
|
|
26
|
+
}
|
|
27
|
+
export declare function getPreviewAuthority(): PreviewAuthoritySnapshot;
|
|
28
|
+
export declare function subscribePreviewAuthority(listener: () => void): () => void;
|
|
29
|
+
/** Runtime bridge. Publish a complete projection to avoid mixed authority. */
|
|
30
|
+
export declare function publishPreviewAuthority(next: PreviewAuthoritySnapshot): void;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const EMPTY_AUTHORITY = Object.freeze({
|
|
2
|
+
client: null,
|
|
3
|
+
httpClient: null,
|
|
4
|
+
sessionId: null,
|
|
5
|
+
previewToken: null,
|
|
6
|
+
variantId: null,
|
|
7
|
+
releaseId: null,
|
|
8
|
+
readContext: null,
|
|
9
|
+
});
|
|
10
|
+
function authorityCell() {
|
|
11
|
+
const existing = globalThis.__storystick_preview_authority__;
|
|
12
|
+
if (existing) {
|
|
13
|
+
if (!(existing.listeners instanceof Set))
|
|
14
|
+
existing.listeners = new Set();
|
|
15
|
+
return existing;
|
|
16
|
+
}
|
|
17
|
+
const created = {
|
|
18
|
+
snapshot: EMPTY_AUTHORITY,
|
|
19
|
+
listeners: new Set(),
|
|
20
|
+
};
|
|
21
|
+
globalThis.__storystick_preview_authority__ = created;
|
|
22
|
+
return created;
|
|
23
|
+
}
|
|
24
|
+
export function getPreviewAuthority() {
|
|
25
|
+
return authorityCell().snapshot;
|
|
26
|
+
}
|
|
27
|
+
export function subscribePreviewAuthority(listener) {
|
|
28
|
+
const cell = authorityCell();
|
|
29
|
+
cell.listeners.add(listener);
|
|
30
|
+
return () => {
|
|
31
|
+
cell.listeners.delete(listener);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Runtime bridge. Publish a complete projection to avoid mixed authority. */
|
|
35
|
+
export function publishPreviewAuthority(next) {
|
|
36
|
+
const cell = authorityCell();
|
|
37
|
+
const current = cell.snapshot;
|
|
38
|
+
if (current.client === next.client &&
|
|
39
|
+
current.httpClient === next.httpClient &&
|
|
40
|
+
current.sessionId === next.sessionId &&
|
|
41
|
+
current.previewToken === next.previewToken &&
|
|
42
|
+
current.variantId === next.variantId &&
|
|
43
|
+
current.releaseId === next.releaseId &&
|
|
44
|
+
current.readContext === next.readContext) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
cell.snapshot = Object.freeze({ ...next });
|
|
48
|
+
for (const listener of cell.listeners) {
|
|
49
|
+
try {
|
|
50
|
+
listener();
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
/* defensive — one observer must not break the authority fan-out */
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-131 Amendment 002 + chantier-decomposition.md §3 — iframe runtime
|
|
3
|
+
* boot orchestrator.
|
|
4
|
+
*
|
|
5
|
+
* Wires schema delivery and preview interaction listeners into a coherent
|
|
6
|
+
* runtime. Called
|
|
7
|
+
* by the iframe-side `<Storystick />` adapter (`@storystick/next`) in
|
|
8
|
+
* preview mode.
|
|
9
|
+
*
|
|
10
|
+
* ┌────────────────────────────────────────────────────────────────┐
|
|
11
|
+
* │ bootIframeRuntime(opts) — once per <Storystick /> mount │
|
|
12
|
+
* │ │
|
|
13
|
+
* │ bootSchema + retry loop │
|
|
14
|
+
* │ │
|
|
15
|
+
* │ window.message → overlay / v2 handlers │
|
|
16
|
+
* │ │
|
|
17
|
+
* │ Returns teardown() — caller invokes on HMR / unmount. │
|
|
18
|
+
* └────────────────────────────────────────────────────────────────┘
|
|
19
|
+
*
|
|
20
|
+
* Idempotent : a second `bootIframeRuntime()` call is a noop while the
|
|
21
|
+
* first is still active (returns the same teardown).
|
|
22
|
+
*/
|
|
23
|
+
declare global {
|
|
24
|
+
interface Window {
|
|
25
|
+
__storystickPreviewOverlayMapOwner?: "boot";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export interface BootIframeRuntimeOpts {
|
|
29
|
+
/** Document under observation. Defaults to `window.document`. */
|
|
30
|
+
document?: Document;
|
|
31
|
+
}
|
|
32
|
+
export interface IframeRuntimeHandle {
|
|
33
|
+
/** Tear down the runtime and release listeners. */
|
|
34
|
+
teardown(): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Boot the iframe runtime. Idempotent — calling a second time before
|
|
38
|
+
* `teardown()` returns the existing handle. Concurrent first-time
|
|
39
|
+
* callers share a single boot promise (StrictMode double-mount safe).
|
|
40
|
+
*
|
|
41
|
+
* Returns `null` if any prerequisite is genuinely missing (no Document,
|
|
42
|
+
* no window). The `<Storystick />` adapter's preview mode is gated
|
|
43
|
+
* server-side, so this path only fires in environments where the
|
|
44
|
+
* window exists.
|
|
45
|
+
*/
|
|
46
|
+
export declare function bootIframeRuntime(opts?: BootIframeRuntimeOpts): Promise<IframeRuntimeHandle | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Test hook — clear the active handle, invoking teardown if present.
|
|
49
|
+
* Required when tests open + tear down many runtimes in sequence and
|
|
50
|
+
* need a clean module state.
|
|
51
|
+
*/
|
|
52
|
+
export declare function _resetBootForTestsOnly(): void;
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-131 Amendment 002 + chantier-decomposition.md §3 — iframe runtime
|
|
3
|
+
* boot orchestrator.
|
|
4
|
+
*
|
|
5
|
+
* Wires schema delivery and preview interaction listeners into a coherent
|
|
6
|
+
* runtime. Called
|
|
7
|
+
* by the iframe-side `<Storystick />` adapter (`@storystick/next`) in
|
|
8
|
+
* preview mode.
|
|
9
|
+
*
|
|
10
|
+
* ┌────────────────────────────────────────────────────────────────┐
|
|
11
|
+
* │ bootIframeRuntime(opts) — once per <Storystick /> mount │
|
|
12
|
+
* │ │
|
|
13
|
+
* │ bootSchema + retry loop │
|
|
14
|
+
* │ │
|
|
15
|
+
* │ window.message → overlay / v2 handlers │
|
|
16
|
+
* │ │
|
|
17
|
+
* │ Returns teardown() — caller invokes on HMR / unmount. │
|
|
18
|
+
* └────────────────────────────────────────────────────────────────┘
|
|
19
|
+
*
|
|
20
|
+
* Idempotent : a second `bootIframeRuntime()` call is a noop while the
|
|
21
|
+
* first is still active (returns the same teardown).
|
|
22
|
+
*/
|
|
23
|
+
import { bootSchema, startSchemaRetryLoop } from "./schema-store.js";
|
|
24
|
+
import { previewRuntime } from "./store.js";
|
|
25
|
+
import { applyPreviewOverlayMap, clearPreviewOverlayPaint, installPreviewEditInteractionGuard, revealPreviewV2SourceInIframe, } from "./preview-overlay-painter.js";
|
|
26
|
+
import { installPreviewWorkspaceShortcuts } from "./workspace-shortcuts.js";
|
|
27
|
+
import { installMomentaryNavigateKeyRelay } from "./momentary-navigate.js";
|
|
28
|
+
import { validateOverlayClear, validateOverlayMap, validatePreviewV2RevealSource, } from "../validators.js";
|
|
29
|
+
import { setInteractionMode } from "../interaction-mode.js";
|
|
30
|
+
import { getReloadHandler } from "../nav-handler.js";
|
|
31
|
+
import { PREVIEW_NAMESPACE, PREVIEW_PROTOCOL_VERSION, validatePreviewEnvelope, } from "@storystick/transport-allowlist";
|
|
32
|
+
// ── Module-scoped singletons (forward-compat with HMR + StrictMode) ──
|
|
33
|
+
let active = null;
|
|
34
|
+
// Boot in-flight slot. Set SYNCHRONOUSLY at the start of bootIframeRuntime
|
|
35
|
+
// (before the first await) so concurrent callers — StrictMode double-mount,
|
|
36
|
+
// HMR re-mount — observe the same boot promise instead of racing to open
|
|
37
|
+
// duplicate listeners. Released once boot resolves
|
|
38
|
+
// (whether to a handle or null).
|
|
39
|
+
let bootInFlight = null;
|
|
40
|
+
function cryptoRandomHex() {
|
|
41
|
+
const bytes = new Uint8Array(16);
|
|
42
|
+
if (typeof crypto !== "undefined" &&
|
|
43
|
+
typeof crypto.getRandomValues === "function") {
|
|
44
|
+
crypto.getRandomValues(bytes);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
for (let index = 0; index < bytes.length; index++) {
|
|
48
|
+
bytes[index] = Math.floor(Math.random() * 256);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
52
|
+
}
|
|
53
|
+
function emitOverlayReady(view, payload) {
|
|
54
|
+
const identity = previewRuntime.getState().identity;
|
|
55
|
+
if (identity === null || identity.parentOrigin === null)
|
|
56
|
+
return;
|
|
57
|
+
const envelope = {
|
|
58
|
+
namespace: PREVIEW_NAMESPACE,
|
|
59
|
+
version: PREVIEW_PROTOCOL_VERSION,
|
|
60
|
+
type: "storystick.preview.overlay-ready",
|
|
61
|
+
sessionId: identity.sessionId,
|
|
62
|
+
projectId: identity.projectId,
|
|
63
|
+
requestId: cryptoRandomHex(),
|
|
64
|
+
nonce: cryptoRandomHex(),
|
|
65
|
+
sentAt: Date.now(),
|
|
66
|
+
payload,
|
|
67
|
+
};
|
|
68
|
+
view.parent.postMessage(envelope, identity.parentOrigin);
|
|
69
|
+
}
|
|
70
|
+
function emitOverlayClick(view, payload) {
|
|
71
|
+
const identity = previewRuntime.getState().identity;
|
|
72
|
+
if (identity === null || identity.parentOrigin === null)
|
|
73
|
+
return;
|
|
74
|
+
const envelope = {
|
|
75
|
+
namespace: PREVIEW_NAMESPACE,
|
|
76
|
+
version: PREVIEW_PROTOCOL_VERSION,
|
|
77
|
+
type: "storystick.preview.overlay-click",
|
|
78
|
+
sessionId: identity.sessionId,
|
|
79
|
+
projectId: identity.projectId,
|
|
80
|
+
requestId: cryptoRandomHex(),
|
|
81
|
+
nonce: cryptoRandomHex(),
|
|
82
|
+
sentAt: Date.now(),
|
|
83
|
+
payload,
|
|
84
|
+
};
|
|
85
|
+
view.parent.postMessage(envelope, identity.parentOrigin);
|
|
86
|
+
}
|
|
87
|
+
function emitIframeInteraction(view, payload) {
|
|
88
|
+
const identity = previewRuntime.getState().identity;
|
|
89
|
+
if (identity === null || identity.parentOrigin === null)
|
|
90
|
+
return;
|
|
91
|
+
const envelope = {
|
|
92
|
+
namespace: PREVIEW_NAMESPACE,
|
|
93
|
+
version: PREVIEW_PROTOCOL_VERSION,
|
|
94
|
+
type: "storystick.preview.iframe-interaction",
|
|
95
|
+
sessionId: identity.sessionId,
|
|
96
|
+
projectId: identity.projectId,
|
|
97
|
+
requestId: cryptoRandomHex(),
|
|
98
|
+
nonce: cryptoRandomHex(),
|
|
99
|
+
sentAt: Date.now(),
|
|
100
|
+
payload,
|
|
101
|
+
};
|
|
102
|
+
view.parent.postMessage(envelope, identity.parentOrigin);
|
|
103
|
+
}
|
|
104
|
+
function emitPreviewV2RevealResult(view, payload) {
|
|
105
|
+
const identity = previewRuntime.getState().identity;
|
|
106
|
+
if (identity === null || identity.parentOrigin === null)
|
|
107
|
+
return;
|
|
108
|
+
const envelope = {
|
|
109
|
+
namespace: PREVIEW_NAMESPACE,
|
|
110
|
+
version: PREVIEW_PROTOCOL_VERSION,
|
|
111
|
+
type: "storystick.preview.v2.reveal-result",
|
|
112
|
+
sessionId: identity.sessionId,
|
|
113
|
+
projectId: identity.projectId,
|
|
114
|
+
requestId: cryptoRandomHex(),
|
|
115
|
+
nonce: cryptoRandomHex(),
|
|
116
|
+
sentAt: Date.now(),
|
|
117
|
+
payload,
|
|
118
|
+
};
|
|
119
|
+
view.parent.postMessage(envelope, identity.parentOrigin);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Boot the iframe runtime. Idempotent — calling a second time before
|
|
123
|
+
* `teardown()` returns the existing handle. Concurrent first-time
|
|
124
|
+
* callers share a single boot promise (StrictMode double-mount safe).
|
|
125
|
+
*
|
|
126
|
+
* Returns `null` if any prerequisite is genuinely missing (no Document,
|
|
127
|
+
* no window). The `<Storystick />` adapter's preview mode is gated
|
|
128
|
+
* server-side, so this path only fires in environments where the
|
|
129
|
+
* window exists.
|
|
130
|
+
*/
|
|
131
|
+
export function bootIframeRuntime(opts) {
|
|
132
|
+
// Codex R1 fix — set the in-flight slot SYNCHRONOUSLY before any
|
|
133
|
+
// await so concurrent callers (StrictMode double-mount, HMR
|
|
134
|
+
// re-mount) share a single boot instead of racing to open duplicate
|
|
135
|
+
// caches / channels / listeners.
|
|
136
|
+
if (active !== null)
|
|
137
|
+
return Promise.resolve(active);
|
|
138
|
+
if (bootInFlight !== null)
|
|
139
|
+
return bootInFlight;
|
|
140
|
+
bootInFlight = (async () => {
|
|
141
|
+
// Preserve the in-flight slot's ordering now that boot has no I/O await:
|
|
142
|
+
// the caller must assign this promise before the finally block clears it.
|
|
143
|
+
await Promise.resolve();
|
|
144
|
+
let keepOverlayMapOwner = false;
|
|
145
|
+
let releaseOverlayMapOwner = () => {
|
|
146
|
+
/* unset until a Window is available */
|
|
147
|
+
};
|
|
148
|
+
try {
|
|
149
|
+
const doc = opts?.document ?? (typeof document !== "undefined" ? document : null);
|
|
150
|
+
if (doc === null)
|
|
151
|
+
return null;
|
|
152
|
+
const view = doc.defaultView ?? (typeof window !== "undefined" ? window : null);
|
|
153
|
+
if (view !== null) {
|
|
154
|
+
const previousOverlayMapOwner = view.__storystickPreviewOverlayMapOwner;
|
|
155
|
+
let released = false;
|
|
156
|
+
view.__storystickPreviewOverlayMapOwner = "boot";
|
|
157
|
+
releaseOverlayMapOwner = () => {
|
|
158
|
+
if (released)
|
|
159
|
+
return;
|
|
160
|
+
released = true;
|
|
161
|
+
if (previousOverlayMapOwner === undefined) {
|
|
162
|
+
delete view.__storystickPreviewOverlayMapOwner;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
view.__storystickPreviewOverlayMapOwner = previousOverlayMapOwner;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// 1. Boot schema. Two cooperating mechanisms :
|
|
170
|
+
// - An EAGER `bootSchema()` call : on a fresh iframe with an
|
|
171
|
+
// already-fetched IDB cache (or a fast network), the schema
|
|
172
|
+
// lands in the in-memory record within microseconds. The
|
|
173
|
+
// retry orchestrator's attempt 1 at t=1s then sees the
|
|
174
|
+
// cache hit and bails without any UI signal — fast path
|
|
175
|
+
// preserved (codex R2 P2 fix).
|
|
176
|
+
// - The retry orchestrator owns the full attempt cycle
|
|
177
|
+
// (§9.T7) : 5 attempts at exponential backoff (1s, 2s,
|
|
178
|
+
// 4s, 8s, 16s — attempt 1 at t=1s, attempt 5 at t=31s),
|
|
179
|
+
// with one warning emit at attempt 1 fail and one error
|
|
180
|
+
// emit at attempt 5 fail. Counter resets on httpClient
|
|
181
|
+
// or projectId change.
|
|
182
|
+
void bootSchema();
|
|
183
|
+
const teardownSchemaRetry = startSchemaRetryLoop();
|
|
184
|
+
let teardownEditInteractionGuard = null;
|
|
185
|
+
const ensureEditInteractionGuard = () => {
|
|
186
|
+
if (view === null || teardownEditInteractionGuard !== null)
|
|
187
|
+
return;
|
|
188
|
+
teardownEditInteractionGuard = installPreviewEditInteractionGuard(view, {
|
|
189
|
+
onInteraction: (payload) => emitIframeInteraction(view, payload),
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
if (previewRuntime.getState().identity?.parentOrigin !== null) {
|
|
193
|
+
ensureEditInteractionGuard();
|
|
194
|
+
}
|
|
195
|
+
const teardownWorkspaceShortcuts = view === null
|
|
196
|
+
? () => { }
|
|
197
|
+
: installPreviewWorkspaceShortcuts(view, () => {
|
|
198
|
+
const state = previewRuntime.getState();
|
|
199
|
+
return state.previewEnded ? null : state.identity;
|
|
200
|
+
}, undefined, previewRuntime.subscribeIdentity);
|
|
201
|
+
const teardownMomentaryNavigateKeyRelay = view === null
|
|
202
|
+
? null
|
|
203
|
+
: installMomentaryNavigateKeyRelay(view, {
|
|
204
|
+
getTargetOrigin: () => previewRuntime.getState().identity?.parentOrigin ?? null,
|
|
205
|
+
});
|
|
206
|
+
// 2. Studio → iframe postMessage path.
|
|
207
|
+
const onMessage = (ev) => {
|
|
208
|
+
if (view === null)
|
|
209
|
+
return;
|
|
210
|
+
const data = ev.data;
|
|
211
|
+
const rawType = data !== null && typeof data === "object"
|
|
212
|
+
? data.type
|
|
213
|
+
: null;
|
|
214
|
+
if (rawType === "storystick.preview.interaction-mode") {
|
|
215
|
+
const identity = previewRuntime.getState().identity;
|
|
216
|
+
if (identity === null || identity.parentOrigin === null)
|
|
217
|
+
return;
|
|
218
|
+
const base = validatePreviewEnvelope(data);
|
|
219
|
+
if (!base.ok ||
|
|
220
|
+
base.message.type !== "storystick.preview.interaction-mode") {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (ev.origin !== identity.parentOrigin)
|
|
224
|
+
return;
|
|
225
|
+
if (base.message.sessionId !== identity.sessionId)
|
|
226
|
+
return;
|
|
227
|
+
if (base.message.projectId !== identity.projectId)
|
|
228
|
+
return;
|
|
229
|
+
ensureEditInteractionGuard();
|
|
230
|
+
setInteractionMode(base.message.payload.mode);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (rawType === "storystick.preview.reload") {
|
|
234
|
+
const identity = previewRuntime.getState().identity;
|
|
235
|
+
if (identity === null || identity.parentOrigin === null)
|
|
236
|
+
return;
|
|
237
|
+
const base = validatePreviewEnvelope(data);
|
|
238
|
+
if (!base.ok || base.message.type !== "storystick.preview.reload") {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (ev.origin !== identity.parentOrigin)
|
|
242
|
+
return;
|
|
243
|
+
if (base.message.sessionId !== identity.sessionId)
|
|
244
|
+
return;
|
|
245
|
+
if (base.message.projectId !== identity.projectId)
|
|
246
|
+
return;
|
|
247
|
+
getReloadHandler()(base.message.payload.mode, {
|
|
248
|
+
commandId: base.message.payload.commandId,
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (rawType === "storystick.preview.overlay-map") {
|
|
253
|
+
const identity = previewRuntime.getState().identity;
|
|
254
|
+
if (identity === null || identity.parentOrigin === null)
|
|
255
|
+
return;
|
|
256
|
+
const overlayMap = validateOverlayMap(data, ev.origin, identity.sessionId, identity.projectId, identity.parentOrigin);
|
|
257
|
+
if (!overlayMap.ok)
|
|
258
|
+
return;
|
|
259
|
+
ensureEditInteractionGuard();
|
|
260
|
+
const result = applyPreviewOverlayMap(overlayMap.envelope.payload, view, {
|
|
261
|
+
onClick: (payload) => emitOverlayClick(view, payload),
|
|
262
|
+
});
|
|
263
|
+
emitOverlayReady(view, {
|
|
264
|
+
generation: result.generation,
|
|
265
|
+
paintedCount: result.paintedCount,
|
|
266
|
+
missingSnapshotItemKeys: result.missingSnapshotItemKeys,
|
|
267
|
+
routeHash: overlayMap.envelope.payload.routeHash,
|
|
268
|
+
codeVersion: overlayMap.envelope.payload.codeVersion,
|
|
269
|
+
renderId: overlayMap.envelope.payload.renderId,
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (rawType === "storystick.preview.overlay-clear") {
|
|
274
|
+
const identity = previewRuntime.getState().identity;
|
|
275
|
+
if (identity === null || identity.parentOrigin === null)
|
|
276
|
+
return;
|
|
277
|
+
const overlayClear = validateOverlayClear(data, ev.origin, identity.sessionId, identity.projectId, identity.parentOrigin);
|
|
278
|
+
if (!overlayClear.ok)
|
|
279
|
+
return;
|
|
280
|
+
ensureEditInteractionGuard();
|
|
281
|
+
clearPreviewOverlayPaint();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (rawType === "storystick.preview.v2.reveal-source") {
|
|
285
|
+
const identity = previewRuntime.getState().identity;
|
|
286
|
+
if (identity === null || identity.parentOrigin === null)
|
|
287
|
+
return;
|
|
288
|
+
const revealSource = validatePreviewV2RevealSource(data, ev.origin, identity.sessionId, identity.projectId, identity.parentOrigin);
|
|
289
|
+
if (!revealSource.ok)
|
|
290
|
+
return;
|
|
291
|
+
const result = revealPreviewV2SourceInIframe(revealSource.envelope.payload, view);
|
|
292
|
+
emitPreviewV2RevealResult(view, {
|
|
293
|
+
requestId: revealSource.envelope.payload.requestId,
|
|
294
|
+
sourceKey: revealSource.envelope.payload.sourceKey,
|
|
295
|
+
targetSelection: revealSource.envelope.payload.targetSelection,
|
|
296
|
+
status: result.status,
|
|
297
|
+
revealedCount: result.revealedCount,
|
|
298
|
+
});
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
return;
|
|
302
|
+
};
|
|
303
|
+
if (view !== null) {
|
|
304
|
+
view.addEventListener("message", onMessage);
|
|
305
|
+
}
|
|
306
|
+
// Deliberate annotation seam: the iframe runtime never observes
|
|
307
|
+
// customer DOM output to infer ownership. It reads the annotations
|
|
308
|
+
// authored by SDK resolution functions.
|
|
309
|
+
const handle = {
|
|
310
|
+
teardown() {
|
|
311
|
+
if (active !== handle)
|
|
312
|
+
return;
|
|
313
|
+
try {
|
|
314
|
+
if (view !== null)
|
|
315
|
+
view.removeEventListener("message", onMessage);
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
/* defensive */
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
teardownEditInteractionGuard?.();
|
|
322
|
+
teardownEditInteractionGuard = null;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
/* defensive */
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
teardownWorkspaceShortcuts();
|
|
329
|
+
teardownMomentaryNavigateKeyRelay?.();
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
/* defensive */
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
clearPreviewOverlayPaint();
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
/* defensive */
|
|
339
|
+
}
|
|
340
|
+
releaseOverlayMapOwner();
|
|
341
|
+
try {
|
|
342
|
+
teardownSchemaRetry();
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
/* defensive */
|
|
346
|
+
}
|
|
347
|
+
active = null;
|
|
348
|
+
},
|
|
349
|
+
};
|
|
350
|
+
active = handle;
|
|
351
|
+
keepOverlayMapOwner = true;
|
|
352
|
+
return handle;
|
|
353
|
+
}
|
|
354
|
+
finally {
|
|
355
|
+
if (!keepOverlayMapOwner) {
|
|
356
|
+
releaseOverlayMapOwner();
|
|
357
|
+
}
|
|
358
|
+
bootInFlight = null;
|
|
359
|
+
}
|
|
360
|
+
})();
|
|
361
|
+
return bootInFlight;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Test hook — clear the active handle, invoking teardown if present.
|
|
365
|
+
* Required when tests open + tear down many runtimes in sequence and
|
|
366
|
+
* need a clean module state.
|
|
367
|
+
*/
|
|
368
|
+
export function _resetBootForTestsOnly() {
|
|
369
|
+
if (active !== null) {
|
|
370
|
+
try {
|
|
371
|
+
active.teardown();
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
/* defensive */
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
active = null;
|
|
378
|
+
bootInFlight = null;
|
|
379
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type PreviewContentRefreshDecision } from '../provenance/index.js';
|
|
2
|
+
import type { PreviewQueryTargetingSignalV1 } from '@storystick/types/preview-query-targeting';
|
|
3
|
+
export declare const PREVIEW_CONTENT_REFRESH_SOURCE = "preview-session-content-revision";
|
|
4
|
+
export type PreviewContentRefreshReason = 'missed-initial-revision' | 'forward-revision-jump' | 'reactive-dependency-change';
|
|
5
|
+
export interface PreviewContentRefreshEvent {
|
|
6
|
+
/**
|
|
7
|
+
* Contract owner for content refreshes. This intentionally names the
|
|
8
|
+
* Convex preview-session row, not postMessage: content refresh is a
|
|
9
|
+
* data-subscription signal consumed by the customer router adapter.
|
|
10
|
+
*/
|
|
11
|
+
source: typeof PREVIEW_CONTENT_REFRESH_SOURCE;
|
|
12
|
+
revision: number;
|
|
13
|
+
previousRevision: number | null;
|
|
14
|
+
reason: PreviewContentRefreshReason;
|
|
15
|
+
refresh: boolean;
|
|
16
|
+
affectedFrameIds: readonly string[];
|
|
17
|
+
decisionReason: PreviewContentRefreshDecision['reason'];
|
|
18
|
+
/**
|
|
19
|
+
* Exact Content Plane source sequence committed before this invalidation.
|
|
20
|
+
* Framework adapters wait until the public projection covers it before
|
|
21
|
+
* replacing a valid server-rendered tree.
|
|
22
|
+
*/
|
|
23
|
+
requiredProjectedThroughSeq?: number;
|
|
24
|
+
queryTargeting?: PreviewQueryTargetingSignalV1;
|
|
25
|
+
}
|
|
26
|
+
export interface ContentRevisionObservation {
|
|
27
|
+
observedRevision: number;
|
|
28
|
+
event: PreviewContentRefreshEvent | null;
|
|
29
|
+
}
|
|
30
|
+
export declare function observeContentRevision(previousRevision: number | null, nextRevision: number, decision?: PreviewContentRefreshDecision, requiredProjectedThroughSeq?: number, queryTargetingChanged?: boolean, queryTargeting?: PreviewQueryTargetingSignalV1): ContentRevisionObservation;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createPreviewContentRefreshDecision, } from '../provenance/index.js';
|
|
2
|
+
export const PREVIEW_CONTENT_REFRESH_SOURCE = 'preview-session-content-revision';
|
|
3
|
+
export function observeContentRevision(previousRevision, nextRevision, decision, requiredProjectedThroughSeq, queryTargetingChanged = false, queryTargeting) {
|
|
4
|
+
const refreshDecision = decision ?? createPreviewContentRefreshDecision({
|
|
5
|
+
refresh: true,
|
|
6
|
+
affectedFrameIds: [],
|
|
7
|
+
reason: 'legacy-refresh',
|
|
8
|
+
});
|
|
9
|
+
if (previousRevision === null) {
|
|
10
|
+
return {
|
|
11
|
+
observedRevision: nextRevision,
|
|
12
|
+
event: nextRevision > 0
|
|
13
|
+
? {
|
|
14
|
+
source: PREVIEW_CONTENT_REFRESH_SOURCE,
|
|
15
|
+
revision: nextRevision,
|
|
16
|
+
previousRevision: null,
|
|
17
|
+
reason: 'missed-initial-revision',
|
|
18
|
+
refresh: refreshDecision.refresh,
|
|
19
|
+
affectedFrameIds: refreshDecision.affectedFrameIds,
|
|
20
|
+
decisionReason: refreshDecision.reason,
|
|
21
|
+
...queryTargetingRequirement(queryTargeting),
|
|
22
|
+
...projectionRequirement(requiredProjectedThroughSeq),
|
|
23
|
+
}
|
|
24
|
+
: null,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (nextRevision <= previousRevision) {
|
|
28
|
+
return {
|
|
29
|
+
observedRevision: previousRevision,
|
|
30
|
+
event: decision !== undefined &&
|
|
31
|
+
(refreshDecision.refresh || queryTargetingChanged)
|
|
32
|
+
? {
|
|
33
|
+
source: PREVIEW_CONTENT_REFRESH_SOURCE,
|
|
34
|
+
revision: previousRevision,
|
|
35
|
+
previousRevision,
|
|
36
|
+
reason: 'reactive-dependency-change',
|
|
37
|
+
refresh: refreshDecision.refresh,
|
|
38
|
+
affectedFrameIds: refreshDecision.affectedFrameIds,
|
|
39
|
+
decisionReason: refreshDecision.reason,
|
|
40
|
+
...queryTargetingRequirement(queryTargeting),
|
|
41
|
+
...projectionRequirement(requiredProjectedThroughSeq),
|
|
42
|
+
}
|
|
43
|
+
: null,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
observedRevision: nextRevision,
|
|
48
|
+
event: {
|
|
49
|
+
source: PREVIEW_CONTENT_REFRESH_SOURCE,
|
|
50
|
+
revision: nextRevision,
|
|
51
|
+
previousRevision,
|
|
52
|
+
reason: 'forward-revision-jump',
|
|
53
|
+
refresh: refreshDecision.refresh,
|
|
54
|
+
affectedFrameIds: refreshDecision.affectedFrameIds,
|
|
55
|
+
decisionReason: refreshDecision.reason,
|
|
56
|
+
...queryTargetingRequirement(queryTargeting),
|
|
57
|
+
...projectionRequirement(requiredProjectedThroughSeq),
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function queryTargetingRequirement(value) {
|
|
62
|
+
return value === undefined ? {} : { queryTargeting: value };
|
|
63
|
+
}
|
|
64
|
+
function projectionRequirement(value) {
|
|
65
|
+
return Number.isSafeInteger(value) && value >= 0
|
|
66
|
+
? { requiredProjectedThroughSeq: value }
|
|
67
|
+
: {};
|
|
68
|
+
}
|