camox 0.59.0 → 0.61.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/core/createApp.d.ts +8 -8
- package/dist/core/createBlock.d.ts +1 -2
- package/dist/core/createLayout.d.ts +10 -2
- package/dist/core/createLayout.js +1 -3
- package/dist/core/editing/BlockEditingRuntime.d.ts +1 -0
- package/dist/core/editing/CompleteBlockEditingRuntime.js +12 -9
- package/dist/core/editing/createEditableBlock.d.ts +4 -4
- package/dist/core/editing/createEditableBlock.js +20 -26
- package/dist/core/lib/artifactData.js +2 -2
- package/dist/core/lib/contentType.js +5 -4
- package/dist/features/preview/components/SelectionEditor.js +1 -1
- package/dist/features/renderer/RendererApp.js +187 -103
- package/dist/features/renderer/rendererHost.js +23 -16
- package/dist/features/renderer/studioConnection.js +8 -4
- package/dist/features/runtime/loopbackFetch.d.ts +8 -0
- package/dist/features/runtime/publicCache.d.ts +21 -0
- package/dist/features/runtime/publishingDraft.d.ts +4 -0
- package/dist/features/runtime/runtime.js +54 -3
- package/dist/features/runtime/worker.js +1 -4
- package/dist/features/runtime/workerRequest.d.ts +8 -0
- package/dist/features/runtime/workerRuntime.d.ts +5 -0
- package/dist/features/runtime/workerRuntime.js +6 -0
- package/dist/features/sdkBundle/buildSdkBundle.d.ts +40 -0
- package/dist/features/sdkBundle/buildSdkBundle.js +323 -0
- package/dist/features/sdkBundle/localSdkBundle.d.ts +44 -0
- package/dist/features/sdkBundle/localSdkBundle.js +162 -0
- package/dist/features/sdkBundle/sdkBundle.d.ts +3 -0
- package/dist/features/sdkBundle/sdkBundle.js +4 -0
- package/dist/features/sdkBundle/sdkBundleName.d.ts +59 -0
- package/dist/features/sdkBundle/sdkBundleName.js +164 -0
- package/dist/features/sdkBundle/specifiers.d.ts +34 -0
- package/dist/features/sdkBundle/specifiers.js +146 -0
- package/dist/features/settings/SocialProfilesSettings.js +284 -151
- package/dist/features/settings/useProjectMutation.js +6 -5
- package/dist/features/studio/FollowAgentProvider.js +71 -12
- package/dist/features/studio/components/ChatWidget.js +85 -43
- package/dist/features/studio/components/Patrol.js +311 -208
- package/dist/features/studio/components/Squareling.js +164 -66
- package/dist/features/studio/components/ThreadComposer.js +139 -69
- package/dist/features/studio/components/ThreadMessages.js +115 -45
- package/dist/features/studio/editorWhereContext.js +11 -0
- package/dist/features/studio/useEditorSelection.js +135 -0
- package/dist/features/vite/hostedChecks.js +1 -1
- package/dist/features/vite/runtimeDev.js +2 -1
- package/dist/features/vite/sdkBundleBuild.js +74 -0
- package/dist/features/vite/staticAssetHeaders.js +7 -4
- package/dist/features/vite/vite.d.ts +0 -2
- package/dist/features/vite/vite.js +33 -3
- package/dist/lib/auth.js +24 -58
- package/dist/lib/server-auth-cookie.js +12 -2
- package/dist/lib/stored-auth-cookies.js +76 -0
- package/dist/lib/use-thread.js +9 -5
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +17 -4
|
@@ -113,9 +113,10 @@ function RendererApp(t0) {
|
|
|
113
113
|
}
|
|
114
114
|
/** A block's thumbnail, rendered by the draft's code into its frame: nothing for a block it lacks. */
|
|
115
115
|
function RendererThumbnail(t0) {
|
|
116
|
-
const $ = c(
|
|
116
|
+
const $ = c(17);
|
|
117
117
|
const { slot, blockType, camoxApp } = t0;
|
|
118
118
|
const frameWindow = slot.ownerDocument.defaultView;
|
|
119
|
+
const left = useLeftInSlot(slot);
|
|
119
120
|
const t1 = frameWindow?.frameElement ?? null;
|
|
120
121
|
let t2;
|
|
121
122
|
if ($[0] !== frameWindow || $[1] !== t1) {
|
|
@@ -130,32 +131,55 @@ function RendererThumbnail(t0) {
|
|
|
130
131
|
const frameContext = t2;
|
|
131
132
|
let t3;
|
|
132
133
|
if ($[3] !== blockType || $[4] !== camoxApp) {
|
|
133
|
-
t3 = /* @__PURE__ */ jsx(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
camoxApp
|
|
138
|
-
})
|
|
139
|
-
}) });
|
|
134
|
+
t3 = /* @__PURE__ */ jsx(ThumbnailBlock, {
|
|
135
|
+
blockType,
|
|
136
|
+
camoxApp
|
|
137
|
+
});
|
|
140
138
|
$[3] = blockType;
|
|
141
139
|
$[4] = camoxApp;
|
|
142
140
|
$[5] = t3;
|
|
143
141
|
} else t3 = $[5];
|
|
144
142
|
let t4;
|
|
145
|
-
if ($[6] !==
|
|
146
|
-
t4 = /* @__PURE__ */ jsx(
|
|
143
|
+
if ($[6] !== left) {
|
|
144
|
+
t4 = /* @__PURE__ */ jsx(RemovesLeft, { nodes: left });
|
|
145
|
+
$[6] = left;
|
|
146
|
+
$[7] = t4;
|
|
147
|
+
} else t4 = $[7];
|
|
148
|
+
let t5;
|
|
149
|
+
if ($[8] !== t3 || $[9] !== t4) {
|
|
150
|
+
t5 = /* @__PURE__ */ jsxs(React.Suspense, {
|
|
151
|
+
fallback: null,
|
|
152
|
+
children: [t3, t4]
|
|
153
|
+
});
|
|
154
|
+
$[8] = t3;
|
|
155
|
+
$[9] = t4;
|
|
156
|
+
$[10] = t5;
|
|
157
|
+
} else t5 = $[10];
|
|
158
|
+
let t6;
|
|
159
|
+
if ($[11] !== left || $[12] !== t5) {
|
|
160
|
+
t6 = /* @__PURE__ */ jsx(ThumbnailErrorBoundary, {
|
|
161
|
+
left,
|
|
162
|
+
children: t5
|
|
163
|
+
});
|
|
164
|
+
$[11] = left;
|
|
165
|
+
$[12] = t5;
|
|
166
|
+
$[13] = t6;
|
|
167
|
+
} else t6 = $[13];
|
|
168
|
+
let t7;
|
|
169
|
+
if ($[14] !== frameContext || $[15] !== t6) {
|
|
170
|
+
t7 = /* @__PURE__ */ jsx(NavigationProvider, {
|
|
147
171
|
location: THUMBNAIL_LOCATION,
|
|
148
172
|
navigate: noNavigation,
|
|
149
173
|
children: /* @__PURE__ */ jsx(FrameContext.Provider, {
|
|
150
174
|
value: frameContext,
|
|
151
|
-
children:
|
|
175
|
+
children: t6
|
|
152
176
|
})
|
|
153
177
|
});
|
|
154
|
-
$[
|
|
155
|
-
$[
|
|
156
|
-
$[
|
|
157
|
-
} else
|
|
158
|
-
return
|
|
178
|
+
$[14] = frameContext;
|
|
179
|
+
$[15] = t6;
|
|
180
|
+
$[16] = t7;
|
|
181
|
+
} else t7 = $[16];
|
|
182
|
+
return t7;
|
|
159
183
|
}
|
|
160
184
|
const THUMBNAIL_LOCATION = {
|
|
161
185
|
href: "",
|
|
@@ -173,7 +197,7 @@ var ThumbnailErrorBoundary = class extends React.Component {
|
|
|
173
197
|
console.error("Camox: a block's thumbnail failed to render.", error);
|
|
174
198
|
}
|
|
175
199
|
render() {
|
|
176
|
-
return this.state.failed ?
|
|
200
|
+
return this.state.failed ? /* @__PURE__ */ jsx(RemovesLeft, { nodes: this.props.left }) : this.props.children;
|
|
177
201
|
}
|
|
178
202
|
};
|
|
179
203
|
function ThumbnailBlock(t0) {
|
|
@@ -188,6 +212,46 @@ function ThumbnailBlock(t0) {
|
|
|
188
212
|
} else t1 = $[1];
|
|
189
213
|
return t1;
|
|
190
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* What another renderer document left in `slot`, read before this one renders into it. Each new
|
|
217
|
+
* revision loads another renderer document, and removing the last one's frame never unmounts
|
|
218
|
+
* what it rendered into the studio's frames, so its page stays there.
|
|
219
|
+
*/
|
|
220
|
+
function useLeftInSlot(slot) {
|
|
221
|
+
const $ = c(2);
|
|
222
|
+
let t0;
|
|
223
|
+
if ($[0] !== slot) {
|
|
224
|
+
t0 = () => [...slot.childNodes];
|
|
225
|
+
$[0] = slot;
|
|
226
|
+
$[1] = t0;
|
|
227
|
+
} else t0 = $[1];
|
|
228
|
+
const [left] = React.useState(t0);
|
|
229
|
+
return left;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Removes the nodes another renderer left, once what replaces them commits: until then, the
|
|
233
|
+
* frame keeps showing the last page rather than nothing.
|
|
234
|
+
*/
|
|
235
|
+
function RemovesLeft(t0) {
|
|
236
|
+
const $ = c(3);
|
|
237
|
+
const { nodes } = t0;
|
|
238
|
+
let t1;
|
|
239
|
+
let t2;
|
|
240
|
+
if ($[0] !== nodes) {
|
|
241
|
+
t1 = () => {
|
|
242
|
+
for (const node of nodes) node.remove();
|
|
243
|
+
};
|
|
244
|
+
t2 = [nodes];
|
|
245
|
+
$[0] = nodes;
|
|
246
|
+
$[1] = t1;
|
|
247
|
+
$[2] = t2;
|
|
248
|
+
} else {
|
|
249
|
+
t1 = $[1];
|
|
250
|
+
t2 = $[2];
|
|
251
|
+
}
|
|
252
|
+
React.useLayoutEffect(t1, t2);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
191
255
|
function locationOf(href) {
|
|
192
256
|
const url = new URL(href);
|
|
193
257
|
return {
|
|
@@ -199,10 +263,11 @@ function locationOf(href) {
|
|
|
199
263
|
}
|
|
200
264
|
/** One frame's page, with what the studio says of the frame around it. */
|
|
201
265
|
function RendererFrameContent(t0) {
|
|
202
|
-
const $ = c(
|
|
266
|
+
const $ = c(65);
|
|
203
267
|
const { frame: t1, connection, camoxApp, codeLoaded, projectUuid, runtimeBasePath } = t0;
|
|
204
268
|
const { frameId, slot, target } = t1;
|
|
205
269
|
const frameWindow = slot.ownerDocument.defaultView;
|
|
270
|
+
const left = useLeftInSlot(slot);
|
|
206
271
|
const frameElement = frameWindow?.frameElement ?? null;
|
|
207
272
|
let t2;
|
|
208
273
|
if ($[0] !== target.href) {
|
|
@@ -293,17 +358,14 @@ function RendererFrameContent(t0) {
|
|
|
293
358
|
} else t9 = $[18];
|
|
294
359
|
let t10;
|
|
295
360
|
if ($[19] !== camoxApp || $[20] !== codeLoaded || $[21] !== projectUuid || $[22] !== rendered || $[23] !== runtimeBasePath || $[24] !== target.derivedLayoutId || $[25] !== target.pathname) {
|
|
296
|
-
t10 = /* @__PURE__ */ jsx(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
derivedLayoutId: target.derivedLayoutId,
|
|
305
|
-
onRendered: rendered
|
|
306
|
-
})
|
|
361
|
+
t10 = /* @__PURE__ */ jsx(FramePage, {
|
|
362
|
+
camoxApp,
|
|
363
|
+
codeLoaded,
|
|
364
|
+
projectUuid,
|
|
365
|
+
runtimeBasePath,
|
|
366
|
+
pathname: target.pathname,
|
|
367
|
+
derivedLayoutId: target.derivedLayoutId,
|
|
368
|
+
onRendered: rendered
|
|
307
369
|
});
|
|
308
370
|
$[19] = camoxApp;
|
|
309
371
|
$[20] = codeLoaded;
|
|
@@ -315,110 +377,128 @@ function RendererFrameContent(t0) {
|
|
|
315
377
|
$[26] = t10;
|
|
316
378
|
} else t10 = $[26];
|
|
317
379
|
let t11;
|
|
318
|
-
if ($[27] !==
|
|
319
|
-
t11 = /* @__PURE__ */ jsx(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
$[27] = failed;
|
|
324
|
-
$[28] = t10;
|
|
325
|
-
$[29] = target.pathname;
|
|
326
|
-
$[30] = t11;
|
|
327
|
-
} else t11 = $[30];
|
|
380
|
+
if ($[27] !== left) {
|
|
381
|
+
t11 = /* @__PURE__ */ jsx(RemovesLeft, { nodes: left });
|
|
382
|
+
$[27] = left;
|
|
383
|
+
$[28] = t11;
|
|
384
|
+
} else t11 = $[28];
|
|
328
385
|
let t12;
|
|
329
|
-
if ($[
|
|
330
|
-
t12 = /* @__PURE__ */
|
|
331
|
-
|
|
332
|
-
children: t11
|
|
386
|
+
if ($[29] !== t10 || $[30] !== t11) {
|
|
387
|
+
t12 = /* @__PURE__ */ jsxs(React.Suspense, {
|
|
388
|
+
fallback: t9,
|
|
389
|
+
children: [t10, t11]
|
|
333
390
|
});
|
|
334
|
-
$[
|
|
335
|
-
$[
|
|
336
|
-
$[
|
|
337
|
-
} else t12 = $[
|
|
391
|
+
$[29] = t10;
|
|
392
|
+
$[30] = t11;
|
|
393
|
+
$[31] = t12;
|
|
394
|
+
} else t12 = $[31];
|
|
338
395
|
let t13;
|
|
339
|
-
if ($[34] !== t12 || $[35] !== target.
|
|
340
|
-
t13 = /* @__PURE__ */ jsx(
|
|
341
|
-
|
|
396
|
+
if ($[32] !== failed || $[33] !== left || $[34] !== t12 || $[35] !== target.pathname) {
|
|
397
|
+
t13 = /* @__PURE__ */ jsx(FrameErrorBoundary, {
|
|
398
|
+
onError: failed,
|
|
399
|
+
left,
|
|
342
400
|
children: t12
|
|
343
|
-
});
|
|
401
|
+
}, target.pathname);
|
|
402
|
+
$[32] = failed;
|
|
403
|
+
$[33] = left;
|
|
344
404
|
$[34] = t12;
|
|
345
|
-
$[35] = target.
|
|
405
|
+
$[35] = target.pathname;
|
|
346
406
|
$[36] = t13;
|
|
347
407
|
} else t13 = $[36];
|
|
348
408
|
let t14;
|
|
349
|
-
if ($[37] !== t13 || $[38] !==
|
|
350
|
-
t14 = /* @__PURE__ */ jsx(
|
|
351
|
-
|
|
409
|
+
if ($[37] !== t13 || $[38] !== t8) {
|
|
410
|
+
t14 = /* @__PURE__ */ jsx(React.Activity, {
|
|
411
|
+
mode: t8,
|
|
352
412
|
children: t13
|
|
353
413
|
});
|
|
354
414
|
$[37] = t13;
|
|
355
|
-
$[38] =
|
|
415
|
+
$[38] = t8;
|
|
356
416
|
$[39] = t14;
|
|
357
417
|
} else t14 = $[39];
|
|
358
418
|
let t15;
|
|
359
|
-
if ($[40] !== t14 || $[41] !== target.
|
|
360
|
-
t15 = /* @__PURE__ */ jsx(
|
|
361
|
-
value: target.
|
|
419
|
+
if ($[40] !== t14 || $[41] !== target.artifactStudio) {
|
|
420
|
+
t15 = /* @__PURE__ */ jsx(ArtifactStudioContext, {
|
|
421
|
+
value: target.artifactStudio,
|
|
362
422
|
children: t14
|
|
363
423
|
});
|
|
364
424
|
$[40] = t14;
|
|
365
|
-
$[41] = target.
|
|
425
|
+
$[41] = target.artifactStudio;
|
|
366
426
|
$[42] = t15;
|
|
367
427
|
} else t15 = $[42];
|
|
368
428
|
let t16;
|
|
369
|
-
if ($[43] !== t15 || $[44] !==
|
|
370
|
-
t16 = /* @__PURE__ */ jsx(
|
|
371
|
-
value:
|
|
429
|
+
if ($[43] !== t15 || $[44] !== target.artifactsRun) {
|
|
430
|
+
t16 = /* @__PURE__ */ jsx(ArtifactsRunContext, {
|
|
431
|
+
value: target.artifactsRun,
|
|
372
432
|
children: t15
|
|
373
433
|
});
|
|
374
434
|
$[43] = t15;
|
|
375
|
-
$[44] =
|
|
435
|
+
$[44] = target.artifactsRun;
|
|
376
436
|
$[45] = t16;
|
|
377
437
|
} else t16 = $[45];
|
|
378
438
|
let t17;
|
|
379
|
-
if ($[46] !== t16 || $[47] !== target.
|
|
380
|
-
t17 = /* @__PURE__ */ jsx(
|
|
381
|
-
value: target.
|
|
439
|
+
if ($[46] !== t16 || $[47] !== target.editable) {
|
|
440
|
+
t17 = /* @__PURE__ */ jsx(EditableSurfaceContext, {
|
|
441
|
+
value: target.editable,
|
|
382
442
|
children: t16
|
|
383
443
|
});
|
|
384
444
|
$[46] = t16;
|
|
385
|
-
$[47] = target.
|
|
445
|
+
$[47] = target.editable;
|
|
386
446
|
$[48] = t17;
|
|
387
447
|
} else t17 = $[48];
|
|
388
448
|
let t18;
|
|
389
|
-
if ($[49] !==
|
|
390
|
-
t18 = /* @__PURE__ */ jsx(
|
|
391
|
-
value:
|
|
449
|
+
if ($[49] !== t17 || $[50] !== workspace) {
|
|
450
|
+
t18 = /* @__PURE__ */ jsx(CanvasWorkspaceContext, {
|
|
451
|
+
value: workspace,
|
|
392
452
|
children: t17
|
|
393
453
|
});
|
|
394
|
-
$[49] =
|
|
395
|
-
$[50] =
|
|
454
|
+
$[49] = t17;
|
|
455
|
+
$[50] = workspace;
|
|
396
456
|
$[51] = t18;
|
|
397
457
|
} else t18 = $[51];
|
|
398
458
|
let t19;
|
|
399
|
-
if ($[52] !==
|
|
400
|
-
t19 = /* @__PURE__ */ jsx(
|
|
401
|
-
|
|
402
|
-
navigate,
|
|
459
|
+
if ($[52] !== t18 || $[53] !== target.owner) {
|
|
460
|
+
t19 = /* @__PURE__ */ jsx(PreviewEditingOwnerContext, {
|
|
461
|
+
value: target.owner,
|
|
403
462
|
children: t18
|
|
404
463
|
});
|
|
405
|
-
$[52] =
|
|
406
|
-
$[53] =
|
|
407
|
-
$[54] =
|
|
408
|
-
|
|
409
|
-
} else t19 = $[55];
|
|
410
|
-
const content = t19;
|
|
464
|
+
$[52] = t18;
|
|
465
|
+
$[53] = target.owner;
|
|
466
|
+
$[54] = t19;
|
|
467
|
+
} else t19 = $[54];
|
|
411
468
|
let t20;
|
|
412
|
-
if ($[
|
|
413
|
-
t20 =
|
|
469
|
+
if ($[55] !== frameContext || $[56] !== t19) {
|
|
470
|
+
t20 = /* @__PURE__ */ jsx(FrameContext.Provider, {
|
|
471
|
+
value: frameContext,
|
|
472
|
+
children: t19
|
|
473
|
+
});
|
|
474
|
+
$[55] = frameContext;
|
|
475
|
+
$[56] = t19;
|
|
476
|
+
$[57] = t20;
|
|
477
|
+
} else t20 = $[57];
|
|
478
|
+
let t21;
|
|
479
|
+
if ($[58] !== location || $[59] !== navigate || $[60] !== t20) {
|
|
480
|
+
t21 = /* @__PURE__ */ jsx(NavigationProvider, {
|
|
481
|
+
location,
|
|
482
|
+
navigate,
|
|
483
|
+
children: t20
|
|
484
|
+
});
|
|
485
|
+
$[58] = location;
|
|
486
|
+
$[59] = navigate;
|
|
487
|
+
$[60] = t20;
|
|
488
|
+
$[61] = t21;
|
|
489
|
+
} else t21 = $[61];
|
|
490
|
+
const content = t21;
|
|
491
|
+
let t22;
|
|
492
|
+
if ($[62] !== content || $[63] !== target.locale) {
|
|
493
|
+
t22 = target.locale ? /* @__PURE__ */ jsx(ViewLocaleContext, {
|
|
414
494
|
value: target.locale,
|
|
415
495
|
children: content
|
|
416
496
|
}) : content;
|
|
417
|
-
$[
|
|
418
|
-
$[
|
|
419
|
-
$[
|
|
420
|
-
} else
|
|
421
|
-
return
|
|
497
|
+
$[62] = content;
|
|
498
|
+
$[63] = target.locale;
|
|
499
|
+
$[64] = t22;
|
|
500
|
+
} else t22 = $[64];
|
|
501
|
+
return t22;
|
|
422
502
|
}
|
|
423
503
|
function _temp2() {
|
|
424
504
|
return _temp;
|
|
@@ -539,19 +619,23 @@ var FrameErrorBoundary = class extends React.Component {
|
|
|
539
619
|
role: "alert",
|
|
540
620
|
"data-camox-renderer-error": true,
|
|
541
621
|
style: ERROR_STYLE,
|
|
542
|
-
children: [
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
622
|
+
children: [
|
|
623
|
+
/* @__PURE__ */ jsx(RemovesLeft, { nodes: this.props.left }),
|
|
624
|
+
/* @__PURE__ */ jsx("p", {
|
|
625
|
+
style: {
|
|
626
|
+
margin: 0,
|
|
627
|
+
fontWeight: 600
|
|
628
|
+
},
|
|
629
|
+
children: "This page couldn’t render."
|
|
630
|
+
}),
|
|
631
|
+
/* @__PURE__ */ jsx("p", {
|
|
632
|
+
style: {
|
|
633
|
+
margin: "8px 0 0",
|
|
634
|
+
fontFamily: "ui-monospace, monospace"
|
|
635
|
+
},
|
|
636
|
+
children: this.state.error
|
|
637
|
+
})
|
|
638
|
+
]
|
|
555
639
|
});
|
|
556
640
|
}
|
|
557
641
|
};
|
|
@@ -6,14 +6,30 @@ import { createContentEditor } from "../../core/editing/contentEdits.js";
|
|
|
6
6
|
import { LIVE_KEY_SCOPE, scopeOfKey } from "@camox/api-contract/query-keys";
|
|
7
7
|
|
|
8
8
|
//#region src/features/renderer/rendererHost.ts
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
/** The studio's state of each store the renderer mirrors. */
|
|
10
|
+
const storeMessages = {
|
|
11
|
+
preview: () => ({
|
|
12
|
+
type: "store",
|
|
13
|
+
store: "preview",
|
|
14
|
+
context: previewStore.getSnapshot().context
|
|
15
|
+
}),
|
|
16
|
+
canvas: () => ({
|
|
17
|
+
type: "store",
|
|
18
|
+
store: "canvas",
|
|
19
|
+
context: canvasStore.getSnapshot().context
|
|
20
|
+
})
|
|
12
21
|
};
|
|
22
|
+
/** The stores the renderer forwards its events to, as the host applies them. */
|
|
13
23
|
const forwarded = {
|
|
14
24
|
preview: previewStore,
|
|
15
25
|
referencePickerFocus
|
|
16
26
|
};
|
|
27
|
+
/** Applies an event the renderer forwarded to the studio's store. */
|
|
28
|
+
const applyStoreEvent = (message) => {
|
|
29
|
+
const store = forwarded[message.store];
|
|
30
|
+
if (!store) return;
|
|
31
|
+
store.send(message.event);
|
|
32
|
+
};
|
|
17
33
|
/**
|
|
18
34
|
* The host of the studio whose cache is `studioCache`, viewing the draft `draftScope` names, which
|
|
19
35
|
* the renderer shows too. Without them, the renderer hears nothing of the studio's cache.
|
|
@@ -45,12 +61,8 @@ function createRendererHost({ studioCache, draftScope, queryClient, notify } = {
|
|
|
45
61
|
const post = (message) => {
|
|
46
62
|
if (welcomed) renderer?.(message);
|
|
47
63
|
};
|
|
48
|
-
const postStore = (store) => post(
|
|
49
|
-
|
|
50
|
-
store,
|
|
51
|
-
context: mirrored[store].getSnapshot().context
|
|
52
|
-
});
|
|
53
|
-
const subscriptions = Object.keys(mirrored).map((store) => mirrored[store].subscribe(() => postStore(store)));
|
|
64
|
+
const postStore = (store) => post(storeMessages[store]());
|
|
65
|
+
const subscriptions = [previewStore.subscribe(() => postStore("preview")), canvasStore.subscribe(() => postStore("canvas"))];
|
|
54
66
|
const shownScope = () => draftScope?.current() ?? LIVE_KEY_SCOPE;
|
|
55
67
|
const shown = (queryKey) => scopeOfKey(queryKey) === shownScope();
|
|
56
68
|
/** Whether a project room invalidation reaches the reads of the draft the renderer shows. */
|
|
@@ -103,7 +115,7 @@ function createRendererHost({ studioCache, draftScope, queryClient, notify } = {
|
|
|
103
115
|
if (message.sdkVersion !== SDK_VERSION) return setStatus("updating");
|
|
104
116
|
welcomed = true;
|
|
105
117
|
setStatus("connected");
|
|
106
|
-
for (const store of Object.keys(
|
|
118
|
+
for (const store of Object.keys(storeMessages)) postStore(store);
|
|
107
119
|
for (const [frameId, { slot, target }] of frames) post({
|
|
108
120
|
type: "frame",
|
|
109
121
|
frameId,
|
|
@@ -123,12 +135,7 @@ function createRendererHost({ studioCache, draftScope, queryClient, notify } = {
|
|
|
123
135
|
});
|
|
124
136
|
for (const listener of connectionListeners) listener();
|
|
125
137
|
return;
|
|
126
|
-
case "storeEvent":
|
|
127
|
-
const store = forwarded[message.store];
|
|
128
|
-
if (!store) return;
|
|
129
|
-
store.send(message.event);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
138
|
+
case "storeEvent": return applyStoreEvent(message);
|
|
132
139
|
case "rendered": return frames.get(message.frameId)?.hears.rendered?.();
|
|
133
140
|
case "error": return frames.get(message.frameId)?.hears.failed?.(message.message);
|
|
134
141
|
case "navigate": return frames.get(message.frameId)?.hears.navigate?.(message.to);
|
|
@@ -5,14 +5,21 @@ import { SDK_VERSION, deferredInbox } from "./protocol.js";
|
|
|
5
5
|
import { answerFromCode } from "./definitionAnswers.js";
|
|
6
6
|
|
|
7
7
|
//#region src/features/renderer/studioConnection.ts
|
|
8
|
+
/** The stores of this document that take the studio's state as it is (`mirror`). */
|
|
8
9
|
const mirrors = {
|
|
9
10
|
preview: previewStore,
|
|
10
11
|
canvas: canvasStore
|
|
11
12
|
};
|
|
13
|
+
/** The stores of this document whose events are forwarded to the studio's. */
|
|
12
14
|
const forwards = {
|
|
13
15
|
preview: previewStore,
|
|
14
16
|
referencePickerFocus
|
|
15
17
|
};
|
|
18
|
+
/** Has this document's copy of a mirrored store take the studio's state. */
|
|
19
|
+
const mirror = (message) => mirrors[message.store]?.send({
|
|
20
|
+
type: "mirror",
|
|
21
|
+
context: message.context
|
|
22
|
+
});
|
|
16
23
|
/**
|
|
17
24
|
* Connects the renderer document to the studio through its handle. This document's stores then
|
|
18
25
|
* mirror the studio's, its own events are forwarded to the studio, which owns their truth, and
|
|
@@ -64,10 +71,7 @@ function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxAp
|
|
|
64
71
|
setFrames(frames.filter(({ frameId }) => frameId !== message.frameId));
|
|
65
72
|
return;
|
|
66
73
|
case "store":
|
|
67
|
-
|
|
68
|
-
type: "mirror",
|
|
69
|
-
context: message.context
|
|
70
|
-
});
|
|
74
|
+
mirror(message);
|
|
71
75
|
return;
|
|
72
76
|
case "draftStarted":
|
|
73
77
|
draftScope.enterStarted(message.draftId);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/features/runtime/loopbackFetch.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Browsers resolve any `*.localhost` name to loopback, but the Workers runtime asks the
|
|
4
|
+
* OS, which need not. Local dev servers (like the per-checkout API) use such names, so
|
|
5
|
+
* the dev worker reaches them on 127.0.0.1 instead.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fetchLocalhostOnLoopback(fetch: typeof globalThis.fetch): typeof globalThis.fetch;
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/features/runtime/publicCache.d.ts
|
|
2
|
+
/** Where a website's public renders are kept, and what they're kept under. */
|
|
3
|
+
export interface PublicCache {
|
|
4
|
+
/** Opens Cloudflare's cache in the request's data center: `PUBLIC_CACHE_NAME`. */
|
|
5
|
+
cache: () => Promise<Cache>;
|
|
6
|
+
/** The project's Live cache key, which changes whenever Live does; null when unreadable. */
|
|
7
|
+
liveCacheKey: () => Promise<string | null>;
|
|
8
|
+
/** The website's build, so a release never serves pages naming the last release's assets. */
|
|
9
|
+
build: string;
|
|
10
|
+
waitUntil: (promise: Promise<unknown>) => void;
|
|
11
|
+
}
|
|
12
|
+
/** The named cache public renders are kept in. */
|
|
13
|
+
export declare const PUBLIC_CACHE_NAME = "camox-public-renders";
|
|
14
|
+
/** The project's Live cache key, as the API serves it from its edge cache. */
|
|
15
|
+
export declare function readLiveCacheKey(apiUrl: string, projectUuid: string): Promise<string | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Answers a public request from the cache, or renders it and keeps the render when it may be
|
|
18
|
+
* shared. Without a Live cache key, it renders without the cache: nothing tells when Live changed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function respondThroughPublicCache(request: Request, publicCache: PublicCache, render: () => Promise<Response | null>): Promise<Response | null>;
|
|
21
|
+
//#endregion
|
|
@@ -2,7 +2,8 @@ import { serializeJsonForHtml } from "../../lib/html.js";
|
|
|
2
2
|
import { createRequestContext } from "../../core/requestContext.js";
|
|
3
3
|
import { UNNAMED_DEFAULT_LOCALE, localizedPath, parseLocalePath } from "../../lib/locale-path.js";
|
|
4
4
|
import { draftNamedBy } from "../../lib/draft-scope.js";
|
|
5
|
-
import { buildClearServerAuthCookieHeader, getServerAuthCookieHeader } from "../../lib/server-auth-cookie.js";
|
|
5
|
+
import { buildClearServerAuthCookieHeader, buildServerAuthCookieHeader, getServerAuthCookieHeader } from "../../lib/server-auth-cookie.js";
|
|
6
|
+
import { getCookie, getSetCookie } from "../../lib/stored-auth-cookies.js";
|
|
6
7
|
import { ARTIFACTS_PATH_PREFIX, RUNTIME_ROUTE_PATHS, matchRuntimeOwnedRoute } from "./runtimeRoutes.js";
|
|
7
8
|
import { reads } from "../../lib/studio-reads.js";
|
|
8
9
|
import { asCollectionItem, recordMarkdownTemplate, recordPageValues } from "../../core/recordItem.js";
|
|
@@ -79,7 +80,7 @@ const PUBLIC_ROUTE_KINDS = /* @__PURE__ */ new Set([
|
|
|
79
80
|
*/
|
|
80
81
|
function isPublicRequest(request, options = {}) {
|
|
81
82
|
if (request.method !== "GET" && request.method !== "HEAD") return false;
|
|
82
|
-
if (isPrivateRender(request) ||
|
|
83
|
+
if (isPrivateRender(request) || new URL(request.url).searchParams.has("ott")) return false;
|
|
83
84
|
const pathname = getRuntimePathname(request.url, options.runtimeBasePath);
|
|
84
85
|
return pathname !== null && PUBLIC_ROUTE_KINDS.has(matchRuntimeRoute(pathname).kind);
|
|
85
86
|
}
|
|
@@ -559,6 +560,51 @@ function isPreviewHandoff(request, options) {
|
|
|
559
560
|
return searchParams.has("camox-preview") && searchParams.has("ott") && !!options.apiUrl && !!options.authenticationUrl && !!options.projectUuid && !!options.renderPage;
|
|
560
561
|
}
|
|
561
562
|
/**
|
|
563
|
+
* Whether a request lands from the studio's sign-in with its one-time token, which the Worker
|
|
564
|
+
* exchanges itself. A preview link's handoff checks its target in the browser first.
|
|
565
|
+
*/
|
|
566
|
+
function isSignInHandoff(request) {
|
|
567
|
+
const { searchParams } = new URL(request.url);
|
|
568
|
+
return request.method === "GET" && searchParams.has("ott") && !searchParams.has("camox-preview");
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Exchanges a sign-in's one-time token for the studio's session, sets the cookie that mirrors it,
|
|
572
|
+
* and sends the browser back to the URL without the token. The page then renders for the member
|
|
573
|
+
* at once, rather than for a visitor, then again once the browser signed in. Null when the
|
|
574
|
+
* exchange fails: the page loads with the token, and the browser tries it and says what failed.
|
|
575
|
+
*/
|
|
576
|
+
async function createSignInResponse(request, apiUrl) {
|
|
577
|
+
const url = new URL(request.url);
|
|
578
|
+
let setCookie;
|
|
579
|
+
try {
|
|
580
|
+
const response = await fetch(`${apiUrl.replace(/\/+$/, "")}/api/auth/one-time-token/verify`, {
|
|
581
|
+
method: "POST",
|
|
582
|
+
headers: {
|
|
583
|
+
"Content-Type": "application/json",
|
|
584
|
+
"Better-Auth-Cookie": ""
|
|
585
|
+
},
|
|
586
|
+
body: JSON.stringify({ token: url.searchParams.get("ott") })
|
|
587
|
+
});
|
|
588
|
+
if (!response.ok) return null;
|
|
589
|
+
setCookie = response.headers.get("Set-Better-Auth-Cookie");
|
|
590
|
+
} catch (error) {
|
|
591
|
+
console.error("[camox] Sign-in token exchange failed.", error);
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
const session = setCookie ? getCookie(getSetCookie(setCookie)) : "";
|
|
595
|
+
if (!session) return null;
|
|
596
|
+
url.searchParams.delete("ott");
|
|
597
|
+
return new Response(null, {
|
|
598
|
+
status: 302,
|
|
599
|
+
headers: {
|
|
600
|
+
Location: `${url.pathname}${url.search}`,
|
|
601
|
+
"Cache-Control": "private, no-store",
|
|
602
|
+
"Referrer-Policy": "no-referrer",
|
|
603
|
+
"Set-Cookie": buildServerAuthCookieHeader(session, { secure: url.protocol === "https:" })
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
562
608
|
* The alternates of the page a request renders, where it exists in each of the scope's locales,
|
|
563
609
|
* and its head with their `hreflang` links. Without a head, there is none to add them to.
|
|
564
610
|
*/
|
|
@@ -1257,7 +1303,8 @@ async function createStudioHtmlResponse({ match, options, pathname, located, req
|
|
|
1257
1303
|
routeKind: match.kind,
|
|
1258
1304
|
runtimeBasePath: normalizeRuntimeBasePath(options.runtimeBasePath),
|
|
1259
1305
|
locale: located.locale,
|
|
1260
|
-
locales: located.locales
|
|
1306
|
+
locales: located.locales,
|
|
1307
|
+
draftId: project ? getRequestDraftId(request) : void 0
|
|
1261
1308
|
};
|
|
1262
1309
|
if (dataOnly) return Response.json(studioRenderInput, { headers: {
|
|
1263
1310
|
"Cache-Control": "private, no-store",
|
|
@@ -1429,6 +1476,10 @@ async function handleCamoxRequest(request, options = {}) {
|
|
|
1429
1476
|
pathname,
|
|
1430
1477
|
request
|
|
1431
1478
|
});
|
|
1479
|
+
if (options.apiUrl && isSignInHandoff(request)) {
|
|
1480
|
+
const signedIn = await createSignInResponse(request, options.apiUrl);
|
|
1481
|
+
if (signedIn) return signedIn;
|
|
1482
|
+
}
|
|
1432
1483
|
const { apiUrl, projectUuid } = options;
|
|
1433
1484
|
const markdownPathname = parseMarkdownPath(pathname);
|
|
1434
1485
|
if (apiUrl && projectUuid && (markdownPathname || prefersMarkdown(request.headers.get("Accept") ?? ""))) {
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { rememberPublishingDraft } from "
|
|
2
|
-
import { fetchLocalhostOnLoopback } from "./loopbackFetch.js";
|
|
3
|
-
import { PUBLIC_CACHE_NAME, readLiveCacheKey, respondThroughPublicCache } from "./publicCache.js";
|
|
4
|
-
import { shouldHandleRequest, withDevHtml } from "./workerRequest.js";
|
|
1
|
+
import { PUBLIC_CACHE_NAME, fetchLocalhostOnLoopback, readLiveCacheKey, rememberPublishingDraft, respondThroughPublicCache, shouldHandleRequest, withDevHtml } from "camox/_internal/workerRuntime";
|
|
5
2
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
6
3
|
import { devHtml, handleCamoxRequest, isPublicRequest, publicCacheSource, readDefinitionSet, runtimeBasePath } from "virtual:camox/server";
|
|
7
4
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/features/runtime/workerRequest.d.ts
|
|
2
|
+
export declare function shouldHandleRequest(request: Request, basePath: string): boolean;
|
|
3
|
+
/** Adds what Vite injects into HTML in dev, such as its client and React Refresh. */
|
|
4
|
+
export declare function withDevHtml(response: Response, html: {
|
|
5
|
+
head: string;
|
|
6
|
+
body: string;
|
|
7
|
+
} | null): Promise<Response>;
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { fetchLocalhostOnLoopback } from "./loopbackFetch.js";
|
|
2
|
+
import { PUBLIC_CACHE_NAME, readLiveCacheKey, respondThroughPublicCache } from "./publicCache.js";
|
|
3
|
+
import { rememberPublishingDraft } from "./publishingDraft.js";
|
|
4
|
+
import { shouldHandleRequest, withDevHtml } from "./workerRequest.js";
|
|
5
|
+
export { PUBLIC_CACHE_NAME, fetchLocalhostOnLoopback, readLiveCacheKey, rememberPublishingDraft, respondThroughPublicCache, shouldHandleRequest, withDevHtml };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { rememberPublishingDraft } from "./publishingDraft.js";
|
|
2
|
+
import { fetchLocalhostOnLoopback } from "./loopbackFetch.js";
|
|
3
|
+
import { PUBLIC_CACHE_NAME, readLiveCacheKey, respondThroughPublicCache } from "./publicCache.js";
|
|
4
|
+
import { shouldHandleRequest, withDevHtml } from "./workerRequest.js";
|
|
5
|
+
|
|
6
|
+
export { PUBLIC_CACHE_NAME, fetchLocalhostOnLoopback, readLiveCacheKey, rememberPublishingDraft, respondThroughPublicCache, shouldHandleRequest, withDevHtml };
|