@turntrout/subfont 1.10.7 → 1.11.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +21 -21
  3. package/lib/FontTracerPool.d.ts +22 -27
  4. package/lib/FontTracerPool.d.ts.map +1 -1
  5. package/lib/FontTracerPool.js +51 -277
  6. package/lib/FontTracerPool.js.map +1 -1
  7. package/lib/HeadlessBrowser.d.ts.map +1 -1
  8. package/lib/HeadlessBrowser.js +44 -28
  9. package/lib/HeadlessBrowser.js.map +1 -1
  10. package/lib/cli.js +14 -10
  11. package/lib/cli.js.map +1 -1
  12. package/lib/codepointMaps.d.ts.map +1 -1
  13. package/lib/codepointMaps.js +0 -3
  14. package/lib/codepointMaps.js.map +1 -1
  15. package/lib/collectTextsByPage.d.ts +2 -1
  16. package/lib/collectTextsByPage.d.ts.map +1 -1
  17. package/lib/collectTextsByPage.js +15 -4
  18. package/lib/collectTextsByPage.js.map +1 -1
  19. package/lib/escapeJsStringLiteral.d.ts.map +1 -1
  20. package/lib/escapeJsStringLiteral.js +12 -5
  21. package/lib/escapeJsStringLiteral.js.map +1 -1
  22. package/lib/extractVisibleText.d.ts.map +1 -1
  23. package/lib/extractVisibleText.js +68 -147
  24. package/lib/extractVisibleText.js.map +1 -1
  25. package/lib/fontConverter.d.ts +5 -1
  26. package/lib/fontConverter.d.ts.map +1 -1
  27. package/lib/fontConverter.js +47 -122
  28. package/lib/fontConverter.js.map +1 -1
  29. package/lib/fontConverterWorker.d.ts +14 -1
  30. package/lib/fontConverterWorker.d.ts.map +1 -1
  31. package/lib/fontConverterWorker.js +16 -16
  32. package/lib/fontConverterWorker.js.map +1 -1
  33. package/lib/fontFaceHelpers.d.ts +3 -2
  34. package/lib/fontFaceHelpers.d.ts.map +1 -1
  35. package/lib/fontFaceHelpers.js +18 -17
  36. package/lib/fontFaceHelpers.js.map +1 -1
  37. package/lib/fontFeatureHelpers.d.ts.map +1 -1
  38. package/lib/fontFeatureHelpers.js +5 -1
  39. package/lib/fontFeatureHelpers.js.map +1 -1
  40. package/lib/fontTracerWorker.d.ts +17 -4
  41. package/lib/fontTracerWorker.d.ts.map +1 -1
  42. package/lib/fontTracerWorker.js +31 -60
  43. package/lib/fontTracerWorker.js.map +1 -1
  44. package/lib/getCssRulesByProperty.d.ts.map +1 -1
  45. package/lib/getCssRulesByProperty.js +11 -2
  46. package/lib/getCssRulesByProperty.js.map +1 -1
  47. package/lib/parseCommandLineOptions.d.ts.map +1 -1
  48. package/lib/parseCommandLineOptions.js +12 -7
  49. package/lib/parseCommandLineOptions.js.map +1 -1
  50. package/lib/piscinaRunWithTimeout.d.ts +18 -0
  51. package/lib/piscinaRunWithTimeout.d.ts.map +1 -0
  52. package/lib/piscinaRunWithTimeout.js +78 -0
  53. package/lib/piscinaRunWithTimeout.js.map +1 -0
  54. package/lib/subfont.js.map +1 -1
  55. package/lib/subsetFontWithGlyphs.d.ts +1 -0
  56. package/lib/subsetFontWithGlyphs.d.ts.map +1 -1
  57. package/lib/subsetFontWithGlyphs.js +4 -2
  58. package/lib/subsetFontWithGlyphs.js.map +1 -1
  59. package/lib/subsetFonts.d.ts +4 -3
  60. package/lib/subsetFonts.d.ts.map +1 -1
  61. package/lib/subsetFonts.js +19 -11
  62. package/lib/subsetFonts.js.map +1 -1
  63. package/lib/subsetGeneration.d.ts +1 -1
  64. package/lib/subsetGeneration.d.ts.map +1 -1
  65. package/lib/subsetGeneration.js +7 -7
  66. package/lib/subsetGeneration.js.map +1 -1
  67. package/lib/types/shared.d.ts +1 -0
  68. package/lib/types/shared.d.ts.map +1 -1
  69. package/lib/types/shared.js.map +1 -1
  70. package/lib/unquote.d.ts +17 -0
  71. package/lib/unquote.d.ts.map +1 -1
  72. package/lib/unquote.js +63 -9
  73. package/lib/unquote.js.map +1 -1
  74. package/package.json +2 -2
@@ -1,179 +1,100 @@
1
1
  "use strict";
2
+ const parse5_1 = require("parse5");
3
+ // Tags whose textual contents (and attribute text) must NOT contribute to
4
+ // the rendered character set we trace for font subsetting. `title` lives in
5
+ // `<head>` for valid documents and is already skipped via the head subtree,
6
+ // but parse5 auto-promotes a stray top-level `<title>` from fragment input
7
+ // into the synthetic head — listing it explicitly makes the intent
8
+ // (browser tab titles aren't rendered with web fonts) match either parse
9
+ // outcome.
2
10
  const INVISIBLE_ELEMENTS = new Set([
3
11
  'script',
4
12
  'style',
5
13
  'svg',
6
14
  'template',
7
15
  'head',
16
+ 'title',
8
17
  'noscript',
9
18
  'iframe',
10
19
  'object',
11
20
  'embed',
12
21
  'datalist',
13
22
  ]);
14
- // Build a regex that strips invisible element blocks (greedy, case-insensitive).
15
- // For void elements like <embed> there is no closing tag — just the opening
16
- // tag is stripped (which the tag-stripping regex below handles).
17
- const invisibleBlockTags = [...INVISIBLE_ELEMENTS].filter((t) => t !== 'embed');
18
- const invisibleBlockRe = new RegExp(`<(${invisibleBlockTags.join('|')})\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>`, 'gi');
19
- const commentRe = /<!--[\s\S]*?-->/g;
20
- // Match text-bearing attributes: alt="...", title='...', placeholder=..., etc.
21
- // Captures the attribute name (group 1) and the value (groups 2, 3, or 4 for
22
- // double-quoted, single-quoted, and unquoted respectively).
23
- // Negative lookbehind prevents matching data- prefixed attributes (e.g. data-alt).
24
- const attrRe = /(?<![-\w])(alt|title|placeholder|value|aria-label)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]*))/gi;
25
- // Match <input ... type="hidden" ...> or <input ... type=hidden ...>
26
- // \b only after the unquoted alternative — quotes already delimit the value.
27
- const hiddenInputRe = /<input\b[^>]*?\btype\s*=\s*(?:"hidden"|'hidden'|hidden\b)[^>]*/gi;
28
- const tagRe = /<[^>]+>/g;
29
- // Named and numeric HTML entity decoder. Covers the XML built-ins plus
30
- // typographic entities commonly found in blog/article content. Rare
31
- // entities are left as-is (their literal characters still enter the
32
- // subset, so glyphs are never lost — just slightly overcounted).
33
- const namedEntities = {
34
- amp: '&',
35
- lt: '<',
36
- gt: '>',
37
- quot: '"',
38
- apos: "'",
39
- nbsp: ' ',
40
- // Typographic quotes & dashes
41
- ldquo: '“',
42
- rdquo: '”',
43
- lsquo: '‘',
44
- rsquo: '’',
45
- mdash: '—',
46
- ndash: '–',
47
- hellip: '…',
48
- laquo: '«',
49
- raquo: '»',
50
- // Common symbols
51
- bull: '•',
52
- middot: '·',
53
- copy: '©',
54
- reg: '®',
55
- trade: '™',
56
- times: '×',
57
- divide: '÷',
58
- minus: '−',
59
- plusmn: '±',
60
- deg: '°',
61
- micro: 'µ',
62
- para: '¶',
63
- sect: '§',
64
- // Currency
65
- euro: '€',
66
- pound: '£',
67
- yen: '¥',
68
- cent: '¢',
69
- // Arrows
70
- larr: '←',
71
- rarr: '→',
72
- uarr: '↑',
73
- darr: '↓',
74
- };
75
- const entityRe = /&(?:#x([0-9a-fA-F]+)|#(\d+)|([a-zA-Z]+));/g;
76
- // Numeric character references may name surrogate halves (U+D800–U+DFFF) or
77
- // values past U+10FFFF; both produce invalid scalar values that break
78
- // downstream iterators (harfbuzz, unicode-range emitter). Skip them.
79
- function codePointToScalar(cp, match) {
80
- if (cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) {
81
- return match;
82
- }
83
- return String.fromCodePoint(cp);
84
- }
85
- function decodeEntities(str) {
86
- return str.replace(entityRe, (match, hex, dec, name) => {
87
- if (hex) {
88
- const cp = parseInt(hex, 16);
89
- return Number.isNaN(cp) ? match : codePointToScalar(cp, match);
90
- }
91
- if (dec) {
92
- const cp = parseInt(dec, 10);
93
- return Number.isNaN(cp) ? match : codePointToScalar(cp, match);
94
- }
95
- if (name && namedEntities[name.toLowerCase()] !== undefined) {
96
- return namedEntities[name.toLowerCase()];
23
+ // Attributes whose values render as visible text in the page (typically
24
+ // surfaced as tooltips, alternative text, or input value labels).
25
+ const EXTRACTABLE_ATTRS = new Set([
26
+ 'alt',
27
+ 'title',
28
+ 'placeholder',
29
+ 'value',
30
+ 'aria-label',
31
+ ]);
32
+ function isHiddenInput(node) {
33
+ if (node.tagName !== 'input' || !node.attrs)
34
+ return false;
35
+ for (const attr of node.attrs) {
36
+ if (attr.name === 'type') {
37
+ return attr.value.toLowerCase() === 'hidden';
97
38
  }
98
- return match;
99
- });
39
+ }
40
+ return false;
100
41
  }
101
- // --- Pipeline stages ---
102
- // Each stage takes an HTML string and returns a transformed string or
103
- // extracted data. Ordering is enforced by the pipeline structure: stages
104
- // that must run on "clean" HTML (invisible blocks removed) receive the
105
- // output of stripInvisible, not the original HTML.
106
- function resetGlobalRegexes() {
107
- invisibleBlockRe.lastIndex = 0;
108
- hiddenInputRe.lastIndex = 0;
109
- attrRe.lastIndex = 0;
42
+ // parse5 maps invalid numeric character references to U+FFFD per spec, so
43
+ // lone surrogates should never appear. This is a belt-and-suspenders pass:
44
+ // downstream code (harfbuzz, unicode-range emitter) breaks on lone surrogates,
45
+ // so any that slip through here must not propagate.
46
+ const LONE_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
47
+ function stripLoneSurrogates(text) {
48
+ return text.replace(LONE_SURROGATE_RE, '');
110
49
  }
111
- function collectHiddenInputValues(html) {
112
- hiddenInputRe.lastIndex = 0;
113
- const values = new Set();
114
- let match;
115
- while ((match = hiddenInputRe.exec(html)) !== null) {
116
- const fragment = match[0];
117
- let m;
118
- const localAttrRe = /\bvalue\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]*))/gi;
119
- while ((m = localAttrRe.exec(fragment)) !== null) {
120
- const val = m[1] ?? m[2] ?? m[3];
121
- if (val)
122
- values.add(val);
50
+ function walk(node, parts) {
51
+ if (node.nodeName === '#text') {
52
+ if (node.value)
53
+ parts.push(node.value);
54
+ return;
55
+ }
56
+ if (node.nodeName === '#comment' || node.nodeName === '#documentType') {
57
+ return;
58
+ }
59
+ if (node.tagName && INVISIBLE_ELEMENTS.has(node.tagName)) {
60
+ return;
61
+ }
62
+ if (node.attrs && node.attrs.length > 0) {
63
+ const hidden = isHiddenInput(node);
64
+ for (const attr of node.attrs) {
65
+ if (!EXTRACTABLE_ATTRS.has(attr.name))
66
+ continue;
67
+ if (hidden && attr.name === 'value')
68
+ continue;
69
+ if (attr.value)
70
+ parts.push(attr.value);
123
71
  }
124
72
  }
125
- return values;
126
- }
127
- function stripInvisible(html) {
128
- invisibleBlockRe.lastIndex = 0;
129
- let text = html.replace(invisibleBlockRe, ' ');
130
- text = text.replace(commentRe, ' ');
131
- return text;
132
- }
133
- function extractAttributes(cleanedHtml, hiddenInputValues) {
134
- attrRe.lastIndex = 0;
135
- const parts = [];
136
- let match;
137
- while ((match = attrRe.exec(cleanedHtml)) !== null) {
138
- const attrName = match[1].toLowerCase();
139
- const val = match[2] ?? match[3] ?? match[4];
140
- if (!val)
141
- continue;
142
- if (attrName === 'value' && hiddenInputValues.has(val))
143
- continue;
144
- parts.push(decodeEntities(val));
73
+ if (node.childNodes) {
74
+ for (const child of node.childNodes) {
75
+ walk(child, parts);
76
+ }
145
77
  }
146
- return parts;
147
- }
148
- function stripTagsAndDecode(cleanedHtml) {
149
- const text = cleanedHtml.replace(tagRe, ' ');
150
- return decodeEntities(text);
151
78
  }
152
79
  /**
153
80
  * Fast extraction of visible text content from HTML source.
154
81
  * Used as a lightweight alternative to full font-tracer for pages
155
82
  * that share the same CSS configuration as an already-traced page.
156
83
  *
157
- * Pipeline:
158
- * 1. Collect hidden-input values (for exclusion)
159
- * 2. Strip invisible blocks + comments
160
- * 3. Extract text-bearing attributes from cleaned HTML
161
- * 4. Strip remaining tags and decode entities
84
+ * Uses parse5 (the WHATWG-spec HTML parser used by jsdom) to:
85
+ * - skip invisible subtrees (script, style, svg, etc.) regardless of
86
+ * attribute contents or nesting peculiarities
87
+ * - decode every named or numeric HTML entity (~2200 entities incl.
88
+ * accented Latin like &eacute; / &ouml; that hand-rolled tables miss)
89
+ * - lowercase tag/attribute names so case variations don't leak text
162
90
  */
163
91
  function extractVisibleText(html) {
164
92
  if (!html)
165
93
  return '';
166
- resetGlobalRegexes();
167
- // Stage 1: identify hidden-input values (on original HTML, since
168
- // hidden inputs are visible elements whose values we want to exclude)
169
- const hiddenInputValues = collectHiddenInputValues(html);
170
- // Stage 2: remove invisible content
171
- const cleaned = stripInvisible(html);
172
- // Stage 3: extract attributes from cleaned HTML (not original!)
173
- const attrTexts = extractAttributes(cleaned, hiddenInputValues);
174
- // Stage 4: strip tags and decode remaining text content
175
- const bodyText = stripTagsAndDecode(cleaned);
176
- return [...attrTexts, bodyText].join(' ');
94
+ const doc = (0, parse5_1.parse)(html);
95
+ const parts = [];
96
+ walk(doc, parts);
97
+ return stripLoneSurrogates(parts.join(' '));
177
98
  }
178
99
  extractVisibleText.INVISIBLE_ELEMENTS =
179
100
  INVISIBLE_ELEMENTS;
@@ -1 +1 @@
1
- {"version":3,"file":"extractVisibleText.js","sourceRoot":"","sources":["../src/extractVisibleText.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"extractVisibleText.js","sourceRoot":"","sources":["../src/extractVisibleText.ts"],"names":[],"mappings":";AAAA,mCAA+B;AAE/B,0EAA0E;AAC1E,4EAA4E;AAC5E,4EAA4E;AAC5E,2EAA2E;AAC3E,mEAAmE;AACnE,yEAAyE;AACzE,WAAW;AACX,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAS;IACzC,QAAQ;IACR,OAAO;IACP,KAAK;IACL,UAAU;IACV,MAAM;IACN,OAAO;IACP,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,UAAU;CACX,CAAC,CAAC;AAEH,wEAAwE;AACxE,kEAAkE;AAClE,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAS;IACxC,KAAK;IACL,OAAO;IACP,aAAa;IACb,OAAO;IACP,YAAY;CACb,CAAC,CAAC;AAYH,SAAS,aAAa,CAAC,IAAgB;IACrC,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAC1D,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,0EAA0E;AAC1E,2EAA2E;AAC3E,+EAA+E;AAC/E,oDAAoD;AACpD,MAAM,iBAAiB,GACrB,yEAAyE,CAAC;AAC5E,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,IAAI,CAAC,IAAgB,EAAE,KAAe;IAC7C,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,KAAK,UAAU,IAAI,IAAI,CAAC,QAAQ,KAAK,eAAe,EAAE,CAAC;QACtE,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,IAAI,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS;YAChD,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;gBAAE,SAAS;YAC9C,IAAI,IAAI,CAAC,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,kBAAkB,CAAC,IAAY;IACtC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,GAAG,GAAG,IAAA,cAAK,EAAC,IAAI,CAAC,CAAC;IACxB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,GAAiB,EAAE,KAAK,CAAC,CAAC;IAC/B,OAAO,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9C,CAAC;AAOA,kBAAyC,CAAC,kBAAkB;IAC3D,kBAAkB,CAAC;AAErB,iBAAS,kBAAwC,CAAC"}
@@ -1,3 +1,7 @@
1
- export declare function convert(buffer: Buffer | Uint8Array, targetFormat: string, sourceFormat?: string): Promise<Buffer>;
1
+ interface ConvertOptions {
2
+ signal?: AbortSignal;
3
+ }
4
+ export declare function convert(buffer: Buffer | Uint8Array, targetFormat: string, sourceFormat?: string, { signal }?: ConvertOptions): Promise<Buffer>;
2
5
  export declare function destroy(): Promise<void>;
6
+ export {};
3
7
  //# sourceMappingURL=fontConverter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fontConverter.d.ts","sourceRoot":"","sources":["../src/fontConverter.ts"],"names":[],"mappings":"AA+IA,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7C"}
1
+ {"version":3,"file":"fontConverter.d.ts","sourceRoot":"","sources":["../src/fontConverter.ts"],"names":[],"mappings":"AAiBA,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAiCD,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,EAAE,MAAM,EAAE,GAAE,cAAmB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ7C"}
@@ -4,136 +4,61 @@ exports.convert = convert;
4
4
  exports.destroy = destroy;
5
5
  const pathModule = require("path");
6
6
  const os = require("os");
7
- const worker_threads_1 = require("worker_threads");
7
+ const piscina_1 = require("piscina");
8
8
  const concurrencyLimit_1 = require("./concurrencyLimit");
9
+ const piscinaRunWithTimeout_1 = require("./piscinaRunWithTimeout");
10
+ /**
11
+ * Font format conversion routed through a piscina worker pool. Each
12
+ * worker thread loads its own wawoff2 WASM instance, enabling safe
13
+ * parallel woff2 compression — wawoff2's shared WASM instance corrupts
14
+ * memory under concurrent main-thread calls.
15
+ */
9
16
  const workerPath = pathModule.join(__dirname, 'fontConverterWorker.js');
10
17
  const CONVERT_TIMEOUT_MS = 120_000;
11
18
  const POOL_SIZE = Math.max(1, Math.min(os.cpus().length, concurrencyLimit_1.MAX_POOL_SIZE));
12
- // Worker lifecycle: Created → Idle → Busy → Idle | Discarded
13
- // Only Idle workers may be handed to callers. Discarded workers are
14
- // terminated and never reused. This structure makes it impossible
15
- // to accidentally reuse a worker that encountered an error.
16
- const _idle = [];
17
- const _alive = new Set();
18
- let _activeCount = 0;
19
- const _queue = [];
20
- function acquireSlot() {
21
- if (_activeCount < POOL_SIZE) {
22
- _activeCount++;
23
- return Promise.resolve();
24
- }
25
- return new Promise((resolve) => {
26
- _queue.push(() => {
27
- _activeCount++;
28
- resolve();
19
+ let _pool = null;
20
+ // Held while `destroy()` is awaiting the underlying piscina teardown.
21
+ // Concurrent `convert()` calls await this before constructing a fresh
22
+ // pool otherwise a `convert()` that lands between `_pool = null` and
23
+ // `pool.destroy()` would spin up a second pool alongside the dying one.
24
+ let _destroyPromise = null;
25
+ function getPool() {
26
+ if (_pool === null) {
27
+ _pool = new piscina_1.Piscina({
28
+ filename: workerPath,
29
+ // Cap concurrency at MAX_POOL_SIZE (shared with the tracer pool).
30
+ // Spin workers up lazily so a process that never converts woff2 pays
31
+ // nothing.
32
+ minThreads: 0,
33
+ maxThreads: POOL_SIZE,
34
+ concurrentTasksPerWorker: 1,
35
+ // Reclaim WASM-bearing workers after a short idle period; long-lived
36
+ // wawoff2 instances accrete memory over the run.
37
+ idleTimeout: 30_000,
29
38
  });
30
- });
31
- }
32
- function releaseSlot() {
33
- _activeCount--;
34
- const next = _queue.shift();
35
- if (next)
36
- next();
37
- }
38
- function createWorker() {
39
- const worker = new worker_threads_1.Worker(workerPath);
40
- worker.unref();
41
- _alive.add(worker);
42
- worker.on('exit', () => {
43
- _alive.delete(worker);
44
- const idx = _idle.indexOf(worker);
45
- if (idx !== -1)
46
- _idle.splice(idx, 1);
47
- });
48
- return worker;
49
- }
50
- function returnToIdle(worker) {
51
- _idle.push(worker);
52
- }
53
- function discard(worker) {
54
- _alive.delete(worker);
55
- const idx = _idle.indexOf(worker);
56
- if (idx !== -1)
57
- _idle.splice(idx, 1);
58
- worker.terminate().catch(() => { });
59
- }
60
- function doConvert(worker, buffer, targetFormat, sourceFormat) {
61
- return new Promise((resolve, reject) => {
62
- let settled = false;
63
- const timer = setTimeout(() => {
64
- if (settled)
65
- return;
66
- settled = true;
67
- cleanup();
68
- discard(worker);
69
- reject(new Error(`Font conversion to ${targetFormat} timed out after ${CONVERT_TIMEOUT_MS}ms`));
70
- }, CONVERT_TIMEOUT_MS);
71
- timer.unref();
72
- const cleanup = () => {
73
- clearTimeout(timer);
74
- worker.off('message', onMessage);
75
- worker.off('error', onError);
76
- worker.off('exit', onExit);
77
- };
78
- const onMessage = (msg) => {
79
- if (settled)
80
- return;
81
- settled = true;
82
- cleanup();
83
- if (msg.type === 'result' && msg.buffer) {
84
- returnToIdle(worker);
85
- resolve(Buffer.from(msg.buffer));
86
- }
87
- else {
88
- discard(worker);
89
- reject(new Error(msg.error || `Font conversion to ${targetFormat} failed`));
90
- }
91
- };
92
- const onError = (err) => {
93
- if (settled)
94
- return;
95
- settled = true;
96
- cleanup();
97
- discard(worker);
98
- reject(err);
99
- };
100
- const onExit = (code) => {
101
- if (settled)
102
- return;
103
- settled = true;
104
- cleanup();
105
- discard(worker);
106
- reject(new Error(`Font converter worker exited unexpectedly with code ${code}`));
107
- };
108
- worker.on('message', onMessage);
109
- worker.on('error', onError);
110
- worker.on('exit', onExit);
111
- try {
112
- worker.postMessage({ buffer, targetFormat, sourceFormat });
113
- }
114
- catch (err) {
115
- settled = true;
116
- cleanup();
117
- discard(worker);
118
- reject(err);
119
- }
120
- });
121
- }
122
- async function convert(buffer, targetFormat, sourceFormat) {
123
- await acquireSlot();
124
- try {
125
- const worker = _idle.pop() ?? createWorker();
126
- return await doConvert(worker, buffer, targetFormat, sourceFormat);
127
39
  }
128
- finally {
129
- releaseSlot();
40
+ return _pool;
41
+ }
42
+ async function convert(buffer, targetFormat, sourceFormat, { signal } = {}) {
43
+ // If a destroy is in flight, wait it out so we don't spawn a new pool
44
+ // alongside the dying one.
45
+ if (_destroyPromise) {
46
+ await _destroyPromise;
130
47
  }
48
+ const task = { buffer, targetFormat, sourceFormat };
49
+ const result = await (0, piscinaRunWithTimeout_1.runWithTimeoutAndSignal)(getPool(), task, signal, CONVERT_TIMEOUT_MS, (ms) => `Font conversion to ${targetFormat} timed out after ${ms}ms`);
50
+ // Structured clone strips the Buffer prototype on its way back; wrap so
51
+ // callers (subsetFonts, sfntCache) receive a Buffer as advertised.
52
+ return Buffer.from(result);
131
53
  }
132
54
  async function destroy() {
133
- _queue.length = 0;
134
- _idle.length = 0;
135
- const workers = Array.from(_alive);
136
- _alive.clear();
137
- await Promise.all(workers.map((w) => w.terminate()));
55
+ if (_pool === null)
56
+ return;
57
+ const pool = _pool;
58
+ _pool = null;
59
+ _destroyPromise = pool.destroy().finally(() => {
60
+ _destroyPromise = null;
61
+ });
62
+ await _destroyPromise;
138
63
  }
139
64
  //# sourceMappingURL=fontConverter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fontConverter.js","sourceRoot":"","sources":["../src/fontConverter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fontConverter.js","sourceRoot":"","sources":["../src/fontConverter.ts"],"names":[],"mappings":";;AAoDA,0BAsBC;AAED,0BAQC;AApFD,mCAAoC;AACpC,yBAA0B;AAC1B,qCAAkC;AAClC,yDAAmD;AACnD,mEAAkE;AAElE;;;;;GAKG;AAEH,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;AACxE,MAAM,kBAAkB,GAAG,OAAO,CAAC;AACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,gCAAa,CAAC,CAAC,CAAC;AAYzE,IAAI,KAAK,GAAmB,IAAI,CAAC;AACjC,sEAAsE;AACtE,sEAAsE;AACtE,uEAAuE;AACvE,wEAAwE;AACxE,IAAI,eAAe,GAAyB,IAAI,CAAC;AAEjD,SAAS,OAAO;IACd,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,KAAK,GAAG,IAAI,iBAAO,CAAC;YAClB,QAAQ,EAAE,UAAU;YACpB,kEAAkE;YAClE,qEAAqE;YACrE,WAAW;YACX,UAAU,EAAE,CAAC;YACb,UAAU,EAAE,SAAS;YACrB,wBAAwB,EAAE,CAAC;YAC3B,qEAAqE;YACrE,iDAAiD;YACjD,WAAW,EAAE,MAAM;SACpB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAEM,KAAK,UAAU,OAAO,CAC3B,MAA2B,EAC3B,YAAoB,EACpB,YAAqB,EACrB,EAAE,MAAM,KAAqB,EAAE;IAE/B,sEAAsE;IACtE,2BAA2B;IAC3B,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,eAAe,CAAC;IACxB,CAAC;IACD,MAAM,IAAI,GAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,IAAA,+CAAuB,EAC1C,OAAO,EAAE,EACT,IAAI,EACJ,MAAM,EACN,kBAAkB,EAClB,CAAC,EAAE,EAAE,EAAE,CAAC,sBAAsB,YAAY,oBAAoB,EAAE,IAAI,CACrE,CAAC;IACF,wEAAwE;IACxE,mEAAmE;IACnE,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAEM,KAAK,UAAU,OAAO;IAC3B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO;IAC3B,MAAM,IAAI,GAAG,KAAK,CAAC;IACnB,KAAK,GAAG,IAAI,CAAC;IACb,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;QAC5C,eAAe,GAAG,IAAI,CAAC;IACzB,CAAC,CAAC,CAAC;IACH,MAAM,eAAe,CAAC;AACxB,CAAC"}
@@ -1,2 +1,15 @@
1
- export {};
1
+ /**
2
+ * Piscina worker handler for font format conversion.
3
+ *
4
+ * Each worker thread loads its own wawoff2 WASM instance via fontverter,
5
+ * enabling safe parallel woff2 compression — wawoff2's shared WASM
6
+ * instance corrupts memory under concurrent use within a single thread.
7
+ */
8
+ interface ConvertTask {
9
+ buffer: Uint8Array | Buffer;
10
+ targetFormat: string;
11
+ sourceFormat?: string;
12
+ }
13
+ declare function convertTask(task: ConvertTask): Promise<Uint8Array>;
14
+ export = convertTask;
2
15
  //# sourceMappingURL=fontConverterWorker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fontConverterWorker.d.ts","sourceRoot":"","sources":["../src/fontConverterWorker.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"fontConverterWorker.d.ts","sourceRoot":"","sources":["../src/fontConverterWorker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,UAAU,WAAW;IACnB,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,iBAAe,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAQjE;AAED,SAAS,WAAW,CAAC"}
@@ -1,4 +1,11 @@
1
1
  "use strict";
2
+ /**
3
+ * Piscina worker handler for font format conversion.
4
+ *
5
+ * Each worker thread loads its own wawoff2 WASM instance via fontverter,
6
+ * enabling safe parallel woff2 compression — wawoff2's shared WASM
7
+ * instance corrupts memory under concurrent use within a single thread.
8
+ */
2
9
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
10
  if (k2 === undefined) k2 = k;
4
11
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -32,22 +39,15 @@ var __importStar = (this && this.__importStar) || (function () {
32
39
  return result;
33
40
  };
34
41
  })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- const worker_threads_1 = require("worker_threads");
37
42
  const fontverter = __importStar(require("fontverter"));
38
- if (!worker_threads_1.parentPort) {
39
- throw new Error('fontConverterWorker must be run as a worker thread');
43
+ async function convertTask(task) {
44
+ // Structured clone delivers Uint8Array on the worker side; wrap so
45
+ // fontverter sees the Buffer it expects. The host wraps the response
46
+ // in Buffer.from on its end — wrapping here would duplicate work
47
+ // since structured clone copies bytes and strips the Buffer prototype
48
+ // on every transfer.
49
+ const buffer = Buffer.from(task.buffer);
50
+ return await fontverter.convert(buffer, task.targetFormat, task.sourceFormat);
40
51
  }
41
- const port = worker_threads_1.parentPort;
42
- port.on('message', async (msg) => {
43
- try {
44
- const buffer = Buffer.from(msg.buffer);
45
- const result = await fontverter.convert(buffer, msg.targetFormat, msg.sourceFormat);
46
- port.postMessage({ type: 'result', buffer: result });
47
- }
48
- catch (rawErr) {
49
- const err = rawErr;
50
- port.postMessage({ type: 'error', error: err.message });
51
- }
52
- });
52
+ module.exports = convertTask;
53
53
  //# sourceMappingURL=fontConverterWorker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fontConverterWorker.js","sourceRoot":"","sources":["../src/fontConverterWorker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mDAA4C;AAC5C,uDAAyC;AAQzC,IAAI,CAAC,2BAAU,EAAE,CAAC;IAChB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,IAAI,GAAG,2BAAU,CAAC;AAExB,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAmB,EAAE,EAAE;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CACrC,MAAM,EACN,GAAG,CAAC,YAAY,EAChB,GAAG,CAAC,YAAY,CACjB,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,MAAe,CAAC;QAC5B,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"fontConverterWorker.js","sourceRoot":"","sources":["../src/fontConverterWorker.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uDAAyC;AAQzC,KAAK,UAAU,WAAW,CAAC,IAAiB;IAC1C,mEAAmE;IACnE,qEAAqE;IACrE,iEAAiE;IACjE,sEAAsE;IACtE,qBAAqB;IACrB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;AAChF,CAAC;AAED,iBAAS,WAAW,CAAC"}
@@ -56,8 +56,9 @@ export declare function cssAssetIsEmpty(cssAsset: {
56
56
  }>;
57
57
  };
58
58
  }): boolean;
59
- export declare function parseFontWeightRange(str: string | undefined): [number, number];
60
- export declare function parseFontStretchRange(str: string | undefined): [number, number];
59
+ export type RangeWarnFn = (err: Error) => void;
60
+ export declare function parseFontWeightRange(str: string | undefined, warn?: RangeWarnFn): [number, number];
61
+ export declare function parseFontStretchRange(str: string | undefined, warn?: RangeWarnFn): [number, number];
61
62
  export declare function uniqueChars(text: string): string;
62
63
  export declare function uniqueCharsFromArray(texts: string[]): string;
63
64
  export declare function hashHexPrefix(stringOrBuffer: string | Buffer | Uint8Array): string;
@@ -1 +1 @@
1
- {"version":3,"file":"fontFaceHelpers.d.ts","sourceRoot":"","sources":["../src/fontFaceHelpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fontFaceHelpers.d.ts","sourceRoot":"","sources":["../src/fontFaceHelpers.ts"],"names":[],"mappings":"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"}