@kumwe/studio-preview 0.1.0-alpha.2
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 +21 -0
- package/README.md +54 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/preview-client.d.ts +75 -0
- package/dist/preview-client.d.ts.map +1 -0
- package/dist/preview-client.js +393 -0
- package/dist/preview-client.js.map +1 -0
- package/dist/preview-host.d.ts +54 -0
- package/dist/preview-host.d.ts.map +1 -0
- package/dist/preview-host.js +330 -0
- package/dist/preview-host.js.map +1 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kumwe Studio contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# `@kumwe/studio-preview`
|
|
2
|
+
|
|
3
|
+
Status: pre-Gate-A foundation alpha. The channel is an executable contract spike, not a qualified adapter.
|
|
4
|
+
|
|
5
|
+
An exact-origin, typed request channel between Studio and a host-rendered preview surface. A host can
|
|
6
|
+
render Twig, Liquid, JSX, or another server template without teaching the canvas to reproduce its
|
|
7
|
+
markup. Wildcard target origins are rejected.
|
|
8
|
+
|
|
9
|
+
The channel handles correlation, timeouts, abort signals, protocol filtering, and disposal. The host
|
|
10
|
+
still owns authentication, authorization, CSP, sandboxing, and rendering.
|
|
11
|
+
|
|
12
|
+
## Host responder and handshake
|
|
13
|
+
|
|
14
|
+
`PreviewClient` is the Studio half of the channel; `PreviewHost` is the preview-surface half. Both
|
|
15
|
+
pin an exact target origin and drop any inbound message whose source window, origin, schema, channel
|
|
16
|
+
ID, session generation, or sequence does not match; each direction stamps its own monotonic sequence
|
|
17
|
+
counter.
|
|
18
|
+
|
|
19
|
+
The handshake and request flow is announce → ready → render → rendered:
|
|
20
|
+
|
|
21
|
+
1. The host constructs a `PreviewHost` with its renderer id, viewport inventory, and a render
|
|
22
|
+
callback, then calls `announce()` to post `studio.preview/ready`.
|
|
23
|
+
2. Studio awaits `client.ready()`, which resolves with the announced payload — immediately when the
|
|
24
|
+
announcement already arrived — and rejects on timeout, abort, or disposal.
|
|
25
|
+
3. Studio requests `studio.preview/render` via `client.render()`. The host invokes its render
|
|
26
|
+
callback and replies with `studio.preview/rendered` carrying the same draft digest as the
|
|
27
|
+
request. A newer request supersedes an in-flight one on both sides, so a stale result is never
|
|
28
|
+
posted or resolved.
|
|
29
|
+
4. A failed render is answered with `studio.preview/error` (code `studio.preview/render-failed`, the
|
|
30
|
+
draft digest as `correlationId`, `retryable: true`) and a generic message — renderer failure
|
|
31
|
+
details never cross the channel.
|
|
32
|
+
5. `client.select()` forwards `studio.preview/select` to the host's `onSelect` listeners.
|
|
33
|
+
|
|
34
|
+
## Marker geometry
|
|
35
|
+
|
|
36
|
+
`client.measure()` posts `studio.preview/measure` with a bounded marker list and resolves with the
|
|
37
|
+
`studio.preview/measurements` answer: per marker, one or more CSS-pixel rectangles relative to the
|
|
38
|
+
preview viewport origin (inline content fragments across lines), plus viewport metrics. Markers the
|
|
39
|
+
renderer cannot place are returned in a distinct `unknown` list, never thrown.
|
|
40
|
+
|
|
41
|
+
The host never reads the DOM. The embedding renderer passes a `measure` callback in
|
|
42
|
+
`PreviewHostOptions`; without one, measure requests are answered with the qualified
|
|
43
|
+
`studio.preview/measure-unavailable` error, and a throwing measurer is answered with
|
|
44
|
+
`studio.preview/measure-failed` — measurer failure details never cross the channel.
|
|
45
|
+
|
|
46
|
+
Geometry is volatile, not document state: each response is stamped with the digest of the render it
|
|
47
|
+
was measured against. A response whose digest no longer matches the client's latest completed render
|
|
48
|
+
resolves as a typed `{ status: 'stale' }` outcome instead of geometry, and a reload voids in-flight
|
|
49
|
+
measurements exactly like it voids renders. Newer measure requests supersede older ones on both
|
|
50
|
+
sides.
|
|
51
|
+
|
|
52
|
+
Version negotiation currently requires the exact draft wire version on both sides: schema filtering
|
|
53
|
+
accepts only `STUDIO_WIRE_PROTOCOL_VERSION`, so a ready announcement from a host speaking any other
|
|
54
|
+
version is discarded and `ready()` times out instead of resolving against an incompatible host.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { PreviewClient, type PreviewClientOptions, type PreviewMeasureOptions, type PreviewMeasureOutcome, type PreviewMessageEvent, type PreviewMessageListener, type PreviewMessageSource, type PreviewMessageTarget, type PreviewProtocolListener, type PreviewReadyOptions, type PreviewRenderOptions, } from './preview-client.js';
|
|
2
|
+
export { PreviewHost, type PreviewHostOptions, type PreviewMeasureCallback, type PreviewMeasurement, type PreviewRenderCallback, type PreviewSelectListener, } from './preview-host.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,GAC3B,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,GAWd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,WAAW,GAMZ,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type PreviewMeasurePayload, type PreviewMeasurementsPayload, type PreviewMessage, type PreviewReadyPayload, type PreviewRenderedPayload, type PreviewRenderPayload, type PreviewSelectPayload, type PreviewTeardownPayload } from '@kumwe/studio-protocol';
|
|
2
|
+
export interface PreviewMessageEvent {
|
|
3
|
+
data: unknown;
|
|
4
|
+
origin: string;
|
|
5
|
+
source: unknown;
|
|
6
|
+
}
|
|
7
|
+
export type PreviewMessageListener = (event: PreviewMessageEvent) => void;
|
|
8
|
+
export interface PreviewMessageSource {
|
|
9
|
+
addEventListener(type: 'message', listener: PreviewMessageListener): void;
|
|
10
|
+
removeEventListener(type: 'message', listener: PreviewMessageListener): void;
|
|
11
|
+
}
|
|
12
|
+
export interface PreviewMessageTarget {
|
|
13
|
+
postMessage(message: unknown, targetOrigin: string): void;
|
|
14
|
+
}
|
|
15
|
+
export interface PreviewClientOptions {
|
|
16
|
+
channelId: string;
|
|
17
|
+
sessionGeneration: string;
|
|
18
|
+
source: PreviewMessageSource;
|
|
19
|
+
target: PreviewMessageTarget;
|
|
20
|
+
targetOrigin: string;
|
|
21
|
+
timeoutMilliseconds?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface PreviewReadyOptions {
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}
|
|
26
|
+
export interface PreviewRenderOptions {
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}
|
|
29
|
+
export interface PreviewMeasureOptions {
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of a `measure()` call. Geometry whose render digest no longer matches the
|
|
34
|
+
* client's latest rendered digest is discarded and surfaced as a `stale` outcome —
|
|
35
|
+
* a typed signal to re-measure, not an error.
|
|
36
|
+
*/
|
|
37
|
+
export type PreviewMeasureOutcome = {
|
|
38
|
+
geometry: PreviewMeasurementsPayload;
|
|
39
|
+
status: 'measured';
|
|
40
|
+
} | {
|
|
41
|
+
measuredDigest: string;
|
|
42
|
+
status: 'stale';
|
|
43
|
+
};
|
|
44
|
+
export type PreviewProtocolListener = (message: PreviewMessage) => void;
|
|
45
|
+
export declare class PreviewClient {
|
|
46
|
+
#private;
|
|
47
|
+
constructor(options: PreviewClientOptions);
|
|
48
|
+
dispose(): void;
|
|
49
|
+
onMessage(listener: PreviewProtocolListener): () => void;
|
|
50
|
+
/**
|
|
51
|
+
* Resolves once the host announces `studio.preview/ready` on this channel. If the
|
|
52
|
+
* announcement was already received, the cached payload resolves immediately.
|
|
53
|
+
*
|
|
54
|
+
* `isPreviewMessage` accepts only ready payloads carrying the exact draft wire protocol
|
|
55
|
+
* version, so an announcement from an incompatible host is filtered out and never resolves
|
|
56
|
+
* this promise — the wait times out instead. The promise also rejects on abort or when the
|
|
57
|
+
* client is disposed.
|
|
58
|
+
*/
|
|
59
|
+
ready(options?: PreviewReadyOptions): Promise<PreviewReadyPayload>;
|
|
60
|
+
render(payload: PreviewRenderPayload, options?: PreviewRenderOptions): Promise<PreviewRenderedPayload>;
|
|
61
|
+
/**
|
|
62
|
+
* Requests the on-screen geometry of render markers from the responder. Resolves with a
|
|
63
|
+
* `measured` outcome carrying viewport-relative CSS-pixel rectangles, or a `stale`
|
|
64
|
+
* outcome when the response was measured against a render this client no longer
|
|
65
|
+
* considers latest. Rejects on teardown, reload, supersession, abort, timeout, and
|
|
66
|
+
* disposal exactly like `render()` does. Requires a completed render: geometry is a
|
|
67
|
+
* volatile measurement of a specific render digest, never document state.
|
|
68
|
+
*/
|
|
69
|
+
measure(payload: PreviewMeasurePayload, options?: PreviewMeasureOptions): Promise<PreviewMeasureOutcome>;
|
|
70
|
+
select(payload: PreviewSelectPayload): void;
|
|
71
|
+
/** Announce channel closure to the host, then dispose this client. */
|
|
72
|
+
teardown(reason: PreviewTeardownPayload['reason']): void;
|
|
73
|
+
}
|
|
74
|
+
export declare function normalizeOrigin(input: string): string;
|
|
75
|
+
//# sourceMappingURL=preview-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-client.d.ts","sourceRoot":"","sources":["../src/preview-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC5B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAE1E,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC1E,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,EAAE,0BAA0B,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC5D;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhD,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;AAuBxE,qBAAa,aAAa;;gBAmBL,OAAO,EAAE,oBAAoB;IAazC,OAAO,IAAI,IAAI;IA2Bf,SAAS,CAAC,QAAQ,EAAE,uBAAuB,GAAG,MAAM,IAAI;IAO/D;;;;;;;;OAQG;IACI,KAAK,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAqCtE,MAAM,CACX,OAAO,EAAE,oBAAoB,EAC7B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,sBAAsB,CAAC;IAiElC;;;;;;;OAOG;IACI,OAAO,CACZ,OAAO,EAAE,qBAAqB,EAC9B,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,qBAAqB,CAAC;IA6D1B,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI;IAqJlD,sEAAsE;IAC/D,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GAAG,IAAI;CAahE;AAGD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUrD"}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { isPreviewMessage, STUDIO_CONTRACT_VERSION, } from '@kumwe/studio-protocol';
|
|
2
|
+
export class PreviewClient {
|
|
3
|
+
#channelId;
|
|
4
|
+
#listener;
|
|
5
|
+
#listeners = new Set();
|
|
6
|
+
#pending = new Map();
|
|
7
|
+
#pendingMeasures = new Map();
|
|
8
|
+
#pendingReady = new Set();
|
|
9
|
+
#sessionGeneration;
|
|
10
|
+
#source;
|
|
11
|
+
#target;
|
|
12
|
+
#targetOrigin;
|
|
13
|
+
#timeoutMilliseconds;
|
|
14
|
+
#disposed = false;
|
|
15
|
+
#lastInboundSequence = -1;
|
|
16
|
+
#latestRenderDigest;
|
|
17
|
+
#latestRenderedDigest;
|
|
18
|
+
#readyPayload;
|
|
19
|
+
#sequence = 0;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.#targetOrigin = normalizeOrigin(options.targetOrigin);
|
|
22
|
+
this.#channelId = options.channelId;
|
|
23
|
+
this.#sessionGeneration = options.sessionGeneration;
|
|
24
|
+
this.#source = options.source;
|
|
25
|
+
this.#target = options.target;
|
|
26
|
+
this.#timeoutMilliseconds = options.timeoutMilliseconds ?? 10_000;
|
|
27
|
+
this.#listener = (event) => {
|
|
28
|
+
this.#receive(event);
|
|
29
|
+
};
|
|
30
|
+
this.#source.addEventListener('message', this.#listener);
|
|
31
|
+
}
|
|
32
|
+
dispose() {
|
|
33
|
+
if (this.#disposed) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.#disposed = true;
|
|
37
|
+
this.#source.removeEventListener('message', this.#listener);
|
|
38
|
+
for (const pending of this.#pending.values()) {
|
|
39
|
+
clearTimeout(pending.timeout);
|
|
40
|
+
pending.cleanup();
|
|
41
|
+
pending.reject(new Error('Preview client was disposed.'));
|
|
42
|
+
}
|
|
43
|
+
this.#pending.clear();
|
|
44
|
+
for (const pending of this.#pendingMeasures.values()) {
|
|
45
|
+
clearTimeout(pending.timeout);
|
|
46
|
+
pending.cleanup();
|
|
47
|
+
pending.reject(new Error('Preview client was disposed.'));
|
|
48
|
+
}
|
|
49
|
+
this.#pendingMeasures.clear();
|
|
50
|
+
for (const pending of this.#pendingReady) {
|
|
51
|
+
clearTimeout(pending.timeout);
|
|
52
|
+
pending.cleanup();
|
|
53
|
+
pending.reject(new Error('Preview client was disposed.'));
|
|
54
|
+
}
|
|
55
|
+
this.#pendingReady.clear();
|
|
56
|
+
this.#listeners.clear();
|
|
57
|
+
}
|
|
58
|
+
onMessage(listener) {
|
|
59
|
+
this.#listeners.add(listener);
|
|
60
|
+
return () => {
|
|
61
|
+
this.#listeners.delete(listener);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolves once the host announces `studio.preview/ready` on this channel. If the
|
|
66
|
+
* announcement was already received, the cached payload resolves immediately.
|
|
67
|
+
*
|
|
68
|
+
* `isPreviewMessage` accepts only ready payloads carrying the exact draft wire protocol
|
|
69
|
+
* version, so an announcement from an incompatible host is filtered out and never resolves
|
|
70
|
+
* this promise — the wait times out instead. The promise also rejects on abort or when the
|
|
71
|
+
* client is disposed.
|
|
72
|
+
*/
|
|
73
|
+
ready(options = {}) {
|
|
74
|
+
if (this.#disposed) {
|
|
75
|
+
return Promise.reject(new Error('Preview client was disposed.'));
|
|
76
|
+
}
|
|
77
|
+
if (options.signal?.aborted === true) {
|
|
78
|
+
return Promise.reject(new Error('Preview ready wait was aborted.', { cause: options.signal.reason }));
|
|
79
|
+
}
|
|
80
|
+
if (this.#readyPayload !== undefined) {
|
|
81
|
+
return Promise.resolve(this.#readyPayload);
|
|
82
|
+
}
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const abort = () => {
|
|
85
|
+
if (this.#pendingReady.delete(pending)) {
|
|
86
|
+
clearTimeout(pending.timeout);
|
|
87
|
+
pending.cleanup();
|
|
88
|
+
pending.reject(new Error('Preview ready wait was aborted.'));
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const cleanup = () => {
|
|
92
|
+
options.signal?.removeEventListener('abort', abort);
|
|
93
|
+
};
|
|
94
|
+
const timeout = setTimeout(() => {
|
|
95
|
+
if (this.#pendingReady.delete(pending)) {
|
|
96
|
+
pending.cleanup();
|
|
97
|
+
pending.reject(new Error('Preview ready wait timed out.'));
|
|
98
|
+
}
|
|
99
|
+
}, this.#timeoutMilliseconds);
|
|
100
|
+
const pending = { cleanup, reject, resolve, timeout };
|
|
101
|
+
this.#pendingReady.add(pending);
|
|
102
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
render(payload, options = {}) {
|
|
106
|
+
if (this.#disposed) {
|
|
107
|
+
return Promise.reject(new Error('Preview client was disposed.'));
|
|
108
|
+
}
|
|
109
|
+
if (options.signal?.aborted === true) {
|
|
110
|
+
return Promise.reject(new Error('Preview render was aborted.', { cause: options.signal.reason }));
|
|
111
|
+
}
|
|
112
|
+
if (this.#pending.has(payload.draftDigest)) {
|
|
113
|
+
return Promise.reject(new Error(`Render ${payload.draftDigest} is already pending.`));
|
|
114
|
+
}
|
|
115
|
+
for (const [digest, pending] of this.#pending) {
|
|
116
|
+
clearTimeout(pending.timeout);
|
|
117
|
+
pending.cleanup();
|
|
118
|
+
pending.reject(new Error(`Preview render ${digest} was superseded by ${payload.draftDigest}.`));
|
|
119
|
+
}
|
|
120
|
+
this.#pending.clear();
|
|
121
|
+
this.#latestRenderDigest = payload.draftDigest;
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const abort = () => {
|
|
124
|
+
const pending = this.#pending.get(payload.draftDigest);
|
|
125
|
+
if (pending !== undefined) {
|
|
126
|
+
clearTimeout(pending.timeout);
|
|
127
|
+
this.#pending.delete(payload.draftDigest);
|
|
128
|
+
pending.cleanup();
|
|
129
|
+
if (this.#latestRenderDigest === payload.draftDigest) {
|
|
130
|
+
this.#latestRenderDigest = undefined;
|
|
131
|
+
}
|
|
132
|
+
pending.reject(new Error('Preview render was aborted.'));
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const cleanup = () => {
|
|
136
|
+
options.signal?.removeEventListener('abort', abort);
|
|
137
|
+
};
|
|
138
|
+
const timeout = setTimeout(() => {
|
|
139
|
+
const pending = this.#pending.get(payload.draftDigest);
|
|
140
|
+
if (pending !== undefined) {
|
|
141
|
+
this.#pending.delete(payload.draftDigest);
|
|
142
|
+
pending.cleanup();
|
|
143
|
+
if (this.#latestRenderDigest === payload.draftDigest) {
|
|
144
|
+
this.#latestRenderDigest = undefined;
|
|
145
|
+
}
|
|
146
|
+
pending.reject(new Error(`Preview render ${payload.draftDigest} timed out.`));
|
|
147
|
+
}
|
|
148
|
+
}, this.#timeoutMilliseconds);
|
|
149
|
+
this.#pending.set(payload.draftDigest, { cleanup, reject, resolve, timeout });
|
|
150
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
151
|
+
this.#post({
|
|
152
|
+
channelId: this.#channelId,
|
|
153
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
154
|
+
kind: 'preview-message',
|
|
155
|
+
payload,
|
|
156
|
+
sequence: this.#sequence++,
|
|
157
|
+
sessionGeneration: this.#sessionGeneration,
|
|
158
|
+
type: 'studio.preview/render',
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Requests the on-screen geometry of render markers from the responder. Resolves with a
|
|
164
|
+
* `measured` outcome carrying viewport-relative CSS-pixel rectangles, or a `stale`
|
|
165
|
+
* outcome when the response was measured against a render this client no longer
|
|
166
|
+
* considers latest. Rejects on teardown, reload, supersession, abort, timeout, and
|
|
167
|
+
* disposal exactly like `render()` does. Requires a completed render: geometry is a
|
|
168
|
+
* volatile measurement of a specific render digest, never document state.
|
|
169
|
+
*/
|
|
170
|
+
measure(payload, options = {}) {
|
|
171
|
+
if (this.#disposed) {
|
|
172
|
+
return Promise.reject(new Error('Preview client was disposed.'));
|
|
173
|
+
}
|
|
174
|
+
if (options.signal?.aborted === true) {
|
|
175
|
+
return Promise.reject(new Error('Preview measure was aborted.', { cause: options.signal.reason }));
|
|
176
|
+
}
|
|
177
|
+
if (this.#latestRenderedDigest === undefined) {
|
|
178
|
+
return Promise.reject(new Error('Preview measure requires a completed render.'));
|
|
179
|
+
}
|
|
180
|
+
if (this.#pendingMeasures.has(payload.requestId)) {
|
|
181
|
+
return Promise.reject(new Error(`Measure ${payload.requestId} is already pending.`));
|
|
182
|
+
}
|
|
183
|
+
for (const [requestId, pending] of this.#pendingMeasures) {
|
|
184
|
+
clearTimeout(pending.timeout);
|
|
185
|
+
pending.cleanup();
|
|
186
|
+
pending.reject(new Error(`Preview measure ${requestId} was superseded by ${payload.requestId}.`));
|
|
187
|
+
}
|
|
188
|
+
this.#pendingMeasures.clear();
|
|
189
|
+
return new Promise((resolve, reject) => {
|
|
190
|
+
const abort = () => {
|
|
191
|
+
const pending = this.#pendingMeasures.get(payload.requestId);
|
|
192
|
+
if (pending !== undefined) {
|
|
193
|
+
clearTimeout(pending.timeout);
|
|
194
|
+
this.#pendingMeasures.delete(payload.requestId);
|
|
195
|
+
pending.cleanup();
|
|
196
|
+
pending.reject(new Error('Preview measure was aborted.'));
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const cleanup = () => {
|
|
200
|
+
options.signal?.removeEventListener('abort', abort);
|
|
201
|
+
};
|
|
202
|
+
const timeout = setTimeout(() => {
|
|
203
|
+
const pending = this.#pendingMeasures.get(payload.requestId);
|
|
204
|
+
if (pending !== undefined) {
|
|
205
|
+
this.#pendingMeasures.delete(payload.requestId);
|
|
206
|
+
pending.cleanup();
|
|
207
|
+
pending.reject(new Error(`Preview measure ${payload.requestId} timed out.`));
|
|
208
|
+
}
|
|
209
|
+
}, this.#timeoutMilliseconds);
|
|
210
|
+
this.#pendingMeasures.set(payload.requestId, { cleanup, reject, resolve, timeout });
|
|
211
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
212
|
+
this.#post({
|
|
213
|
+
channelId: this.#channelId,
|
|
214
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
215
|
+
kind: 'preview-message',
|
|
216
|
+
payload,
|
|
217
|
+
sequence: this.#sequence++,
|
|
218
|
+
sessionGeneration: this.#sessionGeneration,
|
|
219
|
+
type: 'studio.preview/measure',
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
select(payload) {
|
|
224
|
+
this.#assertActive();
|
|
225
|
+
this.#post({
|
|
226
|
+
channelId: this.#channelId,
|
|
227
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
228
|
+
kind: 'preview-message',
|
|
229
|
+
payload,
|
|
230
|
+
sequence: this.#sequence++,
|
|
231
|
+
sessionGeneration: this.#sessionGeneration,
|
|
232
|
+
type: 'studio.preview/select',
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
#assertActive() {
|
|
236
|
+
if (this.#disposed) {
|
|
237
|
+
throw new Error('Preview client was disposed.');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
#post(message) {
|
|
241
|
+
this.#target.postMessage(message, this.#targetOrigin);
|
|
242
|
+
}
|
|
243
|
+
#receive(event) {
|
|
244
|
+
if (event.origin !== this.#targetOrigin ||
|
|
245
|
+
event.source !== this.#target ||
|
|
246
|
+
!isPreviewMessage(event.data) ||
|
|
247
|
+
event.data.channelId !== this.#channelId ||
|
|
248
|
+
event.data.sessionGeneration !== this.#sessionGeneration ||
|
|
249
|
+
event.data.sequence <= this.#lastInboundSequence) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
this.#lastInboundSequence = event.data.sequence;
|
|
253
|
+
if (event.data.type === 'studio.preview/rendered') {
|
|
254
|
+
if (event.data.payload.draftDigest !== this.#latestRenderDigest) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const pending = this.#pending.get(event.data.payload.draftDigest);
|
|
258
|
+
if (pending !== undefined) {
|
|
259
|
+
clearTimeout(pending.timeout);
|
|
260
|
+
pending.cleanup();
|
|
261
|
+
this.#pending.delete(event.data.payload.draftDigest);
|
|
262
|
+
this.#latestRenderDigest = undefined;
|
|
263
|
+
this.#latestRenderedDigest = event.data.payload.draftDigest;
|
|
264
|
+
pending.resolve(event.data.payload);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else if (event.data.type === 'studio.preview/measurements') {
|
|
268
|
+
const pending = this.#pendingMeasures.get(event.data.payload.requestId);
|
|
269
|
+
if (pending !== undefined) {
|
|
270
|
+
clearTimeout(pending.timeout);
|
|
271
|
+
pending.cleanup();
|
|
272
|
+
this.#pendingMeasures.delete(event.data.payload.requestId);
|
|
273
|
+
// Geometry measured against a superseded render is discarded, not surfaced:
|
|
274
|
+
// the typed stale outcome tells the caller to re-measure.
|
|
275
|
+
if (event.data.payload.draftDigest === this.#latestRenderedDigest) {
|
|
276
|
+
pending.resolve({ geometry: event.data.payload, status: 'measured' });
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
pending.resolve({ measuredDigest: event.data.payload.draftDigest, status: 'stale' });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else if (event.data.type === 'studio.preview/error') {
|
|
284
|
+
const message = event.data.payload.message.defaultMessage ?? event.data.payload.message.key;
|
|
285
|
+
const correlationId = event.data.payload.correlationId;
|
|
286
|
+
if (correlationId !== undefined) {
|
|
287
|
+
const pendingRender = this.#pending.get(correlationId);
|
|
288
|
+
const pendingMeasure = this.#pendingMeasures.get(correlationId);
|
|
289
|
+
if (pendingRender === undefined && pendingMeasure === undefined) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (pendingRender !== undefined) {
|
|
293
|
+
clearTimeout(pendingRender.timeout);
|
|
294
|
+
pendingRender.cleanup();
|
|
295
|
+
pendingRender.reject(new Error(message));
|
|
296
|
+
this.#pending.delete(correlationId);
|
|
297
|
+
if (this.#latestRenderDigest === correlationId) {
|
|
298
|
+
this.#latestRenderDigest = undefined;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (pendingMeasure !== undefined) {
|
|
302
|
+
clearTimeout(pendingMeasure.timeout);
|
|
303
|
+
pendingMeasure.cleanup();
|
|
304
|
+
pendingMeasure.reject(new Error(message));
|
|
305
|
+
this.#pendingMeasures.delete(correlationId);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
for (const pending of this.#pending.values()) {
|
|
310
|
+
clearTimeout(pending.timeout);
|
|
311
|
+
pending.cleanup();
|
|
312
|
+
pending.reject(new Error(message));
|
|
313
|
+
}
|
|
314
|
+
this.#pending.clear();
|
|
315
|
+
for (const pending of this.#pendingMeasures.values()) {
|
|
316
|
+
clearTimeout(pending.timeout);
|
|
317
|
+
pending.cleanup();
|
|
318
|
+
pending.reject(new Error(message));
|
|
319
|
+
}
|
|
320
|
+
this.#pendingMeasures.clear();
|
|
321
|
+
this.#latestRenderDigest = undefined;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
else if (event.data.type === 'studio.preview/ready') {
|
|
325
|
+
this.#readyPayload = event.data.payload;
|
|
326
|
+
const waiters = [...this.#pendingReady];
|
|
327
|
+
this.#pendingReady.clear();
|
|
328
|
+
for (const pending of waiters) {
|
|
329
|
+
clearTimeout(pending.timeout);
|
|
330
|
+
pending.cleanup();
|
|
331
|
+
pending.resolve(event.data.payload);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
else if (event.data.type === 'studio.preview/reload' ||
|
|
335
|
+
event.data.type === 'studio.preview/teardown') {
|
|
336
|
+
const reason = event.data.type === 'studio.preview/reload'
|
|
337
|
+
? 'Preview renderer reloaded before responding.'
|
|
338
|
+
: 'Preview channel was torn down.';
|
|
339
|
+
for (const pending of this.#pending.values()) {
|
|
340
|
+
clearTimeout(pending.timeout);
|
|
341
|
+
pending.cleanup();
|
|
342
|
+
pending.reject(new Error(reason));
|
|
343
|
+
}
|
|
344
|
+
this.#pending.clear();
|
|
345
|
+
// A reload voids in-flight measurements exactly like it voids renders, and the
|
|
346
|
+
// digest they were bound to no longer describes what the surface shows.
|
|
347
|
+
for (const pending of this.#pendingMeasures.values()) {
|
|
348
|
+
clearTimeout(pending.timeout);
|
|
349
|
+
pending.cleanup();
|
|
350
|
+
pending.reject(new Error(reason));
|
|
351
|
+
}
|
|
352
|
+
this.#pendingMeasures.clear();
|
|
353
|
+
this.#latestRenderDigest = undefined;
|
|
354
|
+
this.#latestRenderedDigest = undefined;
|
|
355
|
+
// A reloaded renderer announces itself again; the cached payload may
|
|
356
|
+
// no longer describe it.
|
|
357
|
+
this.#readyPayload = undefined;
|
|
358
|
+
}
|
|
359
|
+
const teardown = event.data.type === 'studio.preview/teardown';
|
|
360
|
+
for (const listener of this.#listeners) {
|
|
361
|
+
listener(event.data);
|
|
362
|
+
}
|
|
363
|
+
if (teardown) {
|
|
364
|
+
this.dispose();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/** Announce channel closure to the host, then dispose this client. */
|
|
368
|
+
teardown(reason) {
|
|
369
|
+
this.#assertActive();
|
|
370
|
+
this.#post({
|
|
371
|
+
channelId: this.#channelId,
|
|
372
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
373
|
+
kind: 'preview-message',
|
|
374
|
+
payload: { reason },
|
|
375
|
+
sequence: this.#sequence++,
|
|
376
|
+
sessionGeneration: this.#sessionGeneration,
|
|
377
|
+
type: 'studio.preview/teardown',
|
|
378
|
+
});
|
|
379
|
+
this.dispose();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// Shared with PreviewHost; intentionally not re-exported from the package index.
|
|
383
|
+
export function normalizeOrigin(input) {
|
|
384
|
+
if (input === '*') {
|
|
385
|
+
throw new TypeError('Preview target origin must be exact; wildcard origins are forbidden.');
|
|
386
|
+
}
|
|
387
|
+
const url = new URL(input);
|
|
388
|
+
if (url.origin === 'null') {
|
|
389
|
+
throw new TypeError('Preview target origin must use a network origin.');
|
|
390
|
+
}
|
|
391
|
+
return url.origin;
|
|
392
|
+
}
|
|
393
|
+
//# sourceMappingURL=preview-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-client.js","sourceRoot":"","sources":["../src/preview-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type LocalName, type PreviewMarkerRect, type PreviewRenderedPayload, type PreviewRenderPayload, type PreviewSelectPayload, type PreviewViewportMetrics, type QualifiedName, type StableId } from '@kumwe/studio-protocol';
|
|
2
|
+
import { type PreviewMessageSource, type PreviewMessageTarget } from './preview-client.js';
|
|
3
|
+
export type PreviewRenderCallback = (payload: PreviewRenderPayload) => Promise<PreviewRenderedPayload>;
|
|
4
|
+
/**
|
|
5
|
+
* Raw measurement produced by the embedding renderer. The responder never reads the
|
|
6
|
+
* DOM itself: the renderer supplies marker rectangles and viewport metrics, keeping
|
|
7
|
+
* this package DOM-free and testable. Markers absent from `rects` (or mapped to an
|
|
8
|
+
* empty rectangle list) are reported back as unknown, never thrown.
|
|
9
|
+
*/
|
|
10
|
+
export interface PreviewMeasurement {
|
|
11
|
+
rects: Record<StableId, PreviewMarkerRect[]>;
|
|
12
|
+
viewport: PreviewViewportMetrics;
|
|
13
|
+
}
|
|
14
|
+
export type PreviewMeasureCallback = (markers: StableId[]) => Promise<PreviewMeasurement>;
|
|
15
|
+
export type PreviewSelectListener = (payload: PreviewSelectPayload) => void;
|
|
16
|
+
export interface PreviewHostOptions {
|
|
17
|
+
channelId: string;
|
|
18
|
+
/** Renderer-supplied marker measurer; without one, measure requests are answered as unavailable. */
|
|
19
|
+
measure?: PreviewMeasureCallback;
|
|
20
|
+
render: PreviewRenderCallback;
|
|
21
|
+
renderer: QualifiedName;
|
|
22
|
+
sessionGeneration: string;
|
|
23
|
+
source: PreviewMessageSource;
|
|
24
|
+
target: PreviewMessageTarget;
|
|
25
|
+
targetOrigin: string;
|
|
26
|
+
viewports: LocalName[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The preview-surface half of the channel: answers `studio.preview/render` and
|
|
30
|
+
* `studio.preview/measure` requests from a `PreviewClient` and forwards
|
|
31
|
+
* `studio.preview/select` to registered listeners. Inbound messages are filtered exactly
|
|
32
|
+
* like the client filters its own: pinned origin, expected source window, canonical
|
|
33
|
+
* schema, channel ID, session generation, and a strictly increasing sequence.
|
|
34
|
+
*/
|
|
35
|
+
export declare class PreviewHost {
|
|
36
|
+
#private;
|
|
37
|
+
constructor(options: PreviewHostOptions);
|
|
38
|
+
/**
|
|
39
|
+
* Posts the `studio.preview/ready` announcement carrying the wire protocol version,
|
|
40
|
+
* renderer id, and viewport inventory. Announcement is an explicit step so the host can
|
|
41
|
+
* finish its own setup before opening the channel.
|
|
42
|
+
*/
|
|
43
|
+
announce(): void;
|
|
44
|
+
dispose(): void;
|
|
45
|
+
onSelect(listener: PreviewSelectListener): () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Announce that the renderer reloaded: any in-flight render or measurement is
|
|
48
|
+
* void and the client must resend. The host re-announces readiness afterwards.
|
|
49
|
+
*/
|
|
50
|
+
reload(reason: QualifiedName): void;
|
|
51
|
+
/** Announce channel closure to the client, then dispose this host. */
|
|
52
|
+
teardown(reason: QualifiedName): void;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=preview-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-host.d.ts","sourceRoot":"","sources":["../src/preview-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,iBAAiB,EAGtB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,KAAK,QAAQ,EACd,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,qBAAqB,GAAG,CAClC,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAErC;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC7C,QAAQ,EAAE,sBAAsB,CAAC;CAClC;AAED,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE1F,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;AAE5E,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,QAAQ,EAAE,aAAa,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,SAAS,EAAE,CAAC;CACxB;AAED;;;;;;GAMG;AACH,qBAAa,WAAW;;gBAmBH,OAAO,EAAE,kBAAkB;IAgB9C;;;;OAIG;IACI,QAAQ,IAAI,IAAI;IAiBhB,OAAO,IAAI,IAAI;IAYf,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI;IAO5D;;;OAGG;IACI,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAiB1C,sEAAsE;IAC/D,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;CA2O7C"}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { isPreviewMessage, STUDIO_CONTRACT_VERSION, STUDIO_WIRE_PROTOCOL_VERSION, } from '@kumwe/studio-protocol';
|
|
2
|
+
import { normalizeOrigin, } from './preview-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* The preview-surface half of the channel: answers `studio.preview/render` and
|
|
5
|
+
* `studio.preview/measure` requests from a `PreviewClient` and forwards
|
|
6
|
+
* `studio.preview/select` to registered listeners. Inbound messages are filtered exactly
|
|
7
|
+
* like the client filters its own: pinned origin, expected source window, canonical
|
|
8
|
+
* schema, channel ID, session generation, and a strictly increasing sequence.
|
|
9
|
+
*/
|
|
10
|
+
export class PreviewHost {
|
|
11
|
+
#channelId;
|
|
12
|
+
#listener;
|
|
13
|
+
#measureCallback;
|
|
14
|
+
#renderCallback;
|
|
15
|
+
#renderer;
|
|
16
|
+
#selectListeners = new Set();
|
|
17
|
+
#sessionGeneration;
|
|
18
|
+
#source;
|
|
19
|
+
#target;
|
|
20
|
+
#targetOrigin;
|
|
21
|
+
#viewports;
|
|
22
|
+
#disposed = false;
|
|
23
|
+
#lastInboundSequence = -1;
|
|
24
|
+
#latestMeasureRequestId;
|
|
25
|
+
#latestRenderDigest;
|
|
26
|
+
#measuredRenderDigest;
|
|
27
|
+
#sequence = 0;
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.#targetOrigin = normalizeOrigin(options.targetOrigin);
|
|
30
|
+
this.#channelId = options.channelId;
|
|
31
|
+
this.#sessionGeneration = options.sessionGeneration;
|
|
32
|
+
this.#source = options.source;
|
|
33
|
+
this.#target = options.target;
|
|
34
|
+
this.#measureCallback = options.measure;
|
|
35
|
+
this.#renderCallback = options.render;
|
|
36
|
+
this.#renderer = options.renderer;
|
|
37
|
+
this.#viewports = [...options.viewports];
|
|
38
|
+
this.#listener = (event) => {
|
|
39
|
+
this.#receive(event);
|
|
40
|
+
};
|
|
41
|
+
this.#source.addEventListener('message', this.#listener);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Posts the `studio.preview/ready` announcement carrying the wire protocol version,
|
|
45
|
+
* renderer id, and viewport inventory. Announcement is an explicit step so the host can
|
|
46
|
+
* finish its own setup before opening the channel.
|
|
47
|
+
*/
|
|
48
|
+
announce() {
|
|
49
|
+
this.#assertActive();
|
|
50
|
+
this.#post({
|
|
51
|
+
channelId: this.#channelId,
|
|
52
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
53
|
+
kind: 'preview-message',
|
|
54
|
+
payload: {
|
|
55
|
+
protocolVersion: STUDIO_WIRE_PROTOCOL_VERSION,
|
|
56
|
+
renderer: this.#renderer,
|
|
57
|
+
viewports: [...this.#viewports],
|
|
58
|
+
},
|
|
59
|
+
sequence: this.#sequence++,
|
|
60
|
+
sessionGeneration: this.#sessionGeneration,
|
|
61
|
+
type: 'studio.preview/ready',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
dispose() {
|
|
65
|
+
if (this.#disposed) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.#disposed = true;
|
|
69
|
+
this.#source.removeEventListener('message', this.#listener);
|
|
70
|
+
this.#selectListeners.clear();
|
|
71
|
+
this.#latestMeasureRequestId = undefined;
|
|
72
|
+
this.#latestRenderDigest = undefined;
|
|
73
|
+
this.#measuredRenderDigest = undefined;
|
|
74
|
+
}
|
|
75
|
+
onSelect(listener) {
|
|
76
|
+
this.#selectListeners.add(listener);
|
|
77
|
+
return () => {
|
|
78
|
+
this.#selectListeners.delete(listener);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Announce that the renderer reloaded: any in-flight render or measurement is
|
|
83
|
+
* void and the client must resend. The host re-announces readiness afterwards.
|
|
84
|
+
*/
|
|
85
|
+
reload(reason) {
|
|
86
|
+
this.#assertActive();
|
|
87
|
+
this.#latestMeasureRequestId = undefined;
|
|
88
|
+
this.#latestRenderDigest = undefined;
|
|
89
|
+
this.#measuredRenderDigest = undefined;
|
|
90
|
+
this.#post({
|
|
91
|
+
channelId: this.#channelId,
|
|
92
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
93
|
+
kind: 'preview-message',
|
|
94
|
+
payload: { reason },
|
|
95
|
+
sequence: this.#sequence++,
|
|
96
|
+
sessionGeneration: this.#sessionGeneration,
|
|
97
|
+
type: 'studio.preview/reload',
|
|
98
|
+
});
|
|
99
|
+
this.announce();
|
|
100
|
+
}
|
|
101
|
+
/** Announce channel closure to the client, then dispose this host. */
|
|
102
|
+
teardown(reason) {
|
|
103
|
+
this.#assertActive();
|
|
104
|
+
this.#post({
|
|
105
|
+
channelId: this.#channelId,
|
|
106
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
107
|
+
kind: 'preview-message',
|
|
108
|
+
payload: { reason },
|
|
109
|
+
sequence: this.#sequence++,
|
|
110
|
+
sessionGeneration: this.#sessionGeneration,
|
|
111
|
+
type: 'studio.preview/teardown',
|
|
112
|
+
});
|
|
113
|
+
this.dispose();
|
|
114
|
+
}
|
|
115
|
+
#assertActive() {
|
|
116
|
+
if (this.#disposed) {
|
|
117
|
+
throw new Error('Preview host was disposed.');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
#handleMeasure(payload) {
|
|
121
|
+
const requestId = payload.requestId;
|
|
122
|
+
this.#latestMeasureRequestId = requestId;
|
|
123
|
+
if (this.#measureCallback === undefined) {
|
|
124
|
+
this.#settleMeasureFailure(requestId, {
|
|
125
|
+
code: 'studio.preview/measure-unavailable',
|
|
126
|
+
defaultMessage: 'Preview measurement is unavailable.',
|
|
127
|
+
retryable: false,
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (this.#measuredRenderDigest === undefined) {
|
|
132
|
+
// Nothing has rendered yet, so there is no digest to bind geometry to.
|
|
133
|
+
this.#settleMeasureFailure(requestId, {
|
|
134
|
+
code: 'studio.preview/measure-unavailable',
|
|
135
|
+
defaultMessage: 'Preview measurement is unavailable.',
|
|
136
|
+
retryable: true,
|
|
137
|
+
});
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const markers = [...new Set(payload.markers)];
|
|
141
|
+
let result;
|
|
142
|
+
try {
|
|
143
|
+
result = this.#measureCallback(markers);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
this.#settleMeasureFailure(requestId, measureFailed());
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
void result.then((measurement) => {
|
|
150
|
+
this.#settleMeasured(requestId, markers, measurement);
|
|
151
|
+
}, () => {
|
|
152
|
+
this.#settleMeasureFailure(requestId, measureFailed());
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
#handleRender(payload) {
|
|
156
|
+
const draftDigest = payload.draftDigest;
|
|
157
|
+
this.#latestRenderDigest = draftDigest;
|
|
158
|
+
let result;
|
|
159
|
+
try {
|
|
160
|
+
result = this.#renderCallback(payload);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
this.#settleFailure(draftDigest);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
void result.then((rendered) => {
|
|
167
|
+
this.#settleRendered(draftDigest, rendered);
|
|
168
|
+
}, () => {
|
|
169
|
+
this.#settleFailure(draftDigest);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
#post(message) {
|
|
173
|
+
this.#target.postMessage(message, this.#targetOrigin);
|
|
174
|
+
}
|
|
175
|
+
#receive(event) {
|
|
176
|
+
if (event.origin !== this.#targetOrigin ||
|
|
177
|
+
event.source !== this.#target ||
|
|
178
|
+
!isPreviewMessage(event.data) ||
|
|
179
|
+
event.data.channelId !== this.#channelId ||
|
|
180
|
+
event.data.sessionGeneration !== this.#sessionGeneration ||
|
|
181
|
+
event.data.sequence <= this.#lastInboundSequence) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.#lastInboundSequence = event.data.sequence;
|
|
185
|
+
if (event.data.type === 'studio.preview/render') {
|
|
186
|
+
this.#handleRender(event.data.payload);
|
|
187
|
+
}
|
|
188
|
+
else if (event.data.type === 'studio.preview/measure') {
|
|
189
|
+
this.#handleMeasure(event.data.payload);
|
|
190
|
+
}
|
|
191
|
+
else if (event.data.type === 'studio.preview/select') {
|
|
192
|
+
for (const listener of this.#selectListeners) {
|
|
193
|
+
listener(event.data.payload);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else if (event.data.type === 'studio.preview/teardown') {
|
|
197
|
+
this.dispose();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Measurer failure details never cross the channel: the rejection reason is dropped and a
|
|
201
|
+
// stable generic error is posted instead, correlated by the request identifier.
|
|
202
|
+
#settleMeasureFailure(requestId, failure) {
|
|
203
|
+
if (this.#disposed || this.#latestMeasureRequestId !== requestId) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
this.#latestMeasureRequestId = undefined;
|
|
207
|
+
this.#post({
|
|
208
|
+
channelId: this.#channelId,
|
|
209
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
210
|
+
kind: 'preview-message',
|
|
211
|
+
payload: {
|
|
212
|
+
code: failure.code,
|
|
213
|
+
correlationId: requestId,
|
|
214
|
+
message: { defaultMessage: failure.defaultMessage, key: failure.code },
|
|
215
|
+
retryable: failure.retryable,
|
|
216
|
+
},
|
|
217
|
+
sequence: this.#sequence++,
|
|
218
|
+
sessionGeneration: this.#sessionGeneration,
|
|
219
|
+
type: 'studio.preview/error',
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
// Geometry is stamped with the digest of the render the surface currently shows, and only
|
|
223
|
+
// markers from the request are answered — requested markers the measurer cannot place are
|
|
224
|
+
// listed as unknown, extra markers it invents are dropped. A measurement superseded by a
|
|
225
|
+
// newer request, voided by a reload, or settling after disposal is dropped silently.
|
|
226
|
+
#settleMeasured(requestId, markers, measurement) {
|
|
227
|
+
const draftDigest = this.#measuredRenderDigest;
|
|
228
|
+
if (this.#disposed || this.#latestMeasureRequestId !== requestId || draftDigest === undefined) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.#latestMeasureRequestId = undefined;
|
|
232
|
+
const measurements = {};
|
|
233
|
+
const unknown = [];
|
|
234
|
+
for (const marker of markers) {
|
|
235
|
+
const rects = Object.hasOwn(measurement.rects, marker)
|
|
236
|
+
? measurement.rects[marker]
|
|
237
|
+
: undefined;
|
|
238
|
+
if (rects === undefined || rects.length === 0) {
|
|
239
|
+
unknown.push(marker);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
measurements[marker] = rects.map((rect) => ({
|
|
243
|
+
height: rect.height,
|
|
244
|
+
width: rect.width,
|
|
245
|
+
x: rect.x,
|
|
246
|
+
y: rect.y,
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
this.#post({
|
|
251
|
+
channelId: this.#channelId,
|
|
252
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
253
|
+
kind: 'preview-message',
|
|
254
|
+
payload: {
|
|
255
|
+
draftDigest,
|
|
256
|
+
measurements,
|
|
257
|
+
requestId,
|
|
258
|
+
unknown,
|
|
259
|
+
viewport: {
|
|
260
|
+
devicePixelRatio: measurement.viewport.devicePixelRatio,
|
|
261
|
+
height: measurement.viewport.height,
|
|
262
|
+
scrollX: measurement.viewport.scrollX,
|
|
263
|
+
scrollY: measurement.viewport.scrollY,
|
|
264
|
+
width: measurement.viewport.width,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
sequence: this.#sequence++,
|
|
268
|
+
sessionGeneration: this.#sessionGeneration,
|
|
269
|
+
type: 'studio.preview/measurements',
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
// Renderer failure details never cross the channel: the rejection reason is dropped and a
|
|
273
|
+
// stable generic error is posted instead, correlated by the request's draft digest.
|
|
274
|
+
#settleFailure(draftDigest) {
|
|
275
|
+
if (this.#disposed || this.#latestRenderDigest !== draftDigest) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
this.#latestRenderDigest = undefined;
|
|
279
|
+
this.#post({
|
|
280
|
+
channelId: this.#channelId,
|
|
281
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
282
|
+
kind: 'preview-message',
|
|
283
|
+
payload: {
|
|
284
|
+
code: 'studio.preview/render-failed',
|
|
285
|
+
correlationId: draftDigest,
|
|
286
|
+
message: {
|
|
287
|
+
defaultMessage: 'Preview rendering failed.',
|
|
288
|
+
key: 'studio.preview/render-failed',
|
|
289
|
+
},
|
|
290
|
+
retryable: true,
|
|
291
|
+
},
|
|
292
|
+
sequence: this.#sequence++,
|
|
293
|
+
sessionGeneration: this.#sessionGeneration,
|
|
294
|
+
type: 'studio.preview/error',
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
// The response digest is stamped from the request, so a callback can never answer for a
|
|
298
|
+
// different draft than the one it was asked to render. Results that were superseded by a
|
|
299
|
+
// newer request, or that settle after disposal, are dropped silently.
|
|
300
|
+
#settleRendered(draftDigest, rendered) {
|
|
301
|
+
if (this.#disposed || this.#latestRenderDigest !== draftDigest) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
this.#latestRenderDigest = undefined;
|
|
305
|
+
// The surface now shows this render; measurements are bound to its digest.
|
|
306
|
+
this.#measuredRenderDigest = draftDigest;
|
|
307
|
+
this.#post({
|
|
308
|
+
channelId: this.#channelId,
|
|
309
|
+
contractVersion: STUDIO_CONTRACT_VERSION,
|
|
310
|
+
kind: 'preview-message',
|
|
311
|
+
payload: {
|
|
312
|
+
diagnostics: rendered.diagnostics,
|
|
313
|
+
draftDigest,
|
|
314
|
+
markers: rendered.markers,
|
|
315
|
+
...(rendered.markerMap === undefined ? {} : { markerMap: rendered.markerMap }),
|
|
316
|
+
},
|
|
317
|
+
sequence: this.#sequence++,
|
|
318
|
+
sessionGeneration: this.#sessionGeneration,
|
|
319
|
+
type: 'studio.preview/rendered',
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function measureFailed() {
|
|
324
|
+
return {
|
|
325
|
+
code: 'studio.preview/measure-failed',
|
|
326
|
+
defaultMessage: 'Preview measurement failed.',
|
|
327
|
+
retryable: true,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=preview-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-host.js","sourceRoot":"","sources":["../src/preview-host.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kumwe/studio-preview",
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/kumwe/studio.git",
|
|
7
|
+
"directory": "packages/preview"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/kumwe/studio/tree/main/packages/preview#readme",
|
|
10
|
+
"bugs": "https://github.com/kumwe/studio/issues",
|
|
11
|
+
"description": "Origin-bound request channel for server-rendered Studio previews.",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"sideEffects": false,
|
|
14
|
+
"files": [
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -b"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@kumwe/studio-protocol": "0.1.0-alpha.2"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"provenance": true
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=24.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|