markstream-solid 0.0.0-stage → 2.0.23

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.
Files changed (102) hide show
  1. package/README.md +120 -2
  2. package/dist/client/extended-BTbixd9o.js +38 -0
  3. package/dist/client/index.js +5640 -0
  4. package/dist/client/katexWorkerClient-ZLzkPVv_.js +260 -0
  5. package/dist/client/languageIcon-CDTPjsAQ.js +280 -0
  6. package/dist/client/mermaidWorkerClient-BAvGYsCO.js +243 -0
  7. package/dist/client/utils/index.js +31 -0
  8. package/dist/client/utils/katex-threshold.js +32 -0
  9. package/dist/client/utils/performance-monitor.js +73 -0
  10. package/dist/client/utils/safeRaf.js +27 -0
  11. package/dist/client/workers/katexCdnWorker.js +177 -0
  12. package/dist/client/workers/katexRenderer.worker.js +45 -0
  13. package/dist/client/workers/katexWorkerClient.js +16 -0
  14. package/dist/client/workers/mermaidCdnWorker.js +226 -0
  15. package/dist/client/workers/mermaidParser.worker.js +73 -0
  16. package/dist/client/workers/mermaidWorkerClient.js +13 -0
  17. package/dist/components/BuiltinNodes.d.ts +42 -0
  18. package/dist/components/CodeBlockNode.d.ts +10 -0
  19. package/dist/components/DiagramBlockNode.d.ts +27 -0
  20. package/dist/components/HtmlPreviewFrame.d.ts +10 -0
  21. package/dist/components/MarkstreamProvider.d.ts +5 -0
  22. package/dist/components/MarkstreamVirtualTimeline.d.ts +35 -0
  23. package/dist/components/MathNode.d.ts +6 -0
  24. package/dist/components/NodeRenderer.d.ts +27 -0
  25. package/dist/components/NodeSlot.d.ts +11 -0
  26. package/dist/components/PreCodeBlock.d.ts +3 -0
  27. package/dist/components/PreCodeNode.d.ts +9 -0
  28. package/dist/components/RenderNode.d.ts +11 -0
  29. package/dist/components/StreamingTextNode.d.ts +2 -0
  30. package/dist/components/ToolbarButton.d.ts +14 -0
  31. package/dist/components/ToolbarIcon.d.ts +18 -0
  32. package/dist/components/Tooltip.d.ts +13 -0
  33. package/dist/components/lifecycle.d.ts +6 -0
  34. package/dist/components/mathHeightCache.d.ts +5 -0
  35. package/dist/components/rendererModeDefaults.d.ts +4 -0
  36. package/dist/components/shared/diagram-height.d.ts +16 -0
  37. package/dist/components/shared/node-helpers.d.ts +78 -0
  38. package/dist/components/shared/node-outlet-helpers.d.ts +10 -0
  39. package/dist/components/shared/render-window.d.ts +18 -0
  40. package/dist/components/shared/reuseParsedNodes.d.ts +3 -0
  41. package/dist/components/viewport.d.ts +5 -0
  42. package/dist/components/virtualLayoutKey.d.ts +13 -0
  43. package/dist/configuration.d.ts +9 -0
  44. package/dist/customComponents.d.ts +36 -0
  45. package/dist/enhanceRenderedHtml.d.ts +25 -0
  46. package/dist/hydrateCustomTagContent.d.ts +2 -0
  47. package/dist/i18n/useSafeI18n.d.ts +4 -0
  48. package/dist/icon-themes/index.d.ts +2 -0
  49. package/dist/icon-themes/material/core.d.ts +2 -0
  50. package/dist/icon-themes/material/extended.d.ts +2 -0
  51. package/dist/icon-themes/material/index.d.ts +2 -0
  52. package/dist/icon-themes/registry.d.ts +9 -0
  53. package/dist/icon-themes/types.d.ts +11 -0
  54. package/dist/index.css +3279 -0
  55. package/dist/index.d.ts +48 -0
  56. package/dist/index.px.css +3279 -0
  57. package/dist/index.tailwind.css +3279 -0
  58. package/dist/optional/d2.d.ts +17 -0
  59. package/dist/optional/infographic.d.ts +31 -0
  60. package/dist/optional/katex.d.ts +9 -0
  61. package/dist/optional/mermaid.d.ts +27 -0
  62. package/dist/optional/streamDiffs.d.ts +29 -0
  63. package/dist/renderMarkdownHtml.d.ts +30 -0
  64. package/dist/sanitizeHtmlContent.d.ts +2 -0
  65. package/dist/server/extended-CKyCqQt3.js +69 -0
  66. package/dist/server/index.js +6264 -0
  67. package/dist/server/languageIcon-TXkIEBPf.js +353 -0
  68. package/dist/server/utils/index.js +31 -0
  69. package/dist/server/utils/katex-threshold.js +41 -0
  70. package/dist/server/utils/performance-monitor.js +120 -0
  71. package/dist/server/utils/safeRaf.js +28 -0
  72. package/dist/server/workers/katexCdnWorker.js +190 -0
  73. package/dist/server/workers/katexWorkerClient.js +373 -0
  74. package/dist/server/workers/mermaidCdnWorker.js +238 -0
  75. package/dist/server/workers/mermaidWorkerClient.js +333 -0
  76. package/dist/streamDiffsWorker.d.ts +72 -0
  77. package/dist/tailwind.d.ts +2 -0
  78. package/dist/tailwind.js +3 -0
  79. package/dist/tooltip/singletonTooltip.d.ts +7 -0
  80. package/dist/types/component-props.d.ts +253 -0
  81. package/dist/types/node-renderer-props.d.ts +333 -0
  82. package/dist/useSmoothMarkdownStream.d.ts +22 -0
  83. package/dist/utils/clipboard.d.ts +1 -0
  84. package/dist/utils/d2RenderSalt.d.ts +1 -0
  85. package/dist/utils/footnoteTarget.d.ts +1 -0
  86. package/dist/utils/index.d.ts +8 -0
  87. package/dist/utils/katex-threshold.d.ts +20 -0
  88. package/dist/utils/languageIcon.d.ts +8 -0
  89. package/dist/utils/mermaidRenderId.d.ts +1 -0
  90. package/dist/utils/normalizeKaTeXRenderInput.d.ts +1 -0
  91. package/dist/utils/performance-monitor.d.ts +121 -0
  92. package/dist/utils/resolveLanguageIcon.d.ts +2 -0
  93. package/dist/utils/safeRaf.d.ts +2 -0
  94. package/dist/utils/virtualItemMeasurement.d.ts +5 -0
  95. package/dist/virtual-adapter.d.ts +165 -0
  96. package/dist/workers/katexCdnWorker.d.ts +20 -0
  97. package/dist/workers/katexRenderer.worker.d.ts +1 -0
  98. package/dist/workers/katexWorkerClient.d.ts +35 -0
  99. package/dist/workers/mermaidCdnWorker.d.ts +15 -0
  100. package/dist/workers/mermaidParser.worker.d.ts +1 -0
  101. package/dist/workers/mermaidWorkerClient.d.ts +15 -0
  102. package/package.json +149 -3
@@ -0,0 +1,238 @@
1
+ import { applyMermaidThemeDirective } from "markstream-core";
2
+ function stringifyForWorker(value) {
3
+ return JSON.stringify(value);
4
+ }
5
+ function buildMermaidCDNWorkerSource(options) {
6
+ const mode = options.mode ?? "module";
7
+ const mermaidUrlLiteral = stringifyForWorker(options.mermaidUrl);
8
+ const initLiteral = stringifyForWorker({
9
+ startOnLoad: false,
10
+ securityLevel: "strict",
11
+ flowchart: { htmlLabels: false },
12
+ ...options.initializeOptions || {}
13
+ });
14
+ const sharedLogic = `
15
+ let DEBUG = false
16
+ let mermaid = null
17
+ let mermaidLoadError = null
18
+
19
+ const applyMermaidThemeDirective = ${applyMermaidThemeDirective.toString()}
20
+
21
+ function normalizeMermaidModule(mod) {
22
+ if (!mod)
23
+ return mod
24
+ const candidate = mod && mod.default ? mod.default : mod
25
+ if (candidate && (typeof candidate.render === 'function' || typeof candidate.parse === 'function' || typeof candidate.initialize === 'function'))
26
+ return candidate
27
+ if (candidate && candidate.mermaidAPI && (typeof candidate.mermaidAPI.render === 'function' || typeof candidate.mermaidAPI.parse === 'function')) {
28
+ const api = candidate.mermaidAPI
29
+ return {
30
+ ...candidate,
31
+ render: api.render ? api.render.bind(api) : undefined,
32
+ parse: api.parse ? api.parse.bind(api) : undefined,
33
+ initialize: (opts) => {
34
+ if (typeof candidate.initialize === 'function')
35
+ return candidate.initialize(opts)
36
+ return api.initialize ? api.initialize(opts) : undefined
37
+ },
38
+ }
39
+ }
40
+ if (mod && mod.mermaid && typeof mod.mermaid.parse === 'function')
41
+ return mod.mermaid
42
+ return candidate
43
+ }
44
+
45
+ function applyThemeTo(code, theme) {
46
+ const themeValue = theme === 'dark' ? 'dark' : 'default'
47
+ const themeConfig = \`%%{init: {"theme": "\${themeValue}"}}%%\\n\`
48
+ return applyMermaidThemeDirective(code || '', themeConfig)
49
+ }
50
+
51
+ function findHeaderIndex(lines) {
52
+ const headerRe = /^(?:graph|flowchart|flowchart\\s+tb|flowchart\\s+lr|sequenceDiagram|gantt|classDiagram|stateDiagram(?:-v2)?|erDiagram|journey|pie|quadrantChart|timeline|xychart(?:-beta)?)\\b/
53
+ let inFrontmatter = lines[0]?.trimEnd() === '---'
54
+ for (let i = 0; i < lines.length; i++) {
55
+ const line = (lines[i] || '').trim()
56
+ if (inFrontmatter) {
57
+ if (i > 0 && lines[i].trimEnd() === '---')
58
+ inFrontmatter = false
59
+ continue
60
+ }
61
+ if (!line || line.startsWith('%%'))
62
+ continue
63
+ if (headerRe.test(line))
64
+ return i
65
+ }
66
+ return -1
67
+ }
68
+
69
+ async function canParse(code, theme) {
70
+ const themed = applyThemeTo(code, theme)
71
+ if (mermaid && typeof mermaid.parse === 'function') {
72
+ await mermaid.parse(themed)
73
+ return true
74
+ }
75
+ throw new Error('mermaid.parse not available in worker')
76
+ }
77
+
78
+ async function findLastRenderablePrefix(baseCode, theme) {
79
+ const lines = String(baseCode || '').split(/\\r\\n?|\\n/)
80
+ const headerIndex = findHeaderIndex(lines)
81
+ if (headerIndex === -1)
82
+ return null
83
+ const head = lines.slice(0, headerIndex + 1)
84
+ await canParse(head.join('\\n'), theme)
85
+
86
+ let low = headerIndex + 1
87
+ let high = lines.length
88
+ let lastGood = headerIndex + 1
89
+ let tries = 0
90
+ const MAX_TRIES = 12
91
+
92
+ while (low <= high && tries < MAX_TRIES) {
93
+ const mid = Math.floor((low + high) / 2)
94
+ const candidate = [...head, ...lines.slice(headerIndex + 1, mid)].join('\\n')
95
+ tries += 1
96
+ try {
97
+ await canParse(candidate, theme)
98
+ lastGood = mid
99
+ low = mid + 1
100
+ }
101
+ catch {
102
+ high = mid - 1
103
+ }
104
+ }
105
+
106
+ return [...head, ...lines.slice(headerIndex + 1, lastGood)].join('\\n')
107
+ }
108
+
109
+ function initMermaidOnce() {
110
+ if (!mermaid)
111
+ return
112
+ try {
113
+ if (typeof mermaid.initialize === 'function')
114
+ mermaid.initialize(${initLiteral})
115
+ }
116
+ catch (e) {
117
+ if (DEBUG)
118
+ console.warn('[markstream-solid:mermaid-cdn-worker] initialize failed', e)
119
+ }
120
+ }
121
+
122
+ globalThis.addEventListener('message', async (ev) => {
123
+ const msg = ev.data || {}
124
+ if (msg.type === 'init') {
125
+ DEBUG = !!msg.debug
126
+ return
127
+ }
128
+
129
+ const id = msg.id
130
+ const action = msg.action
131
+ const payload = msg.payload || {}
132
+
133
+ if (!mermaid) {
134
+ const error = mermaidLoadError ? String(mermaidLoadError?.message || mermaidLoadError) : 'Mermaid is not available in worker'
135
+ globalThis.postMessage({ id, ok: false, error })
136
+ return
137
+ }
138
+
139
+ try {
140
+ if (action === 'canParse') {
141
+ const ok = await canParse(payload.code, payload.theme)
142
+ globalThis.postMessage({ id, ok: true, result: ok })
143
+ return
144
+ }
145
+ if (action === 'findPrefix') {
146
+ const result = await findLastRenderablePrefix(payload.code, payload.theme)
147
+ globalThis.postMessage({ id, ok: true, result })
148
+ return
149
+ }
150
+ globalThis.postMessage({ id, ok: false, error: 'Unknown action' })
151
+ }
152
+ catch (e) {
153
+ globalThis.postMessage({ id, ok: false, error: String(e?.message || e) })
154
+ }
155
+ })
156
+ `.trimStart();
157
+ if (mode === "module") {
158
+ return `
159
+ ${sharedLogic}
160
+
161
+ let loadPromise = null
162
+ async function loadMermaid() {
163
+ if (mermaid || mermaidLoadError)
164
+ return
165
+ if (!loadPromise) {
166
+ loadPromise = (async () => {
167
+ try {
168
+ const mod = await import(${mermaidUrlLiteral})
169
+ mermaid = normalizeMermaidModule(mod) || null
170
+ initMermaidOnce()
171
+ }
172
+ catch (e) {
173
+ mermaidLoadError = e
174
+ }
175
+ })()
176
+ }
177
+ await loadPromise
178
+ }
179
+
180
+ await loadMermaid()
181
+ `.trimStart();
182
+ }
183
+ return `
184
+ ${sharedLogic}
185
+
186
+ function loadMermaidClassic() {
187
+ if (mermaid || mermaidLoadError)
188
+ return
189
+ try {
190
+ importScripts(${mermaidUrlLiteral})
191
+ mermaid = normalizeMermaidModule(globalThis.mermaid) || null
192
+ initMermaidOnce()
193
+ }
194
+ catch (e) {
195
+ mermaidLoadError = e
196
+ }
197
+ }
198
+
199
+ loadMermaidClassic()
200
+ `.trimStart();
201
+ }
202
+ function createMermaidWorkerFromCDN(options) {
203
+ const source = buildMermaidCDNWorkerSource(options);
204
+ if (typeof Worker === "undefined" || typeof URL === "undefined" || typeof Blob === "undefined") {
205
+ return {
206
+ worker: null,
207
+ dispose: () => {
208
+ },
209
+ source
210
+ };
211
+ }
212
+ const blob = new Blob([source], { type: "text/javascript" });
213
+ const url = URL.createObjectURL(blob);
214
+ let revoked = false;
215
+ const dispose = () => {
216
+ if (revoked)
217
+ return;
218
+ revoked = true;
219
+ try {
220
+ URL.revokeObjectURL(url);
221
+ } catch {
222
+ }
223
+ };
224
+ const mode = options.mode ?? "module";
225
+ const workerOptions = mode === "module" ? { ...options.workerOptions ?? {}, type: "module" } : options.workerOptions;
226
+ const worker = new Worker(url, workerOptions);
227
+ if (options.debug) {
228
+ try {
229
+ worker.postMessage({ type: "init", debug: true });
230
+ } catch {
231
+ }
232
+ }
233
+ return { worker, dispose, source };
234
+ }
235
+ export {
236
+ buildMermaidCDNWorkerSource,
237
+ createMermaidWorkerFromCDN
238
+ };
@@ -0,0 +1,333 @@
1
+ const defaultMermaidLoader = () => import("mermaid");
2
+ const GLOBAL_MERMAID_KEY = "__MARKSTREAM_SOLID_MERMAID__";
3
+ let cachedMermaid = null;
4
+ let importAttempted = false;
5
+ let lastInitKey = null;
6
+ let pendingImport = null;
7
+ let mermaidLoader = defaultMermaidLoader;
8
+ function computeInitKey(config) {
9
+ const securityLevel = String(config?.securityLevel ?? "strict");
10
+ const htmlLabels = config?.flowchart?.htmlLabels;
11
+ return `${securityLevel}|htmlLabels:${htmlLabels === false ? "0" : "1"}`;
12
+ }
13
+ function normalizeMermaidModule(mod) {
14
+ if (!mod)
15
+ return mod;
16
+ const candidate = mod?.default ?? mod;
17
+ if (candidate && (typeof candidate.render === "function" || typeof candidate.parse === "function" || typeof candidate.initialize === "function"))
18
+ return candidate;
19
+ if (candidate?.mermaidAPI && (typeof candidate.mermaidAPI.render === "function" || typeof candidate.mermaidAPI.parse === "function")) {
20
+ const api = candidate.mermaidAPI;
21
+ return {
22
+ ...candidate,
23
+ render: api.render.bind(api),
24
+ parse: api.parse ? api.parse.bind(api) : void 0,
25
+ initialize: (opts) => {
26
+ if (typeof candidate.initialize === "function")
27
+ return candidate.initialize(opts);
28
+ return api.initialize ? api.initialize(opts) : void 0;
29
+ }
30
+ };
31
+ }
32
+ if (mod?.mermaid && typeof mod.mermaid.render === "function")
33
+ return mod.mermaid;
34
+ return candidate;
35
+ }
36
+ function patchInitialize(target) {
37
+ if (!target)
38
+ return;
39
+ try {
40
+ const originalInitialize = target?.initialize;
41
+ target.initialize = (opts) => {
42
+ const merged = { suppressErrorRendering: true, ...opts || {} };
43
+ if (typeof originalInitialize === "function")
44
+ return originalInitialize.call(target, merged);
45
+ if (target?.mermaidAPI && typeof target.mermaidAPI.initialize === "function")
46
+ return target.mermaidAPI.initialize(merged);
47
+ return void 0;
48
+ };
49
+ } catch {
50
+ }
51
+ }
52
+ function ensureInitialized(instance, config) {
53
+ if (!instance || !config)
54
+ return;
55
+ const key = computeInitKey(config);
56
+ if (lastInitKey === key)
57
+ return;
58
+ try {
59
+ if (typeof instance.initialize === "function")
60
+ instance.initialize(config);
61
+ else if (instance.mermaidAPI?.initialize)
62
+ instance.mermaidAPI.initialize(config);
63
+ lastInitKey = key;
64
+ } catch {
65
+ }
66
+ }
67
+ function getGlobalMermaid() {
68
+ try {
69
+ const globalStore = globalThis;
70
+ return normalizeMermaidModule(globalStore?.[GLOBAL_MERMAID_KEY] ?? globalStore?.mermaid);
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+ function setGlobalMermaid(instance) {
76
+ try {
77
+ ;
78
+ globalThis[GLOBAL_MERMAID_KEY] = instance;
79
+ } catch {
80
+ }
81
+ }
82
+ function resetCachedMermaid() {
83
+ cachedMermaid = null;
84
+ importAttempted = false;
85
+ lastInitKey = null;
86
+ pendingImport = null;
87
+ try {
88
+ delete globalThis[GLOBAL_MERMAID_KEY];
89
+ } catch {
90
+ }
91
+ }
92
+ function setMermaidLoader(loader) {
93
+ mermaidLoader = loader;
94
+ resetCachedMermaid();
95
+ }
96
+ function enableMermaid(loader) {
97
+ setMermaidLoader(loader ?? defaultMermaidLoader);
98
+ }
99
+ function disableMermaid() {
100
+ setMermaidLoader(null);
101
+ }
102
+ function isMermaidEnabled() {
103
+ return typeof mermaidLoader === "function";
104
+ }
105
+ async function getMermaid(initConfig) {
106
+ if (cachedMermaid) {
107
+ ensureInitialized(cachedMermaid, initConfig);
108
+ return cachedMermaid;
109
+ }
110
+ const globalMermaid = getGlobalMermaid();
111
+ if (globalMermaid) {
112
+ patchInitialize(globalMermaid);
113
+ cachedMermaid = globalMermaid;
114
+ setGlobalMermaid(cachedMermaid);
115
+ ensureInitialized(cachedMermaid, initConfig);
116
+ return cachedMermaid;
117
+ }
118
+ if (pendingImport) {
119
+ const instance = await pendingImport;
120
+ if (instance)
121
+ ensureInitialized(instance, initConfig);
122
+ return instance;
123
+ }
124
+ if (importAttempted)
125
+ return null;
126
+ const loader = mermaidLoader;
127
+ if (!loader) {
128
+ importAttempted = true;
129
+ return null;
130
+ }
131
+ pendingImport = (async () => {
132
+ try {
133
+ const mod = await loader();
134
+ const instance = normalizeMermaidModule(mod);
135
+ if (!instance) {
136
+ importAttempted = true;
137
+ return null;
138
+ }
139
+ patchInitialize(instance);
140
+ cachedMermaid = instance;
141
+ setGlobalMermaid(cachedMermaid);
142
+ return cachedMermaid;
143
+ } catch {
144
+ importAttempted = true;
145
+ return null;
146
+ }
147
+ })();
148
+ try {
149
+ const instance = await pendingImport;
150
+ if (instance)
151
+ ensureInitialized(instance, initConfig);
152
+ return instance;
153
+ } finally {
154
+ pendingImport = null;
155
+ }
156
+ }
157
+ let worker = null;
158
+ let workerInitError = null;
159
+ const rpcMap = /* @__PURE__ */ new Map();
160
+ let maxConcurrency = 5;
161
+ let debugClient = false;
162
+ function setMermaidWorkerClientDebug(enabled) {
163
+ debugClient = !!enabled;
164
+ }
165
+ function setMermaidWorkerMaxConcurrency(value) {
166
+ if (Number.isFinite(value) && value > 0)
167
+ maxConcurrency = Math.floor(value);
168
+ }
169
+ function getMermaidWorkerLoad() {
170
+ return { inFlight: rpcMap.size, max: maxConcurrency };
171
+ }
172
+ const MERMAID_WORKER_BUSY_CODE = "WORKER_BUSY";
173
+ const MERMAID_DISABLED_CODE = "MERMAID_DISABLED";
174
+ function setMermaidWorker(nextWorker) {
175
+ worker = nextWorker;
176
+ workerInitError = null;
177
+ const current = nextWorker;
178
+ worker.onmessage = (event) => {
179
+ if (worker !== current)
180
+ return;
181
+ const { id, ok, result, error } = event.data || {};
182
+ const active = rpcMap.get(id);
183
+ if (!active)
184
+ return;
185
+ if (ok === false || error)
186
+ active.reject(new Error(error || "Unknown error"));
187
+ else
188
+ active.resolve(result);
189
+ };
190
+ worker.onerror = (event) => {
191
+ if (worker !== current)
192
+ return;
193
+ if (rpcMap.size === 0) {
194
+ console.debug?.("[markstream-solid:mermaidWorkerClient] Worker error (idle):", event?.message || event);
195
+ return;
196
+ }
197
+ try {
198
+ if (debugClient)
199
+ console.error("[markstream-solid:mermaidWorkerClient] Worker error:", event?.message || event);
200
+ else
201
+ console.debug?.("[markstream-solid:mermaidWorkerClient] Worker error:", event?.message || event);
202
+ } catch {
203
+ }
204
+ for (const [, active] of rpcMap.entries())
205
+ active.reject(new Error(`Worker error: ${event.message}`));
206
+ rpcMap.clear();
207
+ };
208
+ worker.onmessageerror = (event) => {
209
+ if (worker !== current)
210
+ return;
211
+ if (rpcMap.size === 0) {
212
+ console.debug?.("[markstream-solid:mermaidWorkerClient] Worker messageerror (idle):", event);
213
+ return;
214
+ }
215
+ for (const [, active] of rpcMap.entries())
216
+ active.reject(new Error("Worker messageerror"));
217
+ rpcMap.clear();
218
+ };
219
+ }
220
+ function clearMermaidWorker() {
221
+ if (worker) {
222
+ try {
223
+ for (const [, active] of rpcMap.entries())
224
+ active.reject(new Error("Worker cleared"));
225
+ rpcMap.clear();
226
+ worker.terminate?.();
227
+ } catch {
228
+ }
229
+ }
230
+ worker = null;
231
+ workerInitError = null;
232
+ }
233
+ function ensureWorker() {
234
+ if (worker)
235
+ return worker;
236
+ workerInitError = new Error("[markstream-solid:mermaidWorkerClient] No worker instance set. Please inject a Worker via setMermaidWorker().");
237
+ workerInitError.name = "WorkerInitError";
238
+ workerInitError.code = "WORKER_INIT_ERROR";
239
+ return null;
240
+ }
241
+ function callWorker(action, payload, timeout = 1400) {
242
+ if (!isMermaidEnabled()) {
243
+ const error = new Error("Mermaid rendering disabled");
244
+ error.name = "MermaidDisabled";
245
+ error.code = MERMAID_DISABLED_CODE;
246
+ return Promise.reject(error);
247
+ }
248
+ if (workerInitError)
249
+ return Promise.reject(workerInitError);
250
+ const activeWorker = ensureWorker();
251
+ if (!activeWorker)
252
+ return Promise.reject(workerInitError);
253
+ if (rpcMap.size >= maxConcurrency) {
254
+ const error = new Error("Worker busy");
255
+ error.name = "WorkerBusy";
256
+ error.code = MERMAID_WORKER_BUSY_CODE;
257
+ error.inFlight = rpcMap.size;
258
+ error.max = maxConcurrency;
259
+ return Promise.reject(error);
260
+ }
261
+ return new Promise((resolve, reject) => {
262
+ const id = Math.random().toString(36).slice(2);
263
+ let settled = false;
264
+ let timeoutId = null;
265
+ const cleanup = () => {
266
+ if (settled)
267
+ return;
268
+ settled = true;
269
+ if (timeoutId != null)
270
+ clearTimeout(timeoutId);
271
+ rpcMap.delete(id);
272
+ };
273
+ rpcMap.set(id, {
274
+ resolve: (value) => {
275
+ cleanup();
276
+ resolve(value);
277
+ },
278
+ reject: (error) => {
279
+ cleanup();
280
+ reject(error);
281
+ }
282
+ });
283
+ try {
284
+ activeWorker.postMessage({ id, action, payload });
285
+ } catch (error) {
286
+ rpcMap.delete(id);
287
+ reject(error);
288
+ return;
289
+ }
290
+ timeoutId = setTimeout(() => {
291
+ const error = new Error("Worker call timed out");
292
+ error.name = "WorkerTimeout";
293
+ error.code = "WORKER_TIMEOUT";
294
+ const pending = rpcMap.get(id);
295
+ pending?.reject(error);
296
+ }, timeout);
297
+ });
298
+ }
299
+ async function canParseOffthread(code, theme, timeout = 1400) {
300
+ return await callWorker("canParse", { code, theme }, timeout);
301
+ }
302
+ async function findPrefixOffthread(code, theme, timeout = 1400) {
303
+ return await callWorker("findPrefix", { code, theme }, timeout);
304
+ }
305
+ function terminateWorker() {
306
+ if (worker) {
307
+ try {
308
+ for (const [, active] of rpcMap.entries())
309
+ active.reject(new Error("Worker terminated"));
310
+ rpcMap.clear();
311
+ worker.terminate();
312
+ } finally {
313
+ worker = null;
314
+ }
315
+ }
316
+ }
317
+ export {
318
+ MERMAID_DISABLED_CODE,
319
+ MERMAID_WORKER_BUSY_CODE,
320
+ canParseOffthread,
321
+ clearMermaidWorker,
322
+ disableMermaid as d,
323
+ enableMermaid as e,
324
+ findPrefixOffthread,
325
+ getMermaid as g,
326
+ getMermaidWorkerLoad,
327
+ isMermaidEnabled as i,
328
+ setMermaidLoader as s,
329
+ setMermaidWorker,
330
+ setMermaidWorkerClientDebug,
331
+ setMermaidWorkerMaxConcurrency,
332
+ terminateWorker
333
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Host-injected `WorkerPoolManager` for stream-diffs / @pierre/diffs
3
+ * highlighting.
4
+ *
5
+ * markstream-solid deliberately does NOT bundle or spawn the highlight worker
6
+ * itself — worker assets are bundler-specific (`?worker` in Vite, etc.) and
7
+ * would be fragile inside a multi-bundler library. Instead, the host app
8
+ * creates the pool with its own bundler and injects it here; every enhanced
9
+ * code block then forwards it as the `workerManager` runtime option so Shiki
10
+ * tokenization runs off the main thread.
11
+ *
12
+ * When no pool is injected, highlighting stays on the main thread exactly as
13
+ * before. A broken/terminated pool is non-fatal: `@pierre/diffs` falls back to
14
+ * its main-thread highlighter when the pool reports itself unavailable.
15
+ */
16
+ export interface StreamDiffsWorkerPoolLike {
17
+ /**
18
+ * True while the pool is usable. `@pierre/diffs` checks this to decide
19
+ * between worker-based and main-thread highlighting.
20
+ */
21
+ isWorkingPool?: () => boolean;
22
+ /** Resolves once workers are spawned and initialized. */
23
+ initialize?: (languages?: string[]) => Promise<void>;
24
+ /**
25
+ * Updates worker-side render options (theme). Called by markstream-solid on
26
+ * theme changes so worker-generated tokens match the active theme.
27
+ */
28
+ setRenderOptions?: (options: {
29
+ theme?: string | {
30
+ dark: string;
31
+ light: string;
32
+ };
33
+ }) => Promise<void> | void;
34
+ terminate?: () => void;
35
+ }
36
+ /**
37
+ * Inject (or clear) the shared worker pool. Pass `null`/`undefined` to disable
38
+ * worker-based highlighting and fall back to the main thread.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * import DiffsWorker from '@pierre/diffs/worker/worker.js?worker'
43
+ * import { getOrCreateWorkerPoolSingleton } from '@pierre/diffs/worker'
44
+ * import { setStreamDiffsWorkerPool } from 'markstream-solid'
45
+ *
46
+ * const pool = getOrCreateWorkerPoolSingleton({
47
+ * poolOptions: {
48
+ * poolSize: 4,
49
+ * workerFactory: () => new DiffsWorker(),
50
+ * },
51
+ * highlighterOptions: {
52
+ * theme: { dark: 'pierre-dark', light: 'pierre-light' },
53
+ * },
54
+ * })
55
+ * setStreamDiffsWorkerPool(pool)
56
+ * ```
57
+ */
58
+ export declare function setStreamDiffsWorkerPool(pool: StreamDiffsWorkerPoolLike | null | undefined): void;
59
+ export declare function getStreamDiffsWorkerPool(): StreamDiffsWorkerPoolLike | null;
60
+ /** Clear the injected pool without terminating it (host keeps ownership). */
61
+ export declare function clearStreamDiffsWorkerPool(): void;
62
+ /** Terminate the injected pool (if it exposes `terminate`) and clear it. */
63
+ export declare function terminateStreamDiffsWorkerPool(): void;
64
+ /**
65
+ * Forward the active theme to the worker pool so worker-produced tokens match
66
+ * the requested theme. No-op when no pool is injected. Failures are non-fatal:
67
+ * tokens still render, and colors catch up on the next sync.
68
+ */
69
+ export declare function syncStreamDiffsWorkerTheme(theme: string | {
70
+ dark: string;
71
+ light: string;
72
+ }): Promise<void>;
@@ -0,0 +1,2 @@
1
+ export * from './index'
2
+ export { default } from './index'
@@ -0,0 +1,3 @@
1
+ import './index.css'
2
+ export * from './client/index.js'
3
+ export { default } from './client/index.js'
@@ -0,0 +1,7 @@
1
+ export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';
2
+ export declare function showTooltipForAnchor(anchor: HTMLElement | null, content: string, placement?: TooltipPlacement, immediate?: boolean, _origin?: {
3
+ x: number;
4
+ y: number;
5
+ } | undefined, isDark?: boolean | null): void;
6
+ export declare function hideTooltip(immediate?: boolean): void;
7
+ export declare function isTooltipVisible(): boolean;