@storystick/preview 0.0.0-stage → 0.2.0-rc.1
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 +56 -0
- package/README.md +42 -2
- package/dist/.source-hash +1 -0
- package/dist/authoring/runtime-contract.d.ts +92 -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/page-presentation.d.ts +24 -0
- package/dist/page-presentation.js +32 -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 +182 -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 +210 -3
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { decodePreviewProvenanceText } from '../provenance/coded-text.js';
|
|
2
|
+
const OVERLAY_ELEMENT = 'STORYSTICK-PREVIEW-FIELD-OVERLAYS';
|
|
3
|
+
const PREVIEW_TRANSPORT_ATTRIBUTES = new Set(['data-ss-model']);
|
|
4
|
+
let comparisonBlindSpotNoticeEmitted = false;
|
|
5
|
+
/**
|
|
6
|
+
* Dev-only audit for coded text in sinks where the invisible payload is
|
|
7
|
+
* intrinsically dangerous. Rendered text is deliberately ignored: coded text
|
|
8
|
+
* is expected there, and treating it as suspicious would create false positives.
|
|
9
|
+
*/
|
|
10
|
+
export function observeSuspiciousPreviewCodewords(doc, onReports) {
|
|
11
|
+
const view = doc.defaultView;
|
|
12
|
+
if (view === null || doc.documentElement === null)
|
|
13
|
+
return () => undefined;
|
|
14
|
+
if (!comparisonBlindSpotNoticeEmitted) {
|
|
15
|
+
comparisonBlindSpotNoticeEmitted = true;
|
|
16
|
+
console.warn('[storystick] String comparisons on a coded value fail in preview — use clean().');
|
|
17
|
+
}
|
|
18
|
+
const reported = new Set();
|
|
19
|
+
const pendingReports = [];
|
|
20
|
+
const pendingMutations = [];
|
|
21
|
+
let initialAuditDone = false;
|
|
22
|
+
let cancelScheduled = null;
|
|
23
|
+
let disposed = false;
|
|
24
|
+
const sink = (kind, element, attribute, value) => {
|
|
25
|
+
const decoded = decodePreviewProvenanceText(value);
|
|
26
|
+
if (decoded.segments.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
const markerIds = [...new Set(decoded.segments.map((segment) => segment.markerId))];
|
|
29
|
+
const key = `${kind}|${element?.tagName ?? ''}|${attribute ?? ''}|${markerIds.join(',')}|${decoded.text}`;
|
|
30
|
+
if (reported.has(key))
|
|
31
|
+
return;
|
|
32
|
+
reported.add(key);
|
|
33
|
+
pendingReports.push({
|
|
34
|
+
kind,
|
|
35
|
+
...(element ? { element } : {}),
|
|
36
|
+
...(attribute ? { attribute } : {}),
|
|
37
|
+
value,
|
|
38
|
+
cleaned: decoded.text,
|
|
39
|
+
markerIds,
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const process = () => {
|
|
43
|
+
cancelScheduled = null;
|
|
44
|
+
if (disposed)
|
|
45
|
+
return;
|
|
46
|
+
if (!initialAuditDone) {
|
|
47
|
+
initialAuditDone = true;
|
|
48
|
+
auditDocument(doc, sink);
|
|
49
|
+
}
|
|
50
|
+
for (const mutation of pendingMutations.splice(0)) {
|
|
51
|
+
processMutation(doc, mutation, sink);
|
|
52
|
+
}
|
|
53
|
+
if (pendingReports.length > 0) {
|
|
54
|
+
onReports(pendingReports.splice(0));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const schedule = () => {
|
|
58
|
+
if (cancelScheduled !== null || disposed)
|
|
59
|
+
return;
|
|
60
|
+
cancelScheduled = scheduleIdle(view, process);
|
|
61
|
+
};
|
|
62
|
+
const observer = new view.MutationObserver((mutations) => {
|
|
63
|
+
pendingMutations.push(...mutations);
|
|
64
|
+
schedule();
|
|
65
|
+
});
|
|
66
|
+
observer.observe(doc.documentElement, {
|
|
67
|
+
attributes: true,
|
|
68
|
+
characterData: true,
|
|
69
|
+
childList: true,
|
|
70
|
+
subtree: true,
|
|
71
|
+
});
|
|
72
|
+
schedule();
|
|
73
|
+
return () => {
|
|
74
|
+
disposed = true;
|
|
75
|
+
observer.disconnect();
|
|
76
|
+
cancelScheduled?.();
|
|
77
|
+
cancelScheduled = null;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function auditDocument(doc, sink) {
|
|
81
|
+
if (doc.documentElement)
|
|
82
|
+
checkElementAttributes(doc.documentElement, false, sink);
|
|
83
|
+
if (doc.head)
|
|
84
|
+
auditTree(doc, doc.head, true, sink);
|
|
85
|
+
if (doc.body)
|
|
86
|
+
auditTree(doc, doc.body, false, sink);
|
|
87
|
+
const href = doc.location?.href;
|
|
88
|
+
if (!href)
|
|
89
|
+
return;
|
|
90
|
+
if (hasCodedText(href)) {
|
|
91
|
+
sink('url', undefined, undefined, href);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const decoded = decodeURIComponent(href);
|
|
96
|
+
if (hasCodedText(decoded))
|
|
97
|
+
sink('url', undefined, undefined, decoded);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Malformed URLs are outside the detector's remit.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function auditTree(doc, root, inHead, sink) {
|
|
104
|
+
visitNode(doc, root, inHead, sink);
|
|
105
|
+
const nodeFilter = doc.defaultView?.NodeFilter;
|
|
106
|
+
if (!nodeFilter)
|
|
107
|
+
return;
|
|
108
|
+
const walker = doc.createTreeWalker(root, nodeFilter.SHOW_ELEMENT | nodeFilter.SHOW_TEXT, {
|
|
109
|
+
acceptNode: (node) => isOverlayElement(node)
|
|
110
|
+
? nodeFilter.FILTER_REJECT
|
|
111
|
+
: nodeFilter.FILTER_ACCEPT,
|
|
112
|
+
});
|
|
113
|
+
let node;
|
|
114
|
+
while ((node = walker.nextNode()))
|
|
115
|
+
visitNode(doc, node, inHead, sink);
|
|
116
|
+
}
|
|
117
|
+
function visitNode(doc, node, inHead, sink) {
|
|
118
|
+
if (isElement(node)) {
|
|
119
|
+
if (!isOverlayElement(node))
|
|
120
|
+
checkElementAttributes(node, inHead, sink);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (node.nodeType === 3)
|
|
124
|
+
checkTextNode(node, inHead, sink);
|
|
125
|
+
}
|
|
126
|
+
function checkElementAttributes(element, inHead, sink) {
|
|
127
|
+
for (const attribute of Array.from(element.attributes)) {
|
|
128
|
+
if (PREVIEW_TRANSPORT_ATTRIBUTES.has(attribute.name))
|
|
129
|
+
continue;
|
|
130
|
+
if (!hasCodedText(attribute.value))
|
|
131
|
+
continue;
|
|
132
|
+
sink(inHead ? 'head' : 'attribute', element, attribute.name, attribute.value);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function checkTextNode(node, inHead, sink) {
|
|
136
|
+
const value = node.textContent;
|
|
137
|
+
if (!value || !hasCodedText(value))
|
|
138
|
+
return;
|
|
139
|
+
const parent = node.parentElement ?? undefined;
|
|
140
|
+
if (parent?.tagName.toUpperCase() === 'SCRIPT' && isNextFlightPayload(value)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (inHead) {
|
|
144
|
+
sink('head', parent, undefined, value);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
switch (parent?.tagName.toUpperCase()) {
|
|
148
|
+
case 'SCRIPT':
|
|
149
|
+
sink('script', parent, undefined, value);
|
|
150
|
+
return;
|
|
151
|
+
case 'STYLE':
|
|
152
|
+
sink('style', parent, undefined, value);
|
|
153
|
+
return;
|
|
154
|
+
case 'TEXTAREA':
|
|
155
|
+
sink('form-value', parent, undefined, value);
|
|
156
|
+
return;
|
|
157
|
+
default:
|
|
158
|
+
// Ordinary rendered text is the authored carrier, not a leak.
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function isNextFlightPayload(value) {
|
|
162
|
+
const source = value.trimStart();
|
|
163
|
+
return (source.startsWith('self.__next_f.push(') ||
|
|
164
|
+
source.startsWith('(self.__next_f=self.__next_f||[]).push('));
|
|
165
|
+
}
|
|
166
|
+
function processMutation(doc, mutation, sink) {
|
|
167
|
+
const target = mutation.target;
|
|
168
|
+
if (!target.isConnected || isInsideOverlay(target))
|
|
169
|
+
return;
|
|
170
|
+
if (mutation.type === 'attributes') {
|
|
171
|
+
if (!isElement(target) || !mutation.attributeName)
|
|
172
|
+
return;
|
|
173
|
+
// `data-ss-model` is the intentional serialized slice carrier. Keep the
|
|
174
|
+
// mutation path aligned with the initial tree audit: React rewrites this
|
|
175
|
+
// attribute after every authored field edit, but those codewords have not
|
|
176
|
+
// reached a customer render sink.
|
|
177
|
+
if (PREVIEW_TRANSPORT_ATTRIBUTES.has(mutation.attributeName))
|
|
178
|
+
return;
|
|
179
|
+
const value = target.getAttributeNS(mutation.attributeNamespace, mutation.attributeName);
|
|
180
|
+
if (value && hasCodedText(value)) {
|
|
181
|
+
sink(isInsideHead(doc, target) ? 'head' : 'attribute', target, mutation.attributeName, value);
|
|
182
|
+
}
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (mutation.type === 'characterData') {
|
|
186
|
+
checkTextNode(target, isInsideHead(doc, target), sink);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
for (const node of Array.from(mutation.addedNodes)) {
|
|
190
|
+
if (!node.isConnected || isInsideOverlay(node))
|
|
191
|
+
continue;
|
|
192
|
+
auditTree(doc, node, isInsideHead(doc, node), sink);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function isElement(node) {
|
|
196
|
+
return node.nodeType === 1;
|
|
197
|
+
}
|
|
198
|
+
function isOverlayElement(node) {
|
|
199
|
+
return isElement(node) && node.tagName.toUpperCase() === OVERLAY_ELEMENT;
|
|
200
|
+
}
|
|
201
|
+
function isInsideOverlay(node) {
|
|
202
|
+
const element = isElement(node) ? node : node.parentElement;
|
|
203
|
+
return element
|
|
204
|
+
? element.closest(OVERLAY_ELEMENT.toLowerCase()) !== null
|
|
205
|
+
: false;
|
|
206
|
+
}
|
|
207
|
+
function isInsideHead(doc, node) {
|
|
208
|
+
return doc.head?.contains(node) ?? false;
|
|
209
|
+
}
|
|
210
|
+
function hasCodedText(value) {
|
|
211
|
+
return decodePreviewProvenanceText(value).segments.length > 0;
|
|
212
|
+
}
|
|
213
|
+
function scheduleIdle(view, callback) {
|
|
214
|
+
if (typeof view.requestIdleCallback === 'function') {
|
|
215
|
+
const id = view.requestIdleCallback(callback, { timeout: 1000 });
|
|
216
|
+
return () => view.cancelIdleCallback(id);
|
|
217
|
+
}
|
|
218
|
+
const id = view.setTimeout(callback, 0);
|
|
219
|
+
return () => view.clearTimeout(id);
|
|
220
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SuspiciousPreviewCodewordReport } from './suspicious-codeword-detector.js';
|
|
2
|
+
/** Production target for the detector's conditional package export. */
|
|
3
|
+
export declare function observeSuspiciousPreviewCodewords(_doc: Document, _onReports: (reports: readonly SuspiciousPreviewCodewordReport[]) => void): () => void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PreviewProjectionGenerationSignal } from './generation-signal.js';
|
|
2
|
+
/** One view's server refresh cadence. No mounted-query registry is required. */
|
|
3
|
+
export declare function createPreviewGenerationRefresh<TTimer>(options: {
|
|
4
|
+
readonly refresh: () => void;
|
|
5
|
+
readonly delayMs: number;
|
|
6
|
+
readonly setTimer: (callback: () => void, ms: number) => TTimer;
|
|
7
|
+
readonly clearTimer: (timer: TTimer) => void;
|
|
8
|
+
/** Sampled before this server render's content reads, within its context. */
|
|
9
|
+
readonly initialCheckpoint?: PreviewProjectionGenerationSignal | null;
|
|
10
|
+
}): {
|
|
11
|
+
/** Only the adapter's accepted, installed render can cover this checkpoint.
|
|
12
|
+
* A later observed write remains pending; a router event alone is no proof. */
|
|
13
|
+
observeRenderedCheckpoint(signal: PreviewProjectionGenerationSignal | null | undefined): void;
|
|
14
|
+
observe(signal: PreviewProjectionGenerationSignal | null): void;
|
|
15
|
+
/** Recheck after a refresh was deferred behind a native navigation. */
|
|
16
|
+
dispatch(run: () => void): void;
|
|
17
|
+
/** The global framework adapter owns the transition, not customer components. */
|
|
18
|
+
observeTransition(pending: boolean): void;
|
|
19
|
+
/** Reconnect/context activation may have missed a checkpoint already observed. */
|
|
20
|
+
resynchronize(): void;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
};
|
|
23
|
+
export type PreviewGenerationRefresh = ReturnType<typeof createPreviewGenerationRefresh>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** One view's server refresh cadence. No mounted-query registry is required. */
|
|
2
|
+
export function createPreviewGenerationRefresh(options) {
|
|
3
|
+
let latest = null;
|
|
4
|
+
let requested = null;
|
|
5
|
+
let timer = null;
|
|
6
|
+
let busy = false;
|
|
7
|
+
let disposed = false;
|
|
8
|
+
const identity = (signal) => JSON.stringify([signal.generation, signal.projectedThroughSeq, signal.projectionHash, signal.lensHash]);
|
|
9
|
+
const ready = () => latest?.status === 'ready' &&
|
|
10
|
+
Number.isSafeInteger(latest.projectedThroughSeq) &&
|
|
11
|
+
latest.projectedThroughSeq >= 0;
|
|
12
|
+
const covers = (signal) => signal?.status === 'ready' && Number.isSafeInteger(signal.generation) && signal.generation >= 0 &&
|
|
13
|
+
Number.isSafeInteger(signal.projectedThroughSeq) && signal.projectedThroughSeq >= 0 &&
|
|
14
|
+
typeof signal.projectionHash === 'string' && signal.projectionHash.length > 0 &&
|
|
15
|
+
typeof signal.lensHash === 'string' && signal.lensHash.length > 0;
|
|
16
|
+
const initial = options.initialCheckpoint;
|
|
17
|
+
if (covers(initial))
|
|
18
|
+
requested = identity(initial);
|
|
19
|
+
function schedule() {
|
|
20
|
+
if (disposed || busy || timer !== null || !ready() || identity(latest) === requested)
|
|
21
|
+
return;
|
|
22
|
+
// First event owns the deadline. Later events replace the pending checkpoint,
|
|
23
|
+
// rather than postponing refresh indefinitely during concurrent editing.
|
|
24
|
+
timer = options.setTimer(() => {
|
|
25
|
+
timer = null;
|
|
26
|
+
if (disposed || busy || !ready() || identity(latest) === requested)
|
|
27
|
+
return;
|
|
28
|
+
requested = identity(latest);
|
|
29
|
+
busy = true;
|
|
30
|
+
options.refresh();
|
|
31
|
+
}, options.delayMs);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
/** Only the adapter's accepted, installed render can cover this checkpoint.
|
|
35
|
+
* A later observed write remains pending; a router event alone is no proof. */
|
|
36
|
+
observeRenderedCheckpoint(signal) {
|
|
37
|
+
if (!disposed && covers(signal))
|
|
38
|
+
requested = identity(signal);
|
|
39
|
+
},
|
|
40
|
+
observe(signal) {
|
|
41
|
+
if (disposed)
|
|
42
|
+
return;
|
|
43
|
+
latest = signal;
|
|
44
|
+
schedule();
|
|
45
|
+
},
|
|
46
|
+
/** Recheck after a refresh was deferred behind a native navigation. */
|
|
47
|
+
dispatch(run) {
|
|
48
|
+
if (disposed)
|
|
49
|
+
return;
|
|
50
|
+
if (!ready()) {
|
|
51
|
+
busy = false;
|
|
52
|
+
requested = null;
|
|
53
|
+
schedule();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
requested = identity(latest);
|
|
57
|
+
run();
|
|
58
|
+
},
|
|
59
|
+
/** The global framework adapter owns the transition, not customer components. */
|
|
60
|
+
observeTransition(pending) {
|
|
61
|
+
if (disposed)
|
|
62
|
+
return;
|
|
63
|
+
busy = pending;
|
|
64
|
+
if (!pending)
|
|
65
|
+
schedule();
|
|
66
|
+
},
|
|
67
|
+
/** Reconnect/context activation may have missed a checkpoint already observed. */
|
|
68
|
+
resynchronize() {
|
|
69
|
+
if (disposed)
|
|
70
|
+
return;
|
|
71
|
+
requested = null;
|
|
72
|
+
schedule();
|
|
73
|
+
},
|
|
74
|
+
dispose() {
|
|
75
|
+
disposed = true;
|
|
76
|
+
if (timer !== null)
|
|
77
|
+
options.clearTimer(timer);
|
|
78
|
+
timer = null;
|
|
79
|
+
latest = null;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface PreviewProjectionGenerationSignal {
|
|
2
|
+
readonly generation: number;
|
|
3
|
+
readonly status: "ready" | "stale" | "rebuilding" | "error";
|
|
4
|
+
readonly projectedThroughSeq?: number;
|
|
5
|
+
readonly projectionHash?: string;
|
|
6
|
+
readonly lensHash?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function isPreviewProjectionGenerationSignal(value: unknown): value is PreviewProjectionGenerationSignal;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function isPreviewProjectionGenerationSignal(value) {
|
|
2
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
3
|
+
return false;
|
|
4
|
+
const input = value;
|
|
5
|
+
return (Number.isSafeInteger(input.generation) &&
|
|
6
|
+
input.generation >= 0 &&
|
|
7
|
+
(input.status === "ready" ||
|
|
8
|
+
input.status === "stale" ||
|
|
9
|
+
input.status === "rebuilding" ||
|
|
10
|
+
input.status === "error") &&
|
|
11
|
+
(input.projectedThroughSeq === undefined ||
|
|
12
|
+
(Number.isSafeInteger(input.projectedThroughSeq) &&
|
|
13
|
+
input.projectedThroughSeq >= 0)) &&
|
|
14
|
+
(input.projectionHash === undefined ||
|
|
15
|
+
typeof input.projectionHash === "string") &&
|
|
16
|
+
(input.lensHash === undefined || typeof input.lensHash === "string"));
|
|
17
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export interface PreviewProjectionGenerationWatch {
|
|
2
|
+
subscribe(listener: (value: unknown) => void, reconnected?: () => void): () => void;
|
|
3
|
+
}
|
|
4
|
+
/** Adapt Convex's watch shape without coupling the refresh policy to Convex. */
|
|
5
|
+
export declare function createPreviewProjectionGenerationWatch(client: unknown, sessionId: string): PreviewProjectionGenerationWatch | null;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Adapt Convex's watch shape without coupling the refresh policy to Convex. */
|
|
2
|
+
export function createPreviewProjectionGenerationWatch(client, sessionId) {
|
|
3
|
+
const watchQuery = client.watchQuery;
|
|
4
|
+
if (typeof watchQuery !== "function")
|
|
5
|
+
return null;
|
|
6
|
+
const watch = watchQuery.call(client, "sdkQueries:viewGeneration", {
|
|
7
|
+
sessionId,
|
|
8
|
+
});
|
|
9
|
+
if (!watch ||
|
|
10
|
+
typeof watch.onUpdate !== "function" ||
|
|
11
|
+
typeof watch.localQueryResult !== "function") {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
subscribe(listener, reconnected) {
|
|
16
|
+
let disconnected = false;
|
|
17
|
+
const publish = () => {
|
|
18
|
+
if (disconnected) {
|
|
19
|
+
listener(null);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
listener(watch.localQueryResult());
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Failed/absent watch results cannot authorize a queued refresh.
|
|
27
|
+
listener(null);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const connection = client;
|
|
31
|
+
disconnected = connection.connectionState?.().isWebSocketConnected === false;
|
|
32
|
+
const cleanupConnection = connection.subscribeToConnectionState?.((state) => {
|
|
33
|
+
if (!state.isWebSocketConnected) {
|
|
34
|
+
disconnected = true;
|
|
35
|
+
listener(null);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (disconnected) {
|
|
39
|
+
disconnected = false;
|
|
40
|
+
reconnected?.();
|
|
41
|
+
publish();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const cleanup = watch.onUpdate(publish);
|
|
45
|
+
publish();
|
|
46
|
+
return () => {
|
|
47
|
+
if (typeof cleanup === "function")
|
|
48
|
+
cleanup();
|
|
49
|
+
cleanupConnection?.();
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PreviewServerRenderReceipt } from '@storystick/preview/router-subscriber';
|
|
2
|
+
import type { PreviewProjectionGenerationSignal } from './generation-signal.js';
|
|
3
|
+
/** Framework-local proof; projection metadata never crosses the Studio envelope. */
|
|
4
|
+
export interface PreviewFrameworkRenderReceipt extends PreviewServerRenderReceipt {
|
|
5
|
+
readonly projectionCheckpoint?: PreviewProjectionGenerationSignal;
|
|
6
|
+
}
|
|
7
|
+
export declare function readPreviewRenderReceipt(): PreviewServerRenderReceipt | null;
|
|
8
|
+
export declare function commitPreviewRenderReceipt(receipt: PreviewServerRenderReceipt): () => void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// One framework render in this realm, not another preview context authority.
|
|
2
|
+
// Receipt identity changes on each server request, even within one perspective.
|
|
3
|
+
let current = null;
|
|
4
|
+
export function readPreviewRenderReceipt() { return current; }
|
|
5
|
+
export function commitPreviewRenderReceipt(receipt) {
|
|
6
|
+
const presentation = { readContext: receipt.readContext, renderId: receipt.renderId };
|
|
7
|
+
current = presentation;
|
|
8
|
+
return () => { if (current === presentation)
|
|
9
|
+
current = null; };
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PreviewRuntime, PreviewRuntimeState } from "@storystick/preview/runtime/store";
|
|
2
|
+
/** The only runtime fields that can change this React adapter's output. */
|
|
3
|
+
export interface PreviewRuntimeAdapterSnapshot {
|
|
4
|
+
readonly state: PreviewRuntimeState["state"];
|
|
5
|
+
readonly client: PreviewRuntimeState["client"];
|
|
6
|
+
readonly previewToken: string | null;
|
|
7
|
+
readonly sessionId: string | null;
|
|
8
|
+
readonly variantId: string | null;
|
|
9
|
+
readonly releaseId: string | null;
|
|
10
|
+
readonly readContextStatus: "active" | "ended" | null;
|
|
11
|
+
readonly readContext: import('@storystick/types/preview-query-targeting').PreviewReadContext | null;
|
|
12
|
+
readonly renderedReadContext: PreviewRuntimeState['renderedReadContext'];
|
|
13
|
+
readonly readContextNotice: 'release-published' | 'release-archived' | null;
|
|
14
|
+
readonly standaloneStudioUrl: string | null;
|
|
15
|
+
readonly errorCode: string | null;
|
|
16
|
+
}
|
|
17
|
+
export declare const PREVIEW_RUNTIME_SERVER_SNAPSHOT: PreviewRuntimeAdapterSnapshot;
|
|
18
|
+
/**
|
|
19
|
+
* Adapts the process-wide Preview runtime to a referentially stable React
|
|
20
|
+
* snapshot. The underlying store can keep publishing protocol telemetry and
|
|
21
|
+
* content revisions without rerendering the customer adapter when none of its
|
|
22
|
+
* consumed fields changed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createPreviewRuntimeAdapterStore(runtime: Pick<PreviewRuntime, "getState" | "subscribe">): {
|
|
25
|
+
readonly subscribe: PreviewRuntime["subscribe"];
|
|
26
|
+
readonly getSnapshot: () => PreviewRuntimeAdapterSnapshot;
|
|
27
|
+
};
|
|
28
|
+
/** Content invalidations belong to the context actually rendered in this realm.
|
|
29
|
+
* Studio alone commands a different context into an embedded presentation. */
|
|
30
|
+
export declare function canRefreshPresentedPreviewContext(state: Pick<PreviewRuntimeAdapterSnapshot, 'readContext' | 'renderedReadContext'>, embedded: boolean): boolean;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export const PREVIEW_RUNTIME_SERVER_SNAPSHOT = Object.freeze({
|
|
2
|
+
state: "idle",
|
|
3
|
+
client: null,
|
|
4
|
+
previewToken: null,
|
|
5
|
+
sessionId: null,
|
|
6
|
+
variantId: null,
|
|
7
|
+
releaseId: null,
|
|
8
|
+
readContext: null,
|
|
9
|
+
renderedReadContext: null,
|
|
10
|
+
readContextNotice: null,
|
|
11
|
+
readContextStatus: null,
|
|
12
|
+
standaloneStudioUrl: null,
|
|
13
|
+
errorCode: null,
|
|
14
|
+
});
|
|
15
|
+
function selectPreviewRuntimeAdapterSnapshot(state) {
|
|
16
|
+
return {
|
|
17
|
+
state: state.state,
|
|
18
|
+
client: state.client,
|
|
19
|
+
previewToken: state.previewToken,
|
|
20
|
+
sessionId: state.sessionId,
|
|
21
|
+
variantId: state.variantId,
|
|
22
|
+
releaseId: state.releaseId,
|
|
23
|
+
readContext: state.session?.readContext ?? null,
|
|
24
|
+
renderedReadContext: state.renderedReadContext ?? null,
|
|
25
|
+
readContextNotice: state.session?.readContextNotice ?? null,
|
|
26
|
+
readContextStatus: state.session?.readContextStatus ?? null,
|
|
27
|
+
standaloneStudioUrl: state.session?.standaloneStudioUrl ?? null,
|
|
28
|
+
errorCode: state.error?.code ?? null,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function previewRuntimeAdapterSnapshotsEqual(left, right) {
|
|
32
|
+
return (left.state === right.state &&
|
|
33
|
+
left.client === right.client &&
|
|
34
|
+
left.previewToken === right.previewToken &&
|
|
35
|
+
left.sessionId === right.sessionId &&
|
|
36
|
+
left.variantId === right.variantId &&
|
|
37
|
+
left.releaseId === right.releaseId &&
|
|
38
|
+
left.readContextStatus === right.readContextStatus &&
|
|
39
|
+
left.readContext?.contextId === right.readContext?.contextId &&
|
|
40
|
+
left.readContext?.revision === right.readContext?.revision &&
|
|
41
|
+
left.renderedReadContext?.contextId === right.renderedReadContext?.contextId &&
|
|
42
|
+
left.renderedReadContext?.revision === right.renderedReadContext?.revision &&
|
|
43
|
+
left.readContextNotice === right.readContextNotice &&
|
|
44
|
+
left.standaloneStudioUrl === right.standaloneStudioUrl &&
|
|
45
|
+
left.errorCode === right.errorCode);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Adapts the process-wide Preview runtime to a referentially stable React
|
|
49
|
+
* snapshot. The underlying store can keep publishing protocol telemetry and
|
|
50
|
+
* content revisions without rerendering the customer adapter when none of its
|
|
51
|
+
* consumed fields changed.
|
|
52
|
+
*/
|
|
53
|
+
export function createPreviewRuntimeAdapterStore(runtime) {
|
|
54
|
+
let lastSnapshot = null;
|
|
55
|
+
return {
|
|
56
|
+
subscribe: (listener) => runtime.subscribe(listener),
|
|
57
|
+
getSnapshot: () => {
|
|
58
|
+
let nextSnapshot = selectPreviewRuntimeAdapterSnapshot(runtime.getState());
|
|
59
|
+
// Retain only public return metadata through reconnection of the same
|
|
60
|
+
// view. A new view, deactivation or a fresh owner starts without it.
|
|
61
|
+
if (nextSnapshot.sessionId !== null && nextSnapshot.sessionId === lastSnapshot?.sessionId && !nextSnapshot.standaloneStudioUrl) {
|
|
62
|
+
nextSnapshot = { ...nextSnapshot, standaloneStudioUrl: lastSnapshot.standaloneStudioUrl };
|
|
63
|
+
}
|
|
64
|
+
if (lastSnapshot !== null &&
|
|
65
|
+
previewRuntimeAdapterSnapshotsEqual(lastSnapshot, nextSnapshot)) {
|
|
66
|
+
return lastSnapshot;
|
|
67
|
+
}
|
|
68
|
+
lastSnapshot = nextSnapshot;
|
|
69
|
+
return nextSnapshot;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Content invalidations belong to the context actually rendered in this realm.
|
|
74
|
+
* Studio alone commands a different context into an embedded presentation. */
|
|
75
|
+
export function canRefreshPresentedPreviewContext(state, embedded) {
|
|
76
|
+
if (!embedded)
|
|
77
|
+
return true;
|
|
78
|
+
const { readContext: accepted, renderedReadContext: rendered } = state;
|
|
79
|
+
return accepted != null && rendered != null &&
|
|
80
|
+
accepted.contextId === rendered.contextId && accepted.revision === rendered.revision;
|
|
81
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type PreviewGrantFailureCause, type PreviewGrantLifecycle } from "./grant-lifecycle.js";
|
|
2
|
+
export declare const PREVIEW_TOKEN_ROUTE = "/api/storystick/preview/token";
|
|
3
|
+
export declare const PREVIEW_GRANT_RETRY_BACKOFF_MS: readonly [1000, 2000, 5000, 10000, 30000];
|
|
4
|
+
export interface PreviewBrowserGrant {
|
|
5
|
+
token: string;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
refreshAfter: number;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
projectId: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class PreviewGrantRequestError extends Error {
|
|
12
|
+
readonly code: string;
|
|
13
|
+
readonly retryable: boolean;
|
|
14
|
+
readonly retryAfterMs: number | null;
|
|
15
|
+
constructor(args: {
|
|
16
|
+
code: string;
|
|
17
|
+
message: string;
|
|
18
|
+
retryable: boolean;
|
|
19
|
+
retryAfterMs?: number | null;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
type FetchLike = typeof fetch;
|
|
23
|
+
export declare function acquirePreviewBrowserGrant(args: {
|
|
24
|
+
sessionId: string;
|
|
25
|
+
projectId: string;
|
|
26
|
+
tokenRoute?: string;
|
|
27
|
+
signal: AbortSignal;
|
|
28
|
+
fetchFn?: FetchLike;
|
|
29
|
+
}): Promise<PreviewBrowserGrant>;
|
|
30
|
+
export interface PreviewGrantCoordinator {
|
|
31
|
+
start(): void;
|
|
32
|
+
stop(): void;
|
|
33
|
+
markReady(): void;
|
|
34
|
+
reportTransientFailure(cause: PreviewGrantFailureCause): void;
|
|
35
|
+
reportBlocked(code: string, message: string): void;
|
|
36
|
+
retryNow(): void;
|
|
37
|
+
getLifecycle(): PreviewGrantLifecycle;
|
|
38
|
+
}
|
|
39
|
+
export declare function createPreviewGrantCoordinator(args: {
|
|
40
|
+
sessionId: string;
|
|
41
|
+
projectId: string;
|
|
42
|
+
tokenRoute?: string;
|
|
43
|
+
generation: number;
|
|
44
|
+
acquire?: typeof acquirePreviewBrowserGrant;
|
|
45
|
+
onGrant: (grant: PreviewBrowserGrant) => void;
|
|
46
|
+
onLifecycle: (lifecycle: PreviewGrantLifecycle) => void;
|
|
47
|
+
now?: () => number;
|
|
48
|
+
random?: () => number;
|
|
49
|
+
setTimeoutFn?: typeof setTimeout;
|
|
50
|
+
clearTimeoutFn?: typeof clearTimeout;
|
|
51
|
+
windowRef?: Window;
|
|
52
|
+
}): PreviewGrantCoordinator;
|
|
53
|
+
export {};
|