Repository: League-of-Foundry-Developers/foundry-vtt-types
Pull request #2616 (2024-07-09 21:47:45)

client-esm.helpers.compendium-art
Solves #2614.


Patch:
diff --git a/src/foundry/client-esm/data/client-backend.d.mts b/src/foundry/client-esm/data/client-backend.d.mts
index 8435bf6f7..768b01460 100644
--- a/src/foundry/client-esm/data/client-backend.d.mts
+++ b/src/foundry/client-esm/data/client-backend.d.mts
@@ -1,31 +1,38 @@
 import type { ConstructorOf } from "../../../types/utils.d.mts";
-import type { RequestContext } from "../../common/abstract/backend.d.mts";
 import type Document from "../../common/abstract/document.d.mts";
+import type {
+  DatabaseGetOperation,
+  DatabaseCreateOperation,
+  DatabaseUpdateOperation,
+  DatabaseDeleteOperation,
+} from "../../common/abstract/_types.mjs";
+import type { LoggingLevels } from "../../../types/helperTypes.d.mts";
+
 /**
  * The client-side database backend implementation which handles Document modification operations.
  */
 declare class ClientDatabaseBackend extends foundry.abstract.DatabaseBackend {
   protected override _getDocuments<T extends Document<any, any, any>>(
     documentClass: ConstructorOf<T>,
-    request: RequestContext<T>,
+    request: DatabaseGetOperation,
     user: User.ConfiguredInstance,
   ): Promise<T[]>;
 
   protected override _createDocuments<T extends Document<any, any, any>>(
     documentClass: ConstructorOf<T>,
-    request: RequestContext<T>,
+    request: DatabaseCreateOperation<T>,
     user: User.ConfiguredInstance,
   ): Promise<T[]>;
 
   protected override _updateDocuments<T extends Document<any, any, any>>(
     documentClass: ConstructorOf<T>,
-    request: RequestContext<T>,
+    request: DatabaseUpdateOperation<T>,
     user: User.ConfiguredInstance,
   ): Promise<T[]>;
 
   protected override _deleteDocuments<T extends Document<any, any, any>>(
     documentClass: ConstructorOf<T>,
-    request: RequestContext<T>,
+    request: DatabaseDeleteOperation,
     user: User.ConfiguredInstance,
   ): Promise<T[]>;
 
@@ -39,7 +46,7 @@ declare class ClientDatabaseBackend extends foundry.abstract.DatabaseBackend {
 
   override getCompendiumScopes(): string[];
 
-  // TODO: _log
+  protected override _log(level: LoggingLevels, message: string): void;
 }
 
 export default ClientDatabaseBackend;
diff --git a/src/foundry/client-esm/helpers/_types.d.mts b/src/foundry/client-esm/helpers/_types.d.mts
index 5ee346db8..73ea4f170 100644
--- a/src/foundry/client-esm/helpers/_types.d.mts
+++ b/src/foundry/client-esm/helpers/_types.d.mts
@@ -1,5 +1,51 @@
-export interface CompendiumArtInfo {}
+import type { SchemaField } from "../../common/data/fields.d.mts";
+import type { PrototypeToken } from "../data/_module.d.mts";
 
+export interface CompendiumArtInfo {
+  /**
+   * The path to the Actor's portrait image.
+   */
+  actor?: string | undefined;
+
+  /**
+   * The path to the token image, or an object to merge into the Actor's prototype token.
+   */
+  token?: string | SchemaField.InnerAssignmentType<PrototypeToken.Schema> | undefined;
+
+  /**
+   *An optional credit string for use by the game system to apply in an appropriate place.
+   */
+  credit?: string | undefined;
+}
+
+/**
+ * A mapping of compendium pack IDs to Document IDs to art information.
+ */
 export type CompendiumArtMapping = Record<string, Record<string, CompendiumArtInfo>>;
 
-export interface CompendiumArtDescriptor {}
+export interface CompendiumArtDescriptor {
+  /**
+   * The ID of the package providing the art.
+   */
+  packageId: string;
+
+  /**
+   * The title of the package providing the art.
+   */
+  title: string;
+
+  /**
+   * The path to the art mapping file.
+   */
+  mapping: string;
+
+  /**
+   * An optional credit string for use by the game system to apply in an appropriate place.
+   */
+  credit?: string | undefined;
+
+  /**
+   * The package's user-configured priority.
+   */
+  priority: number;
+}
diff --git a/src/foundry/client-esm/helpers/compendium-art.d.mts b/src/foundry/client-esm/helpers/compendium-art.d.mts
index b7c4cb8be..151f109ca 100644
--- a/src/foundry/client-esm/helpers/compendium-art.d.mts
+++ b/src/foundry/client-esm/helpers/compendium-art.d.mts
@@ -1,3 +1,47 @@
-declare class CompendiumArt extends Map {}
+import type { CompendiumArtDescriptor, CompendiumArtInfo, CompendiumArtMapping } from "./_types.d.mts";
+
+/**
+ * A class responsible for managing package-provided art and applying it to Documents in compendium packs.
+ */
+declare class CompendiumArt extends Map<string, CompendiumArtInfo> {
+  /**
+   * The key for the package manifest flag used to store the mapping information.
+   * @defaultValue `"compendiumArtMappings"`
+   */
+  readonly FLAG: string;
+
+  /**
+   * The key for the setting used to store the World's art preferences.
+   * @defaultValue `"compendiumArtConfiguration"`
+   */
+  readonly SETTING: string;
+
+  /**
+   * Whether art application is enabled. This should be switched off when performing client-side compendium migrations
+   * in order to avoid persisting injected data.
+   * @defaultValue `true`
+   */
+  enabled: boolean;
+
+  /**
+   * Retrieve all active packages that provide art mappings in priority order.
+   */
+  getPackages(): CompendiumArtDescriptor[];
+
+  /**
+   * Collate Document art mappings from active packages.
+   * @internal
+   */
+  _registerArt(): Promise<void>;
+
+  /**
+   * Parse a provided art mapping and store it for reference later, and update compendium indices to use the provided
+   * art.
+   * @param packageId - The ID of the package providing the mapping.
+   * @param mapping   - The art mapping information provided by the package.
+   * @param credit    - An optional credit string for use by the game system to apply in an appropriate place.
+   */
+  #parseArtMapping(packageId: string, mapping: CompendiumArtMapping, credit?: string): Promise<void>;
+}
 
 export default CompendiumArt;
diff --git a/src/foundry/common/abstract/_types.d.mts b/src/foundry/common/abstract/_types.d.mts
new file mode 100644
index 000000000..63ea518bd
--- /dev/null
+++ b/src/foundry/common/abstract/_types.d.mts
@@ -0,0 +1,248 @@
+export interface DatabaseGetOperation {
+  /**
+   * A query object which identifies the set of Documents retrieved
+   */
+  query: Record<string, any>;
+
+  /**
+   * Get requests are never broadcast
+   */
+  broadcast?: false | undefined;
+
+  /**
+   * Return indices only instead of full Document records
+   */
+  index?: boolean | undefined;
+
+  /**
+   * An array of field identifiers which should be indexed
+   */
+  indexFields?: string[] | undefined;
+
+  /**
+   * A compendium collection ID which contains the Documents
+   */
+  pack?: string | null | undefined;
+
+  /**
+   * A parent Document within which Documents are embedded
+   */
+  parent?: foundry.abstract.Document.Any | undefined;
+
+  /**
+   * A parent Document UUID provided when the parent instance is unavailable
+   */
+  parentUuid?: string | undefined;
+}
+
+export interface DatabaseCreateOperation<T extends foundry.abstract.Document.Any = foundry.abstract.Document.Any> {
+  /**
+   * Whether the database operation is broadcast to other connected clients
+   */
+  broadcast: boolean;
+
+  /**
+   * An array of data objects from which to create Documents
+   */
+  data: foundry.data.fields.SchemaField.InnerAssignmentType<T["schema"]["fields"]>[];
+
+  /**
+   * Retain the _id values of provided data instead of generating new ids
+   */
+  keepId?: boolean | undefined;
+
+  /**
+   * Retain the _id values of embedded document data instead of generating
+   *    new ids for each embedded document
+   */
+  keepEmbeddedIds?: boolean | undefined;
+
+  /**
+   * The timestamp when the operation was performed
+   */
+  modifiedTime?: number | undefined;
+
+  /**
+   * Block the dispatch of hooks related to this operation
+   */
+  noHook?: boolean | undefined;
+
+  /**
+   * Re-render Applications whose display depends on the created Documents
+   */
+  render?: boolean | undefined;
+
+  /**
+   * Render the sheet Application for any created Documents
+   */
+  renderSheet?: boolean | undefined;
+
+  /**
+   * A parent Document within which Documents are embedded
+   */
+  parent?: foundry.abstract.Document.Any | undefined;
+
+  /**
+   * A compendium collection ID which contains the Documents
+   */
+  pack: string | null;
+
+  /**
+   * A parent Document UUID provided when the parent instance is unavailable
+   */
+  parentUuid?: string | null | undefined;
+
+  /**
+   * An alias for 'data' used internally by the server-side backend
+   */
+  _result?: (string | Record<string, unknown>)[] | undefined;
+}
+
+export interface DatabaseUpdateOperation<T extends foundry.abstract.Document.Any = foundry.abstract.Document.Any> {
+  /**
+   * Whether the database operation is broadcast to other connected clients
+   */
+  broadcast: boolean;
+
+  /**
+   * An array of data objects used to update existing Documents.
+   * Each update object must contain the _id of the target Document
+   */
+  updates: foundry.data.fields.SchemaField.InnerAssignmentType<T["schema"]["fields"]>[];
+
+  /**
+   * Difference each update object against current Document data and only use
+   * differential data for the update operation
+   */
+  diff?: boolean | undefined;
+
+  /**
+   * The timestamp when the operation was performed
+   */
+  modifiedTime?: number | undefined;
+
+  /**
+   * Merge objects recursively. If false, inner objects will be replaced
+   * explicitly. Use with caution!
+   */
+  recursive?: boolean | undefined;
+
+  /**
+   * Re-render Applications whose display depends on the created Documents
+   */
+  render?: boolean | undefined;
+
+  /**
+   * Block the dispatch of hooks related to this operation
+   */
+  noHook?: boolean | undefined;
+
+  /**
+   * A parent Document within which Documents are embedded
+   */
+  parent?: foundry.abstract.Document.Any | undefined;
+
+  /**
+   * A compendium collection ID which contains the Documents
+   */
+  pack: string | null;
+
+  /**
+   * A parent Document UUID provided when the parent instance is unavailable
+   */
+  parentUuid?: string | null | undefined;
+
+  /**
+   * An alias for 'updates' used internally by the server-side backend
+   */
+  _result?: (string | Record<string, unknown>)[] | undefined;
+}
+
+export interface DatabaseDeleteOperation {
+  /**
+   * Whether the database operation is broadcast to other connected clients
+   */
+  broadcast: boolean;
+
+  /**
+   * An array of Document ids which should be deleted
+   */
+  ids: string[];
+
+  /**
+   * Delete all documents in the Collection, regardless of _id
+   */
+  deleteAll?: boolean | undefined;
+
+  /**
+   * The timestamp when the operation was performed
+   */
+  modifiedTime?: number | undefined;
+
+  /**
+   * Block the dispatch of hooks related to this operation
+   */
+  noHook?: boolean | undefined;
+
+  /**
+   * Re-render Applications whose display depends on the deleted Documents
+   */
+  render?: boolean | undefined;
+
+  /**
+   * A parent Document within which Documents are embedded
+   */
+  parent?: foundry.abstract.Document.Any | undefined;
+
+  /**
+   * A compendium collection ID which contains the Documents
+   */
+  pack: string | null;
+
+  /**
+   * A parent Document UUID provided when the parent instance is unavailable
+   */
+  parentUuid?: string | null | undefined;
+
+  /**
+   * An alias for 'ids' used internally by the server-side backend
+   */
+  _result?: (string | Record<string, unknown>)[] | undefined;
+}
+
+export type DatabaseOperationMap = {
+  get: DatabaseGetOperation;
+  create: DatabaseCreateOperation;
+  update: DatabaseUpdateOperation;
+  delete: DatabaseDeleteOperation;
+};
+
+export type DatabaseAction = keyof DatabaseOperationMap;
+export type DatabaseOperation = DatabaseOperationMap[keyof DatabaseOperationMap];
+
+export interface DocumentSocketRequest<Action extends DatabaseAction> {
+  /**
+   * The type of Document being transacted
+   */
+  type: string;
+
+  /**
+   * The action of the request
+   */
+  action: Action;
+
+  /**
+   * Operation parameters for the request
+   */
+  operation: DatabaseOperationMap[Action];
+
+  /**
+   * The id of the requesting User
+   */
+  userId: string;
+
+  /**
+   * Should the response be broadcast to other connected clients?
+   */
+  broadcast: boolean;
+}
diff --git a/src/foundry/common/abstract/backend.d.mts b/src/foundry/common/abstract/backend.d.mts
index d7aa0bb54..8f132eece 100644
--- a/src/foundry/common/abstract/backend.d.mts
+++ b/src/foundry/common/abstract/backend.d.mts
@@ -1,173 +1,136 @@
-import type { ConstructorOf } from "../../../types/utils.d.mts";
+import type { ConstructorOf, InexactPartial } from "../../../types/utils.d.mts";
 import type BaseUser from "../documents/user.d.mts";
 import type Document from "./document.d.mts";
+import type {
+  DatabaseCreateOperation,
+  DatabaseDeleteOperation,
+  DatabaseGetOperation,
+  DatabaseOperation,
+  DatabaseUpdateOperation,
+} from "./_types.mjs";
+import type { LoggingLevels } from "../../../types/helperTypes.d.mts";
 
 /**
- * An interface shared by both the client and server-side which defines how creation, update, and deletion operations are transacted.
+ * An abstract base class extended on both the client and server which defines how Documents are retrieved, created,
+ * updated, and deleted.
  */
 declare abstract class DatabaseBackend {
   /**
-   * Retrieve Documents based on provided query parameters
+   * Retrieve Documents based on provided query parameters.
    * @param documentClass - The Document definition
-   * @param context       - Context for the requested operation
+   * @param operation     - Parameters of the get operation
    * @param user          - The requesting User
-   * @returns The created Document instances
+   * @returns An array of retrieved Document instances or index objects
    */
-  get<T extends Document<any, any, any>>(
+  get<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    context: RequestContext<T>,
+    operation: DatabaseGetOperation,
     user?: BaseUser,
   ): Promise<T>[];
 
   /**
-   * Validate the arguments passed to the get operation
-   * @param context - The requested operation
+   * Retrieve Document instances using the specified operation parameters.
+   * @param documentClass  - The Document class definition
+   * @param operation      - Parameters of the get operation
+   * @param user           - The requesting User
+   * @returns An array of retrieved Document instances or index objects
    */
-  protected _getArgs<T extends Document<any, any, any>>(
-    context?: RequestContext<T>,
-  ): {
-    query: object;
-    options: RequestOptions;
-    pack?: string;
-    parent: ReturnType<DatabaseBackend["_getParent"]>;
-    parentUuid: string | undefined;
-  };
-
-  /**
-   * Get primary Document instances
-   * @remarks
-   * foundry actually declares this function to take parameters `documentClass`, `query`, `options`, and `user` but
-   * that's not how it is called and also not how the subclasses implement it.
-   * See https://gitlab.com/foundrynet/foundryvtt/-/issues/6177
-   */
-  protected abstract _getDocuments<T extends Document<any, any, any>>(
+  protected abstract _getDocuments<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    request: RequestContext<T>,
-    user: BaseUser,
+    operation: DatabaseGetOperation,
+    user?: BaseUser,
   ): Promise<T[]>;
 
   /**
-   * Get the parent Document (if any) associated with a request
-   * @param context - The requested operation
-   * @returns The parent Document, or null
-   */
-  protected _getParent<T extends Document<any, any, any>>(
-    context: RequestContext<T>,
-  ): Promise<Document<any, any, any> | undefined>;
-
-  /**
-   * Perform document creation operations
-   * @param documentClass - The Document definition
-   * @param context       - Context for the requested operation
+   * Create new Documents using provided data and context.
+   * It is recommended to use {@link Document.createDocuments} or {@link Document.create} rather than calling this
+   * method directly.
+   * @param documentClass - The Document class definition
+   * @param operation     - Parameters of the create operation
    * @param user          - The requesting User
-   * @returns The created Document instances
+   * @returns An array of created Document instances
    */
-  create<T extends Document<any, any, any>>(
+  create<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    context: RequestContext<T>,
+    operation: DatabaseCreateOperation<T>,
     user?: BaseUser,
   ): Promise<T[]>;
 
   /**
-   * Validate the arguments passed to the create operation
-   * @param context - The requested operation
-   */
-  protected _createArgs<T extends Document<any, any, any>>({
-    data,
-    options,
-    pack,
-    parentUuid,
-  }?: RequestContext<T>): {
-    data: T["_source"][];
-    options: RequestOptions;
-    pack?: string;
-    parent: ReturnType<DatabaseBackend["_getParent"]>;
-    parentUuid: string | undefined;
-  };
-
-  /**
-   * Create primary Document instances
+   * Create Document instances using provided data and operation parameters.
+   * @param documentClass - The Document class definition
+   * @param operation     - Parameters of the create operation
+   * @param user          - The requesting User
+   * @returns An array of created Document instances
    */
-  protected abstract _createDocuments<T extends Document<any, any, any>>(
+  protected abstract _createDocuments<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    context: RequestContext<T>,
-    user: BaseUser,
+    operation: DatabaseCreateOperation<T>,
+    user?: BaseUser,
   ): Promise<T[]>;
 
   /**
-   * Perform document update operations
-   * @param documentClass - The Document definition
-   * @param context       - Context for the requested operation
+   * Update Documents using provided data and context.
+   * It is recommended to use {@link Document.updateDocuments} or {@link Document#update} rather than calling this
+   * method directly.
+   * @param documentClass - The Document class definition
+   * @param operation     - Parameters of the update operation
    * @param user          - The requesting User
-   * @returns The updated Document instances
+   * @returns  An array of updated Document instances
    */
-  update<T extends Document<any, any, any>>(
+  update<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    context: RequestContext<T>,
+    operation: DatabaseUpdateOperation<T>,
     user?: BaseUser,
   ): Promise<T[]>;
 
   /**
-   * Validate the arguments passed to the update operation
-   */
-  protected _updateArgs<T extends Document<any, any, any>>({
-    updates,
-    options,
-    pack,
-    parentUuid,
-  }?: RequestContext<T>): {
-    updates: T["_source"][];
-    options: RequestOptions;
-    pack?: string;
-    parent: ReturnType<DatabaseBackend["_getParent"]>;
-    parentUuid: string | undefined;
-  };
-
-  /**
-   * Update primary Document instances
+   * Update Document instances using provided data and operation parameters.
+   * @param documentClass - The Document class definition
+   * @param operation     - Parameters of the update operation
+   * @param user          - The requesting User
+   * @returns  An array of updated Document instances
    */
-  protected abstract _updateDocuments<T extends Document<any, any, any>>(
+  protected abstract _updateDocuments<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    request: RequestContext<T>,
+    operation: DatabaseUpdateOperation<T>,
     user: BaseUser,
   ): Promise<T[]>;
 
   /**
-   * Perform document deletion operations
-   * @param documentClass - The Document definition
-   * @param context       - Context for the requested operation
+   * Delete Documents using provided ids and context.
+   * It is recommended to use {@link foundry.abstract.Document.deleteDocuments} or
+   * {@link foundry.abstract.Document#delete} rather than calling this method directly.
+   * @param documentClass - The Document class definition
+   * @param operation     - Parameters of the delete operation
    * @param user          - The requesting User
    * @returns The deleted Document instances
    */
-  delete<T extends Document<any, any, any>>(
+  delete<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    context: RequestContext<T>,
+    operation: DatabaseDeleteOperation,
     user?: BaseUser,
   ): Promise<T[]>;
 
   /**
-   * Validate the arguments passed to the delete operation
-   * @param request - The requested operation
-   */
-  protected _deleteArgs<T extends Document<any, any, any>>(
-    context?: RequestContext<T>,
-  ): {
-    ids: string[];
-    options: RequestOptions;
-    pack?: string;
-    parent: ReturnType<DatabaseBackend["_getParent"]>;
-    parentUuid: string | undefined;
-  };
-
-  /**
-   * Delete primary Document instances
+   * Delete Document instances using provided ids and operation parameters.
+   * @param documentClass - The Document class definition
+   * @param operation     - Parameters of the delete operation
+   * @param user          - The requesting User
    */
-  protected abstract _deleteDocuments<T extends Document<any, any, any>>(
+  protected abstract _deleteDocuments<T extends Document.Any>(
     documentClass: ConstructorOf<T>,
-    request: RequestContext<T>,
+    operation: DatabaseDeleteOperation,
     user: BaseUser,
   ): Promise<T[]>;
 
+  /**
+   * Get the parent Document (if any) associated with a request context.
+   * @param operation - The requested database operation
+   * @returns The parent Document, or null
+   */
+  _getParent(operation: DatabaseOperation): Promise<Document.Any | null>;
+
   /**
    * Describe the scopes which are suitable as the namespace for a flag key
    */
@@ -179,9 +142,11 @@ declare abstract class DatabaseBackend {
   getCompendiumScopes(): string[];
 
   /**
-   * Provide the Logger implementation that should be used for database operations
+   * Log a database operations message.
+   * @param level   - The logging level
+   * @param message - The message
    */
-  protected _getLogger(): Console;
+  protected _log(level: LoggingLevels, message: string): void;
 
   /**
    * Log a database operation for an embedded document, capturing the action taken and relevant IDs
@@ -192,24 +157,24 @@ declare abstract class DatabaseBackend {
   protected _logOperation(
     action: string,
     type: string,
-    documents: Document<any, any, any>[],
+    documents: Document.Any[],
     {
       parent,
       pack,
       level,
-    }?: {
+    }?: InexactPartial<{
       /** A parent document */
-      parent?: Document<any, any, any>;
+      parent: Document.Any;
 
       /** A compendium pack within which the operation occurred */
-      pack?: string;
+      pack: string;
 
       /**
        * The logging level
        * @defaultValue `"info"`
        */
-      level?: string;
-    },
+      level: LoggingLevels;
+    }>,
   ): void;
 
   /**
@@ -218,53 +183,9 @@ declare abstract class DatabaseBackend {
   protected _logError(
     user: BaseUser,
     action: string,
-    subject: Document<any, any, any> | string,
-    { parent, pack }?: { parent?: Document<any, any, any>; pack?: string },
+    subject: Document.Any | string,
+    { parent, pack }?: { parent?: Document.Any; pack?: string },
   ): string;
-
-  /**
-   * Determine a string suffix for a log message based on the parent and/or compendium context.
-   */
-  protected _logContext({ parent, pack }?: { parent?: Document<any, any, any>; pack?: string }): string;
-}
-
-//TODO: Can improve the typing even further here by specifying the parent bit
-export interface RequestContext<T extends Document<any, any, any>> {
-  /** An array of document data */
-  data?: T["_source"][];
-
-  /** An array of document data */
-  updates?: T["_source"][];
-
-  /** An array of document ids */
-  ids?: string[];
-
-  parent?: Document<any, any, any>;
-
-  parentUuid?: string;
-
-  /**
-   * A document search query to execute
-   * @defaultValue `{}`
-   */
-  query?: Record<string, unknown>;
-
-  /**
-   * Operation options
-   * @defaultValue `{}`
-   */
-  options?: RequestOptions;
-
-  /** A Compendium pack identifier */
-  pack?: string;
-}
-
-export interface RequestOptions {
-  index?: boolean;
-  broadcast?: boolean;
-  temporary?: boolean;
-  nohook?: boolean;
-  [key: string]: unknown;
 }
 
 export default DatabaseBackend;
diff --git a/src/types/helperTypes.d.mts b/src/types/helperTypes.d.mts
index 21cf2a70b..e56059feb 100644
--- a/src/types/helperTypes.d.mts
+++ b/src/types/helperTypes.d.mts
@@ -96,3 +96,6 @@ export type LayerClass<T extends DocumentConstructor> = T["metadata"]["name"] ex
     ? CONFIG[T["metadata"]["name"]]["layerClass"]
     : never
   : T;
+
+/** Keys of functions of console.log / globalThis.logger */
+export type LoggingLevels = "debug" | "log" | "info" | "warn" | "error";


Test patch:
diff --git a/tests/foundry/client-esm/data/client-backend.mjs.test-d.ts b/tests/foundry/client-esm/data/client-backend.mjs.test-d.ts
new file mode 100644
index 000000000..022a42ade
--- /dev/null
+++ b/tests/foundry/client-esm/data/client-backend.mjs.test-d.ts
@@ -0,0 +1,15 @@
+import { expectTypeOf } from "vitest";
+
+const myBackend = new foundry.data.ClientDatabaseBackend();
+
+expectTypeOf(myBackend.create(Item, { data: [{ name: "foo" }], broadcast: true, pack: null })).toEqualTypeOf<
+  Promise<Item[]>
+>();
+
+expectTypeOf(myBackend.update(Actor, { updates: [{ name: "foo" }], broadcast: false, pack: null })).toEqualTypeOf<
+  Promise<Actor[]>
+>();
+
+expectTypeOf(myBackend.delete(Scene, { ids: [], broadcast: true, pack: "some.pack" })).toEqualTypeOf<
+  Promise<Scene[]>
+>();
diff --git a/tests/foundry/client-esm/helpers/compendium-art.test-d.ts b/tests/foundry/client-esm/helpers/compendium-art.test-d.ts
new file mode 100644
index 000000000..7c6dfc6d5
--- /dev/null
+++ b/tests/foundry/client-esm/helpers/compendium-art.test-d.ts
@@ -0,0 +1,18 @@
+import { expectTypeOf } from "vitest";
+import { types } from "../../../../src/foundry/client-esm/helpers/_module.mjs";
+
+const caInfo = { actor: "actorId", token: { randomImg: false }, credit: "Me" };
+expectTypeOf(caInfo).toMatchTypeOf<types.CompendiumArtInfo>;
+
+// @ts-expect-error Should reject object not matching prototype tokens schema
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const caError: types.CompendiumArtInfo = { token: { badKey: "1" } };
+
+const compendiumArt = new foundry.helpers.CompendiumArt([
+  ["test", caInfo],
+  ["2", { token: "a/path" }],
+]);
+expectTypeOf(compendiumArt.FLAG).toEqualTypeOf<string>;
+expectTypeOf(compendiumArt.SETTING).toEqualTypeOf<string>;
+expectTypeOf(compendiumArt.enabled).toEqualTypeOf<boolean>;
+expectTypeOf(compendiumArt.getPackages()).toEqualTypeOf<types.CompendiumArtDescriptor[]>;