@liiift-studio/sanity-font-manager 2.5.5 → 2.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +38 -16
- package/dist/index.mjs +39 -15
- package/package.json +1 -1
- package/src/utils/parseFont.js +27 -28
- package/src/utils/setupDecompressors.js +22 -5
package/dist/index.js
CHANGED
|
@@ -7648,6 +7648,25 @@ var require_unbrotli = __commonJS({
|
|
|
7648
7648
|
}
|
|
7649
7649
|
});
|
|
7650
7650
|
|
|
7651
|
+
// src/utils/setupDecompressors.js
|
|
7652
|
+
var import_unbrotli;
|
|
7653
|
+
var init_setupDecompressors = __esm({
|
|
7654
|
+
"src/utils/setupDecompressors.js"() {
|
|
7655
|
+
init_pako_esm();
|
|
7656
|
+
import_unbrotli = __toESM(require_unbrotli());
|
|
7657
|
+
globalThis.pako = pako;
|
|
7658
|
+
if (!globalThis.unbrotli) {
|
|
7659
|
+
try {
|
|
7660
|
+
const brotli = require_unbrotli();
|
|
7661
|
+
if (typeof brotli === "function") {
|
|
7662
|
+
globalThis.unbrotli = brotli;
|
|
7663
|
+
}
|
|
7664
|
+
} catch {
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
}
|
|
7668
|
+
});
|
|
7669
|
+
|
|
7651
7670
|
// node_modules/lib-font/src/utils/shim-fetch.js
|
|
7652
7671
|
var fetchFunction;
|
|
7653
7672
|
var init_shim_fetch = __esm({
|
|
@@ -12433,31 +12452,38 @@ async function parseFont(buffer, filename) {
|
|
|
12433
12452
|
throw new Error(`Font file exceeds ${MAX_FONT_FILE_SIZE / 1024 / 1024}MB limit: ${filename} (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB)`);
|
|
12434
12453
|
}
|
|
12435
12454
|
return new Promise((resolve, reject) => {
|
|
12455
|
+
let settled = false;
|
|
12456
|
+
const settle = (fn) => (...args) => {
|
|
12457
|
+
if (!settled) {
|
|
12458
|
+
settled = true;
|
|
12459
|
+
clearTimeout(timer);
|
|
12460
|
+
fn(...args);
|
|
12461
|
+
}
|
|
12462
|
+
};
|
|
12463
|
+
const timer = setTimeout(() => {
|
|
12464
|
+
settle(reject)(new Error(`Parsing timed out for ${filename} (${PARSE_TIMEOUT_MS / 1e3}s). The file may be corrupted or in an unsupported format.`));
|
|
12465
|
+
}, PARSE_TIMEOUT_MS);
|
|
12436
12466
|
const font2 = new Font("font", { skipStyleSheet: true });
|
|
12437
|
-
font2.onload = (evt) => resolve(evt.detail.font);
|
|
12438
|
-
font2.onerror = (evt) => {
|
|
12467
|
+
font2.onload = settle((evt) => resolve(evt.detail.font));
|
|
12468
|
+
font2.onerror = settle((evt) => {
|
|
12439
12469
|
var _a;
|
|
12440
12470
|
const msg = ((_a = evt.detail) == null ? void 0 : _a.message) || `Failed to parse ${filename}`;
|
|
12441
12471
|
reject(new Error(msg));
|
|
12442
|
-
};
|
|
12472
|
+
});
|
|
12443
12473
|
try {
|
|
12444
12474
|
font2.fromDataBuffer(buffer, filename);
|
|
12445
12475
|
} catch (err2) {
|
|
12446
|
-
reject(new Error(`${filename}: ${err2.message}`));
|
|
12476
|
+
settle(reject)(new Error(`${filename}: ${err2.message}`));
|
|
12447
12477
|
}
|
|
12448
12478
|
});
|
|
12449
12479
|
}
|
|
12450
|
-
var
|
|
12480
|
+
var MAX_FONT_FILE_SIZE, PARSE_TIMEOUT_MS;
|
|
12451
12481
|
var init_parseFont = __esm({
|
|
12452
12482
|
"src/utils/parseFont.js"() {
|
|
12453
|
-
|
|
12454
|
-
import_unbrotli2 = __toESM(require_unbrotli());
|
|
12483
|
+
init_setupDecompressors();
|
|
12455
12484
|
init_lib_font();
|
|
12456
|
-
globalThis.pako = pako;
|
|
12457
|
-
if (!globalThis.unbrotli) {
|
|
12458
|
-
console.warn("[parseFont] globalThis.unbrotli not set after vendor import \u2014 WOFF2 parsing may fail. TTF/OTF files will still work.");
|
|
12459
|
-
}
|
|
12460
12485
|
MAX_FONT_FILE_SIZE = 50 * 1024 * 1024;
|
|
12486
|
+
PARSE_TIMEOUT_MS = 3e4;
|
|
12461
12487
|
}
|
|
12462
12488
|
});
|
|
12463
12489
|
|
|
@@ -16871,11 +16897,7 @@ __export(index_exports, {
|
|
|
16871
16897
|
useSanityClient: () => useSanityClient
|
|
16872
16898
|
});
|
|
16873
16899
|
module.exports = __toCommonJS(index_exports);
|
|
16874
|
-
|
|
16875
|
-
// src/utils/setupDecompressors.js
|
|
16876
|
-
init_pako_esm();
|
|
16877
|
-
var import_unbrotli = __toESM(require_unbrotli());
|
|
16878
|
-
globalThis.pako = pako;
|
|
16900
|
+
init_setupDecompressors();
|
|
16879
16901
|
|
|
16880
16902
|
// src/components/BatchUploadFonts.jsx
|
|
16881
16903
|
var import_react14 = __toESM(require("react"));
|
package/dist/index.mjs
CHANGED
|
@@ -7653,6 +7653,25 @@ var require_unbrotli = __commonJS({
|
|
|
7653
7653
|
}
|
|
7654
7654
|
});
|
|
7655
7655
|
|
|
7656
|
+
// src/utils/setupDecompressors.js
|
|
7657
|
+
var import_unbrotli;
|
|
7658
|
+
var init_setupDecompressors = __esm({
|
|
7659
|
+
"src/utils/setupDecompressors.js"() {
|
|
7660
|
+
init_pako_esm();
|
|
7661
|
+
import_unbrotli = __toESM(require_unbrotli());
|
|
7662
|
+
globalThis.pako = pako;
|
|
7663
|
+
if (!globalThis.unbrotli) {
|
|
7664
|
+
try {
|
|
7665
|
+
const brotli = require_unbrotli();
|
|
7666
|
+
if (typeof brotli === "function") {
|
|
7667
|
+
globalThis.unbrotli = brotli;
|
|
7668
|
+
}
|
|
7669
|
+
} catch {
|
|
7670
|
+
}
|
|
7671
|
+
}
|
|
7672
|
+
}
|
|
7673
|
+
});
|
|
7674
|
+
|
|
7656
7675
|
// node_modules/lib-font/src/utils/shim-fetch.js
|
|
7657
7676
|
var fetchFunction;
|
|
7658
7677
|
var init_shim_fetch = __esm({
|
|
@@ -12438,31 +12457,38 @@ async function parseFont(buffer, filename) {
|
|
|
12438
12457
|
throw new Error(`Font file exceeds ${MAX_FONT_FILE_SIZE / 1024 / 1024}MB limit: ${filename} (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB)`);
|
|
12439
12458
|
}
|
|
12440
12459
|
return new Promise((resolve, reject) => {
|
|
12460
|
+
let settled = false;
|
|
12461
|
+
const settle = (fn) => (...args) => {
|
|
12462
|
+
if (!settled) {
|
|
12463
|
+
settled = true;
|
|
12464
|
+
clearTimeout(timer);
|
|
12465
|
+
fn(...args);
|
|
12466
|
+
}
|
|
12467
|
+
};
|
|
12468
|
+
const timer = setTimeout(() => {
|
|
12469
|
+
settle(reject)(new Error(`Parsing timed out for ${filename} (${PARSE_TIMEOUT_MS / 1e3}s). The file may be corrupted or in an unsupported format.`));
|
|
12470
|
+
}, PARSE_TIMEOUT_MS);
|
|
12441
12471
|
const font2 = new Font("font", { skipStyleSheet: true });
|
|
12442
|
-
font2.onload = (evt) => resolve(evt.detail.font);
|
|
12443
|
-
font2.onerror = (evt) => {
|
|
12472
|
+
font2.onload = settle((evt) => resolve(evt.detail.font));
|
|
12473
|
+
font2.onerror = settle((evt) => {
|
|
12444
12474
|
var _a;
|
|
12445
12475
|
const msg = ((_a = evt.detail) == null ? void 0 : _a.message) || `Failed to parse ${filename}`;
|
|
12446
12476
|
reject(new Error(msg));
|
|
12447
|
-
};
|
|
12477
|
+
});
|
|
12448
12478
|
try {
|
|
12449
12479
|
font2.fromDataBuffer(buffer, filename);
|
|
12450
12480
|
} catch (err2) {
|
|
12451
|
-
reject(new Error(`${filename}: ${err2.message}`));
|
|
12481
|
+
settle(reject)(new Error(`${filename}: ${err2.message}`));
|
|
12452
12482
|
}
|
|
12453
12483
|
});
|
|
12454
12484
|
}
|
|
12455
|
-
var
|
|
12485
|
+
var MAX_FONT_FILE_SIZE, PARSE_TIMEOUT_MS;
|
|
12456
12486
|
var init_parseFont = __esm({
|
|
12457
12487
|
"src/utils/parseFont.js"() {
|
|
12458
|
-
|
|
12459
|
-
import_unbrotli2 = __toESM(require_unbrotli());
|
|
12488
|
+
init_setupDecompressors();
|
|
12460
12489
|
init_lib_font();
|
|
12461
|
-
globalThis.pako = pako;
|
|
12462
|
-
if (!globalThis.unbrotli) {
|
|
12463
|
-
console.warn("[parseFont] globalThis.unbrotli not set after vendor import \u2014 WOFF2 parsing may fail. TTF/OTF files will still work.");
|
|
12464
|
-
}
|
|
12465
12490
|
MAX_FONT_FILE_SIZE = 50 * 1024 * 1024;
|
|
12491
|
+
PARSE_TIMEOUT_MS = 3e4;
|
|
12466
12492
|
}
|
|
12467
12493
|
});
|
|
12468
12494
|
|
|
@@ -16770,10 +16796,8 @@ var init_UploadModal = __esm({
|
|
|
16770
16796
|
}
|
|
16771
16797
|
});
|
|
16772
16798
|
|
|
16773
|
-
// src/
|
|
16774
|
-
|
|
16775
|
-
var import_unbrotli = __toESM(require_unbrotli());
|
|
16776
|
-
globalThis.pako = pako;
|
|
16799
|
+
// src/index.js
|
|
16800
|
+
init_setupDecompressors();
|
|
16777
16801
|
|
|
16778
16802
|
// src/components/BatchUploadFonts.jsx
|
|
16779
16803
|
import React13, { useCallback as useCallback7, useState as useState9, useMemo as useMemo9, useRef as useRef4, useEffect as useEffect6, lazy as lazy2, Suspense } from "react";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liiift-studio/sanity-font-manager",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.6",
|
|
4
4
|
"description": "Sanity Studio plugin — full font management suite with batch upload, format conversion, metadata extraction, CSS generation, collection/pair generation, and script variant support. Supports Sanity v3, v4, and v5.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Liiift Studio",
|
package/src/utils/parseFont.js
CHANGED
|
@@ -1,39 +1,22 @@
|
|
|
1
|
-
// Async font parser —
|
|
1
|
+
// Async font parser — decompressor globals must be set before lib-font is imported
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import '../vendor/unbrotli.js';
|
|
3
|
+
import './setupDecompressors.js';
|
|
5
4
|
import { Font } from 'lib-font';
|
|
6
5
|
|
|
7
|
-
// Immediately set globals — this runs at module evaluation time.
|
|
8
|
-
// lib-font's woff.js reads globalThis.pako and woff2.js reads globalThis.unbrotli
|
|
9
|
-
// at their top level. If this module evaluates before lib-font (which tsup guarantees
|
|
10
|
-
// since we import pako and unbrotli first), the globals will be set in time.
|
|
11
|
-
//
|
|
12
|
-
// When Vite re-bundles our package, it may reorder evaluation so lib-font's woff2.js
|
|
13
|
-
// captures globalThis.unbrotli as undefined. In that case, WOFF2 parsing will fail
|
|
14
|
-
// and buildUploadPlan falls back to TTF companion metadata.
|
|
15
|
-
globalThis.pako = pako;
|
|
16
|
-
// unbrotli.js UMD sets globalThis.unbrotli as a side effect — verify it worked
|
|
17
|
-
if (!globalThis.unbrotli) {
|
|
18
|
-
console.warn('[parseFont] globalThis.unbrotli not set after vendor import — WOFF2 parsing may fail. TTF/OTF files will still work.');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
6
|
/** Maximum font file size accepted for parsing (50 MB) */
|
|
22
7
|
const MAX_FONT_FILE_SIZE = 50 * 1024 * 1024;
|
|
23
8
|
|
|
9
|
+
/** Parse timeout — prevents hanging if lib-font silently fails (30 seconds) */
|
|
10
|
+
const PARSE_TIMEOUT_MS = 30000;
|
|
11
|
+
|
|
24
12
|
/**
|
|
25
13
|
* Parse a font file from an ArrayBuffer.
|
|
26
14
|
* Returns a lib-font Font object with all tables accessible via font.opentype.tables.*.
|
|
27
15
|
*
|
|
28
|
-
* WOFF2 note: If the brotli decoder couldn't be initialized (common with Vite pre-bundling),
|
|
29
|
-
* WOFF2 files will fail to parse. The upload plan handles this gracefully — WOFF2 files
|
|
30
|
-
* that share a name with a TTF/OTF get metadata from the companion file. Standalone WOFF2
|
|
31
|
-
* uploads will show a clear error directing the user to also include TTF/OTF files.
|
|
32
|
-
*
|
|
33
16
|
* @param {ArrayBuffer} buffer - Raw font file bytes
|
|
34
17
|
* @param {string} filename - Original filename (used for format detection by lib-font)
|
|
35
18
|
* @returns {Promise<import('lib-font').Font>} Parsed lib-font Font object
|
|
36
|
-
* @throws {Error} If the file exceeds MAX_FONT_FILE_SIZE or
|
|
19
|
+
* @throws {Error} If the file exceeds MAX_FONT_FILE_SIZE, parsing fails, or times out
|
|
37
20
|
*/
|
|
38
21
|
export async function parseFont(buffer, filename) {
|
|
39
22
|
if (buffer.byteLength > MAX_FONT_FILE_SIZE) {
|
|
@@ -41,17 +24,33 @@ export async function parseFont(buffer, filename) {
|
|
|
41
24
|
}
|
|
42
25
|
|
|
43
26
|
return new Promise((resolve, reject) => {
|
|
27
|
+
let settled = false;
|
|
28
|
+
|
|
29
|
+
const settle = (fn) => (...args) => {
|
|
30
|
+
if (!settled) {
|
|
31
|
+
settled = true;
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
fn(...args);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Timeout guard — prevents infinite hang if lib-font fails silently
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
settle(reject)(new Error(`Parsing timed out for ${filename} (${PARSE_TIMEOUT_MS / 1000}s). The file may be corrupted or in an unsupported format.`));
|
|
40
|
+
}, PARSE_TIMEOUT_MS);
|
|
41
|
+
|
|
44
42
|
const font = new Font('font', { skipStyleSheet: true });
|
|
45
|
-
font.onload = (evt) => resolve(evt.detail.font);
|
|
46
|
-
font.onerror = (evt) => {
|
|
43
|
+
font.onload = settle((evt) => resolve(evt.detail.font));
|
|
44
|
+
font.onerror = settle((evt) => {
|
|
47
45
|
const msg = evt.detail?.message || `Failed to parse ${filename}`;
|
|
48
46
|
reject(new Error(msg));
|
|
49
|
-
};
|
|
47
|
+
});
|
|
48
|
+
|
|
50
49
|
try {
|
|
51
50
|
font.fromDataBuffer(buffer, filename);
|
|
52
51
|
} catch (err) {
|
|
53
|
-
//
|
|
54
|
-
reject(new Error(`${filename}: ${err.message}`));
|
|
52
|
+
// Catches synchronous throws from WOFF2 constructor when brotli is missing
|
|
53
|
+
settle(reject)(new Error(`${filename}: ${err.message}`));
|
|
55
54
|
}
|
|
56
55
|
});
|
|
57
56
|
}
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
// Sets up globalThis.pako and globalThis.unbrotli for lib-font WOFF/WOFF2 decompression.
|
|
2
|
-
//
|
|
3
|
-
// It runs synchronously at module evaluation time to set the globals.
|
|
2
|
+
// Must be imported before lib-font.
|
|
4
3
|
|
|
5
4
|
import pako from 'pako';
|
|
6
|
-
import '../vendor/unbrotli.js';
|
|
7
5
|
|
|
6
|
+
// Set pako for WOFF (zlib) decompression
|
|
8
7
|
globalThis.pako = pako;
|
|
9
|
-
|
|
10
|
-
//
|
|
8
|
+
|
|
9
|
+
// Set unbrotli for WOFF2 (brotli) decompression
|
|
10
|
+
// The vendor unbrotli.js UMD sets globalThis.unbrotli in browser contexts.
|
|
11
|
+
// In Node/bundler contexts it exports via module.exports instead.
|
|
12
|
+
// We use a side-effect import and then check if the global was set.
|
|
13
|
+
import '../vendor/unbrotli.js';
|
|
14
|
+
|
|
15
|
+
// If the UMD didn't set the global (CJS path in Node/bundler), try to require it
|
|
16
|
+
if (!globalThis.unbrotli) {
|
|
17
|
+
try {
|
|
18
|
+
// In bundler context, the UMD file's module.exports is available
|
|
19
|
+
// tsup will resolve this at build time
|
|
20
|
+
const brotli = require('../vendor/unbrotli.js');
|
|
21
|
+
if (typeof brotli === 'function') {
|
|
22
|
+
globalThis.unbrotli = brotli;
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
// Silently fail — WOFF2 parsing will error gracefully
|
|
26
|
+
}
|
|
27
|
+
}
|