@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.
Files changed (247) hide show
  1. package/LICENSE +112 -0
  2. package/PUBLIC-API.md +56 -0
  3. package/README.md +42 -2
  4. package/dist/.source-hash +1 -0
  5. package/dist/authoring/runtime-contract.d.ts +92 -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/page-presentation.d.ts +24 -0
  72. package/dist/page-presentation.js +32 -0
  73. package/dist/provenance/anchor-map.d.ts +95 -0
  74. package/dist/provenance/anchor-map.js +177 -0
  75. package/dist/provenance/carrier-plan.d.ts +51 -0
  76. package/dist/provenance/carrier-plan.js +90 -0
  77. package/dist/provenance/coded-text.d.ts +20 -0
  78. package/dist/provenance/coded-text.js +302 -0
  79. package/dist/provenance/direct-edit-locator.d.ts +29 -0
  80. package/dist/provenance/direct-edit-locator.js +218 -0
  81. package/dist/provenance/editable-leaf.d.ts +134 -0
  82. package/dist/provenance/editable-leaf.js +483 -0
  83. package/dist/provenance/editor-target.d.ts +29 -0
  84. package/dist/provenance/editor-target.js +46 -0
  85. package/dist/provenance/field-leaf-walker.d.ts +21 -0
  86. package/dist/provenance/field-leaf-walker.js +98 -0
  87. package/dist/provenance/frame-dependencies.d.ts +212 -0
  88. package/dist/provenance/frame-dependencies.js +550 -0
  89. package/dist/provenance/index.d.ts +26 -0
  90. package/dist/provenance/index.js +26 -0
  91. package/dist/provenance/local-events.d.ts +1 -0
  92. package/dist/provenance/local-events.js +1 -0
  93. package/dist/provenance/markers.d.ts +21 -0
  94. package/dist/provenance/markers.js +70 -0
  95. package/dist/provenance/multi-frame-anchor-map.d.ts +54 -0
  96. package/dist/provenance/multi-frame-anchor-map.js +109 -0
  97. package/dist/provenance/normalize.d.ts +2 -0
  98. package/dist/provenance/normalize.js +19 -0
  99. package/dist/provenance/overlay-focus-echo.d.ts +17 -0
  100. package/dist/provenance/overlay-focus-echo.js +16 -0
  101. package/dist/provenance/overlay-projection.d.ts +65 -0
  102. package/dist/provenance/overlay-projection.js +201 -0
  103. package/dist/provenance/owner-map.d.ts +55 -0
  104. package/dist/provenance/owner-map.js +239 -0
  105. package/dist/provenance/read-carrier.d.ts +22 -0
  106. package/dist/provenance/read-carrier.js +92 -0
  107. package/dist/provenance/recorder.d.ts +38 -0
  108. package/dist/provenance/recorder.js +82 -0
  109. package/dist/provenance/render-context.d.ts +106 -0
  110. package/dist/provenance/render-context.js +338 -0
  111. package/dist/provenance/reveal-contract.d.ts +44 -0
  112. package/dist/provenance/reveal-contract.js +1 -0
  113. package/dist/provenance/richtext-slice-embed-address.d.ts +20 -0
  114. package/dist/provenance/richtext-slice-embed-address.js +35 -0
  115. package/dist/provenance/runtime-script.d.ts +1 -0
  116. package/dist/provenance/runtime-script.js +2217 -0
  117. package/dist/provenance/sidecar-store.d.ts +63 -0
  118. package/dist/provenance/sidecar-store.js +151 -0
  119. package/dist/provenance/sidecar.d.ts +34 -0
  120. package/dist/provenance/sidecar.js +227 -0
  121. package/dist/provenance/slice-model.d.ts +28 -0
  122. package/dist/provenance/slice-model.js +86 -0
  123. package/dist/provenance/source-identity.d.ts +3 -0
  124. package/dist/provenance/source-identity.js +7 -0
  125. package/dist/provenance/source-map-materializer.d.ts +76 -0
  126. package/dist/provenance/source-map-materializer.js +286 -0
  127. package/dist/provenance/source-registry.d.ts +103 -0
  128. package/dist/provenance/source-registry.js +562 -0
  129. package/dist/provenance/transformed-output-gate.d.ts +161 -0
  130. package/dist/provenance/transformed-output-gate.js +171 -0
  131. package/dist/provenance/types.d.ts +102 -0
  132. package/dist/provenance/types.js +1 -0
  133. package/dist/refresh-policy.d.ts +11 -0
  134. package/dist/refresh-policy.js +14 -0
  135. package/dist/reveal-target.d.ts +8 -0
  136. package/dist/reveal-target.js +47 -0
  137. package/dist/route-paths.d.ts +11 -0
  138. package/dist/route-paths.js +14 -0
  139. package/dist/router-subscriber.d.ts +92 -0
  140. package/dist/router-subscriber.js +44 -0
  141. package/dist/runtime/anchor-types.d.ts +5 -0
  142. package/dist/runtime/anchor-types.js +1 -0
  143. package/dist/runtime/authority-store.d.ts +31 -0
  144. package/dist/runtime/authority-store.js +56 -0
  145. package/dist/runtime/boot.d.ts +52 -0
  146. package/dist/runtime/boot.js +379 -0
  147. package/dist/runtime/content-refresh.d.ts +30 -0
  148. package/dist/runtime/content-refresh.js +68 -0
  149. package/dist/runtime/emit-runtime-error.d.ts +51 -0
  150. package/dist/runtime/emit-runtime-error.js +64 -0
  151. package/dist/runtime/field-proxy.d.ts +112 -0
  152. package/dist/runtime/field-proxy.js +471 -0
  153. package/dist/runtime/form-contract-reporter.d.ts +99 -0
  154. package/dist/runtime/form-contract-reporter.js +391 -0
  155. package/dist/runtime/invalidation-adapter.d.ts +17 -0
  156. package/dist/runtime/invalidation-adapter.js +42 -0
  157. package/dist/runtime/live-query-overlay.d.ts +39 -0
  158. package/dist/runtime/live-query-overlay.js +345 -0
  159. package/dist/runtime/momentary-navigate.d.ts +16 -0
  160. package/dist/runtime/momentary-navigate.js +106 -0
  161. package/dist/runtime/observation-scheduler.d.ts +15 -0
  162. package/dist/runtime/observation-scheduler.js +42 -0
  163. package/dist/runtime/perf-metrics.d.ts +28 -0
  164. package/dist/runtime/perf-metrics.js +90 -0
  165. package/dist/runtime/preview-interaction-policy.d.ts +1 -0
  166. package/dist/runtime/preview-interaction-policy.js +103 -0
  167. package/dist/runtime/preview-overlay-painter.d.ts +27 -0
  168. package/dist/runtime/preview-overlay-painter.js +1732 -0
  169. package/dist/runtime/preview-overlay-sidecar.d.ts +26 -0
  170. package/dist/runtime/preview-overlay-sidecar.js +45 -0
  171. package/dist/runtime/preview-perspective-alignment.d.ts +15 -0
  172. package/dist/runtime/preview-perspective-alignment.js +40 -0
  173. package/dist/runtime/preview-perspective-intent-state.d.ts +23 -0
  174. package/dist/runtime/preview-perspective-intent-state.js +5 -0
  175. package/dist/runtime/preview-transition-state.d.ts +142 -0
  176. package/dist/runtime/preview-transition-state.js +257 -0
  177. package/dist/runtime/render-mode-state.d.ts +51 -0
  178. package/dist/runtime/render-mode-state.js +76 -0
  179. package/dist/runtime/request-id.d.ts +4 -0
  180. package/dist/runtime/request-id.js +8 -0
  181. package/dist/runtime/resolve-schema-field.d.ts +99 -0
  182. package/dist/runtime/resolve-schema-field.js +356 -0
  183. package/dist/runtime/runtime-error-dispatch.d.ts +23 -0
  184. package/dist/runtime/runtime-error-dispatch.js +75 -0
  185. package/dist/runtime/schema-store.d.ts +121 -0
  186. package/dist/runtime/schema-store.js +667 -0
  187. package/dist/runtime/snapshot-assembly.d.ts +104 -0
  188. package/dist/runtime/snapshot-assembly.js +553 -0
  189. package/dist/runtime/snapshot-reporter.d.ts +55 -0
  190. package/dist/runtime/snapshot-reporter.js +375 -0
  191. package/dist/runtime/standalone-overlay-controller.d.ts +33 -0
  192. package/dist/runtime/standalone-overlay-controller.js +281 -0
  193. package/dist/runtime/store.d.ts +307 -0
  194. package/dist/runtime/store.js +1026 -0
  195. package/dist/runtime/windowed-minimap-projection.d.ts +28 -0
  196. package/dist/runtime/windowed-minimap-projection.js +189 -0
  197. package/dist/runtime/workspace-shortcuts.d.ts +30 -0
  198. package/dist/runtime/workspace-shortcuts.js +188 -0
  199. package/dist/sdk-error-copy.d.ts +48 -0
  200. package/dist/sdk-error-copy.js +182 -0
  201. package/dist/select-cursor.d.ts +2 -0
  202. package/dist/select-cursor.js +23 -0
  203. package/dist/server/admission-cookie.d.ts +38 -0
  204. package/dist/server/admission-cookie.js +122 -0
  205. package/dist/server/control-client.d.ts +29 -0
  206. package/dist/server/control-client.js +22 -0
  207. package/dist/server/control-errors.d.ts +22 -0
  208. package/dist/server/control-errors.js +182 -0
  209. package/dist/server/draft-route.d.ts +12 -0
  210. package/dist/server/draft-route.js +45 -0
  211. package/dist/server/extract-token.d.ts +30 -0
  212. package/dist/server/extract-token.js +98 -0
  213. package/dist/server/grant.d.ts +128 -0
  214. package/dist/server/grant.js +395 -0
  215. package/dist/server/ordinary-read-provenance.d.ts +11 -0
  216. package/dist/server/ordinary-read-provenance.js +124 -0
  217. package/dist/server/preview-read-metadata.d.ts +10 -0
  218. package/dist/server/preview-read-metadata.js +27 -0
  219. package/dist/server/provenance-frame-builder.d.ts +53 -0
  220. package/dist/server/provenance-frame-builder.js +102 -0
  221. package/dist/server/provenance-runtime.d.ts +70 -0
  222. package/dist/server/provenance-runtime.js +46 -0
  223. package/dist/server/read-context-command.d.ts +11 -0
  224. package/dist/server/read-context-command.js +53 -0
  225. package/dist/server/read-identity.d.ts +3 -0
  226. package/dist/server/read-identity.js +63 -0
  227. package/dist/server/read-lifecycle.d.ts +17 -0
  228. package/dist/server/read-lifecycle.js +52 -0
  229. package/dist/server/render-frame-provenance.d.ts +133 -0
  230. package/dist/server/render-frame-provenance.js +676 -0
  231. package/dist/server/render-id.d.ts +15 -0
  232. package/dist/server/render-id.js +22 -0
  233. package/dist/server/route-document-provenance.d.ts +77 -0
  234. package/dist/server/route-document-provenance.js +1327 -0
  235. package/dist/server/route-session-cookie.d.ts +33 -0
  236. package/dist/server/route-session-cookie.js +54 -0
  237. package/dist/session-projections.d.ts +33 -0
  238. package/dist/session-projections.js +43 -0
  239. package/dist/session-subscriber.d.ts +124 -0
  240. package/dist/session-subscriber.js +79 -0
  241. package/dist/sha256-fallback.d.ts +30 -0
  242. package/dist/sha256-fallback.js +126 -0
  243. package/dist/types.d.ts +446 -0
  244. package/dist/types.js +85 -0
  245. package/dist/validators.d.ts +61 -0
  246. package/dist/validators.js +110 -0
  247. package/package.json +210 -3
@@ -0,0 +1,446 @@
1
+ /**
2
+ * Storystick Studio ↔ Preview iframe — postMessage protocol types.
3
+ *
4
+ * Authoritative reference for the protocol defined in
5
+ * storystick-hq/spec/preview-system.md §"Communication Protocol"
6
+ * storystick-hq/architecture/decisions/059-studio-shell-redesign.md §6
7
+ * storystick-hq/architecture/decisions/065-field-level-navigation-primitive.md §3.7
8
+ *
9
+ * Two orthogonal axes carried by the protocol itself:
10
+ *
11
+ * render-mode : 'navigation' | 'device'
12
+ * Controls iframe internal viewport (1280px vs device width),
13
+ * scale transform, pointer-events, and where overlays render
14
+ * (parent DOM vs in-iframe).
15
+ *
16
+ * overlay-mode : 'section' | 'field'
17
+ * Controls overlay granularity (slice boundary vs individual
18
+ * field). Independent of render-mode — pairings are defaults,
19
+ * not constraints.
20
+ *
21
+ * Click handling is NOT in this protocol — by design. ADR-065 owns the
22
+ * cross-frame navigation entry point. A child iframe posts the canonical
23
+ * `{ action: 'navigate', verb, value, from }` message exported from
24
+ * `@storystick/preview`. The Studio's field-navigation listener routes that
25
+ * target through the shared arrival service. PR2' does not duplicate it.
26
+ *
27
+ * Versioning convention
28
+ * ---------------------
29
+ * The protocol is a flat discriminated union on `type`. New
30
+ * variants extend the union; existing variants are never mutated.
31
+ * If a wire-level break is ever required, introduce a new top-level
32
+ * variant (e.g. `type: 'v2-section-bounds'`) rather than versioning
33
+ * the envelope. This keeps the runtime check trivially exhaustive
34
+ * via TypeScript's `never` narrowing.
35
+ */
36
+ export type RenderMode = 'navigation' | 'device';
37
+ export type OverlayMode = 'section' | 'field';
38
+ /** Switch the iframe's render configuration. */
39
+ export interface MsgRenderMode {
40
+ type: 'render-mode';
41
+ mode: RenderMode;
42
+ /**
43
+ * ADR-119 D1/D3 — the Studio controller's instance-scoped
44
+ * generation counter. The SDK echoes it back verbatim on every
45
+ * `storystick.preview.form-contract` report so the controller can
46
+ * discard stale cross-doc async measurements soundly (the
47
+ * ratchet-class guard). Optional for legacy senders / tests; the
48
+ * SDK treats an absent epoch as `0`.
49
+ */
50
+ epoch?: number;
51
+ /**
52
+ * Experimental Studio-owned minimap projection. The customer keeps a
53
+ * regular 1440×900 viewport while the SDK temporarily compresses a bounded
54
+ * document window for Navigation paint. Absent/false preserves the existing
55
+ * Form contract and remains compatible with older Studio senders.
56
+ */
57
+ windowedMinimapProjection?: boolean;
58
+ /**
59
+ * Experimental provenance lifecycle mirror. This is distinct from
60
+ * `epoch`: `epoch` remains the ADR-119 viewport/snapshot ratchet,
61
+ * while `previewLifecycle` mirrors the Preview transition identity
62
+ * owned by Studio/ADR-143. Framework SDKs only echo/observe it.
63
+ */
64
+ previewLifecycle?: {
65
+ readonly generation: number;
66
+ readonly sourceOfTruth: 'studio' | 'iframe' | 'system';
67
+ readonly commandId?: string | null;
68
+ };
69
+ }
70
+ export type StudioToIframe = MsgRenderMode | {
71
+ type: 'storystick.preview.windowed-minimap';
72
+ epoch: number;
73
+ windowStart: number;
74
+ renderSpan: number;
75
+ } | {
76
+ type: 'overlay-mode';
77
+ mode: OverlayMode;
78
+ } | {
79
+ type: 'highlight';
80
+ path: string;
81
+ } | {
82
+ type: 'scroll';
83
+ section: number;
84
+ } | {
85
+ type: 'device-width';
86
+ width: number;
87
+ } | {
88
+ type: 'storystick.preview.host-resize';
89
+ active: boolean;
90
+ };
91
+ /**
92
+ * Section bounding rects — emitted in Navigation mode by the
93
+ * `section-reporter` v2 runtime (ADR-112 D11). The observer
94
+ * triptyque (IntersectionObserver auxiliary + ResizeObserver +
95
+ * MutationObserver + `document.fonts.ready`) feeds a single rAF
96
+ * tick that publishes the full set.
97
+ *
98
+ * Coordinate space (ADR-112 D11b) — **document coordinates**, NOT
99
+ * viewport coordinates. `documentRect.{x,y}` is
100
+ * `getBoundingClientRect().{x,y} + window.scroll{X,Y}`, so the
101
+ * value is invariant under user scroll. Studio projects to its
102
+ * own visual pixels via
103
+ * `apps/studio/src/lib/preview-imperative-bridge.ts ::
104
+ * projectDocumentRectToStudio(documentRect, scrollTop, scrollLeft,
105
+ * scale)` — a non-optional `* scale` multiplication, since the
106
+ * iframe renders at logical CSS pixels and Studio displays a
107
+ * scaled mini-map.
108
+ *
109
+ * Wire-level rename (ADR-112 C4): field `rect` → `documentRect`.
110
+ * The break is intentional and loud — TypeScript fails compile on
111
+ * every legacy call site that wasn't migrated atomically.
112
+ *
113
+ * `DOMRect` does not survive structured-clone over postMessage in
114
+ * older browsers (Safari < 16). The SDK emits a plain
115
+ * `{ x, y, width, height }` shape that is structurally compatible
116
+ * with DOMRectReadOnly but JSON-safe.
117
+ */
118
+ export interface SectionRect {
119
+ index: number;
120
+ documentRect: {
121
+ x: number;
122
+ y: number;
123
+ width: number;
124
+ height: number;
125
+ };
126
+ }
127
+ /**
128
+ * ADR-125 D2/D3 (PR2) — a single annotated field's bounding rect. `path`
129
+ * is the walker-canonical field path (ADR-068 grammar) read off the
130
+ * element's `data-ss-field`, relative to its nearest `data-ss-doc`
131
+ * scope; `docId` is that scope (the originating document — propagated
132
+ * across resolved refs by the Proxy, so a click on a cross-doc fragment
133
+ * resolves to the right document). Same coordinate contract as
134
+ * `SectionRect` (document-relative, scroll-invariant).
135
+ */
136
+ export interface FieldRect {
137
+ path: string;
138
+ docId: string | null;
139
+ documentRect: {
140
+ x: number;
141
+ y: number;
142
+ width: number;
143
+ height: number;
144
+ };
145
+ }
146
+ /**
147
+ * ADR-125 D2/D3 (PR2) — field-level bounding rects, emitted by the
148
+ * section-reporter v2 runtime in the SAME rAF-coalesced pass as
149
+ * `section-bounds` (ONE pipeline — not a forked one: same observer
150
+ * triptyque, same schedule, same `epoch` echo). The parent feeds this
151
+ * through the SAME generic D7 settle core + the SAME bounded fail-safe
152
+ * clock as section-bounds, keyed by the SAME ADR-119 controller
153
+ * generation. Sibling message (not a field added to `section-bounds`)
154
+ * purely so the section path PR1b shipped + cross-model-reviewed is
155
+ * byte-unchanged; the shared machinery is the anti-fork requirement,
156
+ * and it is shared.
157
+ */
158
+ export interface MsgFieldBounds {
159
+ type: 'field-bounds';
160
+ /** Always `'document'` — identical posture + rationale as the
161
+ * `section-bounds` coordinate space. */
162
+ coordinateSpace: 'document';
163
+ fields: FieldRect[];
164
+ /** The `MsgRenderMode.epoch` last sent, echoed by the other geometry
165
+ * and form-contract messages (ADR-125 D7
166
+ * ratchet — a report whose epoch ≠ the live generation is
167
+ * discarded). */
168
+ epoch: number;
169
+ }
170
+ /** User completed a section drag-and-drop. */
171
+ export interface MsgDragEnd {
172
+ type: 'drag-end';
173
+ from: number;
174
+ to: number;
175
+ }
176
+ /**
177
+ * ADR-131 §D8.1 — canonical `CoverageTier` tagged union. Single source
178
+ * of truth for "what does this field's coverage look like" surfaced to
179
+ * the Coverage Panel + Studio overlay paint projection (§D8.4).
180
+ *
181
+ * Bound tiers (`explicit`, `observed`) PAINT overlays. `unsupported`
182
+ * records an annotation-model gap; `pending` and `stale` remain generic
183
+ * ambient states for the future Coverage Panel (zero producer today).
184
+ *
185
+ * Owner decision, 2026-08-10: the measurement vocabulary was retired.
186
+ * Field identity is authored by SDK annotations, never inferred from DOM
187
+ * output. Adding a new annotation tier is additive; reintroducing a
188
+ * measurement tier requires an explicit owner decision.
189
+ */
190
+ export type CoverageTier = {
191
+ kind: 'explicit';
192
+ } | {
193
+ kind: 'observed';
194
+ } | {
195
+ kind: 'unsupported';
196
+ reason: 'no-annotation-carrier' | 'annotation-not-forwarded' | 'non-dom-output';
197
+ } | {
198
+ kind: 'pending';
199
+ since: number;
200
+ } | {
201
+ kind: 'stale';
202
+ };
203
+ /**
204
+ * ADR-129 — one item in the atomic preview snapshot. `method` carries
205
+ * the live authored (`explicit`) and provenance (`observed`) paths;
206
+ * `tier` carries their coverage semantics. ADR-138 §5.5 + ADR-139 §2.5
207
+ * extend the wire further with the anchor-typed fields below
208
+ * (`anchorKind`, `anchorKey`, `anchoredPath`),
209
+ * additive optional in v1 ; producers (ADR-140 walker) populate them
210
+ * as the cache-write layer lands. `method` records WHICH RESOLVER
211
+ * PRIORITY SLOT produced this item (provenance signal for the
212
+ * preview-surface gate); `tier` records the COVERAGE SEMANTICS surfaced
213
+ * to the panel + the paint projection at §D8.4. The two unions are NOT
214
+ * congruent (panel-only states have no `method`); both ship.
215
+ *
216
+ * Identity is `(documentId, anchored-canonical-path)` — D1. `path` is
217
+ * the numeric canonical path; `fromAnchors` carries the `_key` of each
218
+ * keyed array hop so the Studio resolver's `substituteAnchors` consumes
219
+ * it with no grammar change (ADR-066 transport shape).
220
+ */
221
+ export interface SnapshotItem {
222
+ kind: 'slice' | 'field';
223
+ /**
224
+ * ADR-142 P0/P1 — iframe-produced sidecar lookup key for in-iframe
225
+ * Preview field painting. Opaque to Studio. This is NOT the Studio
226
+ * paint generation key; Studio mints `paintKey` when it sends an
227
+ * approved overlay-map back to the iframe.
228
+ */
229
+ snapshotItemKey?: string;
230
+ /**
231
+ * Resolver-provenance signal (ADR-131 §D6.1):
232
+ * - `'explicit'` — Layer 3 `data-ss-bind` attribute (was `'binding'`).
233
+ * - `'observed'` — live coded-text provenance owner-map producer.
234
+ */
235
+ method: 'explicit' | 'observed';
236
+ /**
237
+ * Field-ownership / routing identity (ADR-139 §2.5). The doc the
238
+ * Studio click route opens. For Tier-1 explicit `<edit.* doc="X">`
239
+ * this is the customer-declared owner ; for cross-doc observed entries
240
+ * it may differ from the host page's doc.
241
+ */
242
+ documentId: string;
243
+ /**
244
+ * The `_key` of the owning slice (the snapshot↔island join key).
245
+ * PRESENT when `anchorKind === 'slice'` or absent (`'slice'`-by-
246
+ * construction items always set this) ; OMITTED when
247
+ * `anchorKind === 'doc'` or `'document-root'` per ADR-138 §5.5.
248
+ *
249
+ * The walker (ADR-140 §2.8) drives the optionality : for cross-doc /
250
+ * chrome items whose anchor is a `[data-ss-doc]` marker or the
251
+ * document root, there is no slice key, so emitting the empty string
252
+ * would mis-key downstream consumers ; emitting `undefined` makes
253
+ * the absence syntactic.
254
+ */
255
+ sliceKey?: string;
256
+ /** Numeric canonical path — `sections[0]` (slice) | `sections[0].headline` (field). */
257
+ path: string;
258
+ /** ADR-066 keyed-hop anchors for `path` (the slice `_key` hop). */
259
+ fromAnchors: ReadonlyArray<{
260
+ pathPrefix: string;
261
+ key: string;
262
+ }>;
263
+ /**
264
+ * Optional mounted Studio navigation path. C4 nested zone-container
265
+ * overlays keep `path` as the visual ancestry (`sections[0].sidebar[1]`)
266
+ * while Studio mounts the widget at the mapped document field
267
+ * (`sidebar[1]`). When omitted, `path` is already routable.
268
+ */
269
+ navigationPath?: string;
270
+ /** Keyed-hop anchors for `navigationPath`; omitted when `path` is routable. */
271
+ navigationAnchors?: ReadonlyArray<{
272
+ pathPrefix: string;
273
+ key: string;
274
+ }>;
275
+ /** Schema-relative field path; `''` for a `slice` item. */
276
+ field: string;
277
+ /** Document-space rect (`getBoundingClientRect` + scroll) — scroll-invariant. */
278
+ documentRect: {
279
+ x: number;
280
+ y: number;
281
+ width: number;
282
+ height: number;
283
+ };
284
+ /**
285
+ * ADR-131 §D6.5 — canonical coverage tier surfaced to the Coverage
286
+ * Panel + the §D8.4 `tierToVisualStyle(tier, devModeFlag)` paint
287
+ * projection. `method` (above) is the resolver-provenance signal;
288
+ * this is the coverage semantics. Both ship on the wire.
289
+ */
290
+ tier: CoverageTier;
291
+ /**
292
+ * ADR-138 §5.3 + ADR-139 §2.5 — DOM-marker / paint-identity discriminator.
293
+ * When set, narrows how the resolver locates the anchor element:
294
+ * - `'slice'` — DOM lookup via `[data-ss-slice="<anchorKey>"]` ;
295
+ * `anchorKey` is the slice `_key`.
296
+ * - `'doc'` — DOM lookup via `[data-ss-doc="<anchorKey>"]` ;
297
+ * `anchorKey` is the doc id of the host marker.
298
+ * ADR-139 §2.5 relaxes the §2.6 invariant
299
+ * `anchorKey === documentId` ; `anchorKey` is
300
+ * orthogonal to `documentId` (the latter remains
301
+ * field-ownership / routing identity).
302
+ * - `'document-root'` — DOM lookup via `document.body` ; `anchorKey` is
303
+ * the empty string per ADR-138 §2 table.
304
+ *
305
+ * Additive optional in v1 — pre-138 items omit it ; v2+ producers
306
+ * (ADR-140 walker) populate.
307
+ */
308
+ anchorKind?: 'slice' | 'doc' | 'document-root';
309
+ /**
310
+ * DOM-marker key per `anchorKind` (see above). When `anchorKind ===
311
+ * 'document-root'` the value is the empty string (the unique
312
+ * `<body>` is implicit). When `anchorKind === 'doc'` the value lives
313
+ * in the Studio-authoritative document set per ADR-139 §2.3 (the
314
+ * gate validates membership). Additive optional in v1.
315
+ */
316
+ anchorKey?: string;
317
+ /**
318
+ * ADR-138 §5.5 — anchored path relative to the anchor element. The
319
+ * resolver walks from the anchor element along this path during the
320
+ * per-rAF DOM scan (ADR-140 territory). Additive optional in v1.
321
+ */
322
+ anchoredPath?: string | null;
323
+ }
324
+ /**
325
+ * ADR-129 D6 — the ATOMIC preview snapshot. One message per render
326
+ * carries everything the Studio overlay layer needs: the controller
327
+ * `epoch` (echoed from `MsgRenderMode`), the customer-side `renderId`
328
+ * (from the model island), the `pageDocId` the iframe is showing, the
329
+ * set of documentIds present, and every overlay `item`. `codeVersion`
330
+ * carries the upstream build signature and `timestamp` records the
331
+ * producing rAF tick.
332
+ */
333
+ export interface MsgPreviewSnapshot {
334
+ type: 'storystick.preview.snapshot';
335
+ epoch: number;
336
+ renderId: string;
337
+ pageDocId: string;
338
+ /**
339
+ * Optional forward-capability bitmap. Studio must not send newer
340
+ * overlay-map item keys back to runtimes that did not explicitly
341
+ * advertise support for them because older SDK validators reject
342
+ * unknown keys with a strict allowlist.
343
+ */
344
+ capabilities?: {
345
+ crossDocumentOverlayLabels?: true;
346
+ };
347
+ /**
348
+ * ADR-139 §2.1 + §5 — formerly `visibleDocumentIds`, renamed at the
349
+ * wire level (codex R2 P1#3 absorbed at the ADR layer). The field is
350
+ * NEVER consulted by the Studio anti-bleed gate ; ADR-139 ships a
351
+ * Studio-side `authoritativeSet` derivation (`useAuthoritativeDocSet`)
352
+ * that composes membership from four trusted sources (commandedDoc +
353
+ * Studio-side chrome enumeration + Studio-side page-closure walker +
354
+ * SDK transport tap via `previewSessions.knownDocuments`). The
355
+ * iframe-declared set survives only as a debug hint surfaced to the
356
+ * Coverage Panel + harness — the rename makes the non-authoritative
357
+ * role syntactic ; a future producer cannot accidentally consult it
358
+ * for a trust decision because the name itself denies it. Pre-launch
359
+ * posture per the monorepo CLAUDE.md "no legacy support" rule —
360
+ * pre-rename `visibleDocumentIds` is removed entirely (no deprecation
361
+ * period).
362
+ */
363
+ iframeDeclaredDocumentIdsDebugHint: string[];
364
+ items: SnapshotItem[];
365
+ /**
366
+ * ADR-131 §D7.1a — upstream build/schema/config signature the iframe
367
+ * was hydrated with. Studio controller compares
368
+ * `snapshot.codeVersion !== controller.codeVersion` to detect a
369
+ * customer redeploy mid-stream (§D5.7).
370
+ */
371
+ codeVersion: string;
372
+ /**
373
+ * ADR-131 §D3.2 — Unix millis (Date.now()) at the rAF tick that
374
+ * produced this snapshot. The iframe correlation-window sampler
375
+ * subtracts the `T_edit` postMessage receipt timestamp to feed the
376
+ * EMA-based adaptive correlation window.
377
+ */
378
+ timestamp: number;
379
+ /**
380
+ * ADR-131 amendment-003 + ADR-139 §5.5 — SHA-256 hex of the live
381
+ * customer `routeUrl` the iframe is rendering against (post-redirect,
382
+ * NOT the bootstrap URL). Iframe-side `computeRouteHash` is the
383
+ * authoritative producer ; the Studio reads this verbatim and threads
384
+ * it into `useAuthoritativeDocSet` (which feeds
385
+ * `previewSessions.knownDocuments`). The Studio MUST NOT recompute
386
+ * from its own `effectiveSrc` (the iframe `src` attribute), which
387
+ * during the normal boot flow points at the preview-route bootstrap
388
+ * (`/api/storystick/preview?...redirect=...`) ; hashing the bootstrap
389
+ * URL would key a different `(sessionId, routeHash, codeVersion)`
390
+ * row than the SDK transport-tap wrote, and the gate would silently
391
+ * drop legitimate cross-doc overlays (codex R1 P1#2 absorbed).
392
+ *
393
+ * Optional in v1 because pre-amendment-003 runtimes never produced
394
+ * the field ; an absent value forces the Studio hook to pass `'skip'`
395
+ * to `knownDocuments`. The Studio treats `undefined` / `''` /
396
+ * pre-emit as "no SDK-tap data yet" (correct degradation : the gate
397
+ * doesn't paint cross-doc overlays until the iframe has a real route
398
+ * hash to report).
399
+ */
400
+ routeHash?: string;
401
+ /**
402
+ * Live customer URL the iframe is rendering against (post-redirect,
403
+ * NOT the Studio iframe `src` bootstrap URL). Studio uses this as
404
+ * debug context and to keep route-scoped document observations aligned.
405
+ */
406
+ routeUrl?: string;
407
+ }
408
+ export type IframeToStudio = {
409
+ type: 'ready';
410
+ } | {
411
+ type: 'section-bounds';
412
+ coordinateSpace: 'document';
413
+ sections: SectionRect[];
414
+ epoch: number;
415
+ } | MsgFieldBounds | {
416
+ type: 'section-hover';
417
+ index: number | null;
418
+ } | {
419
+ type: 'sections';
420
+ data: unknown[];
421
+ } | MsgDragEnd | {
422
+ type: 'add-section';
423
+ index: number;
424
+ } | {
425
+ type: 'storystick.preview.form-contract';
426
+ epoch: number;
427
+ applied: boolean;
428
+ pageHeight: number;
429
+ viewportHeight: number;
430
+ windowedProjection?: 'pending' | 'active' | 'unsupported';
431
+ windowedProjectionReason?: string;
432
+ windowStart?: number;
433
+ renderSpan?: number;
434
+ compression?: number;
435
+ } | MsgPreviewSnapshot;
436
+ /**
437
+ * Best-effort runtime guard for messages the iframe sends to the
438
+ * Studio. Used by the bridge to ignore unrelated postMessage events
439
+ * (extensions, devtools, third-party scripts) without throwing.
440
+ *
441
+ * The discriminator (`type` string) is the only thing we trust — we
442
+ * narrow with the union after this guard.
443
+ */
444
+ export declare function isIframeToStudio(value: unknown): value is IframeToStudio;
445
+ /** Mirror guard for Studio → iframe (used iframe-side). */
446
+ export declare function isStudioToIframe(value: unknown): value is StudioToIframe;
package/dist/types.js ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Storystick Studio ↔ Preview iframe — postMessage protocol types.
3
+ *
4
+ * Authoritative reference for the protocol defined in
5
+ * storystick-hq/spec/preview-system.md §"Communication Protocol"
6
+ * storystick-hq/architecture/decisions/059-studio-shell-redesign.md §6
7
+ * storystick-hq/architecture/decisions/065-field-level-navigation-primitive.md §3.7
8
+ *
9
+ * Two orthogonal axes carried by the protocol itself:
10
+ *
11
+ * render-mode : 'navigation' | 'device'
12
+ * Controls iframe internal viewport (1280px vs device width),
13
+ * scale transform, pointer-events, and where overlays render
14
+ * (parent DOM vs in-iframe).
15
+ *
16
+ * overlay-mode : 'section' | 'field'
17
+ * Controls overlay granularity (slice boundary vs individual
18
+ * field). Independent of render-mode — pairings are defaults,
19
+ * not constraints.
20
+ *
21
+ * Click handling is NOT in this protocol — by design. ADR-065 owns the
22
+ * cross-frame navigation entry point. A child iframe posts the canonical
23
+ * `{ action: 'navigate', verb, value, from }` message exported from
24
+ * `@storystick/preview`. The Studio's field-navigation listener routes that
25
+ * target through the shared arrival service. PR2' does not duplicate it.
26
+ *
27
+ * Versioning convention
28
+ * ---------------------
29
+ * The protocol is a flat discriminated union on `type`. New
30
+ * variants extend the union; existing variants are never mutated.
31
+ * If a wire-level break is ever required, introduce a new top-level
32
+ * variant (e.g. `type: 'v2-section-bounds'`) rather than versioning
33
+ * the envelope. This keeps the runtime check trivially exhaustive
34
+ * via TypeScript's `never` narrowing.
35
+ */
36
+ // ─── Type guards ─────────────────────────────────────────
37
+ /**
38
+ * Best-effort runtime guard for messages the iframe sends to the
39
+ * Studio. Used by the bridge to ignore unrelated postMessage events
40
+ * (extensions, devtools, third-party scripts) without throwing.
41
+ *
42
+ * The discriminator (`type` string) is the only thing we trust — we
43
+ * narrow with the union after this guard.
44
+ */
45
+ export function isIframeToStudio(value) {
46
+ if (!value || typeof value !== 'object')
47
+ return false;
48
+ const v = value;
49
+ if (typeof v.type !== 'string')
50
+ return false;
51
+ switch (v.type) {
52
+ case 'ready':
53
+ case 'section-bounds':
54
+ case 'field-bounds':
55
+ case 'section-hover':
56
+ case 'sections':
57
+ case 'drag-end':
58
+ case 'add-section':
59
+ case 'storystick.preview.form-contract':
60
+ case 'storystick.preview.snapshot':
61
+ return true;
62
+ default:
63
+ return false;
64
+ }
65
+ }
66
+ /** Mirror guard for Studio → iframe (used iframe-side). */
67
+ export function isStudioToIframe(value) {
68
+ if (!value || typeof value !== 'object')
69
+ return false;
70
+ const v = value;
71
+ if (typeof v.type !== 'string')
72
+ return false;
73
+ switch (v.type) {
74
+ case 'render-mode':
75
+ case 'storystick.preview.windowed-minimap':
76
+ case 'overlay-mode':
77
+ case 'highlight':
78
+ case 'scroll':
79
+ case 'device-width':
80
+ case 'storystick.preview.host-resize':
81
+ return true;
82
+ default:
83
+ return false;
84
+ }
85
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Iframe-side preview-envelope validators (ADR-087 §3.2).
3
+ *
4
+ * Thin wrapper around `validatePreviewEnvelope` from
5
+ * `@storystick/transport-allowlist` (the foundation Lane C shipped).
6
+ * Adds the iframe-side context checks the foundation deliberately left out:
7
+ *
8
+ * - `sessionId` and `projectId` match the iframe's known values
9
+ * (they should never change mid-session).
10
+ * - `event.origin === parentOrigin` once the parent origin is
11
+ * learned (see "learn-and-lock" comment below).
12
+ *
13
+ * The foundation validator owns structure + anti-replay base
14
+ * (`MAX_ENVELOPE_AGE_MS`) + normative error wording. This module owns
15
+ * everything that needs *iframe context*: identity and the locked parent
16
+ * origin.
17
+ *
18
+ * Returning a discriminated `{ ok, ... }` keeps the call-site clean —
19
+ * the consumer handles `ok: false` by either ignoring the message
20
+ * (stale / mis-correlated) or transitioning to `error` (auth failed).
21
+ */
22
+ import { type NavigateEnvelope, type PreviewOverlayClearEnvelope, type PreviewOverlayMapEnvelope, type PreviewV2RevealSourceEnvelope } from '@storystick/transport-allowlist';
23
+ /**
24
+ * Reasons a context-aware validation can fail. Strings are stable —
25
+ * the state machine + tests grep on them. They surface only in
26
+ * iframe-internal logs; NEVER over the postMessage wire (the iframe
27
+ * → parent direction silent on rejections).
28
+ */
29
+ export type ValidationFailure = 'envelope-invalid' | 'wrong-message-type' | 'origin-mismatch' | 'session-id-mismatch' | 'project-id-mismatch';
30
+ export type ValidationResult<T> = {
31
+ ok: true;
32
+ envelope: T;
33
+ } | {
34
+ ok: false;
35
+ reason: ValidationFailure;
36
+ };
37
+ /**
38
+ * Validate an incoming `navigate` envelope against the locked parent
39
+ * origin and the iframe's known sessionId / projectId. Navigate
40
+ * messages are unsolicited (no pending request to correlate against)
41
+ * — we only check origin lock + identity binding.
42
+ *
43
+ * **Pre-lock policy (codex Lane D round 1 P1 fix)** : `parentOrigin
44
+ * === null` means the iframe has not yet locked Studio's origin.
45
+ * Navigate messages received in that window are rejected
46
+ * unconditionally (`origin-mismatch`). Without this, any same-host
47
+ * script with a valid envelope shape could drive `history.pushState`
48
+ * on the iframe before the legitimate Studio handshake finishes.
49
+ * The identity broadcast is the only origin-learning path; navigation MUST
50
+ * wait for that lock.
51
+ */
52
+ export declare function validateNavigate(raw: unknown, eventOrigin: string, knownSessionId: string, knownProjectId: string, parentOrigin: string | null, now?: number): ValidationResult<NavigateEnvelope>;
53
+ export declare function validateOverlayMap(raw: unknown, eventOrigin: string, knownSessionId: string, knownProjectId: string, parentOrigin: string | null, now?: number): ValidationResult<PreviewOverlayMapEnvelope>;
54
+ export declare function validateOverlayClear(raw: unknown, eventOrigin: string, knownSessionId: string, knownProjectId: string, parentOrigin: string | null, now?: number): ValidationResult<PreviewOverlayClearEnvelope>;
55
+ export declare function validatePreviewV2RevealSource(raw: unknown, eventOrigin: string, knownSessionId: string, knownProjectId: string, parentOrigin: string | null, now?: number): ValidationResult<PreviewV2RevealSourceEnvelope>;
56
+ /**
57
+ * Re-export so consumers can import the foundation types from one
58
+ * place. Keeping the wrapper module the surface helps grepping for
59
+ * preview-envelope usage during audits.
60
+ */
61
+ export type { NavigateEnvelope, PreviewOverlayClearEnvelope, PreviewOverlayMapEnvelope, };