@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.
Files changed (245) hide show
  1. package/LICENSE +112 -0
  2. package/PUBLIC-API.md +55 -0
  3. package/README.md +42 -2
  4. package/dist/.source-hash +1 -0
  5. package/dist/authoring/runtime-contract.d.ts +89 -0
  6. package/dist/authoring/runtime-contract.js +28 -0
  7. package/dist/channel-taxonomy.d.ts +17 -0
  8. package/dist/channel-taxonomy.js +46 -0
  9. package/dist/context-command.d.ts +18 -0
  10. package/dist/context-command.js +38 -0
  11. package/dist/dev/suspicious-codeword-detector.d.ts +15 -0
  12. package/dist/dev/suspicious-codeword-detector.js +220 -0
  13. package/dist/dev/suspicious-codeword-detector.noop.d.ts +3 -0
  14. package/dist/dev/suspicious-codeword-detector.noop.js +4 -0
  15. package/dist/framework/browser-context.d.ts +2 -0
  16. package/dist/framework/browser-context.js +2 -0
  17. package/dist/framework/generation-refresh.d.ts +23 -0
  18. package/dist/framework/generation-refresh.js +82 -0
  19. package/dist/framework/generation-signal.d.ts +8 -0
  20. package/dist/framework/generation-signal.js +17 -0
  21. package/dist/framework/projection-generation-watch.d.ts +5 -0
  22. package/dist/framework/projection-generation-watch.js +53 -0
  23. package/dist/framework/render-receipt.d.ts +8 -0
  24. package/dist/framework/render-receipt.js +10 -0
  25. package/dist/framework/runtime-adapter-store.d.ts +30 -0
  26. package/dist/framework/runtime-adapter-store.js +81 -0
  27. package/dist/grant-coordinator.d.ts +53 -0
  28. package/dist/grant-coordinator.js +329 -0
  29. package/dist/grant-lifecycle.d.ts +52 -0
  30. package/dist/grant-lifecycle.js +74 -0
  31. package/dist/identity/__test-adapter.d.ts +34 -0
  32. package/dist/identity/__test-adapter.js +59 -0
  33. package/dist/identity/browser-context-gate.d.ts +4 -0
  34. package/dist/identity/browser-context-gate.js +22 -0
  35. package/dist/identity/browser-context.d.ts +13 -0
  36. package/dist/identity/browser-context.js +22 -0
  37. package/dist/identity/carriers/postmessage.d.ts +84 -0
  38. package/dist/identity/carriers/postmessage.js +177 -0
  39. package/dist/identity/carriers/storage-state.d.ts +41 -0
  40. package/dist/identity/carriers/storage-state.js +99 -0
  41. package/dist/identity/carriers/storage.d.ts +39 -0
  42. package/dist/identity/carriers/storage.js +182 -0
  43. package/dist/identity/carriers/url.d.ts +19 -0
  44. package/dist/identity/carriers/url.js +38 -0
  45. package/dist/identity/identity-state-machine.d.ts +70 -0
  46. package/dist/identity/identity-state-machine.js +244 -0
  47. package/dist/identity/identity-types.d.ts +192 -0
  48. package/dist/identity/identity-types.js +22 -0
  49. package/dist/identity/index.d.ts +18 -0
  50. package/dist/identity/index.js +16 -0
  51. package/dist/identity/preview-cookie.d.ts +9 -0
  52. package/dist/identity/preview-cookie.js +12 -0
  53. package/dist/identity/preview-draft.d.ts +6 -0
  54. package/dist/identity/preview-draft.js +25 -0
  55. package/dist/identity/preview-identity.d.ts +28 -0
  56. package/dist/identity/preview-identity.js +84 -0
  57. package/dist/identity/preview-scope.d.ts +28 -0
  58. package/dist/identity/preview-scope.js +47 -0
  59. package/dist/identity/resolver.d.ts +110 -0
  60. package/dist/identity/resolver.js +334 -0
  61. package/dist/identity/session-query.d.ts +4 -0
  62. package/dist/identity/session-query.js +19 -0
  63. package/dist/index.d.ts +90 -0
  64. package/dist/index.js +788 -0
  65. package/dist/interaction-mode.d.ts +58 -0
  66. package/dist/interaction-mode.js +93 -0
  67. package/dist/nav-handler.d.ts +95 -0
  68. package/dist/nav-handler.js +84 -0
  69. package/dist/overlay-label.d.ts +79 -0
  70. package/dist/overlay-label.js +73 -0
  71. package/dist/provenance/anchor-map.d.ts +95 -0
  72. package/dist/provenance/anchor-map.js +177 -0
  73. package/dist/provenance/carrier-plan.d.ts +51 -0
  74. package/dist/provenance/carrier-plan.js +90 -0
  75. package/dist/provenance/coded-text.d.ts +20 -0
  76. package/dist/provenance/coded-text.js +302 -0
  77. package/dist/provenance/direct-edit-locator.d.ts +29 -0
  78. package/dist/provenance/direct-edit-locator.js +218 -0
  79. package/dist/provenance/editable-leaf.d.ts +134 -0
  80. package/dist/provenance/editable-leaf.js +483 -0
  81. package/dist/provenance/editor-target.d.ts +29 -0
  82. package/dist/provenance/editor-target.js +46 -0
  83. package/dist/provenance/field-leaf-walker.d.ts +21 -0
  84. package/dist/provenance/field-leaf-walker.js +98 -0
  85. package/dist/provenance/frame-dependencies.d.ts +212 -0
  86. package/dist/provenance/frame-dependencies.js +550 -0
  87. package/dist/provenance/index.d.ts +26 -0
  88. package/dist/provenance/index.js +26 -0
  89. package/dist/provenance/local-events.d.ts +1 -0
  90. package/dist/provenance/local-events.js +1 -0
  91. package/dist/provenance/markers.d.ts +21 -0
  92. package/dist/provenance/markers.js +70 -0
  93. package/dist/provenance/multi-frame-anchor-map.d.ts +54 -0
  94. package/dist/provenance/multi-frame-anchor-map.js +109 -0
  95. package/dist/provenance/normalize.d.ts +2 -0
  96. package/dist/provenance/normalize.js +19 -0
  97. package/dist/provenance/overlay-focus-echo.d.ts +17 -0
  98. package/dist/provenance/overlay-focus-echo.js +16 -0
  99. package/dist/provenance/overlay-projection.d.ts +65 -0
  100. package/dist/provenance/overlay-projection.js +201 -0
  101. package/dist/provenance/owner-map.d.ts +55 -0
  102. package/dist/provenance/owner-map.js +239 -0
  103. package/dist/provenance/read-carrier.d.ts +22 -0
  104. package/dist/provenance/read-carrier.js +92 -0
  105. package/dist/provenance/recorder.d.ts +38 -0
  106. package/dist/provenance/recorder.js +82 -0
  107. package/dist/provenance/render-context.d.ts +106 -0
  108. package/dist/provenance/render-context.js +338 -0
  109. package/dist/provenance/reveal-contract.d.ts +44 -0
  110. package/dist/provenance/reveal-contract.js +1 -0
  111. package/dist/provenance/richtext-slice-embed-address.d.ts +20 -0
  112. package/dist/provenance/richtext-slice-embed-address.js +35 -0
  113. package/dist/provenance/runtime-script.d.ts +1 -0
  114. package/dist/provenance/runtime-script.js +2217 -0
  115. package/dist/provenance/sidecar-store.d.ts +63 -0
  116. package/dist/provenance/sidecar-store.js +151 -0
  117. package/dist/provenance/sidecar.d.ts +34 -0
  118. package/dist/provenance/sidecar.js +227 -0
  119. package/dist/provenance/slice-model.d.ts +28 -0
  120. package/dist/provenance/slice-model.js +86 -0
  121. package/dist/provenance/source-identity.d.ts +3 -0
  122. package/dist/provenance/source-identity.js +7 -0
  123. package/dist/provenance/source-map-materializer.d.ts +76 -0
  124. package/dist/provenance/source-map-materializer.js +286 -0
  125. package/dist/provenance/source-registry.d.ts +103 -0
  126. package/dist/provenance/source-registry.js +562 -0
  127. package/dist/provenance/transformed-output-gate.d.ts +161 -0
  128. package/dist/provenance/transformed-output-gate.js +171 -0
  129. package/dist/provenance/types.d.ts +102 -0
  130. package/dist/provenance/types.js +1 -0
  131. package/dist/refresh-policy.d.ts +11 -0
  132. package/dist/refresh-policy.js +14 -0
  133. package/dist/reveal-target.d.ts +8 -0
  134. package/dist/reveal-target.js +47 -0
  135. package/dist/route-paths.d.ts +11 -0
  136. package/dist/route-paths.js +14 -0
  137. package/dist/router-subscriber.d.ts +92 -0
  138. package/dist/router-subscriber.js +44 -0
  139. package/dist/runtime/anchor-types.d.ts +5 -0
  140. package/dist/runtime/anchor-types.js +1 -0
  141. package/dist/runtime/authority-store.d.ts +31 -0
  142. package/dist/runtime/authority-store.js +56 -0
  143. package/dist/runtime/boot.d.ts +52 -0
  144. package/dist/runtime/boot.js +379 -0
  145. package/dist/runtime/content-refresh.d.ts +30 -0
  146. package/dist/runtime/content-refresh.js +68 -0
  147. package/dist/runtime/emit-runtime-error.d.ts +51 -0
  148. package/dist/runtime/emit-runtime-error.js +64 -0
  149. package/dist/runtime/field-proxy.d.ts +112 -0
  150. package/dist/runtime/field-proxy.js +471 -0
  151. package/dist/runtime/form-contract-reporter.d.ts +99 -0
  152. package/dist/runtime/form-contract-reporter.js +391 -0
  153. package/dist/runtime/invalidation-adapter.d.ts +17 -0
  154. package/dist/runtime/invalidation-adapter.js +42 -0
  155. package/dist/runtime/live-query-overlay.d.ts +39 -0
  156. package/dist/runtime/live-query-overlay.js +345 -0
  157. package/dist/runtime/momentary-navigate.d.ts +16 -0
  158. package/dist/runtime/momentary-navigate.js +106 -0
  159. package/dist/runtime/observation-scheduler.d.ts +15 -0
  160. package/dist/runtime/observation-scheduler.js +42 -0
  161. package/dist/runtime/perf-metrics.d.ts +28 -0
  162. package/dist/runtime/perf-metrics.js +90 -0
  163. package/dist/runtime/preview-interaction-policy.d.ts +1 -0
  164. package/dist/runtime/preview-interaction-policy.js +103 -0
  165. package/dist/runtime/preview-overlay-painter.d.ts +27 -0
  166. package/dist/runtime/preview-overlay-painter.js +1732 -0
  167. package/dist/runtime/preview-overlay-sidecar.d.ts +26 -0
  168. package/dist/runtime/preview-overlay-sidecar.js +45 -0
  169. package/dist/runtime/preview-perspective-alignment.d.ts +15 -0
  170. package/dist/runtime/preview-perspective-alignment.js +40 -0
  171. package/dist/runtime/preview-perspective-intent-state.d.ts +23 -0
  172. package/dist/runtime/preview-perspective-intent-state.js +5 -0
  173. package/dist/runtime/preview-transition-state.d.ts +142 -0
  174. package/dist/runtime/preview-transition-state.js +257 -0
  175. package/dist/runtime/render-mode-state.d.ts +51 -0
  176. package/dist/runtime/render-mode-state.js +76 -0
  177. package/dist/runtime/request-id.d.ts +4 -0
  178. package/dist/runtime/request-id.js +8 -0
  179. package/dist/runtime/resolve-schema-field.d.ts +99 -0
  180. package/dist/runtime/resolve-schema-field.js +356 -0
  181. package/dist/runtime/runtime-error-dispatch.d.ts +23 -0
  182. package/dist/runtime/runtime-error-dispatch.js +75 -0
  183. package/dist/runtime/schema-store.d.ts +121 -0
  184. package/dist/runtime/schema-store.js +667 -0
  185. package/dist/runtime/snapshot-assembly.d.ts +104 -0
  186. package/dist/runtime/snapshot-assembly.js +553 -0
  187. package/dist/runtime/snapshot-reporter.d.ts +55 -0
  188. package/dist/runtime/snapshot-reporter.js +375 -0
  189. package/dist/runtime/standalone-overlay-controller.d.ts +33 -0
  190. package/dist/runtime/standalone-overlay-controller.js +281 -0
  191. package/dist/runtime/store.d.ts +307 -0
  192. package/dist/runtime/store.js +1026 -0
  193. package/dist/runtime/windowed-minimap-projection.d.ts +28 -0
  194. package/dist/runtime/windowed-minimap-projection.js +189 -0
  195. package/dist/runtime/workspace-shortcuts.d.ts +30 -0
  196. package/dist/runtime/workspace-shortcuts.js +188 -0
  197. package/dist/sdk-error-copy.d.ts +48 -0
  198. package/dist/sdk-error-copy.js +182 -0
  199. package/dist/select-cursor.d.ts +2 -0
  200. package/dist/select-cursor.js +23 -0
  201. package/dist/server/admission-cookie.d.ts +38 -0
  202. package/dist/server/admission-cookie.js +122 -0
  203. package/dist/server/control-client.d.ts +29 -0
  204. package/dist/server/control-client.js +22 -0
  205. package/dist/server/control-errors.d.ts +22 -0
  206. package/dist/server/control-errors.js +165 -0
  207. package/dist/server/draft-route.d.ts +12 -0
  208. package/dist/server/draft-route.js +45 -0
  209. package/dist/server/extract-token.d.ts +30 -0
  210. package/dist/server/extract-token.js +98 -0
  211. package/dist/server/grant.d.ts +128 -0
  212. package/dist/server/grant.js +395 -0
  213. package/dist/server/ordinary-read-provenance.d.ts +11 -0
  214. package/dist/server/ordinary-read-provenance.js +124 -0
  215. package/dist/server/preview-read-metadata.d.ts +10 -0
  216. package/dist/server/preview-read-metadata.js +27 -0
  217. package/dist/server/provenance-frame-builder.d.ts +53 -0
  218. package/dist/server/provenance-frame-builder.js +102 -0
  219. package/dist/server/provenance-runtime.d.ts +70 -0
  220. package/dist/server/provenance-runtime.js +46 -0
  221. package/dist/server/read-context-command.d.ts +11 -0
  222. package/dist/server/read-context-command.js +53 -0
  223. package/dist/server/read-identity.d.ts +3 -0
  224. package/dist/server/read-identity.js +63 -0
  225. package/dist/server/read-lifecycle.d.ts +17 -0
  226. package/dist/server/read-lifecycle.js +52 -0
  227. package/dist/server/render-frame-provenance.d.ts +133 -0
  228. package/dist/server/render-frame-provenance.js +676 -0
  229. package/dist/server/render-id.d.ts +15 -0
  230. package/dist/server/render-id.js +22 -0
  231. package/dist/server/route-document-provenance.d.ts +77 -0
  232. package/dist/server/route-document-provenance.js +1327 -0
  233. package/dist/server/route-session-cookie.d.ts +33 -0
  234. package/dist/server/route-session-cookie.js +54 -0
  235. package/dist/session-projections.d.ts +33 -0
  236. package/dist/session-projections.js +43 -0
  237. package/dist/session-subscriber.d.ts +124 -0
  238. package/dist/session-subscriber.js +79 -0
  239. package/dist/sha256-fallback.d.ts +30 -0
  240. package/dist/sha256-fallback.js +126 -0
  241. package/dist/types.d.ts +446 -0
  242. package/dist/types.js +85 -0
  243. package/dist/validators.d.ts +61 -0
  244. package/dist/validators.js +110 -0
  245. package/package.json +206 -3
@@ -0,0 +1,28 @@
1
+ export interface WindowedMinimapGeometry {
2
+ pageHeight: number;
3
+ windowStart: number;
4
+ renderSpan: number;
5
+ compression: number;
6
+ rootStyleCssText: string;
7
+ }
8
+ export declare function readWindowedMinimapGeometry(doc: Document): WindowedMinimapGeometry | null;
9
+ /**
10
+ * A reversible lease on the root declarations needed by the bounded minimap
11
+ * projection. It is inactive unless Studio explicitly requests it.
12
+ *
13
+ * The site still receives a normal 1440×900 layout viewport. Only paint is
14
+ * compressed; Studio expands that paint back into the minimap's document
15
+ * coordinate space. Slice snapshots use the geometry above to undo the paint
16
+ * transform before crossing the iframe boundary.
17
+ */
18
+ export declare function createWindowedMinimapProjection(win: Window, doc: Document, viewportHeight?: number): {
19
+ enter(initialRenderSpan?: number): WindowedMinimapGeometry | null;
20
+ update(nextWindowStart: number, nextRenderSpan: number): WindowedMinimapGeometry | null;
21
+ reapplyAfterRootReset(): void;
22
+ refresh(): WindowedMinimapGeometry | null;
23
+ exit(): string[];
24
+ ownsRootStyle(): boolean;
25
+ readonly active: boolean;
26
+ readonly geometry: WindowedMinimapGeometry | null;
27
+ readonly stoppedReason: string | null;
28
+ };
@@ -0,0 +1,189 @@
1
+ const geometryByDocument = new WeakMap();
2
+ export function readWindowedMinimapGeometry(doc) {
3
+ return geometryByDocument.get(doc) ?? null;
4
+ }
5
+ /**
6
+ * A reversible lease on the root declarations needed by the bounded minimap
7
+ * projection. It is inactive unless Studio explicitly requests it.
8
+ *
9
+ * The site still receives a normal 1440×900 layout viewport. Only paint is
10
+ * compressed; Studio expands that paint back into the minimap's document
11
+ * coordinate space. Slice snapshots use the geometry above to undo the paint
12
+ * transform before crossing the iframe boundary.
13
+ */
14
+ export function createWindowedMinimapProjection(win, doc, viewportHeight = 900) {
15
+ const root = doc.documentElement;
16
+ const original = new Map();
17
+ const owned = new Map();
18
+ let active = false;
19
+ let pageHeight = viewportHeight;
20
+ let windowStart = 0;
21
+ let renderSpan = viewportHeight;
22
+ let stoppedReason = null;
23
+ let rootStyleCssText = '';
24
+ const read = (property) => ({
25
+ value: root.style.getPropertyValue(property),
26
+ priority: root.style.getPropertyPriority(property),
27
+ });
28
+ const equal = (property, a, b) => a.value === b.value &&
29
+ // Next.js temporarily writes `scroll-behavior: auto` on the root during
30
+ // navigation without preserving our `!important` priority. The semantic
31
+ // value is unchanged, so this is safe to reclaim on the next projection
32
+ // pass. Value changes and every other leased declaration remain strict.
33
+ (property === 'scroll-behavior' || a.priority === b.priority);
34
+ const set = (property, value) => {
35
+ if (!original.has(property))
36
+ original.set(property, read(property));
37
+ root.style.setProperty(property, value, 'important');
38
+ owned.set(property, read(property));
39
+ rootStyleCssText = root.style.cssText;
40
+ };
41
+ const conflicts = () => [...owned].filter(([property, state]) => !equal(property, read(property), state));
42
+ const restore = () => {
43
+ geometryByDocument.delete(doc);
44
+ const concurrent = conflicts().map(([property]) => property);
45
+ for (const [property, state] of original) {
46
+ if (concurrent.includes(property))
47
+ continue;
48
+ if (state.value)
49
+ root.style.setProperty(property, state.value, state.priority);
50
+ else
51
+ root.style.removeProperty(property);
52
+ }
53
+ original.clear();
54
+ owned.clear();
55
+ rootStyleCssText = '';
56
+ return concurrent;
57
+ };
58
+ const unsupported = () => {
59
+ if (doc.compatMode !== 'CSS1Compat')
60
+ return 'non-standards document';
61
+ const css = win.getComputedStyle(root);
62
+ if (css.writingMode && css.writingMode !== 'horizontal-tb') {
63
+ return 'root writing mode';
64
+ }
65
+ for (const property of ['transform', 'translate', 'scale', 'rotate']) {
66
+ const value = css.getPropertyValue(property);
67
+ if (value !== '' && value !== 'none')
68
+ return 'existing root transform';
69
+ }
70
+ if (css.zoom && Number(css.zoom) !== 1)
71
+ return 'existing root zoom';
72
+ return null;
73
+ };
74
+ const readNaturalHeight = () => Math.max(viewportHeight, doc.body?.scrollHeight ?? 0, doc.body?.offsetHeight ?? 0, doc.scrollingElement?.scrollHeight ?? 0);
75
+ const apply = () => {
76
+ if (!active)
77
+ return;
78
+ // Studio owns the paint window and its inverse transform. A resize report
79
+ // (including an intermediate route subtree) may change pageHeight, but
80
+ // must not silently change this half of the transform pair. Studio clamps
81
+ // the next window to the measured page before sending update().
82
+ const rendered = Math.max(viewportHeight, Number.isFinite(renderSpan) ? renderSpan : viewportHeight);
83
+ renderSpan = rendered;
84
+ windowStart = Math.max(0, Number.isFinite(windowStart) ? windowStart : 0);
85
+ const compression = viewportHeight / rendered;
86
+ set('min-height', `${viewportHeight}px`);
87
+ set('max-height', `${viewportHeight}px`);
88
+ set('transform-origin', '0 0');
89
+ set('scroll-behavior', 'auto');
90
+ set('transform', `scale(${compression})`);
91
+ const targetScroll = windowStart * compression;
92
+ const scroller = doc.scrollingElement;
93
+ if (scroller) {
94
+ scroller.scrollLeft = 0;
95
+ scroller.scrollTop = targetScroll;
96
+ }
97
+ else {
98
+ win.scrollTo({ top: targetScroll, left: 0, behavior: 'instant' });
99
+ }
100
+ const geometry = {
101
+ pageHeight,
102
+ windowStart,
103
+ renderSpan,
104
+ compression,
105
+ rootStyleCssText,
106
+ };
107
+ geometryByDocument.set(doc, geometry);
108
+ };
109
+ return {
110
+ enter(initialRenderSpan = viewportHeight) {
111
+ // Studio reasserts Navigation before it dispatches the next route. The
112
+ // current realm is already projected at that point; resetting its span
113
+ // to the native viewport would expose one enlarged frame before the
114
+ // router starts. The following window message remains the authority for
115
+ // changing an active projection.
116
+ if (active)
117
+ return geometryByDocument.get(doc) ?? null;
118
+ stoppedReason = unsupported();
119
+ if (stoppedReason)
120
+ return null;
121
+ pageHeight = readNaturalHeight();
122
+ renderSpan = initialRenderSpan;
123
+ windowStart = 0;
124
+ active = true;
125
+ apply();
126
+ return geometryByDocument.get(doc) ?? null;
127
+ },
128
+ update(nextWindowStart, nextRenderSpan) {
129
+ if (!active)
130
+ return null;
131
+ if (conflicts().length > 0) {
132
+ this.exit();
133
+ return null;
134
+ }
135
+ windowStart = nextWindowStart;
136
+ renderSpan = nextRenderSpan;
137
+ apply();
138
+ return geometryByDocument.get(doc) ?? null;
139
+ },
140
+ reapplyAfterRootReset() {
141
+ // A router can remount <html> and remove every leased declaration.
142
+ // During a navigation handoff, keep the existing transform pair before
143
+ // paint. This is not permission to overwrite a new site's root styles:
144
+ // partial edits and replacement transforms still take the conflict path.
145
+ if (!active ||
146
+ owned.size === 0 ||
147
+ [...owned.keys()].some((property) => read(property).value !== '') ||
148
+ unsupported()) {
149
+ return;
150
+ }
151
+ original.clear();
152
+ owned.clear();
153
+ apply();
154
+ },
155
+ refresh() {
156
+ if (!active)
157
+ return null;
158
+ if (conflicts().length > 0) {
159
+ this.exit();
160
+ return null;
161
+ }
162
+ pageHeight = readNaturalHeight();
163
+ apply();
164
+ return geometryByDocument.get(doc) ?? null;
165
+ },
166
+ exit() {
167
+ if (!active && original.size === 0)
168
+ return [];
169
+ const concurrent = restore();
170
+ active = false;
171
+ if (concurrent.length > 0) {
172
+ stoppedReason = `concurrent root style: ${concurrent.join(', ')}`;
173
+ }
174
+ return concurrent;
175
+ },
176
+ ownsRootStyle() {
177
+ return active && root.style.cssText === rootStyleCssText;
178
+ },
179
+ get active() {
180
+ return active;
181
+ },
182
+ get geometry() {
183
+ return geometryByDocument.get(doc) ?? null;
184
+ },
185
+ get stoppedReason() {
186
+ return stoppedReason;
187
+ },
188
+ };
189
+ }
@@ -0,0 +1,30 @@
1
+ /** Commands explicitly reserved by an attached Studio, including in Navigate inputs. */
2
+ export declare const previewWorkspaceCommandIds: readonly ["workspace.navigation.toggle", "workspace.preview.toggle", "workspace.details.toggle", "workspace.assistant.toggle", "commands.open", "focus.next", "focus.previous"];
3
+ export type PreviewWorkspaceCommandId = (typeof previewWorkspaceCommandIds)[number];
4
+ export interface PreviewShortcutBinding {
5
+ id: PreviewWorkspaceCommandId;
6
+ key: string;
7
+ meta: boolean;
8
+ ctrl: boolean;
9
+ alt: boolean;
10
+ shift: boolean;
11
+ }
12
+ export interface PreviewShortcutIdentity {
13
+ sessionId: string;
14
+ projectId: string;
15
+ parentOrigin: string | null;
16
+ }
17
+ export interface PreviewShortcutMessage {
18
+ type: 'storystick.preview.shortcuts';
19
+ kind: 'ready' | 'configure' | 'invoke' | 'probe';
20
+ sessionId: string;
21
+ projectId: string;
22
+ relayId: string;
23
+ connectionId?: string;
24
+ revision?: number;
25
+ bindings?: PreviewShortcutBinding[];
26
+ command?: PreviewWorkspaceCommandId;
27
+ sequence?: number;
28
+ }
29
+ /** Self-contained: the exact same implementation is embedded in the early script. */
30
+ export declare function installPreviewWorkspaceShortcuts(win: Window, getIdentity: () => PreviewShortcutIdentity | null, commandIds?: readonly string[], subscribeIdentity?: (listener: () => void) => () => void): () => void;
@@ -0,0 +1,188 @@
1
+ /** Commands explicitly reserved by an attached Studio, including in Navigate inputs. */
2
+ export const previewWorkspaceCommandIds = [
3
+ 'workspace.navigation.toggle',
4
+ 'workspace.preview.toggle',
5
+ 'workspace.details.toggle',
6
+ 'workspace.assistant.toggle',
7
+ 'commands.open',
8
+ 'focus.next',
9
+ 'focus.previous',
10
+ ];
11
+ /** Self-contained: the exact same implementation is embedded in the early script. */
12
+ export function installPreviewWorkspaceShortcuts(win, getIdentity, commandIds = previewWorkspaceCommandIds, subscribeIdentity) {
13
+ if (win.parent === win)
14
+ return () => { };
15
+ const view = win;
16
+ // SDK adapters and the early provenance script share one listener per realm.
17
+ let shared = view.__storystickWorkspaceShortcuts;
18
+ if (!shared) {
19
+ const owners = new Set();
20
+ const type = 'storystick.preview.shortcuts';
21
+ const newRelayId = () => Array.from(win.crypto.getRandomValues(new Uint32Array(4))).join('-');
22
+ let identity = null;
23
+ let relayId = newRelayId();
24
+ let bindings = [];
25
+ let connectionId = null;
26
+ let revision = -1;
27
+ let sequence = 0;
28
+ let disposed = false;
29
+ const readIdentity = () => {
30
+ const next = Array.from(owners)
31
+ .map((read) => read())
32
+ .find((value) => value?.parentOrigin) ?? null;
33
+ if (!next?.parentOrigin || !next.sessionId || !next.projectId)
34
+ return null;
35
+ try {
36
+ if (new URL(next.parentOrigin).origin !== next.parentOrigin ||
37
+ next.parentOrigin === 'null')
38
+ return null;
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ return {
44
+ sessionId: next.sessionId,
45
+ projectId: next.projectId,
46
+ parentOrigin: next.parentOrigin,
47
+ };
48
+ };
49
+ const syncIdentity = () => {
50
+ const next = readIdentity();
51
+ if (JSON.stringify(next) !== JSON.stringify(identity)) {
52
+ identity = next;
53
+ relayId = newRelayId();
54
+ bindings = [];
55
+ revision = -1;
56
+ sequence = 0;
57
+ }
58
+ return identity;
59
+ };
60
+ const post = (message) => {
61
+ if (!identity?.parentOrigin)
62
+ return;
63
+ win.parent.postMessage({
64
+ type,
65
+ sessionId: identity.sessionId,
66
+ projectId: identity.projectId,
67
+ relayId,
68
+ ...message,
69
+ }, identity.parentOrigin);
70
+ };
71
+ const refresh = () => {
72
+ if (disposed)
73
+ return;
74
+ if (syncIdentity())
75
+ post({ kind: 'ready' });
76
+ };
77
+ const onMessage = (event) => {
78
+ if (event.source !== win.parent)
79
+ return;
80
+ // Identity delivery may be handled by a later listener in the same turn.
81
+ if (event.data?.type === 'storystick.preview.session-broadcast') {
82
+ queueMicrotask(refresh);
83
+ return;
84
+ }
85
+ const current = syncIdentity();
86
+ const data = event.data;
87
+ if (!current ||
88
+ event.origin !== current.parentOrigin ||
89
+ data?.type !== type ||
90
+ data.sessionId !== current.sessionId ||
91
+ data.projectId !== current.projectId)
92
+ return;
93
+ if (data.kind === 'probe') {
94
+ refresh();
95
+ return;
96
+ }
97
+ if (data.kind !== 'configure' ||
98
+ data.relayId !== relayId ||
99
+ typeof data.connectionId !== 'string' ||
100
+ !data.connectionId ||
101
+ data.connectionId.length > 128 ||
102
+ !Number.isSafeInteger(data.revision) ||
103
+ data.revision < 0 ||
104
+ (data.connectionId === connectionId && data.revision < revision) ||
105
+ !Array.isArray(data.bindings) ||
106
+ data.bindings.length > 16)
107
+ return;
108
+ // A configuration can reserve only workspace chords, never ordinary typing.
109
+ if (!data.bindings.every((b) => b &&
110
+ commandIds.includes(b.id) &&
111
+ typeof b.key === 'string' &&
112
+ (b.key.length === 1 || b.key === 'f6') &&
113
+ ['meta', 'ctrl', 'alt', 'shift'].every((k) => typeof b[k] === 'boolean') &&
114
+ (b.meta || b.ctrl || b.key === 'f6')))
115
+ return;
116
+ connectionId = data.connectionId;
117
+ revision = data.revision;
118
+ bindings = data.bindings;
119
+ };
120
+ const onKeyDown = (event) => {
121
+ if (!syncIdentity() ||
122
+ event.isComposing ||
123
+ event.keyCode === 229 ||
124
+ event.getModifierState?.('AltGraph') ||
125
+ ['Dead', 'Process', 'Unidentified'].includes(event.key))
126
+ return;
127
+ const binding = bindings.find((b) => b.key === event.key.toLowerCase() &&
128
+ b.meta === event.metaKey &&
129
+ b.ctrl === event.ctrlKey &&
130
+ b.alt === event.altKey &&
131
+ b.shift === event.shiftKey);
132
+ if (!binding)
133
+ return;
134
+ // Cancellation must be synchronous in this document. postMessage cannot
135
+ // cancel the browser/site action after the Studio receives the command.
136
+ event.preventDefault();
137
+ event.stopImmediatePropagation();
138
+ if (!event.repeat)
139
+ post({
140
+ kind: 'invoke',
141
+ command: binding.id,
142
+ connectionId,
143
+ revision,
144
+ sequence: ++sequence,
145
+ });
146
+ };
147
+ const suspend = () => {
148
+ bindings = [];
149
+ revision = -1;
150
+ relayId = newRelayId();
151
+ sequence = 0;
152
+ };
153
+ win.addEventListener('message', onMessage);
154
+ win.addEventListener('keydown', onKeyDown, true);
155
+ win.addEventListener('focus', refresh);
156
+ win.addEventListener('pageshow', refresh);
157
+ win.addEventListener('pagehide', suspend);
158
+ shared = {
159
+ owners,
160
+ refresh,
161
+ dispose: () => {
162
+ disposed = true;
163
+ win.removeEventListener('message', onMessage);
164
+ win.removeEventListener('keydown', onKeyDown, true);
165
+ win.removeEventListener('focus', refresh);
166
+ win.removeEventListener('pageshow', refresh);
167
+ win.removeEventListener('pagehide', suspend);
168
+ delete view.__storystickWorkspaceShortcuts;
169
+ },
170
+ };
171
+ view.__storystickWorkspaceShortcuts = shared;
172
+ }
173
+ shared.owners.add(getIdentity);
174
+ const unsubscribe = subscribeIdentity?.(shared.refresh);
175
+ queueMicrotask(shared.refresh);
176
+ let released = false;
177
+ return () => {
178
+ if (released)
179
+ return;
180
+ released = true;
181
+ unsubscribe?.();
182
+ shared.owners.delete(getIdentity);
183
+ if (shared.owners.size === 0)
184
+ shared.dispose();
185
+ else
186
+ shared.refresh();
187
+ };
188
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * ADR-134 §9.T2 — SDK-side copy table for the `<Storystick />` terminal
3
+ * panel in `@storystick/next`. Mirror of `apps/studio/src/lib/preview-
4
+ * error-copy.ts`, scoped to the SUBSET of codes the customer-side panel
5
+ * actually renders. A contract test at `apps/studio/tests/sdk-error-
6
+ * copy-contract.test.ts` pins overlap rows verbatim against Studio's
7
+ * copy so the two tables can't drift on shared codes.
8
+ *
9
+ * Why a separate table : Studio product copy doesn't ship in customer-
10
+ * runtime bundle (different audience, different vocabulary, different
11
+ * bundle size budget). The SDK surface renders inside the customer's
12
+ * page, so it speaks to the DEVELOPER hosting the customer site rather
13
+ * than to a Studio editor. Phrasing can legitimately diverge on Studio-
14
+ * specific codes ; the contract test ensures shared codes don't.
15
+ *
16
+ * Codes covered :
17
+ * - `runtime.cache_unavailable` (D6 — Layer1 cache failed to open)
18
+ * - `runtime.schema_sync_delayed` (D6 — attempt 1 of schema retry)
19
+ * - `runtime.schema_delivery_failed` (D6 — attempt 5 of schema retry)
20
+ * - `identity_carrier_timeout` when Studio identity cannot be established.
21
+ * - PreviewGrant/context boundary codes emitted by the same-origin token
22
+ * route or Convex subscriptions.
23
+ *
24
+ * Unknown codes fall back to a generic entry. The fallback's body is
25
+ * intentionally honest : the SDK doesn't claim to know what happened.
26
+ */
27
+ export interface SdkErrorCopyEntry {
28
+ title: string;
29
+ body: string;
30
+ /**
31
+ * Non-exhaustive list of likely causes. The SDK panel renders these
32
+ * as a bullet list inside the red surface. Empty array → list is
33
+ * suppressed.
34
+ */
35
+ commonCauses: ReadonlyArray<string>;
36
+ }
37
+ /**
38
+ * Canonical map. Codes here MUST match `apps/studio/src/lib/preview-
39
+ * error-copy.ts` on overlap rows (contract-tested). Title + body
40
+ * fields share verbatim, commonCauses share as a set (order can
41
+ * differ).
42
+ */
43
+ export declare const SDK_ERROR_COPY: Readonly<Record<string, SdkErrorCopyEntry>>;
44
+ /**
45
+ * Look up the structured SDK copy for a code. Always returns an entry
46
+ * (never null) so the panel can render unconditionally.
47
+ */
48
+ export declare function lookupSdkCopy(code: string | null | undefined): SdkErrorCopyEntry;
@@ -0,0 +1,182 @@
1
+ /**
2
+ * ADR-134 §9.T2 — SDK-side copy table for the `<Storystick />` terminal
3
+ * panel in `@storystick/next`. Mirror of `apps/studio/src/lib/preview-
4
+ * error-copy.ts`, scoped to the SUBSET of codes the customer-side panel
5
+ * actually renders. A contract test at `apps/studio/tests/sdk-error-
6
+ * copy-contract.test.ts` pins overlap rows verbatim against Studio's
7
+ * copy so the two tables can't drift on shared codes.
8
+ *
9
+ * Why a separate table : Studio product copy doesn't ship in customer-
10
+ * runtime bundle (different audience, different vocabulary, different
11
+ * bundle size budget). The SDK surface renders inside the customer's
12
+ * page, so it speaks to the DEVELOPER hosting the customer site rather
13
+ * than to a Studio editor. Phrasing can legitimately diverge on Studio-
14
+ * specific codes ; the contract test ensures shared codes don't.
15
+ *
16
+ * Codes covered :
17
+ * - `runtime.cache_unavailable` (D6 — Layer1 cache failed to open)
18
+ * - `runtime.schema_sync_delayed` (D6 — attempt 1 of schema retry)
19
+ * - `runtime.schema_delivery_failed` (D6 — attempt 5 of schema retry)
20
+ * - `identity_carrier_timeout` when Studio identity cannot be established.
21
+ * - PreviewGrant/context boundary codes emitted by the same-origin token
22
+ * route or Convex subscriptions.
23
+ *
24
+ * Unknown codes fall back to a generic entry. The fallback's body is
25
+ * intentionally honest : the SDK doesn't claim to know what happened.
26
+ */
27
+ const PREVIEW_ACCESS_ENDED = {
28
+ title: 'Preview access ended',
29
+ body: 'This preview is no longer active. Return to Storystick Studio to open a new preview.',
30
+ commonCauses: [],
31
+ };
32
+ const PREVIEW_ADMISSION_MISSING = {
33
+ title: 'Preview access is missing',
34
+ body: 'The site did not receive the Preview admission cookie. Open a fresh Preview from Studio. If this continues, check the site’s HTTPS and cookie configuration.',
35
+ commonCauses: [
36
+ 'The browser did not accept or send the Preview cookie in this context.',
37
+ 'The Preview admission expired or was cleared.',
38
+ ],
39
+ };
40
+ const PREVIEW_RENDER_ADMISSION_MISSING = {
41
+ title: 'Preview needs a fresh activation',
42
+ body: 'The site could not confirm Preview for its current deployment. Reopen Preview from Studio.',
43
+ commonCauses: [
44
+ 'The site was redeployed after Preview was opened.',
45
+ 'The browser did not return the site’s Draft Mode cookie.',
46
+ ],
47
+ };
48
+ const PREVIEW_BINDING_MISMATCH = {
49
+ title: 'Preview binding mismatch',
50
+ body: 'This preview does not match the active project, origin, or session. Reopen the document from the correct Storystick Studio project.',
51
+ commonCauses: [],
52
+ };
53
+ const PREVIEW_VIEW_UNAVAILABLE = {
54
+ title: 'This preview has expired',
55
+ body: 'Open a new preview from Studio to continue.',
56
+ commonCauses: [],
57
+ };
58
+ const PREVIEW_ADMISSION_SUPERSEDED = {
59
+ title: 'Preview changed in another view',
60
+ body: 'This page could not reconnect to the current preview. Reopen it from Studio.',
61
+ commonCauses: [],
62
+ };
63
+ const PREVIEW_PROTOCOL_INVALID = {
64
+ title: 'Preview adapter mismatch',
65
+ body: 'The customer preview route returned an incompatible response. Update the Storystick packages together, then reopen the document.',
66
+ commonCauses: [],
67
+ };
68
+ /**
69
+ * Canonical map. Codes here MUST match `apps/studio/src/lib/preview-
70
+ * error-copy.ts` on overlap rows (contract-tested). Title + body
71
+ * fields share verbatim, commonCauses share as a set (order can
72
+ * differ).
73
+ */
74
+ export const SDK_ERROR_COPY = {
75
+ 'runtime.preview_read_unavailable': {
76
+ title: 'Preview content temporarily unavailable',
77
+ body: 'The content service could not answer this page’s request. Retry when the connection is restored.',
78
+ commonCauses: [],
79
+ },
80
+ 'runtime.customer_render_failed': {
81
+ title: 'This page could not render',
82
+ body: 'The customer site reported a rendering error. You can open another document. Retry this page after its rendering error has been corrected.',
83
+ commonCauses: [],
84
+ },
85
+ // ─── D-category runtime warnings/errors (emitted by SDK boot/schema) ──
86
+ 'runtime.cache_unavailable': {
87
+ title: 'Preview cache unavailable',
88
+ body: 'The preview cache could not be opened, so observed overlays are disabled. Authenticated preview still works; the editor will fall back to explicit rendering.',
89
+ commonCauses: [
90
+ 'IndexedDB is disabled (private browsing on older Firefox / Safari).',
91
+ 'A browser extension is blocking storage access.',
92
+ ],
93
+ },
94
+ 'runtime.schema_sync_delayed': {
95
+ title: 'Loading schema is taking longer than usual',
96
+ body: 'Studio is still fetching the project schema. Field-level overlays will be limited until the schema arrives.',
97
+ commonCauses: [
98
+ 'Slow network between the iframe and the Storystick gateway.',
99
+ 'The gateway returned a transient error and the SDK is retrying.',
100
+ ],
101
+ },
102
+ 'runtime.schema_delivery_failed': {
103
+ title: 'Schema delivery failed',
104
+ body: 'The preview schema could not be fetched after 5 attempts. Field-level overlays are unavailable for this session.',
105
+ commonCauses: [
106
+ 'The Storystick gateway is unreachable from the iframe.',
107
+ 'Network conditions prevented the schema HTTP request from completing.',
108
+ 'Reload the iframe to retry from a fresh attempt cycle.',
109
+ ],
110
+ },
111
+ // ─── Grant / origin / session codes ────────────────────────────
112
+ identity_carrier_timeout: {
113
+ title: 'Preview identity could not be established',
114
+ body: 'Studio did not deliver a preview identity to this iframe in time. Reopen the document in Storystick Studio to retry.',
115
+ commonCauses: [],
116
+ },
117
+ PREVIEW_GRANT_MISSING: PREVIEW_ADMISSION_MISSING,
118
+ 'storystick/PREVIEW_GRANT_MISSING': PREVIEW_ADMISSION_MISSING,
119
+ CONTENT_SHAPE_RELOAD_REQUIRED: PREVIEW_RENDER_ADMISSION_MISSING,
120
+ 'storystick/CONTENT_SHAPE_RELOAD_REQUIRED': PREVIEW_RENDER_ADMISSION_MISSING,
121
+ PREVIEW_GRANT_MALFORMED: PREVIEW_ACCESS_ENDED,
122
+ 'storystick/PREVIEW_GRANT_MALFORMED': PREVIEW_ACCESS_ENDED,
123
+ PREVIEW_GRANT_INVALID: PREVIEW_ACCESS_ENDED,
124
+ 'storystick/PREVIEW_GRANT_INVALID': PREVIEW_ACCESS_ENDED,
125
+ PREVIEW_GRANT_REVOKED: PREVIEW_ACCESS_ENDED,
126
+ 'storystick/PREVIEW_GRANT_REVOKED': PREVIEW_ACCESS_ENDED,
127
+ PREVIEW_GRANT_EXPIRED: PREVIEW_ACCESS_ENDED,
128
+ 'storystick/PREVIEW_GRANT_EXPIRED': PREVIEW_ACCESS_ENDED,
129
+ PREVIEW_ACCESS_REVOKED: PREVIEW_ACCESS_ENDED,
130
+ 'storystick/PREVIEW_ACCESS_REVOKED': PREVIEW_ACCESS_ENDED,
131
+ PREVIEW_VIEW_UNAVAILABLE,
132
+ 'storystick/PREVIEW_VIEW_UNAVAILABLE': PREVIEW_VIEW_UNAVAILABLE,
133
+ PREVIEW_ADMISSION_SUPERSEDED,
134
+ 'storystick/PREVIEW_ADMISSION_SUPERSEDED': PREVIEW_ADMISSION_SUPERSEDED,
135
+ PREVIEW_CONTEXT_INVALID: PREVIEW_ACCESS_ENDED,
136
+ 'storystick/PREVIEW_CONTEXT_INVALID': PREVIEW_ACCESS_ENDED,
137
+ PREVIEW_CONTEXT_ENDED: PREVIEW_ACCESS_ENDED,
138
+ PREVIEW_CONTEXT_EXIT_UNAVAILABLE: {
139
+ title: 'Preview exit could not finish',
140
+ body: 'The shared preview ended, but this page could not clear its local preview access. Retry Exit Preview.',
141
+ commonCauses: [],
142
+ },
143
+ PREVIEW_GRANT_REQUIRED: PREVIEW_BINDING_MISMATCH,
144
+ PREVIEW_GRANT_FORBIDDEN: PREVIEW_BINDING_MISMATCH,
145
+ 'storystick/PREVIEW_GRANT_FORBIDDEN': PREVIEW_BINDING_MISMATCH,
146
+ PREVIEW_GRANT_BINDING_MISMATCH: PREVIEW_BINDING_MISMATCH,
147
+ 'storystick/PREVIEW_GRANT_BINDING_MISMATCH': PREVIEW_BINDING_MISMATCH,
148
+ PREVIEW_ORIGIN_MISMATCH: PREVIEW_BINDING_MISMATCH,
149
+ 'storystick/PREVIEW_ORIGIN_MISMATCH': PREVIEW_BINDING_MISMATCH,
150
+ PREVIEW_PROJECT_MISMATCH: PREVIEW_BINDING_MISMATCH,
151
+ 'storystick/PREVIEW_PROJECT_MISMATCH': PREVIEW_BINDING_MISMATCH,
152
+ PREVIEW_TOKEN_PROTOCOL_INVALID: PREVIEW_PROTOCOL_INVALID,
153
+ PREVIEW_REQUIRED: {
154
+ title: 'Preview mode required',
155
+ body: 'This route can only be rendered inside an active Storystick preview session. Open it from Studio to view.',
156
+ commonCauses: [],
157
+ },
158
+ UNKNOWN: {
159
+ title: 'Unknown preview error',
160
+ body: 'The Storystick SDK received an unrecognised error code. Reload the iframe ; if the issue persists, check the Studio logs.',
161
+ commonCauses: [],
162
+ },
163
+ };
164
+ /**
165
+ * Fallback entry. Returned by `lookupSdkCopy` for codes not in the map.
166
+ * Honest body — the SDK doesn't pretend to know.
167
+ */
168
+ const FALLBACK_SDK_ENTRY = {
169
+ title: 'Storystick preview error',
170
+ body: 'Preview connection lost. Reopen the document in Storystick Studio to resume.',
171
+ commonCauses: [],
172
+ };
173
+ /**
174
+ * Look up the structured SDK copy for a code. Always returns an entry
175
+ * (never null) so the panel can render unconditionally.
176
+ */
177
+ export function lookupSdkCopy(code) {
178
+ if (typeof code !== 'string' || code.length === 0) {
179
+ return FALLBACK_SDK_ENTRY;
180
+ }
181
+ return SDK_ERROR_COPY[code] ?? FALLBACK_SDK_ENTRY;
182
+ }
@@ -0,0 +1,2 @@
1
+ /** CSS cursor value, including the tip-aligned hotspot and native fallback. */
2
+ export declare const PREVIEW_SELECT_CURSOR: string;