sdocs-dev 1.1.1 → 1.2.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.
@@ -51,7 +51,7 @@ var STANDALONE_COLOR_IDS = new Set(SDocStyles.STANDALONE_COLOR_IDS);
51
51
  'ctrl-h1-weight','ctrl-h2-weight','ctrl-h3-weight','ctrl-h4-weight',
52
52
  'ctrl-bg-color','ctrl-link-color','ctrl-link-decoration',
53
53
  'ctrl-code-font','ctrl-code-bg','ctrl-code-color',
54
- 'ctrl-bq-border-color','ctrl-bq-color',
54
+ 'ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-color',
55
55
  ].forEach(function(id) {
56
56
  var handler = function() { if (STANDALONE_COLOR_IDS.has(id)) S.overriddenColors.add(id); applyCtrl(id); };
57
57
  document.getElementById(id).addEventListener('input', handler);
@@ -97,7 +97,7 @@ document.getElementById('reset-h4-color').addEventListener('click', function()
97
97
  document.getElementById('reset-p-color').addEventListener('click', function() { resetColorValue('ctrl-p-color'); S.syncAll('controls'); });
98
98
  document.getElementById('reset-list-color').addEventListener('click', function() { resetColorValue('ctrl-list-color'); S.syncAll('controls'); });
99
99
 
100
- ['ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color'].forEach(function(ctrlId) {
100
+ ['ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-color'].forEach(function(ctrlId) {
101
101
  var btnId = 'reset-' + ctrlId.replace('ctrl-', '');
102
102
  document.getElementById(btnId).addEventListener('click', function() {
103
103
  var defaultVal = S.getStandaloneDefault(ctrlId);
@@ -165,54 +165,41 @@ function applyStylesFromMeta(s) {
165
165
  return;
166
166
  }
167
167
 
168
- // Legacy single-theme path: top-level colors go to light theme
168
+ // Legacy single-theme path: top-level colors go to light theme only,
169
+ // then loadThemeColors applies the correct theme's colors.
170
+ var lightOverridden = S.themeOverridden.light;
171
+ var lightColors = S.themeColors.light;
169
172
  var newOverridden = result.overriddenColors;
170
173
 
171
- S.overriddenColors.clear();
172
- setColorValue('ctrl-color', S.getColorDefault(), false);
174
+ lightOverridden.clear();
175
+ S.themeOverridden.dark.clear();
173
176
 
174
177
  newOverridden.forEach(function(id) {
175
- S.overriddenColors.add(id);
176
- setColorValue(id, controls[id], true);
178
+ lightOverridden.add(id);
179
+ lightColors[id] = controls[id];
177
180
  });
178
181
 
179
- // Also apply standalone colors from legacy format
180
- if (s.background) {
181
- S.overriddenColors.add('ctrl-bg-color');
182
- var elBg = document.getElementById('ctrl-bg-color');
183
- if (elBg) { elBg.value = s.background; applyCtrl('ctrl-bg-color'); }
184
- }
185
- if (s.link && s.link.color) {
186
- S.overriddenColors.add('ctrl-link-color');
187
- var el = document.getElementById('ctrl-link-color');
188
- if (el) { el.value = s.link.color; applyCtrl('ctrl-link-color'); }
189
- }
182
+ // Also store standalone colors from legacy format into light theme
183
+ var legacyStandalone = [];
184
+ if (s.background) legacyStandalone.push(['ctrl-bg-color', s.background]);
185
+ if (s.link && s.link.color) legacyStandalone.push(['ctrl-link-color', s.link.color]);
190
186
  if (s.code) {
191
- if (s.code.background) {
192
- S.overriddenColors.add('ctrl-code-bg');
193
- var el2 = document.getElementById('ctrl-code-bg');
194
- if (el2) { el2.value = s.code.background; applyCtrl('ctrl-code-bg'); }
195
- }
196
- if (s.code.color) {
197
- S.overriddenColors.add('ctrl-code-color');
198
- var el3 = document.getElementById('ctrl-code-color');
199
- if (el3) { el3.value = s.code.color; applyCtrl('ctrl-code-color'); }
200
- }
187
+ if (s.code.background) legacyStandalone.push(['ctrl-code-bg', s.code.background]);
188
+ if (s.code.color) legacyStandalone.push(['ctrl-code-color', s.code.color]);
201
189
  }
202
190
  if (s.blockquote) {
203
- if (s.blockquote.borderColor) {
204
- S.overriddenColors.add('ctrl-bq-border-color');
205
- var el4 = document.getElementById('ctrl-bq-border-color');
206
- if (el4) { el4.value = s.blockquote.borderColor; applyCtrl('ctrl-bq-border-color'); }
207
- }
208
- if (s.blockquote.color) {
209
- S.overriddenColors.add('ctrl-bq-color');
210
- var el5 = document.getElementById('ctrl-bq-color');
211
- if (el5) { el5.value = s.blockquote.color; applyCtrl('ctrl-bq-color'); }
212
- }
191
+ if (s.blockquote.borderColor) legacyStandalone.push(['ctrl-bq-border-color', s.blockquote.borderColor]);
192
+ if (s.blockquote.background) legacyStandalone.push(['ctrl-bq-bg', s.blockquote.background]);
193
+ if (s.blockquote.color) legacyStandalone.push(['ctrl-bq-color', s.blockquote.color]);
213
194
  }
195
+ legacyStandalone.forEach(function(pair) {
196
+ lightOverridden.add(pair[0]);
197
+ lightColors[pair[0]] = pair[1];
198
+ });
214
199
 
200
+ // Now apply the active theme's colors (light overrides or dark defaults)
215
201
  S._syncing = wasSyncing;
202
+ S.loadThemeColors(S.activeTheme);
216
203
  }
217
204
 
218
205
  function collectStyles() {
@@ -257,7 +244,7 @@ function resetAllStyles() {
257
244
  'ctrl-p-lh-num','ctrl-p-mb-num',
258
245
  'ctrl-link-color','ctrl-link-decoration',
259
246
  'ctrl-code-font','ctrl-code-bg','ctrl-code-color',
260
- 'ctrl-bq-border-color','ctrl-bq-bw-num','ctrl-bq-size-num','ctrl-bq-color',
247
+ 'ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-bw-num','ctrl-bq-size-num','ctrl-bq-color',
261
248
  'ctrl-list-spacing-num','ctrl-list-indent-num',
262
249
  ].forEach(function(id) { applyCtrl(id); });
263
250
  }
@@ -47,11 +47,12 @@ function buildExportCSS() {
47
47
  var preBG = cv('--md-pre-bg') || codeBG;
48
48
 
49
49
  var bqBorder = cv('--md-bq-border') || '3px solid #2563eb';
50
+ var bqBg = cv('--md-bq-bg') || '#f7f5f2';
50
51
  var bqColor = cv('--md-bq-color') || '#6b6560';
51
52
  var bqPad = cv('--md-bq-padding') || '0.5em 1em';
52
53
  var bqMargin = cv('--md-bq-margin') || '1.2em 0';
53
54
 
54
- return '\nbody {\n font-family: ' + fontFamily + ';\n font-size: ' + baseSize + ';\n color: ' + color + ';\n line-height: ' + lineHeight + ';\n background-color: ' + bgColor + ';\n max-width: 720px;\n margin: 0 auto;\n padding: 40px 48px 60px;\n -webkit-font-smoothing: antialiased;\n}\nh1 { font-family: ' + hFontFamily + '; font-size: ' + h1Size + '; color: ' + h1Color + '; font-weight: ' + h1Weight + '; letter-spacing: -0.02em; line-height: 1.2; margin: 0 0 ' + hMB + '; }\nh2 { font-family: ' + hFontFamily + '; font-size: ' + h2Size + '; color: ' + h2Color + '; font-weight: ' + h2Weight + '; letter-spacing: -0.015em; line-height: 1.3; margin: 1.4em 0 ' + hMB + '; padding-bottom: 0.3em; border-bottom: 1px solid #ede8e2; }\nh3 { font-family: ' + hFontFamily + '; font-size: ' + h3Size + '; color: ' + h3Color + '; font-weight: ' + h3Weight + '; letter-spacing: -0.01em; line-height: 1.4; margin: 1.2em 0 ' + hMB + '; }\nh4 { font-family: ' + hFontFamily + '; font-size: ' + h4Size + '; color: ' + h4Color + '; font-weight: ' + h4Weight + '; line-height: 1.5; margin: 1em 0 ' + hMB + '; }\np { color: ' + pColor + '; line-height: ' + pLH + '; margin: ' + pMargin + '; }\na { color: ' + linkColor + '; text-decoration: ' + linkDec + '; text-underline-offset: 2px; }\ncode { background: ' + codeBG + '; color: ' + codeColor + '; padding: 0.15em 0.45em; border-radius: 4px; font-family: ' + codeFont + '; font-size: 0.85em; }\npre { background: ' + preBG + '; padding: 1.1em 1.25em; border-radius: 8px; overflow-x: auto; margin: 1.2em 0; border: 1px solid #e7e2db; }\npre code { background: none; padding: 0; color: #3c3733; font-size: 0.88em; }\nblockquote { border-left: ' + bqBorder + '; color: ' + bqColor + '; padding: ' + bqPad + '; margin: ' + bqMargin + '; background: #f7f5f2; border-radius: 0 6px 6px 0; }\nblockquote p { margin: 0; color: inherit; }\nul, ol { padding-left: 1.6em; margin: 0.5em 0 1.1em; }\nli { margin-bottom: 0.3em; }\nhr { border: none; border-top: 1px solid #ede8e2; margin: 2em 0; }\ntable { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 0.92em; }\nth, td { border: 1px solid #e2ddd6; padding: 7px 12px; text-align: left; }\nth { background: #f4f1ed; font-weight: 600; }\ntr:nth-child(even) td { background: #fafaf8; }\nimg { max-width: 100%; border-radius: 8px; }\n';
55
+ return '\nbody {\n font-family: ' + fontFamily + ';\n font-size: ' + baseSize + ';\n color: ' + color + ';\n line-height: ' + lineHeight + ';\n background-color: ' + bgColor + ';\n max-width: 720px;\n margin: 0 auto;\n padding: 40px 48px 60px;\n -webkit-font-smoothing: antialiased;\n}\nh1 { font-family: ' + hFontFamily + '; font-size: ' + h1Size + '; color: ' + h1Color + '; font-weight: ' + h1Weight + '; letter-spacing: -0.02em; line-height: 1.2; margin: 0 0 ' + hMB + '; }\nh2 { font-family: ' + hFontFamily + '; font-size: ' + h2Size + '; color: ' + h2Color + '; font-weight: ' + h2Weight + '; letter-spacing: -0.015em; line-height: 1.3; margin: 1.4em 0 ' + hMB + '; padding-bottom: 0.3em; border-bottom: 1px solid #ede8e2; }\nh3 { font-family: ' + hFontFamily + '; font-size: ' + h3Size + '; color: ' + h3Color + '; font-weight: ' + h3Weight + '; letter-spacing: -0.01em; line-height: 1.4; margin: 1.2em 0 ' + hMB + '; }\nh4 { font-family: ' + hFontFamily + '; font-size: ' + h4Size + '; color: ' + h4Color + '; font-weight: ' + h4Weight + '; line-height: 1.5; margin: 1em 0 ' + hMB + '; }\np { color: ' + pColor + '; line-height: ' + pLH + '; margin: ' + pMargin + '; }\na { color: ' + linkColor + '; text-decoration: ' + linkDec + '; text-underline-offset: 2px; }\ncode { background: ' + codeBG + '; color: ' + codeColor + '; padding: 0.15em 0.45em; border-radius: 4px; font-family: ' + codeFont + '; font-size: 0.85em; }\npre { background: ' + preBG + '; padding: 1.1em 1.25em; border-radius: 8px; overflow-x: auto; margin: 1.2em 0; border: 1px solid #e7e2db; }\npre code { background: none; padding: 0; color: #3c3733; font-size: 0.88em; }\nblockquote { border-left: ' + bqBorder + '; color: ' + bqColor + '; padding: ' + bqPad + '; margin: ' + bqMargin + '; background: ' + bqBg + '; border-radius: 0 6px 6px 0; }\nblockquote p { margin: 0; color: inherit; }\nul, ol { padding-left: 1.6em; margin: 0.5em 0 1.1em; }\nli { margin-bottom: 0.3em; }\nhr { border: none; border-top: 1px solid #ede8e2; margin: 2em 0; }\ntable { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 0.92em; }\nth, td { border: 1px solid #e2ddd6; padding: 7px 12px; text-align: left; }\nth { background: #f4f1ed; font-weight: 600; }\ntr:nth-child(even) td { background: #fafaf8; }\nimg { max-width: 100%; border-radius: 8px; }\n';
55
56
  }
56
57
 
57
58
  function buildExportHTML() {
@@ -55,6 +55,7 @@ const CTRL_CSS_MAP = {
55
55
  'ctrl-code-color': { cssVar: '--md-code-color' },
56
56
  'ctrl-bq-border-color': { cssVar: '--md-bq-border', compound: 'bq-border' },
57
57
  'ctrl-bq-bw-num': { cssVar: '--md-bq-border', compound: 'bq-border' },
58
+ 'ctrl-bq-bg': { cssVar: '--md-bq-bg' },
58
59
  'ctrl-bq-size-num': { cssVar: '--md-bq-size', suffix: 'em' },
59
60
  'ctrl-bq-color': { cssVar: '--md-bq-color' },
60
61
  'ctrl-list-spacing-num': { cssVar: '--md-list-spacing', suffix: 'em' },
@@ -170,6 +171,7 @@ function collectStyles(values, overriddenColors) {
170
171
  blockquote: {
171
172
  borderColor: gv('ctrl-bq-border-color'),
172
173
  borderWidth: gn('ctrl-bq-bw-num'),
174
+ background: gv('ctrl-bq-bg'),
173
175
  fontSize: gn('ctrl-bq-size-num'),
174
176
  color: gv('ctrl-bq-color'),
175
177
  },
@@ -257,6 +259,7 @@ function stylesToControls(styles) {
257
259
  const bq = styles.blockquote || {};
258
260
  if (bq.borderColor) controls['ctrl-bq-border-color'] = bq.borderColor;
259
261
  if (bq.borderWidth) controls['ctrl-bq-bw-num'] = bq.borderWidth;
262
+ if (bq.background) controls['ctrl-bq-bg'] = bq.background;
260
263
  if (bq.fontSize) controls['ctrl-bq-size-num'] = bq.fontSize;
261
264
  if (bq.color) controls['ctrl-bq-color'] = bq.color;
262
265
 
@@ -276,7 +279,7 @@ function stylesToControls(styles) {
276
279
  // ═══════════════════════════════════════════════════════
277
280
 
278
281
  var STANDALONE_COLOR_IDS = [
279
- 'ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color',
282
+ 'ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-color',
280
283
  ];
281
284
 
282
285
  var CASCADE_COLOR_IDS = Object.keys(COLOR_VAR_MAP);
@@ -341,6 +344,7 @@ function parseThemeColorBlock(block) {
341
344
  }
342
345
  if (block.blockquote) {
343
346
  if (block.blockquote.borderColor) { colors['ctrl-bq-border-color'] = block.blockquote.borderColor; overridden.add('ctrl-bq-border-color'); }
347
+ if (block.blockquote.background) { colors['ctrl-bq-bg'] = block.blockquote.background; overridden.add('ctrl-bq-bg'); }
344
348
  if (block.blockquote.color) { colors['ctrl-bq-color'] = block.blockquote.color; overridden.add('ctrl-bq-color'); }
345
349
  }
346
350
 
@@ -397,6 +401,10 @@ function collectThemeColors(colorValues, overriddenSet) {
397
401
  if (!block.blockquote) block.blockquote = {};
398
402
  block.blockquote.borderColor = colorValues['ctrl-bq-border-color'];
399
403
  }
404
+ if (overriddenSet.has('ctrl-bq-bg')) {
405
+ if (!block.blockquote) block.blockquote = {};
406
+ block.blockquote.background = colorValues['ctrl-bq-bg'];
407
+ }
400
408
  if (overriddenSet.has('ctrl-bq-color')) {
401
409
  if (!block.blockquote) block.blockquote = {};
402
410
  block.blockquote.color = colorValues['ctrl-bq-color'];
@@ -438,6 +446,7 @@ function collectStylesDual(values, lightOverridden, darkOverridden, lightColors,
438
446
  borderWidth: gn('ctrl-bq-bw-num'),
439
447
  fontSize: gn('ctrl-bq-size-num'),
440
448
  },
449
+
441
450
  };
442
451
 
443
452
  styles.list = {
@@ -525,6 +534,79 @@ stylesToControls = function(styles) {
525
534
  };
526
535
  };
527
536
 
537
+ // ═══════════════════════════════════════════════════════
538
+ // STRIP STYLE DEFAULTS (for shorter URLs)
539
+ // ═══════════════════════════════════════════════════════
540
+
541
+ // Default values matching HTML control defaults in index.html.
542
+ // When a style value equals its default, it can be omitted from serialization
543
+ // because stylesToControls / the browser already falls back to these defaults.
544
+ var STYLE_DEFAULTS = {
545
+ fontFamily: 'Inter',
546
+ baseFontSize: 16,
547
+ lineHeight: 1.75,
548
+ headers: {
549
+ fontFamily: 'inherit',
550
+ scale: 1.0,
551
+ marginBottom: 0.4,
552
+ },
553
+ h1: { fontSize: 2.1, fontWeight: 700 },
554
+ h2: { fontSize: 1.55, fontWeight: 600 },
555
+ h3: { fontSize: 1.2, fontWeight: 600 },
556
+ h4: { fontSize: 1.0, fontWeight: 600 },
557
+ p: { lineHeight: 1.75, marginBottom: 1.1 },
558
+ link: { decoration: 'underline' },
559
+ code: { font: 'JetBrains Mono' },
560
+ blockquote: { borderWidth: 3, fontSize: 1.0 },
561
+ list: { spacing: 0.3, indent: 1.6 },
562
+ };
563
+
564
+ function numEq(a, b) {
565
+ var na = typeof a === 'number' ? a : parseFloat(a);
566
+ var nb = typeof b === 'number' ? b : parseFloat(b);
567
+ if (isNaN(na) || isNaN(nb)) return false;
568
+ return Math.abs(na - nb) < 0.001;
569
+ }
570
+
571
+ /**
572
+ * stripStyleDefaults(styles)
573
+ * Returns a new styles object with default-valued properties removed.
574
+ * light/dark color blocks are preserved as-is (they have no static defaults).
575
+ * Empty sub-objects are removed entirely.
576
+ */
577
+ function stripStyleDefaults(styles) {
578
+ if (!styles || typeof styles !== 'object') return styles;
579
+ var result = {};
580
+ for (var key in styles) {
581
+ if (!styles.hasOwnProperty(key)) continue;
582
+ var val = styles[key];
583
+ var def = STYLE_DEFAULTS[key];
584
+
585
+ // light/dark theme color blocks — always keep
586
+ if (key === 'light' || key === 'dark') {
587
+ result[key] = val;
588
+ continue;
589
+ }
590
+
591
+ if (typeof val === 'object' && val !== null) {
592
+ var sub = {};
593
+ var defObj = (typeof def === 'object' && def !== null) ? def : {};
594
+ for (var sk in val) {
595
+ if (!val.hasOwnProperty(sk)) continue;
596
+ var sv = val[sk];
597
+ var sd = defObj[sk];
598
+ if (sd !== undefined && (sv === sd || String(sv) === String(sd) || numEq(sv, sd))) continue;
599
+ sub[sk] = sv;
600
+ }
601
+ if (Object.keys(sub).length > 0) result[key] = sub;
602
+ } else {
603
+ if (def !== undefined && (val === def || String(val) === String(def) || numEq(val, def))) continue;
604
+ result[key] = val;
605
+ }
606
+ }
607
+ return result;
608
+ }
609
+
528
610
  // ═══════════════════════════════════════════════════════
529
611
  // EXPORTS
530
612
  // ═══════════════════════════════════════════════════════
@@ -544,6 +626,8 @@ exports.collectStylesDual = collectStylesDual;
544
626
  exports.collectThemeColors = collectThemeColors;
545
627
  exports.parseThemeColorBlock = parseThemeColorBlock;
546
628
  exports.stylesToControls = stylesToControls;
629
+ exports.STYLE_DEFAULTS = STYLE_DEFAULTS;
630
+ exports.stripStyleDefaults = stripStyleDefaults;
547
631
 
548
632
  // UMD tail: in Node (tests) this writes to module.exports; in the browser
549
633
  // it creates window.SDocStyles. We use this pattern instead of ES modules
@@ -55,16 +55,18 @@ const LIGHT_DEFAULTS = {
55
55
  codeColor: '#6b21a8',
56
56
  linkColor: '#2563eb',
57
57
  bqBorderColor: '#2563eb',
58
+ bqBg: '#f7f5f2',
58
59
  bqColor: '#6b6560',
59
60
  };
60
61
 
61
62
  const DARK_DEFAULTS = {
62
- bgColor: '#1c1a17',
63
+ bgColor: '#2c2a26',
63
64
  colorDefault: '#e7e5e2',
64
65
  codeBg: '#1a1816',
65
66
  codeColor: '#b8a99a',
66
67
  linkColor: '#60a5fa',
67
68
  bqBorderColor: '#60a5fa',
69
+ bqBg: '#252320',
68
70
  bqColor: '#a8a29e',
69
71
  };
70
72
 
@@ -142,6 +144,7 @@ function loadThemeColors(theme) {
142
144
  'ctrl-code-bg': defaults.codeBg,
143
145
  'ctrl-code-color': defaults.codeColor,
144
146
  'ctrl-bq-border-color': defaults.bqBorderColor,
147
+ 'ctrl-bq-bg': defaults.bqBg,
145
148
  'ctrl-bq-color': defaults.bqColor,
146
149
  };
147
150
  for (var ctrlId in standaloneMap) {
@@ -192,6 +195,7 @@ function updateDefaultColors() {
192
195
  'ctrl-code-bg': defaults.codeBg,
193
196
  'ctrl-code-color': defaults.codeColor,
194
197
  'ctrl-bq-border-color': defaults.bqBorderColor,
198
+ 'ctrl-bq-bg': defaults.bqBg,
195
199
  'ctrl-bq-color': defaults.bqColor,
196
200
  };
197
201
  for (const [ctrlId, val] of Object.entries(standaloneMap)) {
@@ -216,6 +220,7 @@ function getStandaloneDefault(ctrlId) {
216
220
  'ctrl-code-bg': d.codeBg,
217
221
  'ctrl-code-color': d.codeColor,
218
222
  'ctrl-bq-border-color': d.bqBorderColor,
223
+ 'ctrl-bq-bg': d.bqBg,
219
224
  'ctrl-bq-color': d.bqColor,
220
225
  };
221
226
  return map[ctrlId];
@@ -247,6 +252,7 @@ S.getStandaloneDefault = getStandaloneDefault;
247
252
  S.updateDefaultColors = updateDefaultColors;
248
253
  S.toggleTheme = toggleTheme;
249
254
  S.switchThemeAndUpdate = switchThemeAndUpdate;
255
+ S.getPreferredTheme = getPreferredTheme;
250
256
  S.saveCurrentThemeColors = saveCurrentThemeColors;
251
257
  S.loadThemeColors = loadThemeColors;
252
258
  S.updateThemeTabs = updateThemeTabs;
package/public/sw.js ADDED
@@ -0,0 +1,108 @@
1
+ // Service worker — stale-while-revalidate + version-gated cache bust
2
+ var CACHE_NAME = 'sdocs-cache';
3
+
4
+ var APP_SHELL = [
5
+ '/',
6
+ '/public/css/tokens.css',
7
+ '/public/css/layout.css',
8
+ '/public/css/rendered.css',
9
+ '/public/css/panel.css',
10
+ '/public/css/write.css',
11
+ '/public/css/mobile.css',
12
+ '/public/brotli-wasm.js',
13
+ '/public/brotli_wasm_bg.wasm',
14
+ '/public/sdocs-yaml.js',
15
+ '/public/sdocs-styles.js',
16
+ '/public/sdocs-state.js',
17
+ '/public/sdocs-theme.js',
18
+ '/public/sdocs-controls.js',
19
+ '/public/sdocs-export.js',
20
+ '/public/sdocs-write.js',
21
+ '/public/sdocs-app.js',
22
+ '/public/vendor/marked.min.js',
23
+ '/public/fonts/inter-400.woff2',
24
+ '/public/fonts/inter-500.woff2',
25
+ '/public/fonts/inter-600.woff2',
26
+ '/public/default.md',
27
+ ];
28
+
29
+ // Pre-cache app shell on install
30
+ self.addEventListener('install', function (e) {
31
+ e.waitUntil(
32
+ caches.open(CACHE_NAME).then(function (cache) {
33
+ return cache.addAll(APP_SHELL);
34
+ }).then(function () {
35
+ return self.skipWaiting();
36
+ })
37
+ );
38
+ });
39
+
40
+ // Claim clients on activate
41
+ self.addEventListener('activate', function (e) {
42
+ e.waitUntil(self.clients.claim());
43
+ });
44
+
45
+ // Stale-while-revalidate for same-origin, cache-first for fonts
46
+ self.addEventListener('fetch', function (e) {
47
+ var url = new URL(e.request.url);
48
+
49
+ if (e.request.method !== 'GET') return;
50
+
51
+ // Version-check always hits network
52
+ if (url.pathname === '/version-check') return;
53
+
54
+ // Google Fonts: cache-first (they're immutable)
55
+ if (url.hostname === 'fonts.googleapis.com' || url.hostname === 'fonts.gstatic.com') {
56
+ e.respondWith(
57
+ caches.match(e.request).then(function (cached) {
58
+ if (cached) return cached;
59
+ return fetch(e.request).then(function (response) {
60
+ var clone = response.clone();
61
+ caches.open(CACHE_NAME).then(function (cache) { cache.put(e.request, clone); });
62
+ return response;
63
+ });
64
+ })
65
+ );
66
+ return;
67
+ }
68
+
69
+ // Same-origin: stale-while-revalidate
70
+ // Return cached immediately, fetch in background to update cache
71
+ if (url.origin === self.location.origin) {
72
+ e.respondWith(
73
+ caches.open(CACHE_NAME).then(function (cache) {
74
+ return cache.match(e.request).then(function (cached) {
75
+ var networkFetch = fetch(e.request).then(function (response) {
76
+ if (response.ok) {
77
+ cache.put(e.request, response.clone());
78
+ }
79
+ return response;
80
+ }).catch(function () {
81
+ return cached; // offline fallback
82
+ });
83
+
84
+ return cached || networkFetch;
85
+ });
86
+ })
87
+ );
88
+ return;
89
+ }
90
+ });
91
+
92
+ // Version check: if server version differs, purge and re-cache.
93
+ // No reload — stale-while-revalidate ensures next navigation gets fresh content.
94
+ self.addEventListener('message', function (e) {
95
+ if (e.data && e.data.type === 'check-update' && e.data.version) {
96
+ fetch('/version-check').then(function (res) {
97
+ return res.json();
98
+ }).then(function (data) {
99
+ if (data.version !== e.data.version) {
100
+ caches.delete(CACHE_NAME).then(function () {
101
+ return caches.open(CACHE_NAME).then(function (cache) {
102
+ return cache.addAll(APP_SHELL);
103
+ });
104
+ });
105
+ }
106
+ }).catch(function () { /* offline — ignore */ });
107
+ }
108
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * marked v11.2.0 - a markdown parser
3
+ * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed)
4
+ * https://github.com/markedjs/marked
5
+ */
6
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s=/[&<>"']/,r=new RegExp(s.source,"g"),i=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,l=new RegExp(i.source,"g"),o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},a=e=>o[e];function c(e,t){if(t){if(s.test(e))return e.replace(r,a)}else if(i.test(e))return e.replace(l,a);return e}const h=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function p(e){return e.replace(h,((e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const u=/(^|[^\[])\^/g;function k(e,t){let n="string"==typeof e?e:e.source;t=t||"";const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(u,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}function g(e){try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return null}return e}const f={exec:()=>null};function d(e,t){const n=e.replace(/\|/g,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(/ \|/);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length<t;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(/\\\|/g,"|");return n}function x(e,t,n){const s=e.length;if(0===s)return"";let r=0;for(;r<s;){const i=e.charAt(s-r-1);if(i!==t||n){if(i===t||!n)break;r++}else r++}return e.slice(0,s-r)}function b(e,t,n,s){const r=t.href,i=t.title?c(t.title):null,l=e[1].replace(/\\([\[\]])/g,"$1");if("!"!==e[0].charAt(0)){s.state.inLink=!0;const e={type:"link",raw:n,href:r,title:i,text:l,tokens:s.inlineTokens(l)};return s.state.inLink=!1,e}return{type:"image",raw:n,href:r,title:i,text:c(l)}}class w{options;rules;lexer;constructor(t){this.options=t||e.defaults}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:x(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t){const n=e.match(/^(\s+)(?:```)/);if(null===n)return t;const s=n[1];return t.split("\n").map((e=>{const t=e.match(/^\s+/);if(null===t)return e;const[n]=t;return n.length>=s.length?e.slice(s.length):e})).join("\n")}(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=x(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){const e=x(t[0].replace(/^ *>[ \t]?/gm,""),"\n"),n=this.lexer.state.top;this.lexer.state.top=!0;const s=this.lexer.blockTokens(e);return this.lexer.state.top=n,{type:"blockquote",raw:t[0],tokens:s,text:e}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim();const s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=new RegExp(`^( {0,3}${n})((?:[\t ][^\\n]*)?(?:\\n|$))`);let l="",o="",a=!1;for(;e;){let n=!1;if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;l=t[0],e=e.substring(l.length);let s=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=0;this.options.pedantic?(h=2,o=s.trimStart()):(h=t[2].search(/[^ ]/),h=h>4?1:h,o=s.slice(h),h+=t[1].length);let p=!1;if(!s&&/^ *$/.test(c)&&(l+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=new RegExp(`^ {0,${Math.min(3,h-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),n=new RegExp(`^ {0,${Math.min(3,h-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),r=new RegExp(`^ {0,${Math.min(3,h-1)}}(?:\`\`\`|~~~)`),i=new RegExp(`^ {0,${Math.min(3,h-1)}}#`);for(;e;){const a=e.split("\n",1)[0];if(c=a,this.options.pedantic&&(c=c.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),r.test(c))break;if(i.test(c))break;if(t.test(c))break;if(n.test(e))break;if(c.search(/[^ ]/)>=h||!c.trim())o+="\n"+c.slice(h);else{if(p)break;if(s.search(/[^ ]/)>=4)break;if(r.test(s))break;if(i.test(s))break;if(n.test(s))break;o+="\n"+c}p||c.trim()||(p=!0),l+=a+"\n",e=e.substring(a.length+1),s=c.slice(h)}}r.loose||(a?r.loose=!0:/\n *\n *$/.test(l)&&(a=!0));let u,k=null;this.options.gfm&&(k=/^\[[ xX]\] /.exec(o),k&&(u="[ ] "!==k[0],o=o.replace(/^\[[ xX]\] +/,""))),r.items.push({type:"list_item",raw:l,task:!!k,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=l}r.items[r.items.length-1].raw=l.trimEnd(),r.items[r.items.length-1].text=o.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e<r.items.length;e++)if(this.lexer.state.top=!1,r.items[e].tokens=this.lexer.blockTokens(r.items[e].text,[]),!r.loose){const t=r.items[e].tokens.filter((e=>"space"===e.type)),n=t.length>0&&t.some((e=>/\n.*\n/.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e<r.items.length;e++)r.items[e].loose=!0;return r}}html(e){const t=this.rules.block.html.exec(e);if(t){return{type:"html",block:!0,raw:t[0],pre:"pre"===t[1]||"script"===t[1]||"style"===t[1],text:t[0]}}}def(e){const t=this.rules.block.def.exec(e);if(t){const e=t[1].toLowerCase().replace(/\s+/g," "),n=t[2]?t[2].replace(/^<(.*)>$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",s=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:n,title:s}}}table(e){const t=this.rules.block.table.exec(e);if(!t)return;if(!/[:|]/.test(t[2]))return;const n=d(t[1]),s=t[2].replace(/^\||\| *$/g,"").split("|"),r=t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[],i={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===s.length){for(const e of s)/^ *-+: *$/.test(e)?i.align.push("right"):/^ *:-+: *$/.test(e)?i.align.push("center"):/^ *:-+ *$/.test(e)?i.align.push("left"):i.align.push(null);for(const e of n)i.header.push({text:e,tokens:this.lexer.inline(e)});for(const e of r)i.rows.push(d(e,i.header.length).map((e=>({text:e,tokens:this.lexer.inline(e)}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:c(t[1])}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&/^<a /i.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&/^<\/a>/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&/^</.test(e)){if(!/>$/.test(e))return;const t=x(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;let n=0;for(let s=0;s<e.length;s++)if("\\"===e[s])s++;else if(e[s]===t[0])n++;else if(e[s]===t[1]&&(n--,n<0))return s;return-1}(t[2],"()");if(e>-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),/^</.test(n)&&(n=this.options.pedantic&&!/>$/.test(e)?n.slice(1):n.slice(1,-1)),b(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(/\s+/g," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return b(n,e,n[0],this.lexer)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(/[\p{L}\p{N}]/u))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(/\n/g," ");const n=/[^ ]/.test(e),s=/^ /.test(e)&&/ $/.test(e);return n&&s&&(e=e.substring(1,e.length-1)),e=c(e,!0),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=c(t[1]),n="mailto:"+e):(e=c(t[1]),n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=c(t[0]),n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=c(t[0]),n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){let e;return e=this.lexer.state.inRawBlock?t[0]:c(t[0]),{type:"text",raw:t[0],text:e}}}}const m=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,y=/(?:[*+-]|\d{1,9}[.)])/,$=k(/^(?!bull )((?:.|\n(?!\s*?\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,y).getRegex(),z=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,T=/(?!\s*\])(?:\\.|[^\[\]\\])+/,R=k(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label",T).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),_=k(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,y).getRegex(),A="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",S=/<!--(?!-?>)[\s\S]*?(?:-->|$)/,I=k("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))","i").replace("comment",S).replace("tag",A).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),E=k(z).replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex(),Z={blockquote:k(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",E).getRegex(),code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,def:R,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:m,html:I,lheading:$,list:_,newline:/^(?: *(?:\n|$))+/,paragraph:E,table:f,text:/^[^\n]+/},q=k("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex(),L={...Z,table:q,paragraph:k(z).replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",q).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex()},P={...Z,html:k("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",S).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:f,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:k(z).replace("hr",m).replace("heading"," *#{1,6} *[^\n]").replace("lheading",$).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Q=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,v=/^( {2,}|\\)\n(?!\s*$)/,B="\\p{P}$+<=>`^|~",M=k(/^((?![*_])[\spunctuation])/,"u").replace(/punctuation/g,B).getRegex(),O=k(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,B).getRegex(),C=k("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,B).getRegex(),D=k("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,B).getRegex(),j=k(/\\([punct])/,"gu").replace(/punct/g,B).getRegex(),H=k(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),U=k(S).replace("(?:--\x3e|$)","--\x3e").getRegex(),X=k("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",U).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),F=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,N=k(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",F).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),G=k(/^!?\[(label)\]\[(ref)\]/).replace("label",F).replace("ref",T).getRegex(),J=k(/^!?\[(ref)\](?:\[\])?/).replace("ref",T).getRegex(),K={_backpedal:f,anyPunctuation:j,autolink:H,blockSkip:/\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g,br:v,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:f,emStrongLDelim:O,emStrongRDelimAst:C,emStrongRDelimUnd:D,escape:Q,link:N,nolink:J,punctuation:M,reflink:G,reflinkSearch:k("reflink|nolink(?!\\()","g").replace("reflink",G).replace("nolink",J).getRegex(),tag:X,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,url:f},V={...K,link:k(/^!?\[(label)\]\((.*?)\)/).replace("label",F).getRegex(),reflink:k(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",F).getRegex()},W={...K,escape:k(Q).replace("])","~|])").getRegex(),url:k(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/},Y={...W,br:k(v).replace("{2,}","*").getRegex(),text:k(W.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},ee={normal:Z,gfm:L,pedantic:P},te={normal:K,gfm:W,breaks:Y,pedantic:V};class ne{tokens;options;state;tokenizer;inlineQueue;constructor(t){this.tokens=[],this.tokens.links=Object.create(null),this.options=t||e.defaults,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};const n={block:ee.normal,inline:te.normal};this.options.pedantic?(n.block=ee.pedantic,n.inline=te.pedantic):this.options.gfm&&(n.block=ee.gfm,this.options.breaks?n.inline=te.breaks:n.inline=te.gfm),this.tokenizer.rules=n}static get rules(){return{block:ee,inline:te}}static lex(e,t){return new ne(t).lex(e)}static lexInline(e,t){return new ne(t).inlineTokens(e)}lex(e){e=e.replace(/\r\n|\r/g,"\n"),this.blockTokens(e,this.tokens);for(let e=0;e<this.inlineQueue.length;e++){const t=this.inlineQueue[e];this.inlineTokens(t.src,t.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[]){let n,s,r,i;for(e=this.options.pedantic?e.replace(/\t/g," ").replace(/^ +$/gm,""):e.replace(/^( *)(\t+)/gm,((e,t,n)=>t+" ".repeat(n.length)));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.space(e))e=e.substring(n.raw.length),1===n.raw.length&&t.length>0?t[t.length-1].raw+="\n":t.push(n);else if(n=this.tokenizer.code(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?t.push(n):(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.fences(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.heading(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.hr(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.blockquote(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.list(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.html(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.def(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?this.tokens.links[n.tag]||(this.tokens.links[n.tag]={href:n.href,title:n.title}):(s.raw+="\n"+n.raw,s.text+="\n"+n.raw,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.table(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.lheading(e))e=e.substring(n.raw.length),t.push(n);else{if(r=e,this.options.extensions&&this.options.extensions.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(this.state.top&&(n=this.tokenizer.paragraph(r)))s=t[t.length-1],i&&"paragraph"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n),i=r.length!==e.length,e=e.substring(n.raw.length);else if(n=this.tokenizer.text(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n,s,r,i,l,o,a=e;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(i=this.tokenizer.rules.inline.reflinkSearch.exec(a));)e.includes(i[0].slice(i[0].lastIndexOf("[")+1,-1))&&(a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(i=this.tokenizer.rules.inline.blockSkip.exec(a));)a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(i=this.tokenizer.rules.inline.anyPunctuation.exec(a));)a=a.slice(0,i.index)+"++"+a.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;e;)if(l||(o=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.escape(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.tag(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.link(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.emStrong(e,a,o))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.codespan(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.br(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.del(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.autolink(e))e=e.substring(n.raw.length),t.push(n);else if(this.state.inLink||!(n=this.tokenizer.url(e))){if(r=e,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(n=this.tokenizer.inlineText(r))e=e.substring(n.raw.length),"_"!==n.raw.slice(-1)&&(o=n.raw.slice(-1)),l=!0,s=t[t.length-1],s&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}else e=e.substring(n.raw.length),t.push(n);return t}}class se{options;constructor(t){this.options=t||e.defaults}code(e,t,n){const s=(t||"").match(/^\S*/)?.[0];return e=e.replace(/\n$/,"")+"\n",s?'<pre><code class="language-'+c(s)+'">'+(n?e:c(e,!0))+"</code></pre>\n":"<pre><code>"+(n?e:c(e,!0))+"</code></pre>\n"}blockquote(e){return`<blockquote>\n${e}</blockquote>\n`}html(e,t){return e}heading(e,t,n){return`<h${t}>${e}</h${t}>\n`}hr(){return"<hr>\n"}list(e,t,n){const s=t?"ol":"ul";return"<"+s+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"</"+s+">\n"}listitem(e,t,n){return`<li>${e}</li>\n`}checkbox(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox">'}paragraph(e){return`<p>${e}</p>\n`}table(e,t){return t&&(t=`<tbody>${t}</tbody>`),"<table>\n<thead>\n"+e+"</thead>\n"+t+"</table>\n"}tablerow(e){return`<tr>\n${e}</tr>\n`}tablecell(e,t){const n=t.header?"th":"td";return(t.align?`<${n} align="${t.align}">`:`<${n}>`)+e+`</${n}>\n`}strong(e){return`<strong>${e}</strong>`}em(e){return`<em>${e}</em>`}codespan(e){return`<code>${e}</code>`}br(){return"<br>"}del(e){return`<del>${e}</del>`}link(e,t,n){const s=g(e);if(null===s)return n;let r='<a href="'+(e=s)+'"';return t&&(r+=' title="'+t+'"'),r+=">"+n+"</a>",r}image(e,t,n){const s=g(e);if(null===s)return n;let r=`<img src="${e=s}" alt="${n}"`;return t&&(r+=` title="${t}"`),r+=">",r}text(e){return e}}class re{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,n){return""+n}image(e,t,n){return""+n}br(){return""}}class ie{options;renderer;textRenderer;constructor(t){this.options=t||e.defaults,this.options.renderer=this.options.renderer||new se,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new re}static parse(e,t){return new ie(t).parse(e)}static parseInline(e,t){return new ie(t).parseInline(e)}parse(e,t=!0){let n="";for(let s=0;s<e.length;s++){const r=e[s];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[r.type]){const e=r,t=this.options.extensions.renderers[e.type].call({parser:this},e);if(!1!==t||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(e.type)){n+=t||"";continue}}switch(r.type){case"space":continue;case"hr":n+=this.renderer.hr();continue;case"heading":{const e=r;n+=this.renderer.heading(this.parseInline(e.tokens),e.depth,p(this.parseInline(e.tokens,this.textRenderer)));continue}case"code":{const e=r;n+=this.renderer.code(e.text,e.lang,!!e.escaped);continue}case"table":{const e=r;let t="",s="";for(let t=0;t<e.header.length;t++)s+=this.renderer.tablecell(this.parseInline(e.header[t].tokens),{header:!0,align:e.align[t]});t+=this.renderer.tablerow(s);let i="";for(let t=0;t<e.rows.length;t++){const n=e.rows[t];s="";for(let t=0;t<n.length;t++)s+=this.renderer.tablecell(this.parseInline(n[t].tokens),{header:!1,align:e.align[t]});i+=this.renderer.tablerow(s)}n+=this.renderer.table(t,i);continue}case"blockquote":{const e=r,t=this.parse(e.tokens);n+=this.renderer.blockquote(t);continue}case"list":{const e=r,t=e.ordered,s=e.start,i=e.loose;let l="";for(let t=0;t<e.items.length;t++){const n=e.items[t],s=n.checked,r=n.task;let o="";if(n.task){const e=this.renderer.checkbox(!!s);i?n.tokens.length>0&&"paragraph"===n.tokens[0].type?(n.tokens[0].text=e+" "+n.tokens[0].text,n.tokens[0].tokens&&n.tokens[0].tokens.length>0&&"text"===n.tokens[0].tokens[0].type&&(n.tokens[0].tokens[0].text=e+" "+n.tokens[0].tokens[0].text)):n.tokens.unshift({type:"text",text:e+" "}):o+=e+" "}o+=this.parse(n.tokens,i),l+=this.renderer.listitem(o,r,!!s)}n+=this.renderer.list(l,t,s);continue}case"html":{const e=r;n+=this.renderer.html(e.text,e.block);continue}case"paragraph":{const e=r;n+=this.renderer.paragraph(this.parseInline(e.tokens));continue}case"text":{let i=r,l=i.tokens?this.parseInline(i.tokens):i.text;for(;s+1<e.length&&"text"===e[s+1].type;)i=e[++s],l+="\n"+(i.tokens?this.parseInline(i.tokens):i.text);n+=t?this.renderer.paragraph(l):l;continue}default:{const e='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(e),"";throw new Error(e)}}}return n}parseInline(e,t){t=t||this.renderer;let n="";for(let s=0;s<e.length;s++){const r=e[s];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[r.type]){const e=this.options.extensions.renderers[r.type].call({parser:this},r);if(!1!==e||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=e||"";continue}}switch(r.type){case"escape":{const e=r;n+=t.text(e.text);break}case"html":{const e=r;n+=t.html(e.text);break}case"link":{const e=r;n+=t.link(e.href,e.title,this.parseInline(e.tokens,t));break}case"image":{const e=r;n+=t.image(e.href,e.title,e.text);break}case"strong":{const e=r;n+=t.strong(this.parseInline(e.tokens,t));break}case"em":{const e=r;n+=t.em(this.parseInline(e.tokens,t));break}case"codespan":{const e=r;n+=t.codespan(e.text);break}case"br":n+=t.br();break;case"del":{const e=r;n+=t.del(this.parseInline(e.tokens,t));break}case"text":{const e=r;n+=t.text(e.text);break}default:{const e='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(e),"";throw new Error(e)}}}return n}}class le{options;constructor(t){this.options=t||e.defaults}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}}class oe{defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};options=this.setOptions;parse=this.#e(ne.lex,ie.parse);parseInline=this.#e(ne.lexInline,ie.parseInline);Parser=ie;Renderer=se;TextRenderer=re;Lexer=ne;Tokenizer=w;Hooks=le;constructor(...e){this.use(...e)}walkTokens(e,t){let n=[];for(const s of e)switch(n=n.concat(t.call(this,s)),s.type){case"table":{const e=s;for(const s of e.header)n=n.concat(this.walkTokens(s.tokens,t));for(const s of e.rows)for(const e of s)n=n.concat(this.walkTokens(e.tokens,t));break}case"list":{const e=s;n=n.concat(this.walkTokens(e.items,t));break}default:{const e=s;this.defaults.extensions?.childTokens?.[e.type]?this.defaults.extensions.childTokens[e.type].forEach((s=>{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new se(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new w(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new le;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.hooks[s],i=t[s];le.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return ne.lex(e,t??this.defaults)}parser(e,t){return ie.parse(e,t??this.defaults)}#e(e,t){return(n,s)=>{const r={...s},i={...this.defaults,...r};!0===this.defaults.async&&!1===r.async&&(i.silent||console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored."),i.async=!0);const l=this.#t(!!i.silent,!!i.async);if(null==n)return l(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof n)return l(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i),i.async)return Promise.resolve(i.hooks?i.hooks.preprocess(n):n).then((t=>e(t,i))).then((e=>i.hooks?i.hooks.processAllTokens(e):e)).then((e=>i.walkTokens?Promise.all(this.walkTokens(e,i.walkTokens)).then((()=>e)):e)).then((e=>t(e,i))).then((e=>i.hooks?i.hooks.postprocess(e):e)).catch(l);try{i.hooks&&(n=i.hooks.preprocess(n));let s=e(n,i);i.hooks&&(s=i.hooks.processAllTokens(s)),i.walkTokens&&this.walkTokens(s,i.walkTokens);let r=t(s,i);return i.hooks&&(r=i.hooks.postprocess(r)),r}catch(e){return l(e)}}}#t(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="<p>An error occurred:</p><pre>"+c(n.message+"",!0)+"</pre>";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const ae=new oe;function ce(e,t){return ae.parse(e,t)}ce.options=ce.setOptions=function(e){return ae.setOptions(e),ce.defaults=ae.defaults,n(ce.defaults),ce},ce.getDefaults=t,ce.defaults=e.defaults,ce.use=function(...e){return ae.use(...e),ce.defaults=ae.defaults,n(ce.defaults),ce},ce.walkTokens=function(e,t){return ae.walkTokens(e,t)},ce.parseInline=ae.parseInline,ce.Parser=ie,ce.parser=ie.parse,ce.Renderer=se,ce.TextRenderer=re,ce.Lexer=ne,ce.lexer=ne.lex,ce.Tokenizer=w,ce.Hooks=le,ce.parse=ce;const he=ce.options,pe=ce.setOptions,ue=ce.use,ke=ce.walkTokens,ge=ce.parseInline,fe=ce,de=ie.parse,xe=ne.lex;e.Hooks=le,e.Lexer=ne,e.Marked=oe,e.Parser=ie,e.Renderer=se,e.TextRenderer=re,e.Tokenizer=w,e.getDefaults=t,e.lexer=xe,e.marked=ce,e.options=he,e.parse=fe,e.parseInline=ge,e.parser=de,e.setOptions=pe,e.use=ue,e.walkTokens=ke}));
package/server.js CHANGED
@@ -1,9 +1,27 @@
1
1
  const http = require('http');
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
+ const crypto = require('crypto');
4
5
 
5
6
  const PORT = process.env.PORT || 3000;
6
7
 
8
+ // Auto-version: hash all non-font files in public/ at startup.
9
+ // Any file change = new hash = clients purge their SW cache.
10
+ const appHash = crypto.createHash('md5');
11
+ (function walkDir(dir) {
12
+ const entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
13
+ for (const entry of entries) {
14
+ if (entry.isDirectory()) {
15
+ if (entry.name === 'fonts') continue;
16
+ walkDir(path.join(dir, entry.name));
17
+ } else {
18
+ appHash.update(entry.name);
19
+ appHash.update(fs.readFileSync(path.join(dir, entry.name)));
20
+ }
21
+ }
22
+ })(path.join(__dirname, 'public'));
23
+ const APP_VERSION = appHash.digest('hex').slice(0, 10);
24
+
7
25
  const MIME = {
8
26
  '.html': 'text/html; charset=utf-8',
9
27
  '.css': 'text/css',
@@ -11,9 +29,18 @@ const MIME = {
11
29
  '.json': 'application/json',
12
30
  '.md': 'text/plain',
13
31
  '.smd': 'text/plain',
32
+ '.woff2': 'font/woff2',
33
+ '.wasm': 'application/wasm',
14
34
  };
15
35
 
16
- function serveFile(res, filePath) {
36
+ function cacheHeader(ext) {
37
+ if (ext === '.html') return 'no-cache';
38
+ if (ext === '.woff2') return 'public, max-age=31536000, immutable';
39
+ if (ext === '.css' || ext === '.js') return 'public, max-age=86400';
40
+ return 'no-cache';
41
+ }
42
+
43
+ function serveFile(res, filePath, extraHeaders) {
17
44
  fs.readFile(filePath, (err, data) => {
18
45
  if (err) {
19
46
  res.writeHead(404, { 'Content-Type': 'text/plain' });
@@ -21,7 +48,12 @@ function serveFile(res, filePath) {
21
48
  return;
22
49
  }
23
50
  const ext = path.extname(filePath);
24
- res.writeHead(200, { 'Content-Type': MIME[ext] || 'application/octet-stream' });
51
+ const headers = {
52
+ 'Content-Type': MIME[ext] || 'application/octet-stream',
53
+ 'Cache-Control': cacheHeader(ext),
54
+ };
55
+ Object.assign(headers, extraHeaders);
56
+ res.writeHead(200, headers);
25
57
  res.end(data);
26
58
  });
27
59
  }
@@ -36,8 +68,39 @@ const server = http.createServer((req, res) => {
36
68
  return;
37
69
  }
38
70
 
71
+ // Version check — used by service worker to detect updates
72
+ if (pathname === '/version-check') {
73
+ const v = url.searchParams.get('v') || '';
74
+ console.log([
75
+ new Date().toISOString(),
76
+ req.headers['x-forwarded-for'] || req.socket.remoteAddress,
77
+ req.headers['user-agent'] || '',
78
+ req.headers['referer'] || '',
79
+ req.headers['accept-language'] || '',
80
+ v ? 'cached:' + v : 'no-cache',
81
+ ].join(' | '));
82
+ res.writeHead(200, {
83
+ 'Content-Type': 'application/json',
84
+ 'Cache-Control': 'no-cache',
85
+ });
86
+ res.end(JSON.stringify({ version: APP_VERSION }));
87
+ return;
88
+ }
89
+
39
90
  if (pathname === '/' || pathname === '/new') {
40
- serveFile(res, path.join(__dirname, 'public', 'index.html'));
91
+ const htmlPath = path.join(__dirname, 'public', 'index.html');
92
+ fs.readFile(htmlPath, 'utf8', (err, html) => {
93
+ if (err) { res.writeHead(500); res.end('Error'); return; }
94
+ html = html.replace('__APP_VERSION__', APP_VERSION);
95
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-cache' });
96
+ res.end(html);
97
+ });
98
+ return;
99
+ }
100
+
101
+ // Service worker must be served from root scope
102
+ if (pathname === '/sw.js') {
103
+ serveFile(res, path.join(__dirname, 'public', 'sw.js'), { 'Cache-Control': 'no-cache' });
41
104
  return;
42
105
  }
43
106