@symbo.ls/mermaid 3.14.0 → 3.14.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/package.json +6 -2
- package/src/bundle.js +58 -7
- package/src/render.js +22 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbo.ls/mermaid",
|
|
3
|
-
"version": "3.14.
|
|
3
|
+
"version": "3.14.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "CC-BY-NC-4.0",
|
|
6
6
|
"description": "Self-sustaining server runner for Symbols projects from JSON. Renders DOMQL projects to HTML with optional brender SSR.",
|
|
@@ -17,7 +17,11 @@
|
|
|
17
17
|
"./utils/logger": "./src/utils/logger.js",
|
|
18
18
|
"./template.html": "./src/template.html"
|
|
19
19
|
},
|
|
20
|
-
"files": [
|
|
20
|
+
"files": [
|
|
21
|
+
"index.js",
|
|
22
|
+
"src",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
21
25
|
"scripts": {
|
|
22
26
|
"start": "node bin/start.js"
|
|
23
27
|
},
|
package/src/bundle.js
CHANGED
|
@@ -48,14 +48,58 @@ export function getBundleScript(appKey, data, req, { ProjectDataService } = {})
|
|
|
48
48
|
// Serialize the project data as JSON (same as templates __mockedData approach)
|
|
49
49
|
const jsonData = JSON.stringify(data);
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
/*
|
|
52
|
+
* Determine liveSync setting.
|
|
53
|
+
*
|
|
54
|
+
* Realtime is enabled on Symbols-managed dev hosts (any *.symbo.ls env,
|
|
55
|
+
* *.preview.symbols.app, and localhost / *.localhost for local dev) and
|
|
56
|
+
* disabled on custom domains so we don't leak the realtime backend to
|
|
57
|
+
* third-party hosts. Post-§45 the appkey is a bare `owner/key` slug, so
|
|
58
|
+
* gating on `appKey.endsWith('symbo.ls')` would always evaluate false
|
|
59
|
+
* (rendering all browsers blind). The signal we want is the request host.
|
|
60
|
+
*/
|
|
61
|
+
// Resolve incoming host across Express (req.headers.host),
|
|
62
|
+
// Cloudflare Workers / Fetch (req.headers is a Headers instance with .get),
|
|
63
|
+
// and plain options bags ({ host }). Falls back to req.url parsing so a
|
|
64
|
+
// missing Host header still degrades to a URL-based read instead of ''.
|
|
65
|
+
const rawHost =
|
|
66
|
+
(req?.headers && typeof req.headers.get === 'function' && req.headers.get('host')) ||
|
|
67
|
+
req?.headers?.host ||
|
|
68
|
+
req?.host ||
|
|
69
|
+
(req?.url && (() => { try { return new URL(req.url).host; } catch { return ''; } })()) ||
|
|
70
|
+
'';
|
|
71
|
+
const host = String(rawHost).toLowerCase().split(':')[0];
|
|
72
|
+
// Express exposes parsed query on req.query; CF Workers expose req.url only —
|
|
73
|
+
// pull `release` / `version` from a parsed URL when the structured form is
|
|
74
|
+
// absent so feature flags work in both runtimes.
|
|
75
|
+
const queryFrom = (() => {
|
|
76
|
+
if (req?.query) return req.query;
|
|
77
|
+
try { return Object.fromEntries(new URL(req?.url || '', 'http://x').searchParams); } catch { return {}; }
|
|
78
|
+
})();
|
|
79
|
+
const release = queryFrom.release || false;
|
|
80
|
+
const version = queryFrom.version;
|
|
81
|
+
const isSymboLs =
|
|
82
|
+
host.endsWith('.symbo.ls') ||
|
|
83
|
+
host.endsWith('.preview.symbols.app') ||
|
|
84
|
+
host === 'localhost' ||
|
|
85
|
+
host.endsWith('.localhost');
|
|
55
86
|
const shouldDisableLiveSync = Boolean(release) || Boolean(version) || !isSymboLs;
|
|
56
87
|
|
|
88
|
+
// Inject the persisted `_id` so the realtime client can hand the socket
|
|
89
|
+
// server a concrete projectId (mongo _id) on handshake. Without this, the
|
|
90
|
+
// server falls back to a `/v1/projects/by-key/...` lookup that 404s on the
|
|
91
|
+
// current API and drops the connection mid-join.
|
|
92
|
+
const projectId =
|
|
93
|
+
(data && (data._id || data.projectId || data.id)) ||
|
|
94
|
+
null;
|
|
57
95
|
const settingsStr = isSymboLs
|
|
58
|
-
? JSON.stringify({
|
|
96
|
+
? JSON.stringify({
|
|
97
|
+
...data.settings,
|
|
98
|
+
liveSync: !shouldDisableLiveSync,
|
|
99
|
+
inspect: true,
|
|
100
|
+
verbose: !shouldDisableLiveSync,
|
|
101
|
+
projectId,
|
|
102
|
+
})
|
|
59
103
|
: 'null';
|
|
60
104
|
|
|
61
105
|
// Generate the client script - same pattern as templates/start.js runFromJson
|
|
@@ -85,14 +129,21 @@ export function getBundleScript(appKey, data, req, { ProjectDataService } = {})
|
|
|
85
129
|
// way so pre-rendered children land at document.body level — matching the
|
|
86
130
|
// level at which DOMQL creates its own elements. The __BRENDER__ flag and
|
|
87
131
|
// __BR_REGISTRY__ map were injected into <head> by the server.
|
|
88
|
-
// Theme initialization: set data-theme before app renders to avoid FOUC
|
|
132
|
+
// Theme initialization: set data-theme before app renders to avoid FOUC.
|
|
133
|
+
// 'auto' means "follow OS preference" — resolve through matchMedia and
|
|
134
|
+
// emit the concrete light/dark value. Writing the literal "auto" string
|
|
135
|
+
// would leave [data-theme="dark"] / [data-theme="light"] selectors
|
|
136
|
+
// unmatched + the page would render with system-default colors instead
|
|
137
|
+
// of the chosen theme. Matches resolveAndApplyTheme in smbls/src/index.js.
|
|
89
138
|
if (context.useDocumentTheme !== false) {
|
|
90
139
|
(function() {
|
|
91
140
|
try {
|
|
92
141
|
var t = null;
|
|
93
142
|
var key = context.themeStorageKey;
|
|
94
143
|
if (key) { try { t = localStorage.getItem(key) } catch(e) {} }
|
|
95
|
-
if (!t
|
|
144
|
+
if (!t || t === 'auto') {
|
|
145
|
+
t = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
146
|
+
}
|
|
96
147
|
if (t) document.documentElement.setAttribute('data-theme', t);
|
|
97
148
|
} catch(e) {}
|
|
98
149
|
})();
|
package/src/render.js
CHANGED
|
@@ -309,7 +309,10 @@ export async function renderProjectHtml(data, options = {}) {
|
|
|
309
309
|
const bundle = getBundleScript(appkey, data, req, { ProjectDataService });
|
|
310
310
|
|
|
311
311
|
// ── Importmap ─────────────────────────────────────────────────────────────
|
|
312
|
-
|
|
312
|
+
// esm.sh is the default — it resolves transitive deps correctly and matches
|
|
313
|
+
// the `context.packageManager = 'esm.sh'` set by bundle.js at runtime.
|
|
314
|
+
// Skypack frequently 500s on transitive deps (e.g. lit-html via ninja-keys).
|
|
315
|
+
const importmap = getImportMapScript(data, data?.settings?.cdnProvider || 'esmsh');
|
|
313
316
|
|
|
314
317
|
// ── HTML template ─────────────────────────────────────────────────────────
|
|
315
318
|
const indexHtmlFromFiles = data?.files && data.files['index.html'];
|
|
@@ -378,23 +381,35 @@ export async function renderProjectHtml(data, options = {}) {
|
|
|
378
381
|
}
|
|
379
382
|
|
|
380
383
|
/**
|
|
381
|
-
* Render the "project not published" 404 fallback page.
|
|
384
|
+
* Render the "project not published" 404 fallback page. When `reason` is
|
|
385
|
+
* 'not_public', renders a tailored "site not yet public" message —
|
|
386
|
+
* specifically for paid custom domains pointing at a project whose
|
|
387
|
+
* visibility is still private.
|
|
382
388
|
*/
|
|
383
|
-
export function renderNotPublishedHtml(appkey, channel = 'production') {
|
|
389
|
+
export function renderNotPublishedHtml(appkey, channel = 'production', reason = null) {
|
|
384
390
|
const envLabel = channel !== 'production' ? ` (${channel})` : '';
|
|
391
|
+
const isNotPublic = reason === 'not_public';
|
|
392
|
+
const title = isNotPublic ? 'Site Not Yet Public' : 'Not Published';
|
|
393
|
+
const heading = isNotPublic
|
|
394
|
+
? `This site isn't public yet${envLabel}`
|
|
395
|
+
: `This project hasn't been published yet${envLabel}`;
|
|
396
|
+
const body = isNotPublic
|
|
397
|
+
? `The owner has connected this domain but the project's visibility is set to private. Once they switch it to public in the workspace settings, the site will appear here automatically.`
|
|
398
|
+
: `Run <code>smbls publish</code> to deploy your project, or visit <a href="https://symbols.app">symbols.app</a> to get started.`;
|
|
385
399
|
return `<!doctype html>
|
|
386
400
|
<html>
|
|
387
401
|
<head>
|
|
388
402
|
<meta charset="UTF-8">
|
|
389
403
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
390
404
|
<meta name="robots" content="noindex">
|
|
391
|
-
<title
|
|
405
|
+
<title>${title}</title>
|
|
392
406
|
<style>
|
|
393
407
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
394
408
|
body { min-height: 100vh; display: flex; align-items: center; justify-content: center; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0a0a0a; color: #fafafa; }
|
|
395
|
-
.container { text-align: center; max-width:
|
|
409
|
+
.container { text-align: center; max-width: 520px; padding: 2rem; }
|
|
396
410
|
h1 { font-size: 1.25rem; font-weight: 500; margin-bottom: 0.75rem; }
|
|
397
411
|
p { color: #888; font-size: 0.875rem; line-height: 1.6; }
|
|
412
|
+
code { background: #1a1a1a; padding: 0.1rem 0.35rem; border-radius: 3px; font-size: 0.8rem; color: #ccc; }
|
|
398
413
|
a { color: #888; text-decoration: underline; text-underline-offset: 2px; }
|
|
399
414
|
a:hover { color: #fafafa; }
|
|
400
415
|
.env { display: inline-block; font-size: 0.75rem; color: #555; background: #1a1a1a; padding: 0.2rem 0.5rem; border-radius: 4px; margin-top: 1rem; }
|
|
@@ -402,8 +417,8 @@ export function renderNotPublishedHtml(appkey, channel = 'production') {
|
|
|
402
417
|
</head>
|
|
403
418
|
<body>
|
|
404
419
|
<div class="container">
|
|
405
|
-
<h1
|
|
406
|
-
<p
|
|
420
|
+
<h1>${heading}</h1>
|
|
421
|
+
<p>${body}</p>
|
|
407
422
|
<span class="env">${appkey}${envLabel}</span>
|
|
408
423
|
</div>
|
|
409
424
|
</body>
|