diff --git a/dist/fuse-worker.cjs b/dist/fuse-worker.cjs index 05f6f32f6..8f0910c88 100644 --- a/dist/fuse-worker.cjs +++ b/dist/fuse-worker.cjs @@ -15,6 +15,7 @@ const FUSE_WORKER_TOKEN_SEARCH_UNSUPPORTED = "FuseWorker does not support useTok //#endregion //#region src/workers/FuseWorker.ts const DEFAULT_MAX_WORKERS = 8; +const TRUSTED_TYPES_POLICY = globalThis?.window?.trustedTypes?.createPolicy("fuse-trusted-worker-url", { createScriptURL: (url) => url }); function getDefaultWorkerCount() { const hw = typeof navigator !== "undefined" ? navigator.hardwareConcurrency || 4 : 4; return Math.min(hw, DEFAULT_MAX_WORKERS); @@ -41,7 +42,11 @@ var FuseWorker = class FuseWorker { this._workerOptions = workerOptions || {}; FuseWorker._assertNoFunctionOptions(this._options); if (this._options.useTokenSearch) throw new Error(FUSE_WORKER_TOKEN_SEARCH_UNSUPPORTED); - this._workerUrl = this._workerOptions.workerUrl || resolveDefaultWorkerUrl(); + if (this._workerOptions.workerUrl) this._workerUrl = this._workerOptions.workerUrl; + else { + const defaultWorkerUrl = resolveDefaultWorkerUrl(); + this._workerUrl = TRUSTED_TYPES_POLICY ? TRUSTED_TYPES_POLICY.createScriptURL(defaultWorkerUrl.toString()) : defaultWorkerUrl; + } } static _assertNoFunctionOptions(options) { if (typeof options.sortFn === "function") throw new Error(FUSE_WORKER_UNSUPPORTED_FN_OPTION("sortFn")); diff --git a/dist/fuse-worker.d.cts b/dist/fuse-worker.d.cts index c6c78963a..e8bfea893 100644 --- a/dist/fuse-worker.d.cts +++ b/dist/fuse-worker.d.cts @@ -201,13 +201,28 @@ type Expression = string | KeyedLeaf | PathLeafString | { } | { $or?: ChildExpression[]; }; +/** https://developer.mozilla.org/en-US/docs/Web/API/TrustedScriptURL */ +type TrustedScriptURL = { + toString(): string; +}; +declare global { + interface Window { + trustedTypes: { + createPolicy: (name: string, options: { + createScriptURL: (url: string) => string; + }) => { + createScriptURL: (url: string) => TrustedScriptURL; + }; + }; + } +} //#endregion //#region src/workers/FuseWorker.d.ts interface FuseWorkerOptions { /** Number of parallel workers. Defaults to navigator.hardwareConcurrency (max 8). */ numWorkers?: number; /** Custom URL to the worker script. If not provided, resolves automatically via import.meta.url. */ - workerUrl?: string | URL; + workerUrl?: string | URL | TrustedScriptURL; } declare class FuseWorker { private _options; diff --git a/dist/fuse-worker.d.ts b/dist/fuse-worker.d.ts index c6c78963a..e8bfea893 100644 --- a/dist/fuse-worker.d.ts +++ b/dist/fuse-worker.d.ts @@ -201,13 +201,28 @@ type Expression = string | KeyedLeaf | PathLeafString | { } | { $or?: ChildExpression[]; }; +/** https://developer.mozilla.org/en-US/docs/Web/API/TrustedScriptURL */ +type TrustedScriptURL = { + toString(): string; +}; +declare global { + interface Window { + trustedTypes: { + createPolicy: (name: string, options: { + createScriptURL: (url: string) => string; + }) => { + createScriptURL: (url: string) => TrustedScriptURL; + }; + }; + } +} //#endregion //#region src/workers/FuseWorker.d.ts interface FuseWorkerOptions { /** Number of parallel workers. Defaults to navigator.hardwareConcurrency (max 8). */ numWorkers?: number; /** Custom URL to the worker script. If not provided, resolves automatically via import.meta.url. */ - workerUrl?: string | URL; + workerUrl?: string | URL | TrustedScriptURL; } declare class FuseWorker { private _options; diff --git a/dist/fuse-worker.mjs b/dist/fuse-worker.mjs index 1a6ddc4ec..691006f4f 100644 --- a/dist/fuse-worker.mjs +++ b/dist/fuse-worker.mjs @@ -13,6 +13,7 @@ const FUSE_WORKER_TOKEN_SEARCH_UNSUPPORTED = "FuseWorker does not support useTok //#endregion //#region src/workers/FuseWorker.ts const DEFAULT_MAX_WORKERS = 8; +const TRUSTED_TYPES_POLICY = globalThis?.window?.trustedTypes?.createPolicy("fuse-trusted-worker-url", { createScriptURL: (url) => url }); function getDefaultWorkerCount() { const hw = typeof navigator !== "undefined" ? navigator.hardwareConcurrency || 4 : 4; return Math.min(hw, DEFAULT_MAX_WORKERS); @@ -38,7 +39,11 @@ var FuseWorker = class FuseWorker { this._workerOptions = workerOptions || {}; FuseWorker._assertNoFunctionOptions(this._options); if (this._options.useTokenSearch) throw new Error(FUSE_WORKER_TOKEN_SEARCH_UNSUPPORTED); - this._workerUrl = this._workerOptions.workerUrl || resolveDefaultWorkerUrl(); + if (this._workerOptions.workerUrl) this._workerUrl = this._workerOptions.workerUrl; + else { + const defaultWorkerUrl = resolveDefaultWorkerUrl(); + this._workerUrl = TRUSTED_TYPES_POLICY ? TRUSTED_TYPES_POLICY.createScriptURL(defaultWorkerUrl.toString()) : defaultWorkerUrl; + } } static _assertNoFunctionOptions(options) { if (typeof options.sortFn === "function") throw new Error(FUSE_WORKER_UNSUPPORTED_FN_OPTION("sortFn")); diff --git a/dist/fuse.d.cts b/dist/fuse.d.cts index 2d123f90e..b91508d29 100644 --- a/dist/fuse.d.cts +++ b/dist/fuse.d.cts @@ -288,6 +288,21 @@ type Expression = string | KeyedLeaf | PathLeafString | { } | { $or?: ChildExpression[]; }; +/** https://developer.mozilla.org/en-US/docs/Web/API/TrustedScriptURL */ +type TrustedScriptURL = { + toString(): string; +}; +declare global { + interface Window { + trustedTypes: { + createPolicy: (name: string, options: { + createScriptURL: (url: string) => string; + }) => { + createScriptURL: (url: string) => TrustedScriptURL; + }; + }; + } +} //#endregion //#region src/tools/FuseIndex.d.ts declare class FuseIndex { diff --git a/dist/fuse.d.ts b/dist/fuse.d.ts index 295642824..aa2e9c179 100644 --- a/dist/fuse.d.ts +++ b/dist/fuse.d.ts @@ -288,6 +288,21 @@ type Expression = string | KeyedLeaf | PathLeafString | { } | { $or?: ChildExpression[]; }; +/** https://developer.mozilla.org/en-US/docs/Web/API/TrustedScriptURL */ +type TrustedScriptURL = { + toString(): string; +}; +declare global { + interface Window { + trustedTypes: { + createPolicy: (name: string, options: { + createScriptURL: (url: string) => string; + }) => { + createScriptURL: (url: string) => TrustedScriptURL; + }; + }; + } +} //#endregion //#region src/tools/FuseIndex.d.ts declare class FuseIndex { diff --git a/src/types.ts b/src/types.ts index cacaf5d8d..a4402dd70 100644 --- a/src/types.ts +++ b/src/types.ts @@ -369,3 +369,21 @@ export type Expression = | PathLeafString | { $and?: ChildExpression[] } | { $or?: ChildExpression[] } + +/** https://developer.mozilla.org/en-US/docs/Web/API/TrustedScriptURL */ +export type TrustedScriptURL = { + toString(): string; +} + +declare global { +interface Window { + trustedTypes: { + createPolicy: (name: string, options: { + createScriptURL: (url: string) => string, + })=> { + + createScriptURL: (url: string) => TrustedScriptURL, + }, + } +} +} diff --git a/src/workers/FuseWorker.ts b/src/workers/FuseWorker.ts index 428327eb7..a48a02367 100644 --- a/src/workers/FuseWorker.ts +++ b/src/workers/FuseWorker.ts @@ -6,14 +6,15 @@ import type { FuseOptionKey, FuseResult, FuseSearchOptions, - Expression + Expression, + TrustedScriptURL } from '../types' export interface FuseWorkerOptions { /** Number of parallel workers. Defaults to navigator.hardwareConcurrency (max 8). */ numWorkers?: number /** Custom URL to the worker script. If not provided, resolves automatically via import.meta.url. */ - workerUrl?: string | URL + workerUrl?: string | URL | TrustedScriptURL } interface PendingCall { @@ -28,6 +29,13 @@ interface Shard { const DEFAULT_MAX_WORKERS = 8 +const TRUSTED_TYPES_POLICY = globalThis?.window?.trustedTypes?.createPolicy( + 'fuse-trusted-worker-url', + { + createScriptURL: (url) => url + } +) + function getDefaultWorkerCount(): number { const hw = typeof navigator !== 'undefined' ? navigator.hardwareConcurrency || 4 : 4 @@ -89,7 +97,7 @@ export default class FuseWorker { private _initPromise: Promise | null = null private _pending: Map = new Map() private _nextId = 0 - private _workerUrl: string | URL + private _workerUrl: string | URL | TrustedScriptURL constructor( docs: ReadonlyArray, @@ -108,7 +116,17 @@ export default class FuseWorker { if (this._options.useTokenSearch) { throw new Error(ErrorMsg.FUSE_WORKER_TOKEN_SEARCH_UNSUPPORTED) } - this._workerUrl = this._workerOptions.workerUrl || resolveDefaultWorkerUrl() + + if (this._workerOptions.workerUrl) { + // Don't apply the trusted types policy as workerUrl is outside our control + this._workerUrl = this._workerOptions.workerUrl + } else { + const defaultWorkerUrl = resolveDefaultWorkerUrl() + + this._workerUrl = TRUSTED_TYPES_POLICY + ? TRUSTED_TYPES_POLICY.createScriptURL(defaultWorkerUrl.toString()) + : defaultWorkerUrl + } } private static _assertNoFunctionOptions(options: IFuseOptions): void { @@ -152,6 +170,7 @@ export default class FuseWorker { } private _spawnWorker(): Worker { + // @ts-expect-error the types for Worker are not updated yet to accept TrustedScriptURL const worker = new Worker(this._workerUrl, { type: 'module' }) worker.onmessage = (e: MessageEvent) => {