New:Socket for Asana Is Now Available.Learn more
Sign In

@file-viewer/ppt

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@file-viewer/ppt - npm Package Compare versions

Comparing version
0.3.1
to
0.3.2
+1
-1
index.mjs

@@ -1,2 +0,2 @@

const MANIFEST = Object.freeze({"kind":"flyfish-ppt-public-native-wasm-v2","product":"Flyfish PPT Viewer","format":"PowerPoint 97-2003 (.ppt)","packageName":"@file-viewer/ppt","packageVersion":"0.3.1","engine":"flyfish-classic-ppt-native-engine","engineBuild":"593d0a6cf32f928f","id":"FV-PPT-PUBLIC-WATERMARKED-V2","feature":"ppt","edition":"public-watermarked","holder":"Individuals and Organizations","distribution":"proprietary-public-binary","commercialUse":true,"publicAnyOrigin":true,"watermarkRequired":true,"watermarkText":"Flyfish Viewer","usePolicy":"public-watermarked-general-use","licensePolicy":"flyfish-public-watermarked-binary-license-v2","sourceCodeRights":false,"sourceDeliveryRights":false,"apacheLicenseApplies":false,"redistributionAllowed":true,"redistributionPolicy":"unmodified-integrated-bundling-only","standaloneRedistributionAllowed":false,"watermarkRemovalRequiresCommercialAuthorization":true,"runtimeLicenseRequired":false,"renderer":"native-wasm-worker-offscreen-canvas","integrity":"native-wasm-font-sha256-v2","wasmFile":"ppt-native.wasm","wasmBytes":1557871,"workerFile":"worker.mjs","fontPack":{"kind":"flyfish-cjk-font-pack-v1","file":"ppt-font-cjk.otf","bytes":16437364,"sha256":"2c76254f6fc379fddfce0a7e84fb5385bb135d3e399294f6eeb6680d0365b74b"},"workerDefault":true,"virtualScrollDefault":true,"frameCache":"indexeddb-final-watermarked-png-lru","watermarkEnforcement":"native-final-frame","wasmSha256":"8e95d7de0e322d6c96dcd7ea18c5cd9b6783cb82f3fe1c8714008119f19e7915"});
const MANIFEST = Object.freeze({"kind":"flyfish-ppt-public-native-wasm-v2","product":"Flyfish PPT Viewer","format":"PowerPoint 97-2003 (.ppt)","packageName":"@file-viewer/ppt","packageVersion":"0.3.2","engine":"flyfish-classic-ppt-native-engine","engineBuild":"ee7c677fc3007f1b","id":"FV-PPT-PUBLIC-WATERMARKED-V2","feature":"ppt","edition":"public-watermarked","holder":"Individuals and Organizations","distribution":"proprietary-public-binary","commercialUse":true,"publicAnyOrigin":true,"watermarkRequired":true,"watermarkText":"Flyfish Viewer","usePolicy":"public-watermarked-general-use","licensePolicy":"flyfish-public-watermarked-binary-license-v2","sourceCodeRights":false,"sourceDeliveryRights":false,"apacheLicenseApplies":false,"redistributionAllowed":true,"redistributionPolicy":"unmodified-integrated-bundling-only","standaloneRedistributionAllowed":false,"watermarkRemovalRequiresCommercialAuthorization":true,"runtimeLicenseRequired":false,"renderer":"native-wasm-worker-offscreen-canvas","integrity":"native-wasm-font-sha256-v2","wasmFile":"ppt-native.wasm","wasmBytes":1557871,"workerFile":"worker.mjs","fontPack":{"kind":"flyfish-cjk-font-pack-v1","file":"ppt-font-cjk.otf","bytes":16437364,"sha256":"2c76254f6fc379fddfce0a7e84fb5385bb135d3e399294f6eeb6680d0365b74b"},"workerDefault":true,"virtualScrollDefault":true,"frameCache":"indexeddb-final-watermarked-png-lru","watermarkEnforcement":"native-final-frame","wasmSha256":"6d209f487ab8be74f23b463eaecafd9f588948e75670f82e69d7b7d6b10cb6a7"});
const DEFAULT_WASM_URL = new URL('./ppt-native.wasm', import.meta.url);

@@ -3,0 +3,0 @@ const DEFAULT_FONT_URL = new URL(`./${MANIFEST.fontPack.file}`, import.meta.url);

@@ -6,5 +6,5 @@ {

"packageName": "@file-viewer/ppt",
"packageVersion": "0.3.1",
"packageVersion": "0.3.2",
"engine": "flyfish-classic-ppt-native-engine",
"engineBuild": "593d0a6cf32f928f",
"engineBuild": "ee7c677fc3007f1b",
"id": "FV-PPT-PUBLIC-WATERMARKED-V2",

@@ -44,3 +44,3 @@ "feature": "ppt",

"watermarkEnforcement": "native-final-frame",
"wasmSha256": "8e95d7de0e322d6c96dcd7ea18c5cd9b6783cb82f3fe1c8714008119f19e7915"
"wasmSha256": "6d209f487ab8be74f23b463eaecafd9f588948e75670f82e69d7b7d6b10cb6a7"
}
+0
-3

@@ -65,3 +65,2 @@ @file-viewer/ppt

DEFINITIONS

@@ -122,3 +121,2 @@ "Font Software" refers to the set of files released by the Copyright

TERMINATION

@@ -128,3 +126,2 @@ This license becomes null and void if any of the above conditions are not met.

DISCLAIMER

@@ -131,0 +128,0 @@ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

{
"name": "@file-viewer/ppt",
"version": "0.3.1",
"version": "0.3.2",
"description": "Professional native WebAssembly canvas viewer for PowerPoint 97-2003 (.ppt) files.",

@@ -5,0 +5,0 @@ "type": "module",

@@ -196,5 +196,5 @@ # @file-viewer/ppt

const viewer = await createPptViewer({
workerUrl: new URL('/vendor/file-viewer/ppt/0.3.1/worker.mjs', location.origin),
wasmUrl: new URL('/vendor/file-viewer/ppt/0.3.1/ppt-native.wasm', location.origin),
fontUrl: new URL('/vendor/file-viewer/ppt/0.3.1/ppt-font-cjk.otf', location.origin)
workerUrl: new URL('/vendor/file-viewer/ppt/0.3.2/worker.mjs', location.origin),
wasmUrl: new URL('/vendor/file-viewer/ppt/0.3.2/ppt-native.wasm', location.origin),
fontUrl: new URL('/vendor/file-viewer/ppt/0.3.2/ppt-font-cjk.otf', location.origin)
});

@@ -451,3 +451,3 @@ ```

将资源发布在版本化或内容寻址目录(如 `/vendor/file-viewer/ppt/0.3.1/`)后,
将资源发布在版本化或内容寻址目录(如 `/vendor/file-viewer/ppt/0.3.2/`)后,
可配置:

@@ -454,0 +454,0 @@

@@ -1,3 +0,733 @@

import { createFrameCache } from './frame-cache.mjs';
/**
* Bounded, best-effort cache for final watermarked PNG frames.
*
* This module is intentionally storage-only. It does not parse PPT data, inspect
* font assets, or transform renderer output. Every storage failure degrades to a
* cache miss so IndexedDB can never become a rendering dependency.
*/
const DB_VERSION = 1;
const FRAME_STORE = "frames";
const META_STORE = "meta";
const DOCUMENT_INDEX = "byDocument";
const ACCESS_INDEX = "byLastAccess";
const USAGE_KEY = "usage";
const MIB = 1024 * 1024;
const DEFAULT_DB_NAME = "flyfish-ppt-frame-cache-v1";
const DEFAULT_MAX_BYTES = 256 * MIB;
const DEFAULT_MAX_ENTRIES = 256;
const DEFAULT_MAX_ITEM_BYTES = 32 * MIB;
const MAX_DATABASE_NAME_LENGTH = 128;
const MAX_DOCUMENT_ID_LENGTH = 256;
const MAX_VARIANT_LENGTH = 256;
const MAX_PAGE_INDEX = 10_000_000;
const MAX_DIMENSION = 65_535;
const OPEN_TIMEOUT_MS = 1_000;
function clampInteger(value, fallback, minimum, maximum) {
let numeric;
try {
numeric = Number(value);
} catch {
return fallback;
}
if (!Number.isFinite(numeric)) {
return fallback;
}
return Math.min(maximum, Math.max(minimum, Math.trunc(numeric)));
}
function normalizeBoundedString(value, maximumLength, { trim = false } = {}) {
if (typeof value !== "string") {
return null;
}
const normalized = trim ? value.trim() : value;
if (normalized.length === 0 || normalized.length > maximumLength) {
return null;
}
return normalized;
}
/**
* Pure limit normalization used by both production code and unit tests.
*/
function normalizeFrameCacheLimits(options = {}) {
const source = options && typeof options === "object" ? options : {};
const maxBytes = clampInteger(source.maxBytes, DEFAULT_MAX_BYTES, 0, 2 * 1024 * MIB);
const maxEntries = clampInteger(source.maxEntries, DEFAULT_MAX_ENTRIES, 0, 4_096);
const defaultItemBytes = Math.min(DEFAULT_MAX_ITEM_BYTES, maxBytes);
const configuredItemBytes = source.maxItemBytes ?? source.maxEntryBytes;
const maxItemBytes = maxBytes === 0
? 0
: clampInteger(configuredItemBytes, defaultItemBytes, 0, maxBytes);
return Object.freeze({ maxBytes, maxEntries, maxItemBytes });
}
/**
* Pure cache-key normalization. Invalid or potentially collision-prone inputs
* return null instead of being truncated.
*/
function normalizeFrameCacheKey(input, pageIndex, variant = "") {
const source = input && typeof input === "object"
? input
: { documentId: input, pageIndex, variant };
const documentId = normalizeBoundedString(source.documentId, MAX_DOCUMENT_ID_LENGTH, { trim: true });
let normalizedPageIndex;
let normalizedVariant;
try {
normalizedPageIndex = Number(source.pageIndex);
normalizedVariant = source.variant == null ? "" : String(source.variant);
} catch {
return null;
}
if (
documentId == null
|| !Number.isSafeInteger(normalizedPageIndex)
|| normalizedPageIndex < 0
|| normalizedPageIndex > MAX_PAGE_INDEX
|| normalizedVariant.length > MAX_VARIANT_LENGTH
) {
return null;
}
// Length-prefixing prevents separators inside opaque identifiers from
// creating collisions.
const key = `v1:${documentId.length}:${documentId}:${normalizedPageIndex}:${normalizedVariant.length}:${normalizedVariant}`;
return Object.freeze({
key,
documentId,
pageIndex: normalizedPageIndex,
variant: normalizedVariant,
});
}
function createFrameCacheKey(documentId, pageIndex, variant = "") {
return normalizeFrameCacheKey(documentId, pageIndex, variant)?.key ?? null;
}
function normalizeDatabaseName(value) {
return normalizeBoundedString(value, MAX_DATABASE_NAME_LENGTH, { trim: true }) ?? DEFAULT_DB_NAME;
}
function isPngBlob(blob) {
return Boolean(
blob
&& typeof blob === "object"
&& Number.isSafeInteger(blob.size)
&& blob.size > 0
&& typeof blob.arrayBuffer === "function"
&& typeof blob.type === "string"
&& blob.type.toLowerCase() === "image/png",
);
}
function normalizeDimension(value) {
let numeric;
try {
numeric = Number(value);
} catch {
return null;
}
return Number.isSafeInteger(numeric) && numeric > 0 && numeric <= MAX_DIMENSION
? numeric
: null;
}
function normalizePutArguments(keyInput, frameInput, limits) {
const frame = frameInput && typeof frameInput === "object" ? frameInput : keyInput;
const key = normalizeFrameCacheKey(keyInput);
const width = normalizeDimension(frame?.width);
const height = normalizeDimension(frame?.height);
const blob = frame?.blob;
if (key == null || width == null || height == null || !isPngBlob(blob)) {
return null;
}
if (blob.size > limits.maxItemBytes || blob.size > limits.maxBytes) {
return null;
}
return { ...key, blob, width, height, byteSize: blob.size };
}
function requestResult(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
});
}
function transactionError(transaction, fallbackMessage) {
return transaction.error ?? new Error(fallbackMessage);
}
function openDatabase(factory, dbName) {
return new Promise((resolve, reject) => {
let settled = false;
let request;
let timer = null;
const settle = (callback, value) => {
if (settled) {
if (value && typeof value.close === "function") {
value.close();
}
return;
}
settled = true;
if (timer != null) {
clearTimeout(timer);
}
callback(value);
};
try {
request = factory.open(dbName, DB_VERSION);
} catch (error) {
settle(reject, error);
return;
}
request.onupgradeneeded = () => {
const database = request.result;
let frameStore;
if (!database.objectStoreNames.contains(FRAME_STORE)) {
frameStore = database.createObjectStore(FRAME_STORE, { keyPath: "key" });
} else {
frameStore = request.transaction.objectStore(FRAME_STORE);
}
if (!frameStore.indexNames.contains(DOCUMENT_INDEX)) {
frameStore.createIndex(DOCUMENT_INDEX, "documentId", { unique: false });
}
if (!frameStore.indexNames.contains(ACCESS_INDEX)) {
frameStore.createIndex(ACCESS_INDEX, "lastAccess", { unique: false });
}
if (!database.objectStoreNames.contains(META_STORE)) {
database.createObjectStore(META_STORE, { keyPath: "key" });
}
};
request.onsuccess = () => settle(resolve, request.result);
request.onerror = () => settle(reject, request.error ?? new Error("Unable to open IndexedDB"));
request.onblocked = () => settle(reject, new Error("IndexedDB open was blocked"));
if (typeof setTimeout === "function") {
timer = setTimeout(() => {
settle(reject, new Error("IndexedDB open timed out"));
}, OPEN_TIMEOUT_MS);
}
});
}
function isStoredFrameValid(record) {
return Boolean(
record
&& typeof record === "object"
&& typeof record.key === "string"
&& typeof record.documentId === "string"
&& Number.isSafeInteger(record.pageIndex)
&& normalizeDimension(record.width) != null
&& normalizeDimension(record.height) != null
&& Number.isSafeInteger(record.byteSize)
&& record.byteSize > 0
&& isPngBlob(record.blob)
&& record.blob.size === record.byteSize,
);
}
function reconcileUsage(database, limits) {
return new Promise((resolve, reject) => {
let transaction;
try {
transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
} catch (error) {
reject(error);
return;
}
const frames = transaction.objectStore(FRAME_STORE);
const meta = transaction.objectStore(META_STORE);
let totalBytes = 0;
let totalEntries = 0;
const writeUsage = () => {
meta.put({
key: USAGE_KEY,
totalBytes,
totalEntries,
updatedAt: Date.now(),
});
};
const withinLimits = () => (
totalBytes <= limits.maxBytes
&& totalEntries <= limits.maxEntries
);
const trimOldest = () => {
if (withinLimits()) {
writeUsage();
return;
}
const trimRequest = frames.index(ACCESS_INDEX).openCursor();
trimRequest.onsuccess = () => {
const cursor = trimRequest.result;
if (cursor == null) {
totalBytes = 0;
totalEntries = 0;
writeUsage();
return;
}
const record = cursor.value;
cursor.delete();
if (isStoredFrameValid(record)) {
totalBytes = Math.max(0, totalBytes - record.byteSize);
totalEntries = Math.max(0, totalEntries - 1);
}
if (withinLimits()) {
writeUsage();
} else {
cursor.continue();
}
};
};
const cursorRequest = frames.openCursor();
cursorRequest.onsuccess = () => {
const cursor = cursorRequest.result;
if (cursor == null) {
trimOldest();
return;
}
const record = cursor.value;
if (isStoredFrameValid(record) && record.byteSize <= limits.maxItemBytes) {
totalBytes += record.byteSize;
totalEntries += 1;
} else {
cursor.delete();
}
cursor.continue();
};
transaction.oncomplete = () => resolve({ totalBytes, totalEntries });
transaction.onerror = () => reject(transactionError(transaction, "IndexedDB reconciliation failed"));
transaction.onabort = () => reject(transactionError(transaction, "IndexedDB reconciliation was aborted"));
});
}
function readUsageRecord(value) {
const totalBytes = Number.isSafeInteger(value?.totalBytes) && value.totalBytes >= 0
? value.totalBytes
: 0;
const totalEntries = Number.isSafeInteger(value?.totalEntries) && value.totalEntries >= 0
? value.totalEntries
: 0;
return { totalBytes, totalEntries };
}
function putFrame(database, record, limits) {
return new Promise((resolve, reject) => {
let transaction;
try {
transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
} catch (error) {
reject(error);
return;
}
const frames = transaction.objectStore(FRAME_STORE);
const meta = transaction.objectStore(META_STORE);
let existing;
let usage;
let existingReady = false;
let usageReady = false;
let started = false;
const failRequest = () => {
try {
transaction.abort();
} catch {
// The transaction may already have been aborted by the browser.
}
};
const finalizeWrite = () => {
const now = record.lastAccess;
frames.put(record);
meta.put({
key: USAGE_KEY,
totalBytes: usage.totalBytes,
totalEntries: usage.totalEntries,
updatedAt: now,
});
};
const evictIfNeeded = () => {
if (started || !existingReady || !usageReady) {
return;
}
started = true;
const oldBytes = isStoredFrameValid(existing) ? existing.byteSize : 0;
const oldEntries = isStoredFrameValid(existing) ? 1 : 0;
usage.totalBytes = Math.max(0, usage.totalBytes - oldBytes) + record.byteSize;
usage.totalEntries = Math.max(0, usage.totalEntries - oldEntries) + 1;
const withinLimits = () => (
usage.totalBytes <= limits.maxBytes
&& usage.totalEntries <= limits.maxEntries
);
if (withinLimits()) {
finalizeWrite();
return;
}
const cursorRequest = frames.index(ACCESS_INDEX).openCursor();
cursorRequest.onsuccess = () => {
const cursor = cursorRequest.result;
if (cursor == null) {
if (withinLimits()) {
finalizeWrite();
} else {
failRequest();
}
return;
}
const candidate = cursor.value;
if (candidate?.key !== record.key && isStoredFrameValid(candidate)) {
cursor.delete();
usage.totalBytes = Math.max(0, usage.totalBytes - candidate.byteSize);
usage.totalEntries = Math.max(0, usage.totalEntries - 1);
} else if (candidate?.key !== record.key) {
cursor.delete();
}
if (withinLimits()) {
finalizeWrite();
} else {
cursor.continue();
}
};
cursorRequest.onerror = failRequest;
};
const existingRequest = frames.get(record.key);
existingRequest.onsuccess = () => {
existing = existingRequest.result;
existingReady = true;
evictIfNeeded();
};
existingRequest.onerror = failRequest;
const usageRequest = meta.get(USAGE_KEY);
usageRequest.onsuccess = () => {
usage = readUsageRecord(usageRequest.result);
usageReady = true;
evictIfNeeded();
};
usageRequest.onerror = failRequest;
transaction.oncomplete = () => resolve(true);
transaction.onerror = () => reject(transactionError(transaction, "IndexedDB frame write failed"));
transaction.onabort = () => reject(transactionError(transaction, "IndexedDB frame write was aborted"));
});
}
function getFrame(database, key, nextAccess) {
return new Promise((resolve, reject) => {
let transaction;
try {
transaction = database.transaction(FRAME_STORE, "readwrite");
} catch (error) {
reject(error);
return;
}
const store = transaction.objectStore(FRAME_STORE);
let result = null;
const request = store.get(key.key);
request.onsuccess = () => {
const record = request.result;
if (!isStoredFrameValid(record)) {
if (record != null) {
store.delete(key.key);
}
return;
}
record.lastAccess = nextAccess();
store.put(record);
result = {
blob: record.blob,
width: record.width,
height: record.height,
byteSize: record.byteSize,
lastAccess: record.lastAccess,
};
};
transaction.oncomplete = () => resolve(result);
transaction.onerror = () => reject(transactionError(transaction, "IndexedDB frame read failed"));
transaction.onabort = () => reject(transactionError(transaction, "IndexedDB frame read was aborted"));
});
}
function deleteFrame(database, key) {
return new Promise((resolve, reject) => {
let transaction;
try {
transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
} catch (error) {
reject(error);
return;
}
const frames = transaction.objectStore(FRAME_STORE);
const meta = transaction.objectStore(META_STORE);
let deleted = false;
const getRequest = frames.get(key.key);
getRequest.onsuccess = () => {
const existing = getRequest.result;
if (existing == null) {
return;
}
deleted = true;
const existingIsValid = isStoredFrameValid(existing);
const usageRequest = meta.get(USAGE_KEY);
usageRequest.onsuccess = () => {
const usage = readUsageRecord(usageRequest.result);
frames.delete(key.key);
meta.put({
key: USAGE_KEY,
totalBytes: Math.max(0, usage.totalBytes - (existingIsValid ? existing.byteSize : 0)),
totalEntries: Math.max(0, usage.totalEntries - (existingIsValid ? 1 : 0)),
updatedAt: Date.now(),
});
};
};
transaction.oncomplete = () => resolve(deleted);
transaction.onerror = () => reject(transactionError(transaction, "IndexedDB frame delete failed"));
transaction.onabort = () => reject(transactionError(transaction, "IndexedDB frame delete was aborted"));
});
}
function clearDocumentFrames(database, documentId) {
return new Promise((resolve, reject) => {
let transaction;
try {
transaction = database.transaction([FRAME_STORE, META_STORE], "readwrite");
} catch (error) {
reject(error);
return;
}
const frames = transaction.objectStore(FRAME_STORE);
const meta = transaction.objectStore(META_STORE);
let usage = null;
let cursorFinished = false;
let deletedEntries = 0;
let deletedBytes = 0;
let finalized = false;
const maybeFinalize = () => {
if (finalized || usage == null || !cursorFinished) {
return;
}
finalized = true;
meta.put({
key: USAGE_KEY,
totalBytes: Math.max(0, usage.totalBytes - deletedBytes),
totalEntries: Math.max(0, usage.totalEntries - deletedEntries),
updatedAt: Date.now(),
});
};
const usageRequest = meta.get(USAGE_KEY);
usageRequest.onsuccess = () => {
usage = readUsageRecord(usageRequest.result);
maybeFinalize();
};
const cursorRequest = frames.index(DOCUMENT_INDEX).openCursor(documentId);
cursorRequest.onsuccess = () => {
const cursor = cursorRequest.result;
if (cursor == null) {
cursorFinished = true;
maybeFinalize();
return;
}
const record = cursor.value;
if (isStoredFrameValid(record)) {
deletedEntries += 1;
deletedBytes += record.byteSize;
}
cursor.delete();
cursor.continue();
};
transaction.oncomplete = () => resolve(deletedEntries);
transaction.onerror = () => reject(transactionError(transaction, "IndexedDB document clear failed"));
transaction.onabort = () => reject(transactionError(transaction, "IndexedDB document clear was aborted"));
});
}
/**
* Create a cache facade that is safe in Window and DedicatedWorkerGlobalScope.
* The facade is synchronous; all storage methods are asynchronous and never
* throw for storage availability, quota, cloning, or transaction failures.
*/
function createFrameCache(options = {}) {
const source = options && typeof options === "object" ? options : {};
const limits = normalizeFrameCacheLimits(source);
const dbName = normalizeDatabaseName(source.dbName);
const factory = source.indexedDB ?? globalThis.indexedDB;
const enabled = source.enabled !== false;
let closed = false;
let disabledReason = !enabled
? "disabled"
: factory && typeof factory.open === "function"
? null
: "unavailable";
let databasePromise = null;
let lastAccess = 0;
const nextAccess = () => {
lastAccess = Math.max(Date.now(), lastAccess + 1);
return lastAccess;
};
const disable = (error) => {
if (disabledReason == null) {
disabledReason = typeof error?.name === "string" && error.name
? error.name
: "storage-error";
}
if (databasePromise != null) {
databasePromise.then((database) => database?.close()).catch(() => {});
}
};
const getDatabase = async () => {
if (closed || disabledReason != null) {
return null;
}
if (databasePromise == null) {
databasePromise = openDatabase(factory, dbName)
.then(async (database) => {
database.onversionchange = () => {
database.close();
disable({ name: "version-change" });
};
await reconcileUsage(database, limits);
return database;
})
.catch((error) => {
disable(error);
return null;
});
}
return databasePromise;
};
const run = async (operation, fallback) => {
if (closed || disabledReason != null) {
return fallback;
}
const database = await getDatabase();
if (database == null) {
return fallback;
}
try {
return await operation(database);
} catch (error) {
// QuotaExceededError, Safari's InvalidStateError / TransactionInactiveError,
// private-mode failures, and structured-clone failures all become misses.
disable(error);
return fallback;
}
};
return Object.freeze({
async get(keyInput) {
const key = normalizeFrameCacheKey(keyInput);
if (key == null) {
return null;
}
return run((database) => getFrame(database, key, nextAccess), null);
},
async put(keyInput, frameInput) {
const input = normalizePutArguments(keyInput, frameInput, limits);
if (input == null) {
return false;
}
const record = {
...input,
lastAccess: nextAccess(),
};
return run((database) => putFrame(database, record, limits), false);
},
async delete(keyInput) {
const key = normalizeFrameCacheKey(keyInput);
if (key == null) {
return false;
}
return run((database) => deleteFrame(database, key), false);
},
async clearDocument(documentId) {
const normalized = normalizeBoundedString(documentId, MAX_DOCUMENT_ID_LENGTH, { trim: true });
if (normalized == null) {
return 0;
}
return run((database) => clearDocumentFrames(database, normalized), 0);
},
async stats() {
const unavailable = () => ({
available: false,
disabledReason: closed ? "closed" : disabledReason ?? "unavailable",
entries: 0,
totalBytes: 0,
...limits,
});
if (closed || disabledReason != null) {
return unavailable();
}
const result = await run(async (database) => {
let transaction;
try {
transaction = database.transaction(META_STORE, "readonly");
} catch (error) {
throw error;
}
const value = await requestResult(transaction.objectStore(META_STORE).get(USAGE_KEY));
const usage = readUsageRecord(value);
return {
available: true,
disabledReason: null,
entries: usage.totalEntries,
totalBytes: usage.totalBytes,
...limits,
};
}, null);
return result ?? unavailable();
},
close() {
if (closed) {
return;
}
closed = true;
if (databasePromise != null) {
databasePromise.then((database) => database?.close()).catch(() => {});
}
},
});
}
const WASM_EXPORTS = Object.freeze([

@@ -4,0 +734,0 @@ 'memory',

Sorry, the diff of this file is not supported yet