@storystick/preview 0.2.0-rc.0 → 0.2.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PUBLIC-API.md +3 -2
- package/dist/.source-hash +1 -1
- package/dist/authoring/runtime-contract.d.ts +5 -2
- package/dist/authoring/runtime-contract.js +1 -1
- package/dist/page-presentation.d.ts +24 -0
- package/dist/page-presentation.js +32 -0
- package/dist/server/control-errors.js +34 -17
- package/package.json +8 -4
package/PUBLIC-API.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @storystick/preview API contract
|
|
2
2
|
|
|
3
|
-
Install this candidate explicitly with `@storystick/preview@0.2.0-rc.
|
|
3
|
+
Install this candidate explicitly with `@storystick/preview@0.2.0-rc.1` after registry bootstrap and publication. This repository alone does not make the candidate or beta channel available on npm.
|
|
4
4
|
|
|
5
|
-
Version 0.2.0-rc.
|
|
5
|
+
Version 0.2.0-rc.1, cohort `sdk-0.2.0-rc.1`. ESM distribution; no CommonJS or universal Edge compatibility is promised.
|
|
6
6
|
|
|
7
7
|
This package supports the integration facades; installing it directly is an advanced use. Reserved contracts are required between SDK packages and must be upgraded with the same cohort. Their public export paths do not promise independent stability.
|
|
8
8
|
|
|
@@ -35,6 +35,7 @@ This package supports the integration facades; installing it directly is an adva
|
|
|
35
35
|
| `./provenance` | Reserved SDK contract |
|
|
36
36
|
| `./provenance/richtext-slice-embed-address` | Reserved SDK contract |
|
|
37
37
|
| `./authoring/runtime-contract` | Reserved SDK contract |
|
|
38
|
+
| `./page-presentation` | Reserved SDK contract |
|
|
38
39
|
| `./sdk-error-copy` | Reserved SDK contract |
|
|
39
40
|
| `./session-subscriber` | Reserved SDK contract |
|
|
40
41
|
| `./provenance/source-registry` | Reserved SDK contract |
|
package/dist/.source-hash
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
bd76a6ce0bc6a45860a5c7a43beca2a761804917b32721b33339d3cbe862a05d
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PreviewPerspective, PreviewReadContext } from '@storystick/types/preview-query-targeting';
|
|
2
2
|
import type { PreviewV2RevealSourceRequest, PreviewV2RevealSliceRequest } from '../provenance/reveal-contract.js';
|
|
3
3
|
import type { ImperativeEditorNavigationTarget } from '@storystick/types/editor-destination';
|
|
4
|
-
export declare const STORYSTICK_AUTHORING_RUNTIME_CONTRACT_VERSION:
|
|
4
|
+
export declare const STORYSTICK_AUTHORING_RUNTIME_CONTRACT_VERSION: 11;
|
|
5
5
|
export declare const STORYSTICK_AUTHORING_RUNTIME_GLOBAL: "StorystickAuthoringRuntime";
|
|
6
6
|
export declare const STORYSTICK_AUTHORING_RUNTIME_PATH: "/authoring-runtime/authoring-runtime.js";
|
|
7
7
|
export interface PreviewAuthoringAdmission {
|
|
@@ -45,9 +45,10 @@ export interface PreviewAuthoringRuntimeMountOptions {
|
|
|
45
45
|
root: ShadowRoot;
|
|
46
46
|
container: HTMLElement;
|
|
47
47
|
target?: PreviewAuthoringTarget;
|
|
48
|
-
surface?: PreviewAuthoringSurface;
|
|
48
|
+
surface?: PreviewAuthoringSurface | null;
|
|
49
49
|
header?: {
|
|
50
50
|
leading: HTMLElement;
|
|
51
|
+
title: HTMLElement;
|
|
51
52
|
trailing: HTMLElement;
|
|
52
53
|
};
|
|
53
54
|
assistantThreadId?: string | null;
|
|
@@ -85,5 +86,7 @@ export interface PreviewAuthoringRuntimeHandle {
|
|
|
85
86
|
}
|
|
86
87
|
export interface PreviewAuthoringRuntimeModule {
|
|
87
88
|
readonly contractVersion: typeof STORYSTICK_AUTHORING_RUNTIME_CONTRACT_VERSION;
|
|
89
|
+
/** Fetch code only. Admission, queries and mounting still require an explicit open. */
|
|
90
|
+
preload(surface: PreviewAuthoringSurface): Promise<void>;
|
|
88
91
|
mount(options: PreviewAuthoringRuntimeMountOptions): PreviewAuthoringRuntimeHandle;
|
|
89
92
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const STORYSTICK_AUTHORING_RUNTIME_CONTRACT_VERSION =
|
|
1
|
+
export const STORYSTICK_AUTHORING_RUNTIME_CONTRACT_VERSION = 11;
|
|
2
2
|
export const STORYSTICK_AUTHORING_RUNTIME_GLOBAL = 'StorystickAuthoringRuntime';
|
|
3
3
|
export const STORYSTICK_AUTHORING_RUNTIME_PATH = '/authoring-runtime/authoring-runtime.js';
|
|
4
4
|
export function isPreviewAuthoringAdmission(value, now = Date.now()) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Framework-independent presentation for Preview's opening and failure pages.
|
|
2
|
+
* The activation route can render the same surface before any React runtime. */
|
|
3
|
+
export declare const STORYSTICK_MARK_VIEW_BOX = "0 0 12 11";
|
|
4
|
+
export declare const STORYSTICK_MARK_RECTS: readonly [{
|
|
5
|
+
readonly x: 0;
|
|
6
|
+
readonly y: 4;
|
|
7
|
+
readonly width: 3;
|
|
8
|
+
readonly height: 7;
|
|
9
|
+
readonly rx: 1;
|
|
10
|
+
}, {
|
|
11
|
+
readonly x: 4.5;
|
|
12
|
+
readonly y: 0;
|
|
13
|
+
readonly width: 3;
|
|
14
|
+
readonly height: 11;
|
|
15
|
+
readonly rx: 1;
|
|
16
|
+
}, {
|
|
17
|
+
readonly x: 9;
|
|
18
|
+
readonly y: 6;
|
|
19
|
+
readonly width: 3;
|
|
20
|
+
readonly height: 5;
|
|
21
|
+
readonly rx: 1;
|
|
22
|
+
}];
|
|
23
|
+
export declare const PREVIEW_PAGE_BRAND_HTML: string;
|
|
24
|
+
export declare const PREVIEW_PAGE_STYLES = "\n [data-ss-preview-page] { box-sizing: border-box; display: flex; min-height: 100svh; width: 100%; padding: 32px 24px; background: var(--ss-surface-page, #fff); color: var(--ss-text-primary, oklch(.2 .007 258.364)); font: 400 14px/20px \"Storystick Inter\", \"Inter Variable\", ui-sans-serif, system-ui, sans-serif; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; color-scheme: light; }\n [data-ss-preview-page-content] { width: 100%; max-width: 360px; margin: auto; text-align: center; overflow-wrap: anywhere; }\n [data-ss-preview-page-brand] { display: flex; align-items: center; justify-content: center; gap: 9px; margin-bottom: 32px; font-size: 15px; font-weight: 500; letter-spacing: -.015em; }\n [data-ss-preview-page-brand] svg { flex: none; width: 15px; height: 14px; transform: rotate(90deg); }\n [data-ss-preview-page-heading] { display: flex; align-items: center; justify-content: center; gap: 10px; }\n [data-ss-preview-page-title] { margin: 0; color: inherit; font: inherit; font-size: 20px; line-height: 28px; font-weight: 500; letter-spacing: -.025em; text-wrap: balance; }\n [data-ss-preview-page-description] { margin: 12px 0 0; color: var(--ss-text-secondary, oklch(.471 .006 258.364)); font: inherit; text-wrap: pretty; }\n [data-ss-preview-page-actions] { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; margin-top: 24px; }\n [data-ss-preview-page-action] { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; min-height: 36px; padding: 8px 16px; border: 0; border-radius: 999px; background: var(--ss-surface-card, #fff); color: inherit; box-shadow: var(--ss-shadow-control, 0 0 1px rgb(0 0 0 / .22), 0 2px 4px rgb(0 0 0 / .04)); font: inherit; line-height: 20px; text-decoration: none; cursor: pointer; transition: background-color 140ms ease; }\n [data-ss-preview-page-action]:hover { background: var(--ss-surface-field, oklch(.958 .001 255)); }\n [data-ss-preview-page-action='primary'] { background: var(--ss-text-primary, oklch(.2 .007 258.364)); color: #fff; box-shadow: none; }\n [data-ss-preview-page-action='primary']:hover { background: #303034; }\n [data-ss-preview-page-action]:focus-visible, [data-ss-preview-page] summary:focus-visible { outline: 2px solid var(--ss-focus-color, oklch(.614 .194 257)); outline-offset: 3px; }\n [data-ss-preview-page] details { margin-top: 24px; color: var(--ss-text-secondary, oklch(.471 .006 258.364)); font-size: 12px; line-height: 18px; }\n [data-ss-preview-page] summary { width: fit-content; margin-inline: auto; border-radius: 4px; cursor: pointer; }\n [data-ss-preview-page] pre { box-sizing: border-box; max-height: 240px; margin: 12px 0 0; overflow: auto; padding: 12px; border-radius: 12px; background: var(--ss-surface-field, oklch(.958 .001 255)); font: 12px/18px ui-monospace, monospace; white-space: pre-wrap; text-align: left; }\n [data-ss-preview-page-progress] { position: relative; display: inline-block; flex: none; width: 15px; height: 15px; color: var(--ss-text-tertiary, oklch(.515 .006 258.364)); animation: ss-preview-page-orbit 720ms linear infinite; }\n [data-ss-preview-page-progress]::before { content: ''; position: absolute; inset: 0; box-sizing: border-box; border: 2px solid currentColor; border-radius: 50%; opacity: .2; }\n [data-ss-preview-page-progress]::after { content: ''; position: absolute; top: 1px; left: calc(50% - 2px); width: 4px; height: 4px; border-radius: 50%; background: currentColor; }\n @keyframes ss-preview-page-orbit { to { transform: rotate(360deg); } }\n @media (prefers-reduced-motion: reduce) { [data-ss-preview-page-progress] { animation: none; } [data-ss-preview-page-action] { transition: none; } }\n";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Framework-independent presentation for Preview's opening and failure pages.
|
|
2
|
+
* The activation route can render the same surface before any React runtime. */
|
|
3
|
+
export const STORYSTICK_MARK_VIEW_BOX = '0 0 12 11';
|
|
4
|
+
export const STORYSTICK_MARK_RECTS = [
|
|
5
|
+
{ x: 0, y: 4, width: 3, height: 7, rx: 1 },
|
|
6
|
+
{ x: 4.5, y: 0, width: 3, height: 11, rx: 1 },
|
|
7
|
+
{ x: 9, y: 6, width: 3, height: 5, rx: 1 },
|
|
8
|
+
];
|
|
9
|
+
export const PREVIEW_PAGE_BRAND_HTML = `<div data-ss-preview-page-brand><svg viewBox="${STORYSTICK_MARK_VIEW_BOX}" fill="currentColor" aria-hidden="true">${STORYSTICK_MARK_RECTS.map(rect => `<rect ${Object.entries(rect).map(([key, value]) => `${key}="${value}"`).join(' ')} />`).join('')}</svg><span>Storystick</span></div>`;
|
|
10
|
+
export const PREVIEW_PAGE_STYLES = `
|
|
11
|
+
[data-ss-preview-page] { box-sizing: border-box; display: flex; min-height: 100svh; width: 100%; padding: 32px 24px; background: var(--ss-surface-page, #fff); color: var(--ss-text-primary, oklch(.2 .007 258.364)); font: 400 14px/20px "Storystick Inter", "Inter Variable", ui-sans-serif, system-ui, sans-serif; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; color-scheme: light; }
|
|
12
|
+
[data-ss-preview-page-content] { width: 100%; max-width: 360px; margin: auto; text-align: center; overflow-wrap: anywhere; }
|
|
13
|
+
[data-ss-preview-page-brand] { display: flex; align-items: center; justify-content: center; gap: 9px; margin-bottom: 32px; font-size: 15px; font-weight: 500; letter-spacing: -.015em; }
|
|
14
|
+
[data-ss-preview-page-brand] svg { flex: none; width: 15px; height: 14px; transform: rotate(90deg); }
|
|
15
|
+
[data-ss-preview-page-heading] { display: flex; align-items: center; justify-content: center; gap: 10px; }
|
|
16
|
+
[data-ss-preview-page-title] { margin: 0; color: inherit; font: inherit; font-size: 20px; line-height: 28px; font-weight: 500; letter-spacing: -.025em; text-wrap: balance; }
|
|
17
|
+
[data-ss-preview-page-description] { margin: 12px 0 0; color: var(--ss-text-secondary, oklch(.471 .006 258.364)); font: inherit; text-wrap: pretty; }
|
|
18
|
+
[data-ss-preview-page-actions] { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; margin-top: 24px; }
|
|
19
|
+
[data-ss-preview-page-action] { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; min-height: 36px; padding: 8px 16px; border: 0; border-radius: 999px; background: var(--ss-surface-card, #fff); color: inherit; box-shadow: var(--ss-shadow-control, 0 0 1px rgb(0 0 0 / .22), 0 2px 4px rgb(0 0 0 / .04)); font: inherit; line-height: 20px; text-decoration: none; cursor: pointer; transition: background-color 140ms ease; }
|
|
20
|
+
[data-ss-preview-page-action]:hover { background: var(--ss-surface-field, oklch(.958 .001 255)); }
|
|
21
|
+
[data-ss-preview-page-action='primary'] { background: var(--ss-text-primary, oklch(.2 .007 258.364)); color: #fff; box-shadow: none; }
|
|
22
|
+
[data-ss-preview-page-action='primary']:hover { background: #303034; }
|
|
23
|
+
[data-ss-preview-page-action]:focus-visible, [data-ss-preview-page] summary:focus-visible { outline: 2px solid var(--ss-focus-color, oklch(.614 .194 257)); outline-offset: 3px; }
|
|
24
|
+
[data-ss-preview-page] details { margin-top: 24px; color: var(--ss-text-secondary, oklch(.471 .006 258.364)); font-size: 12px; line-height: 18px; }
|
|
25
|
+
[data-ss-preview-page] summary { width: fit-content; margin-inline: auto; border-radius: 4px; cursor: pointer; }
|
|
26
|
+
[data-ss-preview-page] pre { box-sizing: border-box; max-height: 240px; margin: 12px 0 0; overflow: auto; padding: 12px; border-radius: 12px; background: var(--ss-surface-field, oklch(.958 .001 255)); font: 12px/18px ui-monospace, monospace; white-space: pre-wrap; text-align: left; }
|
|
27
|
+
[data-ss-preview-page-progress] { position: relative; display: inline-block; flex: none; width: 15px; height: 15px; color: var(--ss-text-tertiary, oklch(.515 .006 258.364)); animation: ss-preview-page-orbit 720ms linear infinite; }
|
|
28
|
+
[data-ss-preview-page-progress]::before { content: ''; position: absolute; inset: 0; box-sizing: border-box; border: 2px solid currentColor; border-radius: 50%; opacity: .2; }
|
|
29
|
+
[data-ss-preview-page-progress]::after { content: ''; position: absolute; top: 1px; left: calc(50% - 2px); width: 4px; height: 4px; border-radius: 50%; background: currentColor; }
|
|
30
|
+
@keyframes ss-preview-page-orbit { to { transform: rotate(360deg); } }
|
|
31
|
+
@media (prefers-reduced-motion: reduce) { [data-ss-preview-page-progress] { animation: none; } [data-ss-preview-page-action] { transition: none; } }
|
|
32
|
+
`;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { PREVIEW_PAGE_BRAND_HTML, PREVIEW_PAGE_STYLES } from "../page-presentation.js";
|
|
1
2
|
import { StorystickError } from "@storystick/client";
|
|
2
3
|
import { mapPreviewSessionError } from "@storystick/preview/session-subscriber";
|
|
3
4
|
export function previewInitialRouteErrorResponse(request, error) {
|
|
4
|
-
if (
|
|
5
|
+
if (requestAcceptsHtml(request)) {
|
|
5
6
|
return previewHtmlErrorResponse(error, new URL(request.url).searchParams.get("_ss_session"));
|
|
6
7
|
}
|
|
7
8
|
return previewErrorResponse(error);
|
|
@@ -63,7 +64,11 @@ function buildHtmlError(error, sessionId) {
|
|
|
63
64
|
? `<script>window.parent.postMessage(${JSON.stringify({ type: 'storystick.preview.activation-error', sessionId, code: error.code })}, '*');</script>`
|
|
64
65
|
: '';
|
|
65
66
|
const code = escapeHtml(error.code);
|
|
66
|
-
const
|
|
67
|
+
const details = escapeHtml([
|
|
68
|
+
error.code, error.message,
|
|
69
|
+
...('upstreamCode' in error && error.upstreamCode ? [`Upstream code: ${error.upstreamCode}`] : []),
|
|
70
|
+
...('upstreamRef' in error && error.upstreamRef ? [`Reference: ${error.upstreamRef}`] : []),
|
|
71
|
+
].join('\n'));
|
|
67
72
|
const retryScript = error.retryable
|
|
68
73
|
? `<script>
|
|
69
74
|
(() => {
|
|
@@ -88,6 +93,10 @@ function buildHtmlError(error, sessionId) {
|
|
|
88
93
|
} catch (_) {}
|
|
89
94
|
if (attempt >= maxAttempts) {
|
|
90
95
|
document.body.dataset.previewRecovery = 'stopped';
|
|
96
|
+
document.title = 'Preview unavailable';
|
|
97
|
+
document.querySelector('[data-ss-preview-page-progress]')?.remove();
|
|
98
|
+
document.querySelector('[data-ss-preview-page-title]').textContent = 'Preview unavailable';
|
|
99
|
+
document.querySelector('[data-ss-preview-page-description]').textContent = 'The site could not reconnect. Try again, or reopen Preview from Studio.';
|
|
91
100
|
return;
|
|
92
101
|
}
|
|
93
102
|
const delay = Math.min(5000, Math.round(500 * Math.pow(1.5, attempt - 1)));
|
|
@@ -97,29 +106,37 @@ function buildHtmlError(error, sessionId) {
|
|
|
97
106
|
})();
|
|
98
107
|
</script>`
|
|
99
108
|
: "";
|
|
100
|
-
const title = error.retryable ? "Preview
|
|
101
|
-
const
|
|
102
|
-
? "
|
|
103
|
-
: error.code === "PREVIEW_PROJECT_MISMATCH"
|
|
109
|
+
const title = error.retryable ? "Preview reconnecting" : "Preview unavailable";
|
|
110
|
+
const description = error.retryable
|
|
111
|
+
? "We’re reconnecting to your site. Your preview will open here when it’s ready."
|
|
112
|
+
: error.code === "PREVIEW_PROJECT_MISMATCH"
|
|
113
|
+
? "This site belongs to another project. Open Preview from the correct project in Studio."
|
|
114
|
+
: "Reopen this preview from Storystick Studio to continue.";
|
|
104
115
|
return `<!doctype html>
|
|
105
116
|
<html lang="en">
|
|
106
117
|
<head>
|
|
107
118
|
<meta charset="utf-8">
|
|
108
119
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
109
120
|
<title>${title}</title>
|
|
110
|
-
<style>
|
|
111
|
-
:root { color-scheme: light dark; font-family: system-ui, sans-serif; }
|
|
112
|
-
body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: Canvas; color: CanvasText; }
|
|
113
|
-
main { max-width: 28rem; padding: 1.5rem; line-height: 1.5; }
|
|
114
|
-
h1 { font-size: 1rem; margin: 0 0 .5rem; }
|
|
115
|
-
p { margin: 0; color: color-mix(in srgb, CanvasText 70%, transparent); }
|
|
116
|
-
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .8125rem; }
|
|
117
|
-
</style>
|
|
121
|
+
<style>body { margin: 0; } ${PREVIEW_PAGE_STYLES}</style>
|
|
118
122
|
</head>
|
|
119
123
|
<body>
|
|
120
|
-
<main
|
|
121
|
-
<
|
|
122
|
-
|
|
124
|
+
<main data-ss-preview-page>
|
|
125
|
+
<div data-ss-preview-page-content>
|
|
126
|
+
${PREVIEW_PAGE_BRAND_HTML}
|
|
127
|
+
<div role="${error.retryable ? 'status' : 'alert'}">
|
|
128
|
+
<div data-ss-preview-page-heading>
|
|
129
|
+
${error.retryable ? '<span data-ss-preview-page-progress aria-hidden="true"></span>' : ''}
|
|
130
|
+
<h1 data-ss-preview-page-title>${title}</h1>
|
|
131
|
+
</div>
|
|
132
|
+
<p data-ss-preview-page-description>${description}</p>
|
|
133
|
+
</div>
|
|
134
|
+
${error.retryable ? '<div data-ss-preview-page-actions><button type="button" data-ss-preview-page-action="primary" onclick="window.location.reload()">Try again</button></div>' : ''}
|
|
135
|
+
<details>
|
|
136
|
+
<summary>Technical details</summary>
|
|
137
|
+
<pre data-preview-error="${code}">${details}</pre>
|
|
138
|
+
</details>
|
|
139
|
+
</div>
|
|
123
140
|
</main>
|
|
124
141
|
${diagnostic}
|
|
125
142
|
${retryScript}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storystick/preview",
|
|
3
|
-
"version": "0.2.0-rc.
|
|
3
|
+
"version": "0.2.0-rc.1",
|
|
4
4
|
"license": "FSL-1.1-MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -115,6 +115,10 @@
|
|
|
115
115
|
"types": "./dist/authoring/runtime-contract.d.ts",
|
|
116
116
|
"import": "./dist/authoring/runtime-contract.js"
|
|
117
117
|
},
|
|
118
|
+
"./page-presentation": {
|
|
119
|
+
"types": "./dist/page-presentation.d.ts",
|
|
120
|
+
"import": "./dist/page-presentation.js"
|
|
121
|
+
},
|
|
118
122
|
"./sdk-error-copy": {
|
|
119
123
|
"types": "./dist/sdk-error-copy.d.ts",
|
|
120
124
|
"import": "./dist/sdk-error-copy.js"
|
|
@@ -177,9 +181,9 @@
|
|
|
177
181
|
},
|
|
178
182
|
"dependencies": {
|
|
179
183
|
"convex": "1.42.3",
|
|
180
|
-
"@storystick/client": "0.2.0-rc.
|
|
181
|
-
"@storystick/transport-allowlist": "0.1.0-rc.
|
|
182
|
-
"@storystick/types": "0.1.0-rc.
|
|
184
|
+
"@storystick/client": "0.2.0-rc.1",
|
|
185
|
+
"@storystick/transport-allowlist": "0.1.0-rc.1",
|
|
186
|
+
"@storystick/types": "0.1.0-rc.1"
|
|
183
187
|
},
|
|
184
188
|
"devDependencies": {
|
|
185
189
|
"fake-indexeddb": "^6.2.5",
|