Repository: League-of-Foundry-Developers/foundry-vtt-types
Pull request #3038 (2025-01-26 06:09:06)

Types and tests for `client/pixi/workers/**` and `public/scripts/workers/**`
Adds a new dependency (`@pixi/basis`) and a new export path (`worker`) to package.json


Patch:
diff --git a/package-lock.json b/package-lock.json
index 3d7cee98d..7c54bb5c2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
       "version": "12.331.3-beta",
       "license": "MIT",
       "dependencies": {
+        "@pixi/basis": "^7.4.2",
         "@pixi/graphics-smooth": "^1.1.0",
         "@pixi/particle-emitter": "^5.0.8",
         "@types/earcut": "^3.0.0",
@@ -716,6 +717,17 @@
         "@pixi/core": "7.4.2"
       }
     },
+    "node_modules/@pixi/basis": {
+      "version": "7.4.2",
+      "resolved": "https://registry.npmjs.org/@pixi/basis/-/basis-7.4.2.tgz",
+      "integrity": "sha512-OnTyvy0woQuTyDIoZokz9HGWrmncgBl3mchT4gX0M+rESAQa+q+Q8uW1dq9RsBt21mrQoSBfJrjqb+fLkgrmug==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@pixi/assets": "7.4.2",
+        "@pixi/compressed-textures": "7.4.2",
+        "@pixi/core": "7.4.2"
+      }
+    },
     "node_modules/@pixi/color": {
       "version": "7.4.2",
       "license": "MIT",
diff --git a/package.json b/package.json
index 4fe4e5f96..774adcf1e 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,12 @@
     },
     "./configuration": {
       "types": "./src/configuration/index.d.mts"
+    },
+    "./worker": {
+      "types": "./src/foundry/public/scripts/workers/index.d.mts"
+    },
+    "./worker/image-compressor": {
+      "types": "./src/foundry/public/scripts/workers/image-compressor.d.mts"
     }
   },
   "scripts": {
@@ -67,6 +73,7 @@
     "typescript"
   ],
   "dependencies": {
+    "@pixi/basis": "^7.4.2",
     "@pixi/graphics-smooth": "^1.1.0",
     "@pixi/particle-emitter": "^5.0.8",
     "@types/earcut": "^3.0.0",
diff --git a/src/foundry/client/pixi/workers/texture-worker.d.mts b/src/foundry/client/pixi/workers/texture-worker.d.mts
index 4928ed2b3..6624447f3 100644
--- a/src/foundry/client/pixi/workers/texture-worker.d.mts
+++ b/src/foundry/client/pixi/workers/texture-worker.d.mts
@@ -1,4 +1,11 @@
-export {};
+import type { NullishProps } from "../../../../utils/index.d.mts";
+import type {
+  _ProcessBufferToBase64Options,
+  Debug,
+  ProcessBufferRedToBufferRGBAReturn,
+  ProcessBufferRGBAToBufferREDReturn,
+  ProcessBufferToBase64Return,
+} from "../../../../types/workers/image-compressor.d.mts";
 
 declare global {
   /**
@@ -23,8 +30,8 @@ declare global {
       buffer: Uint8ClampedArray,
       width: number,
       height: number,
-      options?: TextureCompressor.compressBase64Options,
-    ): Promise<unknown>;
+      options?: TextureCompressor.CompressBase64Options,
+    ): Promise<ProcessBufferToBase64Return>;
 
     /**
      * Expand a buffer in RED format to a buffer in RGBA format.
@@ -36,8 +43,8 @@ declare global {
       buffer: Uint8ClampedArray,
       width: number,
       height: number,
-      options?: TextureCompressor.expandRedToRGBAOptions,
-    ): Promise<unknown>;
+      options?: TextureCompressor.ExpandOrReduceBufferOptions,
+    ): Promise<ProcessBufferRedToBufferRGBAReturn>;
 
     /**
      * Expand a buffer in RED format to a buffer in RGBA format.
@@ -49,77 +56,50 @@ declare global {
       buffer: Uint8ClampedArray,
       width: number,
       height: number,
-      options?: TextureCompressor.reduceRGBAToRedOptions,
-    ): Promise<unknown>;
+      options?: TextureCompressor.ExpandOrReduceBufferOptions,
+    ): Promise<ProcessBufferRGBAToBufferREDReturn>;
   }
 
   namespace TextureCompressor {
-    interface ConstructorOptions {
+    type Any = AnyTextureCompressor;
+    type AnyConstructor = typeof AnyTextureCompressor;
+
+    /** @internal */
+    type _ConstructorOptions = NullishProps<{
       /**
        * Should the worker run in debug mode?
        * @defaultValue `false`
        */
-      debug?: boolean;
+      debug: boolean;
 
       /**
        * @defaultValue `["./workers/image-compressor.js", "./spark-md5.min.js"]`
+       * @remarks Undocumented by Foundry
        */
-      scripts?: string[];
+      scripts: string[];
 
       /**
        * @defaultValue `false`
+       * @remarks Undocumented by Foundry
        */
-      loadPrimitives?: boolean;
+      loadPrimitives: boolean;
 
       /**
        * Do we need to control the hash?
        * @defaultValue `false`
        */
       controlHash?: boolean;
-    }
-
-    interface compressBase64Options {
-      /**
-       * The required image type.
-       * @defaultValue `"image/png"`
-       */
-      type?: string;
-
-      /**
-       * The required image quality.
-       * @defaultValue `1`
-       */
-      quality?: number;
-
-      /**
-       * The debug option.
-       * @defaultValue `false`
-       */
-      debug?: boolean;
+    }>;
 
-      readFormat: PIXI.FORMATS;
-    }
+    /** Options for the {@link TextureCompressor} constructor */
+    interface ConstructorOptions extends _ConstructorOptions {}
 
-    interface expandRedToRGBAOptions {
-      /**
-       * The debug option
-       * @defaultValue `false`
-       */
-      debug: boolean;
-    }
-
-    interface reduceRGBAToRedOptions {
-      /**
-       * The debug option
-       * @defaultValue `false`
-       */
-      debug?: boolean;
-
-      compression: (typeof TextureExtractor)["COMPRESSION_MODES"];
+    interface CompressBase64Options extends _ProcessBufferToBase64Options, Debug {}
 
-      type: string;
-
-      quality: number;
-    }
+    interface ExpandOrReduceBufferOptions extends Pick<_ProcessBufferToBase64Options, "hash">, Debug {}
   }
 }
+
+declare abstract class AnyTextureCompressor extends TextureCompressor {
+  constructor(arg0: never, ...args: never[]);
+}
diff --git a/src/foundry/public/scripts/workers/image-compressor.d.mts b/src/foundry/public/scripts/workers/image-compressor.d.mts
new file mode 100644
index 000000000..44638912c
--- /dev/null
+++ b/src/foundry/public/scripts/workers/image-compressor.d.mts
@@ -0,0 +1,23 @@
+// eslint-disable-next-line import/extensions
+import * as worker from "../../../../types/workers/image-compressor.mjs";
+
+declare global {
+  export import FORMATS = worker.FORMATS;
+  export import Debug = worker.Debug;
+
+  export import ProcessBufferToBase64Options = worker.ProcessBufferToBase64Options;
+  export import ExpandOrReduceBufferOptions = worker.ExpandOrReduceBufferOptions;
+  export import ProcessBufferToBase64Return = worker.ProcessBufferToBase64Return;
+  export import ProcessBufferRedToBufferRGBAReturn = worker.ProcessBufferRedToBufferRGBAReturn;
+  export import ProcessBufferRGBAToBufferREDReturn = worker.ProcessBufferRGBAToBufferREDReturn;
+
+  export import processBufferToBase64 = worker.processBufferToBase64;
+  export import processBufferRedToBufferRGBA = worker.processBufferRedToBufferRGBA;
+  export import processBufferRGBAToBufferRED = worker.processBufferRGBAToBufferRED;
+  export import controlHashes = worker.controlHashes;
+  export import pixelsToOffscreenCanvas = worker.pixelsToOffscreenCanvas;
+  export import offscreenToBase64 = worker.offscreenToBase64;
+  export import blobToBase64 = worker.blobToBase64;
+  export import expandBuffer = worker.expandBuffer;
+  export import reduceBuffer = worker.reduceBuffer;
+}
diff --git a/src/foundry/public/scripts/workers/index.d.mts b/src/foundry/public/scripts/workers/index.d.mts
new file mode 100644
index 000000000..0f0fb335d
--- /dev/null
+++ b/src/foundry/public/scripts/workers/index.d.mts
@@ -0,0 +1,1 @@
+import "./image-compressor.d.mts";
diff --git a/src/types/workers/image-compressor.d.mts b/src/types/workers/image-compressor.d.mts
new file mode 100644
index 000000000..491c3fc0d
--- /dev/null
+++ b/src/types/workers/image-compressor.d.mts
@@ -0,0 +1,176 @@
+import type { EmptyObject, InexactPartial } from "../../utils/index.d.mts";
+
+export declare const FORMATS: {
+  RED: typeof PIXI.FORMATS.RED;
+  RGBA: typeof PIXI.FORMATS.RGBA;
+};
+
+export interface Debug {
+  /**
+   * Debug option.
+   * @remarks Enables logging via `console.debug`
+   */
+  debug?: boolean | undefined | null;
+}
+
+/** @internal */
+export type _ProcessBufferToBase64Options = InexactPartial<{
+  /**
+   * The required image type.
+   * @defaultValue `"image/png"`
+   * @remarks Can't be null as it only has a parameter default
+   */
+  type: string;
+
+  /**
+   * The required image quality.
+   * @defaultValue `1`
+   * @remarks Can't be null as it only has a parameter default
+   */
+  quality: number;
+
+  /**
+   * Hash to test.
+   * @remarks Can't be null as it's passed directly to the `controlHashes` function,
+   * where it is only checked for `=== undefined`
+   */
+  hash: string;
+
+  /**
+   * The format the buffer is in
+   * @remarks Only matters whether it's `FORMATS.RED` or not. Property is undocumented by foundry.
+   */
+  readFormat: PIXI.FORMATS | null;
+}>;
+
+/** @internal */
+// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+type _BaseBufferOptions = {
+  /** Buffer used to create the image data. */
+  buffer: Uint8ClampedArray;
+
+  /** Buffered image width. */
+  width: number;
+
+  /** Buffered image height. */
+  height: number;
+};
+
+export interface ProcessBufferToBase64Options extends _BaseBufferOptions, _ProcessBufferToBase64Options, Debug {}
+
+export interface ExpandOrReduceBufferOptions
+  extends _BaseBufferOptions,
+    Debug,
+    Pick<_ProcessBufferToBase64Options, "hash"> {}
+
+export type ProcessBufferToBase64Return = [
+  {
+    base64img: string | undefined;
+    buffer: Uint8ClampedArray;
+    hash: string | undefined;
+  },
+  [bufferBuffer: ArrayBufferLike],
+];
+
+export type ProcessBufferRedToBufferRGBAReturn = [
+  {
+    rgbaBuffer: Uint8ClampedArray | undefined;
+    buffer: Uint8ClampedArray;
+    hash: string | undefined;
+  },
+  [rgbaBufferBuffer: ArrayBufferLike, bufferBuffer: ArrayBufferLike],
+];
+
+export type ProcessBufferRGBAToBufferREDReturn = [
+  {
+    redBuffer: Uint8ClampedArray | undefined;
+    buffer: Uint8ClampedArray;
+    hash: string | undefined;
+  },
+  [bufferBuffer: ArrayBufferLike],
+];
+
+/**
+ * Process the image compression.
+ */
+export declare function processBufferToBase64(
+  options: ProcessBufferToBase64Options,
+): Promise<ProcessBufferToBase64Return>;
+
+/**
+ * Expand a single RED channel buffer into a RGBA buffer and returns it to the main thread.
+ * The created RGBA buffer is transfered.
+ */
+export declare function processBufferRedToBufferRGBA(
+  options: ExpandOrReduceBufferOptions,
+): Promise<ProcessBufferRedToBufferRGBAReturn>;
+
+/**
+ * Reduce a RGBA buffer into a single RED buffer and returns it to the main thread.
+ * The created RGBA buffer is transfered.
+ */
+export declare function processBufferRGBAToBufferRED(
+  options: ExpandOrReduceBufferOptions,
+): Promise<ProcessBufferRGBAToBufferREDReturn>;
+
+/**
+ * Control the hash of a provided buffer.
+ * @param buffer - Buffer to control.
+ * @param hash   - Hash to test.
+ * @returns Returns an empty object if `hash === undefined` else returns `{same: <boolean to know if the hashes are the same>, hash: <the previous or the new hash>}`
+ */
+export declare function controlHashes(buffer: Uint8ClampedArray, hash?: undefined): EmptyObject;
+export declare function controlHashes(buffer: Uint8ClampedArray, hash: string): { same: boolean; hash: string };
+export declare function controlHashes(
+  buffer: Uint8ClampedArray,
+  hash?: string | undefined,
+): EmptyObject | { same: boolean; hash: string };
+
+/**
+ * Create an offscreen canvas element containing the pixel data.
+ * @param buffer - Buffer used to create the image data.
+ * @param width  - Buffered image width.
+ * @param height - Buffered image height.
+ */
+export declare function pixelsToOffscreenCanvas(
+  buffer: Uint8ClampedArray,
+  width: number,
+  height: number,
+  { debug }?: Debug,
+): OffscreenCanvas;
+
+/**
+ * Asynchronously convert a canvas element to base64.
+ * @returns The base64 string of the canvas.
+ */
+export declare function offscreenToBase64(
+  offscreen: OffscreenCanvas,
+  type?: string,
+  quality?: number,
+  { debug }?: Debug,
+): Promise<string>;
+
+/**
+ * Convert a blob to a base64 string.
+ */
+export declare function blobToBase64(blob: Blob): Promise<string>;
+
+/**
+ * Expand a single RED channel buffer into a RGBA buffer.
+ */
+export declare function expandBuffer(
+  buffer: Uint8ClampedArray,
+  width: number,
+  height: number,
+  { debug }?: Debug,
+): Uint8ClampedArray;
+
+/**
+ * Reduce a RGBA channel buffer into a RED buffer (in-place).
+ */
+export declare function reduceBuffer(
+  buffer: Uint8ClampedArray,
+  width: number,
+  height: number,
+  { debug }?: Debug,
+): Uint8ClampedArray;


Test patch:
diff --git a/tests/foundry/public/scripts/workers/image-compressor.test-d.ts b/tests/foundry/public/scripts/workers/image-compressor.test-d.ts
new file mode 100644
index 000000000..276bc5f8f
--- /dev/null
+++ b/tests/foundry/public/scripts/workers/image-compressor.test-d.ts
@@ -0,0 +1,54 @@
+import { expectTypeOf } from "vitest";
+import type { EmptyObject } from "fvtt-types/utils";
+// eslint-disable-next-line import/extensions
+import type * as _ from "fvtt-types/worker";
+
+declare const someBlob: Blob;
+declare const someBuffer: Uint8ClampedArray;
+declare const someOC: OffscreenCanvas;
+
+expectTypeOf(
+  processBufferToBase64({
+    buffer: someBuffer,
+    width: 500,
+    height: 500,
+    type: "image/webp",
+    quality: 0.8,
+    readFormat: PIXI.FORMATS.RED,
+    debug: true,
+    hash: "asdageherhr",
+  }),
+).toEqualTypeOf<Promise<ProcessBufferToBase64Return>>();
+
+expectTypeOf(
+  processBufferRedToBufferRGBA({
+    buffer: someBuffer,
+    width: 500,
+    height: 500,
+    debug: true,
+    hash: "asfasfgdgha",
+  }),
+).toEqualTypeOf<Promise<ProcessBufferRedToBufferRGBAReturn>>();
+
+expectTypeOf(
+  processBufferRGBAToBufferRED({
+    buffer: someBuffer,
+    width: 500,
+    height: 500,
+    debug: true,
+    hash: "asdfasdf",
+  }),
+).toEqualTypeOf<Promise<ProcessBufferRGBAToBufferREDReturn>>();
+
+expectTypeOf(controlHashes(someBuffer)).toEqualTypeOf<EmptyObject>();
+expectTypeOf(controlHashes(someBuffer, "some hash")).toEqualTypeOf<{ same: boolean; hash: string }>();
+
+expectTypeOf(pixelsToOffscreenCanvas(someBuffer, 500, 500, { debug: true })).toEqualTypeOf<OffscreenCanvas>();
+
+expectTypeOf(offscreenToBase64(someOC, "image/jpeg", 0.85)).toEqualTypeOf<Promise<string>>();
+
+expectTypeOf(blobToBase64(someBlob)).toEqualTypeOf<Promise<string>>();
+
+expectTypeOf(expandBuffer(someBuffer, 500, 500, { debug: undefined })).toEqualTypeOf<Uint8ClampedArray>();
+
+expectTypeOf(reduceBuffer(someBuffer, 500, 500, { debug: null })).toEqualTypeOf<Uint8ClampedArray>();