Repository: League-of-Foundry-Developers/foundry-vtt-types
Pull request #2771 (2024-08-06 11:08:39)

V12/client/core/keybindings, keyboard, issues, socket, documentindex
Addresses #2753, #2754, #2755, #2759, and #2751


Patch:
diff --git a/src/foundry/client/core/document-index.d.mts b/src/foundry/client/core/document-index.d.mts
index e850af238..f9f638a79 100644
--- a/src/foundry/client/core/document-index.d.mts
+++ b/src/foundry/client/core/document-index.d.mts
@@ -1,95 +1,8 @@
+import type { DOCUMENT_OWNERSHIP_LEVELS } from "../../common/constants.d.mts";
+
 export {};
 
 declare global {
-  /**
-   * A data structure for quickly retrieving objects by a string prefix.
-   * Note that this works well for languages with alphabets (latin, cyrillic, korean, etc.), but may need more nuanced
-   * handling for languages that compose characters and letters.
-   */
-  class WordTree {
-    /**
-     * Create a new node.
-     */
-    get node(): WordTree.Node;
-
-    /**
-     * Insert an entry into the tree.
-     * @param string - The string key for the entry.
-     * @param entry  - The entry to store.
-     * @returns The node the entry was added to.
-     */
-    addLeaf(string: string, entry: WordTree.Entry): WordTree.Node;
-
-    /**
-     * Return entries that match the given string prefix.
-     * @param prefix  - The prefix.
-     * @param options - Additional options to configure behaviour.
-     * @returns A number of entries that have the given prefix.
-     */
-    lookup(
-      prefix: string,
-      options?: {
-        /**
-         * The maximum number of items to retrieve. It is important to set this value as
-         * very short prefixes will naturally match large numbers of entries. (default: `10`)
-         */
-        limit: number;
-      },
-    ): WordTree.Entry[];
-
-    /**
-     * Returns the node at the given prefix.
-     * @param prefix - The prefix.
-     */
-    nodeAtPrefix(prefix: string): WordTree.Node;
-
-    /**
-     * Perform a breadth-first search starting from the given node and retrieving any entries along the way, until we
-     * reach the limit.
-     * @param node    - The starting node.
-     * @param entries - The accumulated entries.
-     * @param queue   - The working queue of nodes to search.
-     * @param options - Additional options for the search.
-     * @internal
-     */
-    protected _breadthFirstSearch(
-      node: WordTree.Node,
-      entries: WordTree.Entry[],
-      queue: WordTree.Node[],
-      options?: {
-        /** The maximum number of entries to retrieve before stopping. (default: `10`) */
-        limit: 10;
-      },
-    ): void;
-  }
-  export namespace WordTree {
-    /**
-     * A leaf entry in the tree.
-     */
-    interface Entry {
-      /** An object that this entry represents. */
-      entry: Document | object;
-
-      /** The document type. */
-      documentName: string;
-
-      /** The document's UUID. */
-      uuid: string;
-
-      /** The pack ID. */
-      pack?: string;
-    }
-
-    /**
-     * A word tree node consists of zero or more 1-character keys, and a leaves property that contains any objects that
-     * terminate at the current string prefix.
-     */
-    interface Node {
-      /** Any leaves at this node. */
-      leaves: Entry[];
-    }
-  }
-
   /**
    * This class is responsible for indexing all documents available in the world and storing them in a word tree structure
    * that allows for fast searching.
@@ -100,13 +13,13 @@ declare global {
      * A collection of WordTree structures for each document type.
      * @defaultValue `{}`
      */
-    trees: Record<string, WordTree>;
+    trees: Record<string, foundry.utils.WordTree>;
 
     /**
      * A reverse-lookup of a document's UUID to its parent node in the word tree.
      * @defaultValue `{}`
      */
-    uuids: Record<string, WordTree.Node>;
+    uuids: Record<string, foundry.utils.StringTree.StringTreeNode>;
 
     /**
      * Returns a Promise that resolves when the indexing process is complete.
@@ -122,7 +35,7 @@ declare global {
      * Return entries that match the given string prefix.
      * @param prefix  - The prefix.
      * @param options - Additional options to configure behaviour.
-     * A number of entries that have the given prefix, grouped by document type.
+     * @returns A number of entries that have the given prefix, grouped by document type.
      */
     lookup(
       prefix: string,
@@ -130,6 +43,7 @@ declare global {
         /**
          * The maximum number of items per document type to retrieve. It is important to set this
          * value as very short prefixes will naturally match large numbers of entries. (default: `10`)
+         * (default: `10`)
          */
         limit?: number;
         /**
@@ -137,8 +51,16 @@ declare global {
          * will be searched for. (default: `[]`)
          */
         documentTypes?: string[];
+        /**
+         * A filter function to apply to each candidate entry.
+         */
+        filterEntries?: foundry.utils.StringTree.StringTreeEntryFilter;
+        /**
+         * Only return entries that the user meets this ownership level for.
+         */
+        ownership?: DOCUMENT_OWNERSHIP_LEVELS;
       },
-    ): Record<string, WordTree.Entry[]>;
+    ): Record<string, foundry.utils.WordTree.WordTreeEntry[]>;
 
     /**
      * Add an entry to the index.
diff --git a/src/foundry/client/core/issues.d.mts b/src/foundry/client/core/issues.d.mts
index e712f6b3e..cd051a000 100644
--- a/src/foundry/client/core/issues.d.mts
+++ b/src/foundry/client/core/issues.d.mts
@@ -1,4 +1,5 @@
 import type { DocumentConstructor, DocumentType } from "../../../types/helperTypes.d.mts";
+import type Document from "../../common/abstract/document.d.mts";
 import type { DataModelValidationError } from "../../common/data/validation-failure.d.mts";
 
 declare global {
@@ -11,109 +12,8 @@ declare global {
    * A class responsible for tracking issues in the current world.
    */
   class ClientIssues {
-    /**
-     * Keep track of valid Documents in the world that are using module-provided sub-types.
-     * @remarks the keys are module ids.
-     */
-    #moduleTypeMap: Map<string, ModuleSubTypeCounts>;
-
-    /**
-     * Keep track of document validation failures.
-     */
-    #documentValidationFailures: Record<
-      DocumentType,
-      Record<string, { name: string; error: DataModelValidationError }>
-    >;
-
-    /**
-     * Keep track of any usability issues related to browser or technology versions.
-     */
-    #usabilityIssues: Record<string, ClientIssues.UsabilityIssue>;
-
-    /** The minimum supported resolution. */
-    static #MIN_RESOLUTION: { WIDTH: 1024; HEIGHT: 700 };
-
-    /**
-     * The minimum supported client versions.
-     */
-    static #BROWSER_TESTS: {
-      /**
-       * @defaultValue
-       * ```typescript
-       * {
-       *   minimum: 24;
-       *   match: RegExp;
-       *   message: "ERROR.ElectronVersion";
-       * }
-       * ```
-       */
-      Electron: ClientIssues.BROWSER_TEST;
-      /**
-       * @defaultValue
-       * ```
-       * {
-       *   minimum: 92;
-       *   match: RegExp;
-       *   message: "ERROR.BrowserVersion";
-       * }
-       * ```
-       */
-      Chromium: ClientIssues.BROWSER_TEST;
-      /**
-       * @defaultValue
-       * ```
-       * {
-       *   minimum: 90;
-       *   match: RegExp;
-       *   message: "ERROR.BrowserVersion";
-       * }
-       * ```
-       */
-      Firefox: ClientIssues.BROWSER_TEST;
-      /**
-       * @defaultValue
-       * ```
-       * {
-       *   minimum: 15.4;
-       *   match: RegExp;
-       *   message: "ERROR.BrowserVersion";
-       * }
-       * ```
-       */
-      Safari: ClientIssues.BROWSER_TEST;
-    };
-
-    /**
-     * Add a Document to the count of module-provided sub-types.
-     * @param documentName      - The Document name.
-     * @param subType           - The Document's sub-type.
-     */
-    #countDocumentSubType(
-      documentName: DocumentType,
-      subType: string,
-      options?: {
-        /**
-         * Decrement the counter rather than incrementing it.
-         * @defaultValue `false`
-         */
-        decrement?: boolean;
-      },
-    ): void;
-
-    /**
-     * Detect the user's browser and display a notification if it is below the minimum required version.
-     */
-    #detectBrowserVersion(): void;
-
-    /**
-     * Record a reference to a resolution notification ID so that we can remove it if the problem is remedied.
-     */
-    #resolutionTooLowNotification: number;
-
-    /**
-     * Detect the user's resolution and display a notification if it is too small.
-     */
-    #detectResolution(): void;
+    // placeholder private member
+    #clientIssues: true;
 
     /**
      * Detect and display warnings for known performance issues which may occur due to the user's hardware or browser
@@ -124,21 +24,21 @@ declare global {
 
     /**
      * Add an invalid Document to the module-provided sub-type counts.
-     * @param documentName      - The Document name.
+     * @param cls               - The Document class.
      * @param source            - The Document's source data.
      * @internal
      *
      * @remarks official documentation says "invalid", but the document can be valid, it is simply not yet validated.
      */
     _countDocumentSubType(
-      documentName: DocumentType,
+      cls: Document.Any,
       source: unknown,
       options?: {
         /**
          * Decrement the counter rather than incrementing it.
          * @defaultValue `false`
          */
-        decrement?: boolean;
+        decrement?: boolean | undefined;
       },
     ): void;
 
@@ -189,17 +89,6 @@ declare global {
   }
 
   namespace ClientIssues {
-    interface BROWSER_TEST {
-      /** The minimum supported version for this browser. */
-      minimum: number;
-
-      /** A regular expression to match the browser against the user agent string. */
-      match: RegExp;
-
-      /** A message to display if the user's browser version does not meet the minimum. */
-      message: string;
-    }
-
     interface UsabilityIssue {
       /** The pre-localized message to display in relation to the usability issue. */
       message: string;
diff --git a/src/foundry/client/core/keybindings.d.mts b/src/foundry/client/core/keybindings.d.mts
index f3eb47963..92b990707 100644
--- a/src/foundry/client/core/keybindings.d.mts
+++ b/src/foundry/client/core/keybindings.d.mts
@@ -149,16 +149,18 @@ declare global {
      */
     static _compareActions(a: KeybindingAction, b: KeybindingAction): number;
 
-    /** Register core keybindings */
-    protected _registerCoreKeybindings(): void;
+    /**
+     * Register core keybindings.
+     * @param view           - The active game view
+     */
+    protected _registerCoreKeybindings(view: Game.View): void;
 
     /**
      * Handle Select all action
-     * @param event   - The originating keyboard event
      * @param context - The context data of the event
      * @internal
      */
-    protected static _onSelectAllObjects(event?: KeyboardEvent, context?: KeyboardEventContext): boolean;
+    protected static _onSelectAllObjects(context?: KeyboardEventContext): boolean;
 
     /**
      * Handle Cycle View actions
@@ -172,15 +174,14 @@ declare global {
      * @param context - The context data of the event
      * @internal
      */
-    protected static _onDismiss(context?: KeyboardEventContext): boolean;
+    protected static _onDismiss(context?: KeyboardEventContext): Promise<boolean>;
 
     /**
      * Open Character sheet for current token or controlled actor
-     * @param event   -
      * @param context - The context data of the event
      * @internal
      */
-    protected static _onToggleCharacterSheet(event?: KeyboardEvent, context?: KeyboardEventContext): ActorSheet | null;
+    protected static _onToggleCharacterSheet(context?: KeyboardEventContext): ReturnType<Game["toggleCharacterSheet"]>;
 
     /**
      * Handle action to target the currently hovered token.
@@ -191,11 +192,10 @@ declare global {
 
     /**
      * Handle DELETE Keypress Events
-     * @param event   - The originating keyboard event
      * @param context - The context data of the event
      * @internal
      */
-    protected static _onDelete(event: KeyboardEvent, context?: KeyboardEventContext): boolean;
+    protected static _onDelete(context?: KeyboardEventContext): boolean;
 
     /**
      * Handle keyboard movement once a small delay has elapsed to allow for multiple simultaneous key-presses.
diff --git a/src/foundry/client/core/keyboard.d.mts b/src/foundry/client/core/keyboard.d.mts
index d247ef40c..101a28ff6 100644
--- a/src/foundry/client/core/keyboard.d.mts
+++ b/src/foundry/client/core/keyboard.d.mts
@@ -50,7 +50,7 @@ declare global {
     static CONTROL_KEY_STRING: "⌘" | "Control";
 
     /**
-     * An special mapping of how special KeyboardEvent#code values should map to displayed strings or symbols.
+     * A special mapping of how special KeyboardEvent#code values should map to displayed strings or symbols.
      * Values in this configuration object override any other display formatting rules which may be applied.
      */
     static KEYCODE_DISPLAY_MAPPING: {
@@ -138,6 +138,13 @@ declare global {
      */
     isModifierActive(modifier: string): boolean;
 
+    /**
+     * Report whether a core action key is currently actively depressed.
+     * @param action       - The core action to verify (ex: "target")
+     * @returns              Is this core action key currently down (active)?
+     */
+    isCoreActionKeyActive(action: string): boolean;
+
     /**
      * Converts a Keyboard Context event into a string representation, such as "C" or "Control+C"
      * @param context          - The standardized context of the event
diff --git a/src/foundry/client/core/socket.d.mts b/src/foundry/client/core/socket.d.mts
index d6ad813ef..0b6246141 100644
--- a/src/foundry/client/core/socket.d.mts
+++ b/src/foundry/client/core/socket.d.mts
@@ -1,3 +1,5 @@
+import type { DatabaseOperationMap, DocumentSocketRequest } from "../../common/abstract/_types.d.mts";
+
 export {};
 
 declare global {
@@ -5,46 +7,12 @@ declare global {
     /**
      * Standardize the way that socket messages are dispatched and their results are handled
      * @param eventName - The socket event name being handled
-     * @param request   - Data provided to the Socket event
+     * @param request   - Request data provided to the Socket event
      * @returns A Promise which resolves to the SocketResponse
      */
-    static dispatch(eventName: string, request: SocketInterface.Request): Promise<SocketInterface.Response>;
-
-    /* -------------------------------------------- */
-
-    /**
-     * Handle an error returned from the database, displaying it on screen and in the console
-     * @param err - The provided Error message
-     */
-    protected static _handleError(err: Error): Error;
-  }
-
-  namespace SocketInterface {
-    namespace Requests {
-      interface ModifyEmbeddedDocument {
-        action: Action;
-        data: any; // TODO: add generics to this
-        options: any;
-        parentId: string;
-        parentType: string;
-        type: string;
-      }
-
-      // TODO: add remaining actions
-      type Action = "create" | "update" | "delete";
-    }
-
-    namespace Responses {
-      interface ModifyEmbeddedDocument {
-        request: Requests.ModifyEmbeddedDocument;
-        result: any[]; // TODO
-        userId: string;
-      }
-    }
-
-    // TODO: go through all SocketInterface.dispatch calls and collect requests
-    type Request = Requests.ModifyEmbeddedDocument;
-
-    type Response = Responses.ModifyEmbeddedDocument;
+    static dispatch<DatabaseAction extends keyof DatabaseOperationMap>(
+      eventName: string,
+      request: DocumentSocketRequest<DatabaseAction> | ManageCompendiumRequest,
+    ): Promise<SocketResponse>;
   }
 }
diff --git a/src/foundry/client/core/workers.d.mts b/src/foundry/client/core/workers.d.mts
index bf2479834..922ea34e8 100644
--- a/src/foundry/client/core/workers.d.mts
+++ b/src/foundry/client/core/workers.d.mts
@@ -10,12 +10,6 @@ declare global {
 
     /** The task action being performed, from WorkerManager.WORKER_TASK_ACTIONS */
     action: ValueOf<typeof WorkerManager.WORKER_TASK_ACTIONS>;
-
-    /** A Promise resolution handler */
-    resolve?: VoidFunction;
-
-    /** A Promise rejection handler */
-    reject?: VoidFunction;
   }
 
   /**
@@ -26,11 +20,6 @@ declare global {
   class AsyncWorker extends Worker {
     constructor(name: string, options?: Partial<AsyncWorker.Options>);
 
-    /**
-     * A Promise which resolves once the Worker is ready to accept tasks
-     */
-    ready: Promise<void>;
-
     name: string;
 
     /**
@@ -40,9 +29,9 @@ declare global {
     static WORKER_HARNESS_JS: string;
 
     /**
-     * A queue of active tasks that this Worker is executing.
+     * A Promise which resolves once the Worker is ready to accept tasks
      */
-    tasks: Map<number, WorkerTask>;
+    get ready(): Promise<void>;
 
     /**
      * An auto-incrementing task index.
@@ -70,15 +59,6 @@ declare global {
      * @returns A Promise which resolves with the returned result of the function once complete.
      */
     executeFunction(functionName: string, args?: any[], transfer?: any[]): Promise<unknown>;
-
-    /**
-     * Dispatch a task to a named Worker, awaiting confirmation of the result.
-     * @param taskData - Data to dispatch to the Worker as part of the task.
-     * @param transfer - An array of transferable objects which are transferred to the worker thread. (default: `[]`)
-     * @returns A Promise which wraps the task transaction.
-     * @internal
-     */
-    protected _dispatchTask(taskData?: WorkerTask, transfer?: any[]): Promise<unknown>;
   }
 
   /**
diff --git a/src/foundry/common/types.d.mts b/src/foundry/common/types.d.mts
index f77bb2786..3f701d473 100644
--- a/src/foundry/common/types.d.mts
+++ b/src/foundry/common/types.d.mts
@@ -144,10 +144,10 @@ declare global {
     /** The namespace the setting belongs to */
     namespace: string;
 
-    /** The human readable name */
+    /** The human-readable name */
     name?: string | undefined;
 
-    /** An additional human readable hint */
+    /** An additional human-readable hint */
     hint?: string | undefined;
 
     /**
@@ -363,40 +363,9 @@ declare global {
   type RequestData = Record<string, unknown> | Record<string, unknown>[] | string | string[];
 
   interface SocketRequest {
-    /**
-     * The server-side action being requested
-     */
-    action?: string | undefined;
-
-    /**
-     * The type of object being modified
-     */
-    type?: string | undefined;
-
-    /**
-     * Data applied to the operation
-     */
-    data?: RequestData | undefined;
-
-    /**
-     * A Compendium pack name
-     */
-    pack?: string | undefined;
-
-    /**
-     * The type of parent document
-     */
-    parentType?: string | undefined;
-
-    /**
-     * The ID of a parent document
-     */
-    parentId?: string | undefined;
-
-    /**
-     * Additional options applied to the request
-     */
+    /** Additional options applied to the request */
     options?: Record<string, unknown> | undefined;
+    broadcast?: boolean | undefined;
   }
 
   interface SocketResponse {
diff --git a/src/foundry/common/utils/string-tree.d.mts b/src/foundry/common/utils/string-tree.d.mts
index f99fc9b5b..f113ec0ee 100644
--- a/src/foundry/common/utils/string-tree.d.mts
+++ b/src/foundry/common/utils/string-tree.d.mts
@@ -33,6 +33,8 @@ declare class StringTree<EntryType> {
     options?: InexactPartial<{
       /** The maximum number of items to retrieve. */
       limit: number;
+      /** A filter function to apply to each candidate entry. */
+      filterEntries?: StringTree.StringTreeEntryFilter | undefined;
     }>,
   ): StringTree.StringTreeNode[];
 
@@ -82,6 +84,12 @@ declare namespace StringTree {
     [StringTree.leaves]: Record<string, unknown>[];
     [key: string]: StringTreeNode;
   }
+
+  /**
+   * @param entry   - The entry to filter.
+   * @returns Whether the entry should be included in the result set.
+   */
+  type StringTreeEntryFilter = (entry: unknown) => boolean;
 }
 
 export default StringTree;
diff --git a/src/foundry/common/utils/word-tree.d.mts b/src/foundry/common/utils/word-tree.d.mts
index 6537b63aa..7fc92ad2d 100644
--- a/src/foundry/common/utils/word-tree.d.mts
+++ b/src/foundry/common/utils/word-tree.d.mts
@@ -26,11 +26,14 @@ declare class WordTree extends StringTree<WordTree.WordTreeEntry> {
     prefix: string,
     options?: InexactPartial<{
       /**
-       * The maximum number of items to retrieve. Defaults to 10. It is important
+       * The maximum number of items to retrieve. It is important
        * to set this value as very short prefixes will naturally match large numbers
        * of entries.
+       * (default: `10`)
        */
       limit: number;
+      /** A filter function to apply to each candidate entry. */
+      filterEntries?: StringTree.StringTreeEntryFilter | undefined;
     }>,
   ): WordTree.WordTreeEntry[];
   lookup(strings: string[], options?: InexactPartial<{ limit: number }>): StringTree.StringTreeNode[];


Test patch:
diff --git a/tests/foundry/client/core/document-index.test-d.ts b/tests/foundry/client/core/document-index.test-d.ts
new file mode 100644
index 000000000..fb61f4ef9
--- /dev/null
+++ b/tests/foundry/client/core/document-index.test-d.ts
@@ -0,0 +1,16 @@
+import { expectTypeOf } from "vitest";
+
+const docindex = new DocumentIndex();
+
+expectTypeOf(docindex.trees).toEqualTypeOf<Record<string, foundry.utils.WordTree>>();
+expectTypeOf(docindex.uuids).toEqualTypeOf<Record<string, foundry.utils.StringTree.StringTreeNode>>();
+expectTypeOf(docindex.ready).toEqualTypeOf<Promise<void> | null>();
+expectTypeOf(docindex.index()).toEqualTypeOf<Promise<void>>();
+
+expectTypeOf(docindex.lookup("")).toEqualTypeOf<Record<string, foundry.utils.WordTree.WordTreeEntry[]>>();
+
+declare const doc: JournalEntry;
+
+expectTypeOf(docindex.addDocument(doc)).toEqualTypeOf<void>();
+expectTypeOf(docindex.removeDocument(doc)).toEqualTypeOf<void>();
+expectTypeOf(docindex.replaceDocument(doc)).toEqualTypeOf<void>();
diff --git a/tests/foundry/client/core/issues.test-d.ts b/tests/foundry/client/core/issues.test-d.ts
new file mode 100644
index 000000000..0df1b8914
--- /dev/null
+++ b/tests/foundry/client/core/issues.test-d.ts
@@ -0,0 +1,13 @@
+import { expectTypeOf } from "vitest";
+import type { DocumentType } from "../../../../src/types/helperTypes.d.mts";
+import type { DataModelValidationError } from ",,/../../src/foundry/common/data/validation-failure.d.mts";
+
+const issues = new ClientIssues();
+
+expectTypeOf(issues.getSubTypeCountsFor("")).toEqualTypeOf<ModuleSubTypeCounts | undefined>();
+expectTypeOf(issues.getAllSubtypeCounts()).toEqualTypeOf<IterableIterator<[string, ModuleSubTypeCounts]>>();
+expectTypeOf(issues.usabilityIssues).toEqualTypeOf<Record<string, ClientIssues.UsabilityIssue>>();
+expectTypeOf(issues.packageCompatibilityIssues).toEqualTypeOf<{ error: string[]; warning: string[] }>();
+expectTypeOf(issues.validationFailures).toEqualTypeOf<
+  Record<DocumentType, Record<string, { name: string; error: DataModelValidationError }>>
+>();
diff --git a/tests/foundry/client/core/keybindings.test-d.ts b/tests/foundry/client/core/keybindings.test-d.ts
new file mode 100644
index 000000000..aaca5e90a
--- /dev/null
+++ b/tests/foundry/client/core/keybindings.test-d.ts
@@ -0,0 +1,19 @@
+import { expectTypeOf } from "vitest";
+
+const keybindings = new ClientKeybindings();
+
+expectTypeOf(keybindings.actions).toEqualTypeOf<Map<string, KeybindingActionConfig>>();
+expectTypeOf(keybindings.activeKeys).toEqualTypeOf<Map<string, KeybindingAction[]>>();
+expectTypeOf(keybindings.bindings).toEqualTypeOf<Map<string, KeybindingActionBinding[]> | undefined>();
+expectTypeOf(keybindings.moveKeys).toEqualTypeOf<Set<string>>();
+expectTypeOf(keybindings.initialize()).toEqualTypeOf<void>();
+
+declare const kbac: KeybindingActionConfig;
+
+expectTypeOf(keybindings.register("", "", kbac)).toEqualTypeOf<void>();
+expectTypeOf(keybindings.get("", "")).toEqualTypeOf<KeybindingActionBinding[]>();
+expectTypeOf(keybindings.set("", "")).toEqualTypeOf<Promise<void>>();
+expectTypeOf(keybindings.resetDefaults()).toEqualTypeOf<Promise<void>>();
+
+expectTypeOf(ClientKeybindings.MOVEMENT_DIRECTIONS).toEqualTypeOf<ClientKeybindings.MovementDirections>();
+expectTypeOf(ClientKeybindings.ZOOM_DIRECTIONS).toEqualTypeOf<ClientKeybindings.ZoomDirections>();
diff --git a/tests/foundry/client/core/keyboard.test-d.ts b/tests/foundry/client/core/keyboard.test-d.ts
new file mode 100644
index 000000000..5d5e4edf4
--- /dev/null
+++ b/tests/foundry/client/core/keyboard.test-d.ts
@@ -0,0 +1,55 @@
+import { expectTypeOf } from "vitest";
+
+const keyboard = new KeyboardManager();
+
+expectTypeOf(keyboard.downKeys).toEqualTypeOf<Set<string>>();
+expectTypeOf(keyboard.moveKeys).toEqualTypeOf<Set<string>>();
+expectTypeOf(keyboard.hasFocus).toEqualTypeOf<boolean>();
+expectTypeOf(keyboard.isModifierActive("")).toEqualTypeOf<boolean>();
+expectTypeOf(keyboard.isCoreActionKeyActive("")).toEqualTypeOf<boolean>();
+expectTypeOf(keyboard.releaseKeys()).toEqualTypeOf<void>();
+
+expectTypeOf(KeyboardManager.MODIFIER_KEYS).toEqualTypeOf<{
+  CONTROL: "Control";
+  SHIFT: "Shift";
+  ALT: "Alt";
+}>();
+expectTypeOf(KeyboardManager.MODIFIER_CODES).toEqualTypeOf<{
+  Alt: ["AltLeft", "AltRight"];
+  Control: ["ControlLeft", "ControlRight", "MetaLeft", "MetaRight", "Meta", "OsLeft", "OsRight"];
+  Shift: ["ShiftLeft", "ShiftRight"];
+}>();
+expectTypeOf(KeyboardManager.PROTECTED_KEYS).toEqualTypeOf<
+  ["F5", "F11", "F12", "PrintScreen", "ScrollLock", "NumLock", "CapsLock"]
+>();
+expectTypeOf(KeyboardManager.CONTROL_KEY_STRING).toEqualTypeOf<"⌘" | "Control">();
+expectTypeOf(KeyboardManager.KEYCODE_DISPLAY_MAPPING).toEqualTypeOf<{
+  ArrowLeft: "←" | "🡸";
+  ArrowRight: "→" | "🡺";
+  ArrowUp: "↑" | "🡹";
+  ArrowDown: "↓" | "🡻";
+  Backquote: "`";
+  Backslash: "\\";
+  BracketLeft: "[";
+  BracketRight: "]";
+  Comma: ",";
+  Control: (typeof KeyboardManager)["CONTROL_KEY_STRING"];
+  Equal: "=";
+  Meta: "⌘" | "⊞";
+  MetaLeft: "⌘" | "⊞";
+  MetaRight: "⌘" | "⊞";
+  OsLeft: "⌘" | "⊞";
+  OsRight: "⌘" | "⊞";
+  Minus: "-";
+  NumpadAdd: "Numpad+";
+  NumpadSubtract: "Numpad-";
+  Period: ".";
+  Quote: "'";
+  Semicolon: ";";
+  Slash: "/";
+}>();
+expectTypeOf(KeyboardManager.emulateKeypress(true, "")).toEqualTypeOf<KeyboardEventContext>();
+expectTypeOf(KeyboardManager.getKeycodeDisplayString("")).toEqualTypeOf<string>();
+
+declare const event: KeyboardEvent;
+expectTypeOf(KeyboardManager.getKeyboardEventContext(event, true)).toEqualTypeOf<KeyboardEventContext>();
diff --git a/tests/foundry/client/core/socket.test-d.ts b/tests/foundry/client/core/socket.test-d.ts
new file mode 100644
index 000000000..56afb82a7
--- /dev/null
+++ b/tests/foundry/client/core/socket.test-d.ts
@@ -0,0 +1,8 @@
+import { expectTypeOf } from "vitest";
+import type { DocumentSocketRequest } from "../../../../src/foundry/common/abstract/_types.d.mts";
+
+declare const request: DocumentSocketRequest<"get">;
+declare const request2: ManageCompendiumRequest;
+
+expectTypeOf(SocketInterface.dispatch("", request)).toEqualTypeOf<Promise<SocketResponse>>();
+expectTypeOf(SocketInterface.dispatch("", request2)).toEqualTypeOf<Promise<SocketResponse>>();
diff --git a/tests/foundry/client/core/workers.test-d.ts b/tests/foundry/client/core/workers.test-d.ts
new file mode 100644
index 000000000..bac0052d8
--- /dev/null
+++ b/tests/foundry/client/core/workers.test-d.ts
@@ -0,0 +1,23 @@
+import { expectTypeOf } from "vitest";
+
+const asyncWorker = new AsyncWorker("");
+
+expectTypeOf(asyncWorker.name).toEqualTypeOf<string>();
+expectTypeOf(asyncWorker.ready).toEqualTypeOf<Promise<void>>();
+expectTypeOf(asyncWorker.loadFunction("", () => null)).toEqualTypeOf<Promise<unknown>>();
+expectTypeOf(asyncWorker.executeFunction("")).toEqualTypeOf<Promise<unknown>>();
+
+expectTypeOf(AsyncWorker.WORKER_HARNESS_JS).toEqualTypeOf<string>();
+
+const manager = new WorkerManager();
+
+expectTypeOf(manager.createWorker("")).toEqualTypeOf<Promise<AsyncWorker>>();
+expectTypeOf(manager.retireWorker("")).toEqualTypeOf<void>();
+
+expectTypeOf(WorkerManager.WORKER_TASK_ACTIONS).toEqualTypeOf<
+  Readonly<{
+    INIT: "init";
+    LOAD: "load";
+    EXECUTE: "execute";
+  }>
+>();
diff --git a/tests/foundry/common/utils/word-tree.mjs.test-d.ts b/tests/foundry/common/utils/word-tree.mjs.test-d.ts
index 580d546a6..c910b07db 100644
--- a/tests/foundry/common/utils/word-tree.mjs.test-d.ts
+++ b/tests/foundry/common/utils/word-tree.mjs.test-d.ts
@@ -3,6 +3,7 @@ import { expectTypeOf } from "vitest";
 const w = new foundry.utils.WordTree();
 declare const entry: foundry.utils.WordTree.WordTreeEntry;
 
-expectTypeOf(w.addLeaf("a", entry)).toEqualTypeOf<foundry.utils.WordTree.WordTreeEntry>();
+expectTypeOf(w.addLeaf("a", entry)).toEqualTypeOf<foundry.utils.StringTree.StringTreeNode>();
+expectTypeOf(w.addLeaf(["a"], entry)).toEqualTypeOf<foundry.utils.StringTree.StringTreeNode>();
 expectTypeOf(w.lookup("a", { limit: 4 })).toEqualTypeOf<foundry.utils.WordTree.WordTreeEntry[]>();
 expectTypeOf(w.nodeAtPrefix("a")).toEqualTypeOf<foundry.utils.WordTree.WordTreeEntry>();