@symbo.ls/mermaid 3.14.4 → 3.14.6
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/CHANGELOG.md +18 -0
- package/dist/esm/bin/start.js +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/src/bundle.js +97 -0
- package/dist/esm/src/render.js +61 -0
- package/dist/esm/src/route.js +1 -0
- package/dist/esm/src/server.js +1 -0
- package/dist/esm/src/utils/deepDestringify.js +1 -0
- package/dist/esm/src/utils/funcql-transpile.js +1 -0
- package/dist/esm/src/utils/logger.js +1 -0
- package/dist/esm/src/utils/vartranformer.js +1 -0
- package/package.json +63 -18
- package/bin/start.js +0 -60
- package/index.js +0 -21
- package/src/bundle.js +0 -217
- package/src/render.js +0 -502
- package/src/route.js +0 -80
- package/src/server.js +0 -190
- package/src/template.html +0 -23
- package/src/utils/deepDestringify.js +0 -149
- package/src/utils/funcql-transpile.js +0 -346
- package/src/utils/logger.js +0 -131
- package/src/utils/vartranformer.js +0 -30
package/src/bundle.js
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import log from './utils/logger.js';
|
|
2
|
-
// The smbls IIFE source as a string. Single source of truth — generated by
|
|
3
|
-
// `smbls build:iife` and exported from the smbls package itself, so this works
|
|
4
|
-
// identically in Node, CF Workers, and any other runtime as a static import.
|
|
5
|
-
import smblsIife from 'smbls/iife-string';
|
|
6
|
-
|
|
7
|
-
log.debug(`[BUNDLE] smbls IIFE loaded from smbls/iife-string (${smblsIife.length} bytes)`);
|
|
8
|
-
|
|
9
|
-
// FRAMEWORK-6: any `<` in JSON that gets inlined into a `<script>` block can
|
|
10
|
-
// terminate the wrapper (`</script>`) or trigger HTML-comment / CDATA modes
|
|
11
|
-
// (`<!--`, `<![CDATA[`) inside the script-data state. Replacing every `<`
|
|
12
|
-
// with the JS unicode escape `<` neutralizes HTML interpretation while
|
|
13
|
-
// preserving the runtime string value — `<` decodes to `<` at JS parse
|
|
14
|
-
// time, so the embedded object is identical to the original. Standard
|
|
15
|
-
// mitigation: see OWASP §RULE-3.1, React's renderToString, Rails json_escape.
|
|
16
|
-
const escapeJsonForScript = (s) => s.replace(/</g, '\\u003c');
|
|
17
|
-
|
|
18
|
-
export function getSmblsIife() {
|
|
19
|
-
return smblsIife;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Generate the client-side bundle script that creates the Smbls app.
|
|
24
|
-
* Uses the same approach as templates/start.js runFromJson:
|
|
25
|
-
* Smbls.deepDestringifyFunctions(data) -> Smbls.create(app, context)
|
|
26
|
-
*/
|
|
27
|
-
export function getBundleScript(appKey, data, req, { ProjectDataService } = {}) {
|
|
28
|
-
log.debug(`[BUNDLE] getBundleScript started for ${appKey}`);
|
|
29
|
-
|
|
30
|
-
if (!data) {
|
|
31
|
-
log.warn('[BUNDLE] No data provided, returning empty');
|
|
32
|
-
return '';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Ensure data is fully merged before bundling
|
|
36
|
-
try {
|
|
37
|
-
if (data.merged) {
|
|
38
|
-
Object.assign(data, data.merged);
|
|
39
|
-
log.debug(`[BUNDLE] Applied precomputed merged data for project ${data.id}`);
|
|
40
|
-
} else if (
|
|
41
|
-
ProjectDataService &&
|
|
42
|
-
Array.isArray(data.sharedLibraries) &&
|
|
43
|
-
data.sharedLibraries.length > 0
|
|
44
|
-
) {
|
|
45
|
-
const mergedData = ProjectDataService.mergeSharedLibraries(
|
|
46
|
-
data,
|
|
47
|
-
data.sharedLibraries,
|
|
48
|
-
data.projectType,
|
|
49
|
-
);
|
|
50
|
-
Object.assign(data, mergedData);
|
|
51
|
-
log.debug(`[BUNDLE] Merged ${data.sharedLibraries.length} shared libraries`);
|
|
52
|
-
}
|
|
53
|
-
} catch (mergeError) {
|
|
54
|
-
log.error(`[BUNDLE] Failed to ensure merged data: ${mergeError.message}`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Serialize the project data as JSON (same as templates __mockedData approach).
|
|
58
|
-
// escapeJsonForScript: see FRAMEWORK-6 — any `</script>` (or `<!--`) inside a
|
|
59
|
-
// string value would break out of the inline `<script>` wrapper.
|
|
60
|
-
const jsonData = escapeJsonForScript(JSON.stringify(data));
|
|
61
|
-
|
|
62
|
-
/*
|
|
63
|
-
* Determine liveSync setting.
|
|
64
|
-
*
|
|
65
|
-
* Realtime is enabled on Symbols-managed dev hosts (any *.symbo.ls env,
|
|
66
|
-
* *.preview.symbols.app, and localhost / *.localhost for local dev) and
|
|
67
|
-
* disabled on custom domains so we don't leak the realtime backend to
|
|
68
|
-
* third-party hosts. Post-§45 the appkey is a bare `owner/key` slug, so
|
|
69
|
-
* gating on `appKey.endsWith('symbo.ls')` would always evaluate false
|
|
70
|
-
* (rendering all browsers blind). The signal we want is the request host.
|
|
71
|
-
*/
|
|
72
|
-
// Resolve incoming host across Express (req.headers.host),
|
|
73
|
-
// Cloudflare Workers / Fetch (req.headers is a Headers instance with .get),
|
|
74
|
-
// and plain options bags ({ host }). Falls back to req.url parsing so a
|
|
75
|
-
// missing Host header still degrades to a URL-based read instead of ''.
|
|
76
|
-
const rawHost =
|
|
77
|
-
(req?.headers && typeof req.headers.get === 'function' && req.headers.get('host')) ||
|
|
78
|
-
req?.headers?.host ||
|
|
79
|
-
req?.host ||
|
|
80
|
-
(req?.url && (() => { try { return new URL(req.url).host; } catch { return ''; } })()) ||
|
|
81
|
-
'';
|
|
82
|
-
const host = String(rawHost).toLowerCase().split(':')[0];
|
|
83
|
-
// Express exposes parsed query on req.query; CF Workers expose req.url only —
|
|
84
|
-
// pull `release` / `version` from a parsed URL when the structured form is
|
|
85
|
-
// absent so feature flags work in both runtimes.
|
|
86
|
-
const queryFrom = (() => {
|
|
87
|
-
if (req?.query) return req.query;
|
|
88
|
-
try { return Object.fromEntries(new URL(req?.url || '', 'http://x').searchParams); } catch { return {}; }
|
|
89
|
-
})();
|
|
90
|
-
const release = queryFrom.release || false;
|
|
91
|
-
const version = queryFrom.version;
|
|
92
|
-
const isSymboLs =
|
|
93
|
-
host.endsWith('.symbo.ls') ||
|
|
94
|
-
host.endsWith('.preview.symbols.app') ||
|
|
95
|
-
host === 'localhost' ||
|
|
96
|
-
host.endsWith('.localhost');
|
|
97
|
-
const shouldDisableLiveSync = Boolean(release) || Boolean(version) || !isSymboLs;
|
|
98
|
-
|
|
99
|
-
// Inject the persisted `_id` so the realtime client can hand the socket
|
|
100
|
-
// server a concrete projectId (mongo _id) on handshake. Without this, the
|
|
101
|
-
// server falls back to a `/v1/projects/by-key/...` lookup that 404s on the
|
|
102
|
-
// current API and drops the connection mid-join.
|
|
103
|
-
const projectId =
|
|
104
|
-
(data && (data._id || data.projectId || data.id)) ||
|
|
105
|
-
null;
|
|
106
|
-
const settingsStr = isSymboLs
|
|
107
|
-
? escapeJsonForScript(JSON.stringify({
|
|
108
|
-
...data.settings,
|
|
109
|
-
liveSync: !shouldDisableLiveSync,
|
|
110
|
-
inspect: true,
|
|
111
|
-
verbose: !shouldDisableLiveSync,
|
|
112
|
-
projectId,
|
|
113
|
-
}))
|
|
114
|
-
: 'null';
|
|
115
|
-
|
|
116
|
-
// Generate the client script - same pattern as templates/start.js runFromJson
|
|
117
|
-
const script = `
|
|
118
|
-
var context = Smbls.deepDestringifyFunctions(${jsonData});
|
|
119
|
-
context.packageManager = 'esm.sh';
|
|
120
|
-
if (context.db && context.db.createClient) delete context.db.createClient;
|
|
121
|
-
if (context.fetch && context.fetch.createClient) delete context.fetch.createClient;
|
|
122
|
-
|
|
123
|
-
// Runtime defaults (these are baked into the starter-kit/frank but missing from server data)
|
|
124
|
-
if (context.useReset === undefined) context.useReset = true;
|
|
125
|
-
if (context.useVariable === undefined) context.useVariable = true;
|
|
126
|
-
if (context.useFontImport === undefined) context.useFontImport = true;
|
|
127
|
-
if (context.useIconSprite === undefined) context.useIconSprite = true;
|
|
128
|
-
if (context.useSvgSprite === undefined) context.useSvgSprite = true;
|
|
129
|
-
if (context.useDefaultConfig === undefined) context.useDefaultConfig = true;
|
|
130
|
-
if (context.useDocumentTheme === undefined) context.useDocumentTheme = true;
|
|
131
|
-
if (!context.routerOptions) context.routerOptions = { scrollToTop: true };
|
|
132
|
-
|
|
133
|
-
var app = context.app || {};
|
|
134
|
-
delete context.app;
|
|
135
|
-
var settings = ${settingsStr};
|
|
136
|
-
if (settings) context.editor = settings;
|
|
137
|
-
|
|
138
|
-
// Theme initialization: set data-theme before app renders to avoid FOUC.
|
|
139
|
-
// Mirrors the precedence in resolveAndApplyTheme (packages/smbls/src/index.js):
|
|
140
|
-
// 1. URL param ?globalTheme=<name> — embedded-iframe override
|
|
141
|
-
// 2. localStorage[themeStorageKey] — persisted user choice
|
|
142
|
-
// 3. context.globalTheme — project's configured value
|
|
143
|
-
// 4. matchMedia(prefers-color-scheme: dark) — OS fallback (when 'auto')
|
|
144
|
-
//
|
|
145
|
-
// Writing the literal 'auto' as data-theme would leave the
|
|
146
|
-
// [data-theme="dark"] / [data-theme="light"] CSS selectors unmatched and
|
|
147
|
-
// the page would render with system defaults instead of the chosen
|
|
148
|
-
// theme — so 'auto' is always resolved to a concrete light/dark value.
|
|
149
|
-
//
|
|
150
|
-
// PRIOR BUG: this script previously ignored context.globalTheme entirely
|
|
151
|
-
// and went straight to matchMedia after localStorage. A project with
|
|
152
|
-
// globalTheme: light in config.js would render in OS dark on a
|
|
153
|
-
// dark-mode device because the inline boot ran first and locked in
|
|
154
|
-
// dark before resolveAndApplyTheme could correct it.
|
|
155
|
-
//
|
|
156
|
-
// IDEMPOTENT GUARD: the SSR-side render in @symbo.ls/mermaid/render.js
|
|
157
|
-
// now bakes data-theme onto <html> for concrete-theme projects and
|
|
158
|
-
// emits an inline <head> script that runs synchronously before paint.
|
|
159
|
-
// When that path runs, data-theme is already set by the time the bundle
|
|
160
|
-
// executes — skip this block to avoid re-resolving and overwriting
|
|
161
|
-
// (which would race with URL/localStorage values the head script
|
|
162
|
-
// already honored). Kept as a safety net for older renders / cases
|
|
163
|
-
// where the head script couldn't run.
|
|
164
|
-
if (
|
|
165
|
-
context.useDocumentTheme !== false &&
|
|
166
|
-
!document.documentElement.hasAttribute('data-theme')
|
|
167
|
-
) {
|
|
168
|
-
(function() {
|
|
169
|
-
try {
|
|
170
|
-
var t = null;
|
|
171
|
-
// 1. URL param wins (used by preview/canvas iframe embedding).
|
|
172
|
-
try {
|
|
173
|
-
var p = new URLSearchParams(window.location.search).get('globalTheme');
|
|
174
|
-
if (p) t = p;
|
|
175
|
-
} catch(e) {}
|
|
176
|
-
// 2. localStorage — only consulted when no forcing source above.
|
|
177
|
-
if (!t) {
|
|
178
|
-
var key = context.themeStorageKey;
|
|
179
|
-
if (key) { try { t = localStorage.getItem(key) } catch(e) {} }
|
|
180
|
-
}
|
|
181
|
-
// 3. Project's configured globalTheme (config.js export). Honors an
|
|
182
|
-
// explicit 'light'/'dark'/<scheme> instead of falling through to OS.
|
|
183
|
-
if (!t && context.globalTheme && context.globalTheme !== 'auto') {
|
|
184
|
-
t = context.globalTheme;
|
|
185
|
-
}
|
|
186
|
-
// 4. OS preference fallback — only when nothing concrete chose.
|
|
187
|
-
if (!t || t === 'auto') {
|
|
188
|
-
t = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
189
|
-
}
|
|
190
|
-
if (t) document.documentElement.setAttribute('data-theme', t);
|
|
191
|
-
} catch(e) {}
|
|
192
|
-
})();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// When brender pre-rendered this page, adopt the existing DOM nodes
|
|
196
|
-
// instead of tearing them down. The [data-ssr] wrapper is moved out of
|
|
197
|
-
// the way so pre-rendered children land at document.body level — matching
|
|
198
|
-
// the level at which DOMQL creates its own elements. The __BRENDER__ flag
|
|
199
|
-
// and __BR_REGISTRY__ map were injected into <head> by the server.
|
|
200
|
-
var ssrShell = document.querySelector('[data-ssr]');
|
|
201
|
-
if (window.__BRENDER__ && ssrShell) {
|
|
202
|
-
// Move pre-rendered children to body before DOMQL skeleton creation
|
|
203
|
-
var frag = document.createDocumentFragment();
|
|
204
|
-
while (ssrShell.firstChild) frag.appendChild(ssrShell.firstChild);
|
|
205
|
-
document.body.insertBefore(frag, ssrShell);
|
|
206
|
-
ssrShell.remove();
|
|
207
|
-
} else if (ssrShell) {
|
|
208
|
-
// No brender hydration — remove empty/stale SSR shell
|
|
209
|
-
ssrShell.remove();
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
Smbls.create(app, context);
|
|
213
|
-
`;
|
|
214
|
-
|
|
215
|
-
log.debug(`[BUNDLE] Script generated (${script.length} bytes)`);
|
|
216
|
-
return script;
|
|
217
|
-
}
|