@tinacms/bridge 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/forms.d.ts +5 -7
- package/dist/forms.test.d.ts +1 -0
- package/dist/index.d.ts +8 -35
- package/dist/index.js +126 -9
- package/dist/island-refresh.d.ts +15 -15
- package/dist/island-refresh.test.d.ts +1 -0
- package/dist/preview.d.ts +7 -20
- package/dist/preview.js +12 -1
- package/dist/refresh-forms.test.d.ts +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.test-d.d.ts +1 -0
- package/package.json +1 -1
package/dist/forms.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { DataStore } from './types';
|
|
2
|
+
export declare const FORM_SELECTOR = "[data-tina-form]";
|
|
3
|
+
export declare const FORM_ATTR = "data-tina-form";
|
|
4
|
+
export declare const PRIMARY_FORM_ATTR = "data-tina-primary";
|
|
2
5
|
export declare function initForms(store: DataStore): void;
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
* against the previous mount and post `close` / `open` for the delta.
|
|
6
|
-
*
|
|
7
|
-
* Safe to call even if the bridge isn't initialised — used for setups
|
|
8
|
-
* that wire `astro:page-load` unconditionally. No-op outside an iframe.
|
|
9
|
-
*/
|
|
6
|
+
/** Diff active forms against the DOM and post the deltas. Safe to call
|
|
7
|
+
* before init() — no-op then. */
|
|
10
8
|
export declare function refreshForms(): void;
|
|
11
9
|
export declare function reportQuickEdit(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,44 +1,17 @@
|
|
|
1
|
-
import { refreshForms } from './forms';
|
|
2
1
|
export interface BridgeOptions {
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
* The first refetch after page load fires immediately so newly-created
|
|
6
|
-
* docs reach a populated state ASAP. Default 300ms.
|
|
7
|
-
*/
|
|
2
|
+
/** Debounce for refetches after the first edit. The first refetch
|
|
3
|
+
* fires immediately. Default 300ms. */
|
|
8
4
|
debounceMs?: number;
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
11
|
-
* accepted only when `event.origin` matches one of these AND
|
|
12
|
-
* `event.source` is `window.parent`. Outbound posts use the first entry
|
|
13
|
-
* (or the single string) as `targetOrigin`.
|
|
14
|
-
*
|
|
15
|
-
* Defaults to `window.location.origin` — correct when the admin is
|
|
16
|
-
* mounted at `/admin` on the same host (the common case). Override when
|
|
17
|
-
* the admin runs on a different origin (cross-domain self-hosted
|
|
18
|
-
* deployments, Codespaces, Docker setups). Mirrors the role of
|
|
19
|
-
* `server.allowedOrigins` in `tina.config` for the dev server's CORS,
|
|
20
|
-
* but applied to the in-iframe postMessage channel instead of HTTP.
|
|
21
|
-
*/
|
|
5
|
+
/** Allowed origin(s) of the admin parent for in-iframe postMessage.
|
|
6
|
+
* Defaults to `window.location.origin` (same-host `/admin`). */
|
|
22
7
|
adminOrigin?: string | string[];
|
|
23
8
|
}
|
|
24
9
|
export declare function init(options?: BridgeOptions): void;
|
|
25
10
|
/**
|
|
26
|
-
* Re-scan
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* before `init()` — no-op when the bridge isn't running.
|
|
30
|
-
*
|
|
31
|
-
* Astro projects using `@tinacms/astro/integration` get this wired
|
|
32
|
-
* automatically (the middleware splices the bootstrap script that
|
|
33
|
-
* listens for `astro:page-load`). Sites consuming `@tinacms/bridge`
|
|
34
|
-
* directly need:
|
|
35
|
-
*
|
|
36
|
-
* ```ts
|
|
37
|
-
* import { init, refreshForms } from '@tinacms/bridge';
|
|
38
|
-
* init();
|
|
39
|
-
* document.addEventListener('astro:page-load', refreshForms);
|
|
40
|
-
* ```
|
|
11
|
+
* Re-scan for `[data-tina-form]` payloads after a soft navigation
|
|
12
|
+
* (Astro view transitions, Turbo, htmx). On a prerendered page with no
|
|
13
|
+
* server-injected payloads, prime from the island endpoints first.
|
|
41
14
|
*/
|
|
42
|
-
export
|
|
15
|
+
export declare function refreshForms(): void;
|
|
43
16
|
export { tinaField } from './tina-field';
|
|
44
17
|
export type * from './types';
|
package/dist/index.js
CHANGED
|
@@ -132,6 +132,7 @@ function initDataStore() {
|
|
|
132
132
|
const listeners = /* @__PURE__ */ new Set();
|
|
133
133
|
return {
|
|
134
134
|
get: (id) => data.get(id),
|
|
135
|
+
has: (id) => data.has(id),
|
|
135
136
|
seed(id, next) {
|
|
136
137
|
data.set(id, next);
|
|
137
138
|
},
|
|
@@ -151,6 +152,7 @@ function initDataStore() {
|
|
|
151
152
|
}
|
|
152
153
|
const FORM_SELECTOR = "[data-tina-form]";
|
|
153
154
|
const FORM_ATTR = "data-tina-form";
|
|
155
|
+
const PRIMARY_FORM_ATTR = "data-tina-primary";
|
|
154
156
|
const RETRY_INTERVAL_MS = 250;
|
|
155
157
|
const MAX_ATTEMPTS = 40;
|
|
156
158
|
let controller = null;
|
|
@@ -163,19 +165,19 @@ function initForms(store) {
|
|
|
163
165
|
store,
|
|
164
166
|
active: /* @__PURE__ */ new Map(),
|
|
165
167
|
acknowledged: /* @__PURE__ */ new Set(),
|
|
168
|
+
primaryId: null,
|
|
166
169
|
retryTimer: null,
|
|
167
170
|
attempts: 0
|
|
168
171
|
};
|
|
169
172
|
window.addEventListener("message", onAck);
|
|
170
173
|
window.addEventListener("beforeunload", onBeforeUnload);
|
|
171
|
-
refreshForms();
|
|
172
174
|
}
|
|
173
|
-
function refreshForms() {
|
|
175
|
+
function refreshForms$1() {
|
|
174
176
|
if (!controller) {
|
|
175
177
|
debug("refreshForms called before initForms; ignoring");
|
|
176
178
|
return;
|
|
177
179
|
}
|
|
178
|
-
const next = readPayloads();
|
|
180
|
+
const { payloads: next, primaryId } = readPayloads();
|
|
179
181
|
const nextIds = new Set(next.map((p) => p.id));
|
|
180
182
|
for (const [id] of controller.active) {
|
|
181
183
|
if (nextIds.has(id))
|
|
@@ -188,6 +190,7 @@ function refreshForms() {
|
|
|
188
190
|
controller.store.seed(payload.id, payload.data ?? {});
|
|
189
191
|
}
|
|
190
192
|
controller.active = new Map(next.map((p) => [p.id, p]));
|
|
193
|
+
controller.primaryId = primaryId && nextIds.has(primaryId) ? primaryId : null;
|
|
191
194
|
if (next.some((p) => !controller.acknowledged.has(p.id))) {
|
|
192
195
|
startAnnounceLoop();
|
|
193
196
|
}
|
|
@@ -196,6 +199,7 @@ function refreshForms() {
|
|
|
196
199
|
function readPayloads() {
|
|
197
200
|
const elements = document.querySelectorAll(FORM_SELECTOR);
|
|
198
201
|
const payloads = [];
|
|
202
|
+
let primaryId = null;
|
|
199
203
|
for (const el of elements) {
|
|
200
204
|
const raw = el.getAttribute(FORM_ATTR);
|
|
201
205
|
if (!raw)
|
|
@@ -205,12 +209,15 @@ function readPayloads() {
|
|
|
205
209
|
if (!payload.id || !payload.query)
|
|
206
210
|
continue;
|
|
207
211
|
payloads.push(payload);
|
|
212
|
+
if (primaryId === null && el.hasAttribute(PRIMARY_FORM_ATTR)) {
|
|
213
|
+
primaryId = payload.id;
|
|
214
|
+
}
|
|
208
215
|
} catch (error) {
|
|
209
216
|
debug("failed to parse form payload", error);
|
|
210
217
|
}
|
|
211
218
|
}
|
|
212
219
|
debug("discovered", payloads.length, "form(s)");
|
|
213
|
-
return payloads;
|
|
220
|
+
return { payloads, primaryId };
|
|
214
221
|
}
|
|
215
222
|
function onAck(event) {
|
|
216
223
|
if (!isFromAdmin(event))
|
|
@@ -281,6 +288,12 @@ function announce() {
|
|
|
281
288
|
getAdminOrigin()
|
|
282
289
|
);
|
|
283
290
|
}
|
|
291
|
+
if (controller.primaryId && pending.some((p) => p.id === controller.primaryId)) {
|
|
292
|
+
window.parent.postMessage(
|
|
293
|
+
{ type: "user-select-form", formId: controller.primaryId },
|
|
294
|
+
getAdminOrigin()
|
|
295
|
+
);
|
|
296
|
+
}
|
|
284
297
|
controller.retryTimer = setTimeout(announce, RETRY_INTERVAL_MS);
|
|
285
298
|
}
|
|
286
299
|
function reportQuickEdit() {
|
|
@@ -291,8 +304,11 @@ function reportQuickEdit() {
|
|
|
291
304
|
);
|
|
292
305
|
}
|
|
293
306
|
const PREVIEW_CONTENT_TYPE = "application/x-tina-preview+json";
|
|
307
|
+
const PRIME_HEADER = "X-Tina-Prime";
|
|
294
308
|
const ISLAND_SELECTOR = "[data-tina-island]";
|
|
295
309
|
const ENDPOINT_ATTR = "data-tina-island";
|
|
310
|
+
const PRIMARY_ISLAND_ATTR = "data-tina-island-primary";
|
|
311
|
+
const PRIMED_FORM_ATTR = "data-tina-primed";
|
|
296
312
|
function initIslandRefresh(store, options) {
|
|
297
313
|
let pendingRefresh = null;
|
|
298
314
|
const refreshAll = () => {
|
|
@@ -322,6 +338,10 @@ function initIslandRefresh(store, options) {
|
|
|
322
338
|
if (!message || typeof message !== "object")
|
|
323
339
|
return;
|
|
324
340
|
if (message.type === "updateData" && typeof message.id === "string") {
|
|
341
|
+
if (!store.has(message.id)) {
|
|
342
|
+
debug("updateData for unknown id", message.id, "— ignoring");
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
325
345
|
debug("updateData received for", message.id);
|
|
326
346
|
store.set(message.id, message.data ?? {});
|
|
327
347
|
}
|
|
@@ -350,6 +370,10 @@ async function refreshIsland(island, store) {
|
|
|
350
370
|
debug("island refetch failed", endpoint, response.status);
|
|
351
371
|
return;
|
|
352
372
|
}
|
|
373
|
+
if (!isHtmlResponse(response)) {
|
|
374
|
+
debug("island refetch wrong content-type", endpoint);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
353
377
|
const html = await response.text();
|
|
354
378
|
swapIslandHtml(island, html);
|
|
355
379
|
reportQuickEdit();
|
|
@@ -357,11 +381,66 @@ async function refreshIsland(island, store) {
|
|
|
357
381
|
debug("island refetch error", endpoint, error);
|
|
358
382
|
}
|
|
359
383
|
}
|
|
384
|
+
async function primeIslands() {
|
|
385
|
+
const islands = document.querySelectorAll(ISLAND_SELECTOR);
|
|
386
|
+
const results = await Promise.all(Array.from(islands, primeIsland));
|
|
387
|
+
for (const formEl of results.flat()) {
|
|
388
|
+
formEl.setAttribute(PRIMED_FORM_ATTR, "");
|
|
389
|
+
document.body.appendChild(formEl);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
async function primeIsland(island) {
|
|
393
|
+
const endpoint = island.getAttribute(ENDPOINT_ATTR);
|
|
394
|
+
if (!endpoint)
|
|
395
|
+
return [];
|
|
396
|
+
const isPrimary = island.hasAttribute(PRIMARY_ISLAND_ATTR);
|
|
397
|
+
try {
|
|
398
|
+
debug("priming island", endpoint);
|
|
399
|
+
const response = await fetch(endpoint, {
|
|
400
|
+
method: "POST",
|
|
401
|
+
headers: {
|
|
402
|
+
"Content-Type": PREVIEW_CONTENT_TYPE,
|
|
403
|
+
[PRIME_HEADER]: "1"
|
|
404
|
+
},
|
|
405
|
+
body: "{}",
|
|
406
|
+
cache: "no-store",
|
|
407
|
+
credentials: "same-origin"
|
|
408
|
+
});
|
|
409
|
+
if (!response.ok) {
|
|
410
|
+
debug("island prime failed", endpoint, response.status);
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
if (!isHtmlResponse(response)) {
|
|
414
|
+
debug("island prime wrong content-type", endpoint);
|
|
415
|
+
return [];
|
|
416
|
+
}
|
|
417
|
+
const template = document.createElement("template");
|
|
418
|
+
template.innerHTML = (await response.text()).trim();
|
|
419
|
+
const formEls = Array.from(
|
|
420
|
+
template.content.querySelectorAll(FORM_SELECTOR)
|
|
421
|
+
);
|
|
422
|
+
if (isPrimary && formEls[0]) {
|
|
423
|
+
formEls[0].setAttribute(PRIMARY_FORM_ATTR, "");
|
|
424
|
+
}
|
|
425
|
+
return formEls;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
debug("island prime error", endpoint, error);
|
|
428
|
+
return [];
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
function isHtmlResponse(response) {
|
|
432
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
433
|
+
return contentType.includes("text/html");
|
|
434
|
+
}
|
|
435
|
+
function isAllowedSwapAttribute(name) {
|
|
436
|
+
if (name === "class" || name === "id")
|
|
437
|
+
return true;
|
|
438
|
+
return name.startsWith("data-tina-");
|
|
439
|
+
}
|
|
360
440
|
function swapIslandHtml(island, html) {
|
|
361
441
|
const template = document.createElement("template");
|
|
362
442
|
template.innerHTML = html.trim();
|
|
363
|
-
const
|
|
364
|
-
const replacement = fragment.firstElementChild;
|
|
443
|
+
const replacement = template.content.firstElementChild;
|
|
365
444
|
if (replacement) {
|
|
366
445
|
for (const attr of Array.from(island.attributes)) {
|
|
367
446
|
if (attr.name === ENDPOINT_ATTR)
|
|
@@ -369,6 +448,8 @@ function swapIslandHtml(island, html) {
|
|
|
369
448
|
island.removeAttribute(attr.name);
|
|
370
449
|
}
|
|
371
450
|
for (const attr of Array.from(replacement.attributes)) {
|
|
451
|
+
if (!isAllowedSwapAttribute(attr.name))
|
|
452
|
+
continue;
|
|
372
453
|
island.setAttribute(attr.name, attr.value);
|
|
373
454
|
}
|
|
374
455
|
island.innerHTML = replacement.innerHTML;
|
|
@@ -388,11 +469,10 @@ const tinaField = (object, property, index) => {
|
|
|
388
469
|
const fullPath = typeof index === "number" ? [...path, property, index] : [...path, property];
|
|
389
470
|
return `${queryId}---${fullPath.join(".")}`;
|
|
390
471
|
};
|
|
391
|
-
let
|
|
472
|
+
let running = false;
|
|
392
473
|
function init(options = {}) {
|
|
393
|
-
if (
|
|
474
|
+
if (running)
|
|
394
475
|
return;
|
|
395
|
-
initialized = true;
|
|
396
476
|
if (typeof window === "undefined" || window.parent === window) {
|
|
397
477
|
debug("not in an iframe; bridge is a no-op");
|
|
398
478
|
return;
|
|
@@ -404,6 +484,43 @@ function init(options = {}) {
|
|
|
404
484
|
initIslandRefresh(store, { debounceMs });
|
|
405
485
|
initClickToFocus();
|
|
406
486
|
initForms(store);
|
|
487
|
+
running = true;
|
|
488
|
+
refreshForms();
|
|
489
|
+
}
|
|
490
|
+
let primingInFlight = null;
|
|
491
|
+
let reprimePending = false;
|
|
492
|
+
function refreshForms() {
|
|
493
|
+
if (!running) {
|
|
494
|
+
debug("refreshForms called before init() finished; ignoring");
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
removePrimedForms();
|
|
498
|
+
const hasServerForms = document.querySelector("[data-tina-form]");
|
|
499
|
+
if (!hasServerForms && document.querySelector("[data-tina-island]")) {
|
|
500
|
+
if (primingInFlight) {
|
|
501
|
+
reprimePending = true;
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
debug("no server-injected forms; priming from island endpoints");
|
|
505
|
+
primingInFlight = primeIslands().finally(() => {
|
|
506
|
+
primingInFlight = null;
|
|
507
|
+
});
|
|
508
|
+
void primingInFlight.then(() => {
|
|
509
|
+
if (reprimePending) {
|
|
510
|
+
reprimePending = false;
|
|
511
|
+
refreshForms();
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
refreshForms$1();
|
|
515
|
+
});
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
refreshForms$1();
|
|
519
|
+
}
|
|
520
|
+
function removePrimedForms() {
|
|
521
|
+
for (const el of document.querySelectorAll(`[${PRIMED_FORM_ATTR}]`)) {
|
|
522
|
+
el.remove();
|
|
523
|
+
}
|
|
407
524
|
}
|
|
408
525
|
export {
|
|
409
526
|
init,
|
package/dist/island-refresh.d.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import type { DataStore } from './types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* hitting the canonical content store.
|
|
8
|
-
*
|
|
9
|
-
* Why POST: HTTP headers are capped at ~8 KB (server-dependent) — large
|
|
10
|
-
* posts overflow easily — and are restricted to Latin-1 so UTF-8 content
|
|
11
|
-
* needs base64 padding. A POST body has neither limit and round-trips
|
|
12
|
-
* UTF-8 directly.
|
|
13
|
-
*
|
|
14
|
-
* The very first updateData fires immediately so newly-created docs leave
|
|
15
|
-
* the empty-template state ASAP. Subsequent updates collapse into a single
|
|
16
|
-
* debounced refetch — each refresh re-renders every island anyway, so a
|
|
17
|
-
* per-id timer would just fire N redundant times for the same DOM scan.
|
|
3
|
+
* Listen for admin `updateData` events and re-fetch every island on the
|
|
4
|
+
* page with the unsaved data POSTed as a JSON body. POST (vs header)
|
|
5
|
+
* avoids the ~8KB Latin-1 cap. Refetches collapse into one debounced
|
|
6
|
+
* pass (every refresh re-renders every island).
|
|
18
7
|
*/
|
|
19
8
|
export interface IslandRefreshOptions {
|
|
20
9
|
debounceMs: number;
|
|
21
10
|
}
|
|
11
|
+
/** Marks a `[data-tina-form]` div that a prime pass appended (vs. one the
|
|
12
|
+
* server injected), so a later re-scan can drop it before re-priming. */
|
|
13
|
+
export declare const PRIMED_FORM_ATTR = "data-tina-primed";
|
|
22
14
|
export declare function initIslandRefresh(store: DataStore, options: IslandRefreshOptions): void;
|
|
15
|
+
/**
|
|
16
|
+
* Hydrate `[data-tina-form]` payloads for prerendered pages by hitting
|
|
17
|
+
* each island endpoint with the prime header set; the endpoint prepends
|
|
18
|
+
* payloads to the region HTML. The caller follows up with refreshForms()
|
|
19
|
+
* to announce them. Region HTML isn't swapped — canonical data is
|
|
20
|
+
* already on the page; the first real `updateData` handles updates.
|
|
21
|
+
*/
|
|
22
|
+
export declare function primeIslands(): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/preview.d.ts
CHANGED
|
@@ -1,29 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* { [queryId]: data, ... }
|
|
6
|
-
*
|
|
7
|
-
* Server-side island handlers call `readOverlay(request, queryId)` to
|
|
8
|
-
* fetch the overlay data for their own query without having to know the
|
|
9
|
-
* transport details (POST body vs header, JSON vs base64-encoded JSON).
|
|
10
|
-
*
|
|
11
|
-
* Runs in Node (Astro server endpoints, Hugo plugins, etc.) — no DOM
|
|
12
|
-
* dependencies. The browser-side encoder lives in island-refresh.ts.
|
|
2
|
+
* Server-side helpers for the X-Tina-Preview channel. The bridge POSTs
|
|
3
|
+
* island refetches with body `{ [queryId]: data, ... }`; handlers read
|
|
4
|
+
* their slice via `readOverlay(request, queryId)`.
|
|
13
5
|
*/
|
|
14
6
|
export declare const PREVIEW_HEADER = "X-Tina-Preview";
|
|
15
7
|
export declare const PREVIEW_CONTENT_TYPE = "application/x-tina-preview+json";
|
|
8
|
+
/** Set on the one-time prime refetch for prerendered pages; the endpoint
|
|
9
|
+
* prepends `<div data-tina-form>` payloads to the region HTML. */
|
|
10
|
+
export declare const PRIME_HEADER = "X-Tina-Prime";
|
|
16
11
|
export interface PreviewEnvelope {
|
|
17
12
|
[queryId: string]: unknown;
|
|
18
13
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Read the overlay envelope for a given query id from an incoming
|
|
21
|
-
* request. Returns `undefined` if no overlay is present (production
|
|
22
|
-
* traffic, or an island refetch with no matching id).
|
|
23
|
-
*/
|
|
24
14
|
export declare function readOverlay<T>(request: Request, queryId: string): Promise<T | undefined>;
|
|
25
|
-
/**
|
|
26
|
-
* Read and parse the full overlay envelope (every form on the page),
|
|
27
|
-
* for callers that want to inspect the raw payload.
|
|
28
|
-
*/
|
|
15
|
+
/** Read and parse the full overlay envelope (every form on the page). */
|
|
29
16
|
export declare function readEnvelope(request: Request): Promise<PreviewEnvelope | undefined>;
|
package/dist/preview.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const PREVIEW_HEADER = "X-Tina-Preview";
|
|
2
2
|
const PREVIEW_CONTENT_TYPE = "application/x-tina-preview+json";
|
|
3
|
+
const PRIME_HEADER = "X-Tina-Prime";
|
|
3
4
|
const MAX_ENVELOPE_BYTES = 1e6;
|
|
4
5
|
async function readOverlay(request, queryId) {
|
|
5
6
|
const envelope = await readEnvelope(request);
|
|
@@ -8,7 +9,16 @@ async function readOverlay(request, queryId) {
|
|
|
8
9
|
const value = envelope[queryId];
|
|
9
10
|
return value === void 0 ? void 0 : value;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
const envelopeCache = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
function readEnvelope(request) {
|
|
14
|
+
let cached = envelopeCache.get(request);
|
|
15
|
+
if (!cached) {
|
|
16
|
+
cached = parseEnvelope(request);
|
|
17
|
+
envelopeCache.set(request, cached);
|
|
18
|
+
}
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
async function parseEnvelope(request) {
|
|
12
22
|
const contentType = request.headers.get("content-type") ?? "";
|
|
13
23
|
if (!contentType.includes(PREVIEW_CONTENT_TYPE))
|
|
14
24
|
return void 0;
|
|
@@ -29,6 +39,7 @@ async function readEnvelope(request) {
|
|
|
29
39
|
export {
|
|
30
40
|
PREVIEW_CONTENT_TYPE,
|
|
31
41
|
PREVIEW_HEADER,
|
|
42
|
+
PRIME_HEADER,
|
|
32
43
|
readEnvelope,
|
|
33
44
|
readOverlay
|
|
34
45
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export interface FormPayload {
|
|
|
45
45
|
export interface DataStore {
|
|
46
46
|
/** Latest resolved data per form id. */
|
|
47
47
|
get(id: string): object | undefined;
|
|
48
|
+
/** Whether a form id has been seeded or set. */
|
|
49
|
+
has(id: string): boolean;
|
|
48
50
|
/** Populate without notifying subscribers (used for the initial seed). */
|
|
49
51
|
seed(id: string, data: object): void;
|
|
50
52
|
/** Replace cached data for a form and notify subscribers. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|