UNPKG

fvtt-types

Version:
777 lines (635 loc) 25.9 kB
import type { GetKey, AnyObject, InexactPartial, AnyMutableObject, Identity, AnyArray, NullishProps } from "#utils"; import type DataModel from "../abstract/data.d.mts"; import type { ReleaseData } from "../config.d.mts"; import type * as fields from "../data/fields.d.mts"; import type { DataModelValidationFailure } from "../data/validation-failure.d.mts"; import type { BaseFolder } from "../documents/_module.d.mts"; import type { LogCompatibilityWarningOptions } from "../utils/logging.d.mts"; type DataSchema = foundry.data.fields.DataSchema; declare const __BasePackageBrand: unique symbol; declare const __PackageSchema: unique symbol; declare namespace BasePackage { interface Any extends AnyBasePackage {} interface AnyConstructor extends Identity<typeof AnyBasePackage> {} // Documented at https://gist.github.com/LukeAbby/c7420b053d881db4a4d4496b95995c98 namespace Internal { type Constructor = (abstract new (...args: never) => Instance.Any) & { [__BasePackageBrand]: never; }; interface Instance<PackageSchema extends BasePackage.Internal.Schema> { [__PackageSchema]: PackageSchema; } namespace Instance { interface Any extends Instance<BasePackage.Internal.Schema> {} } interface Schema extends Omit<BasePackage.Schema, "version"> {} } interface OptionalString { required: false; blank: false; initial: undefined; } interface PackageAuthorSchema extends DataSchema { /** * The author name */ name: fields.StringField<{ required: true; blank: false }>; /** * The author email address */ email: fields.StringField<OptionalString>; /** * A website url for the author */ url: fields.StringField<OptionalString>; /** * A Discord username for the author */ discord: fields.StringField<OptionalString>; flags: fields.ObjectField; } interface PackageMediaSchema extends DataSchema { /** Usage type for the media asset. "setup" means it will be used on the setup screen. */ type: fields.StringField<OptionalString>; /** A web url link to the media element. */ url: fields.StringField<OptionalString>; /** A caption for the media element. */ caption: fields.StringField<OptionalString>; /** Should the media play on loop? */ loop: fields.BooleanField<{ required: false; blank: false; initial: false }>; /** A link to the thumbnail for the media element. */ thumbnail: fields.StringField<OptionalString>; /** An object of optional key/value flags. */ flags: fields.ObjectField; } type OwnershipRecord = Record< keyof typeof foundry.CONST.USER_ROLES, keyof typeof foundry.CONST.DOCUMENT_OWNERSHIP_LEVELS | undefined >; interface PackageCompendiumSchema extends DataSchema { /** * The canonical compendium name. This should contain no spaces or special characters */ name: fields.StringField<{ required: true; blank: false; validate: (n: string) => boolean; validationError: "may not contain periods"; }>; /** * The human-readable compendium name */ label: fields.StringField<{ required: true; blank: false }>; banner: fields.StringField<OptionalString>; /** * The local relative path to the compendium source directory. The filename should match the name attribute */ path: fields.StringField<{ required: false }>; /** * The specific document type that is contained within this compendium pack */ type: fields.StringField<{ required: true; blank: false; choices: foundry.CONST.COMPENDIUM_DOCUMENT_TYPES[]; validationError: "must be a value in CONST.COMPENDIUM_DOCUMENT_TYPES"; }>; /** * Denote that this compendium pack requires a specific game system to function properly */ system: fields.StringField<OptionalString>; ownership: CompendiumOwnershipField; flags: fields.ObjectField; } interface PackageLanguageSchema extends DataSchema { /** * A string language code which is validated by Intl.getCanonicalLocales */ lang: fields.StringField<{ required: true; blank: false; // Foundry is using the truthiness of this function // validate: typeof Intl.getCanonicalLocales; validationError: "must be supported by the Intl.getCanonicalLocales function"; }>; /** * The human-readable language name */ name: fields.StringField<{ required: false }>; /** * The relative path to included JSON translation strings */ path: fields.StringField<{ required: true; blank: false }>; /** * Only apply this set of translations when a specific system is being used */ system: fields.StringField<OptionalString>; /** * Only apply this set of translations when a specific module is active */ module: fields.StringField<OptionalString>; flags: fields.ObjectField; } interface PackageCompatibilitySchema extends DataSchema { /** * The Package will not function before this version */ minimum: fields.StringField<{ required: false; blank: false; initial: undefined }>; /** * Verified compatible up to this version */ verified: fields.StringField<{ required: false; blank: false; initial: undefined }>; /** * The Package will not function after this version */ maximum: fields.StringField<{ required: false; blank: false; initial: undefined }>; } interface PackageRelationshipsSchema extends DataSchema { /** * Systems that this Package supports */ systems: fields.SetField<RelatedPackage<"system">>; /** * Packages that are required for base functionality */ requires: fields.SetField<RelatedPackage>; /** * Packages that are recommended for optimal functionality */ recommends: fields.SetField<RelatedPackage>; conflicts: fields.SetField<RelatedPackage>; flags: fields.ObjectField; } interface RelatedPackageSchema<PackageType extends foundry.CONST.PACKAGE_TYPES = foundry.CONST.PACKAGE_TYPES> extends DataSchema { /** * The id of the related package */ id: fields.StringField<{ required: true; blank: false }>; /** * The type of the related package */ type: fields.StringField<{ choices: PackageType[]; initial: "module" }>; /** * An explicit manifest URL, otherwise learned from the Foundry web server */ manifest: fields.StringField<{ required: false; blank: false; initial: undefined }>; /** * The compatibility data with this related Package */ compatibility: PackageCompatibility; /** * The reason for this relationship */ reason: fields.StringField<{ required: false; blank: false; initial: undefined }>; } /** @internal */ interface _PackageCompendiumFolderSchema extends DataSchema { /** Name for the folder. Multiple packages with identical folder names will merge by name. */ name: fields.StringField<{ required: true; blank: false }>; /** Alphabetical or manual sorting. */ sorting: fields.StringField<{ required: false; blank: false; initial: undefined; choices: typeof BaseFolder.SORTING_MODES; }>; /** A hex string for the pack's color. */ color: fields.ColorField; /** A list of the pack names to include in this folder. */ packs: fields.SetField<fields.StringField<{ required: true; blank: false }>>; } // Foundry starts Depth at 1 and increments from there type FolderRecursion = [never, 2, 3]; type PackageCompendiumFolderSchema<Depth> = Depth extends number ? _PackageCompendiumFolderSchema & { /** Nested folder data, up to three levels. */ folders: fields.SetField<fields.SchemaField<PackageCompendiumFolderSchema<FolderRecursion[Depth]>>>; } : _PackageCompendiumFolderSchema; interface CreateData extends fields.SchemaField.CreateData<Schema> {} interface Schema extends DataSchema { /** * The machine-readable unique package id, should be lower-case with no spaces or special characters */ id: fields.StringField<{ required: true; blank: false; validate: typeof BasePackage.validateId; }>; /** * The human-readable package title, containing spaces and special characters */ title: fields.StringField<{ required: true; blank: false }>; /** * An optional package description, may contain HTML */ description: fields.StringField<{ required: true }>; /** * An array of author objects who are co-authors of this package. Preferred to the singular author field. */ authors: fields.SetField<fields.SchemaField<PackageAuthorSchema>>; /** * A web url where more details about the package may be found */ url: fields.StringField<OptionalString>; /** * A web url or relative file path where license details may be found */ license: fields.StringField<OptionalString>; /** * A web url or relative file path where readme instructions may be found */ readme: fields.StringField<OptionalString>; /** * A web url where bug reports may be submitted and tracked */ bugs: fields.StringField<OptionalString>; /** * A web url where notes detailing package updates are available */ changelog: fields.StringField<OptionalString>; /** * An object of optional key/value flags. Packages can use this namespace for their own purposes, * preferably within a namespace matching their package ID. */ flags: fields.ObjectField; /** An array of objects containing media info about the package. */ media: fields.SetField<fields.SchemaField<PackageMediaSchema>>; // Moved to base-module and base-system to avoid conflict with base-world // version: fields.StringField<{ required: true; blank: false; initial: "0" }>; /** * The compatibility of this version with the core Foundry software. See https://foundryvtt.com/article/versioning/ * for more info on how the core software structures its releases. */ compatibility: PackageCompatibility; /** * An array of urls or relative file paths for JavaScript files to include */ scripts: fields.SetField<fields.StringField<{ required: true; blank: false }>>; /** * An array of urls or relative file paths for ESModule files to include */ esmodules: fields.SetField<fields.StringField<{ required: true; blank: false }>>; /** * An array of urls or relative file paths for CSS stylesheet files to include */ styles: fields.SetField<fields.StringField<{ required: true; blank: false }>>; /** * An array of language data objects which are included by this package */ languages: fields.SetField<fields.SchemaField<PackageLanguageSchema>>; /** * An array of compendium packs which are included by this package */ packs: PackageCompendiumPacks<fields.SchemaField<PackageCompendiumSchema>>; /** * An array of pack folders that will be initialized once per world. */ packFolders: fields.SetField<fields.SchemaField<PackageCompendiumFolderSchema<1>>>; /** * An organized object of relationships to other Packages */ relationships: PackageRelationships; /** * Whether to require a package-specific socket namespace for this package */ socket: fields.BooleanField; /** * A publicly accessible web URL which provides the latest available package manifest file. Required in order to support module updates. */ manifest: fields.StringField; /** * A publicly accessible web URL where the source files for this package may be downloaded. Required in order to support module installation. */ download: fields.StringField<{ required: false; blank: false; initial: undefined }>; /** * Whether this package uses the protected content access system. */ protected: fields.BooleanField; /** * Whether this package is a free Exclusive pack. */ exclusive: fields.BooleanField; /** * Whether updates should leave the contents of the package's /storage folder. */ persistentStorage: fields.BooleanField; } /** * @remarks Package flags do not operate under the same rules as Document flags * 1. They are constructed directly from the provided manifest.json files * 2. There are no helper getFlag/setFlag functions * 3. There is no enforced namespacing * 4. There are *many* layers that accept flags, rather than just the top level */ namespace Flags { /** * Flags used by the core software. * @remarks Flags for the top level of the schema. Notably *not* namespaced as "core..." */ interface Core { /** Can you upload to this package's folder using the built-in FilePicker. */ canUpload?: boolean | undefined; /** Configuration information for hot reload logic */ hotReload?: HotReloadConfig | undefined; /** * Mapping information for CompendiumArt. * Each key is a unique system ID, e.g. "dnd5e" or "pf2e". */ compendiumArtMappings?: Record<string, CompendiumArtFlag> | undefined; /** A mapping of token subject paths to configured subject images. */ tokenRingSubjectMappings?: Record<string, string> | undefined; } interface HotReloadConfig { /** A list of file extensions, e.g. `["css", "hbs", "json"]` */ extensions?: string[] | undefined; /** File paths to watch, e.g. `["src/styles", "templates", "lang"]` */ paths?: string[] | undefined; } interface CompendiumArtFlag { /** 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; } } interface PackageManifestData { availability: foundry.CONST.PACKAGE_AVAILABILITY_CODES; locked: boolean; exclusive: boolean; owned: boolean; tags: string[]; hasStorage: boolean; } /** @internal */ type _Installed = NullishProps<{ /** Is the package installed? */ installed: boolean; }>; interface LogOptions extends _Installed, InexactPartial<LogCompatibilityWarningOptions> {} interface MigrateDataOptions extends _Installed {} interface CleanDataOptions extends fields.DataField.CleanOptions { /** * Is the package installed? * @remarks Only used to pass on to {@link BasePackage._logWarning | `BasePackage#_logWarning`} */ installed?: boolean | null | undefined; } } /** * A custom SchemaField for defining package compatibility versions. */ export class PackageCompatibility extends fields.SchemaField<BasePackage.PackageCompatibilitySchema> { constructor(options: fields.SchemaField.Options<BasePackage.PackageCompatibilitySchema>); } /** * A custom SchemaField for defining package relationships. */ export class PackageRelationships extends fields.SchemaField<BasePackage.PackageRelationshipsSchema> { constructor(options: fields.SchemaField.Options<BasePackage.PackageRelationshipsSchema>); } // omitted private class PackageRelationshipField /** * A custom SchemaField for defining a related Package. * It may be required to be a specific type of package, by passing the packageType option to the constructor. */ export class RelatedPackage< PackageType extends foundry.CONST.PACKAGE_TYPES = foundry.CONST.PACKAGE_TYPES, > extends fields.SchemaField<BasePackage.RelatedPackageSchema<PackageType>> { constructor({ packageType, ...options }: InexactPartial<{ /** @defaultValue `"module"` */ packageType: PackageType; options: fields.SchemaField.Options<BasePackage.RelatedPackageSchema<PackageType>>; }>); } /** * A custom SchemaField for defining the folder structure of the included compendium packs. */ export class PackageCompendiumFolder<Depth extends number> extends fields.SchemaField< BasePackage.PackageCompendiumFolderSchema<Depth> > { constructor({ depth, ...options }: InexactPartial<{ /** @defaultValue `1` */ depth: Depth; options: fields.SchemaField.Options<BasePackage.PackageCompendiumFolderSchema<Depth>>; }>); } /** * A special ObjectField which captures a mapping of USER_ROLES to DOCUMENT_OWNERSHIP_LEVELS. */ export class CompendiumOwnershipField extends fields.ObjectField< fields.ObjectField.DefaultOptions, BasePackage.OwnershipRecord, BasePackage.OwnershipRecord, BasePackage.OwnershipRecord > { static override get _defaults(): { /** @defaultValue `{PLAYER: "OBSERVER", ASSISTANT: "OWNER"}` */ initial: BasePackage.OwnershipRecord; /** * @defaultValue `"is not a mapping of USER_ROLES to DOCUMENT_OWNERSHIP_LEVELS"` */ validationError: string; }; /** @remarks `options` is unused in `CompendiumOwnershipField` */ protected override _validateType( value: Record<keyof typeof foundry.CONST.USER_ROLES, keyof typeof foundry.CONST.DOCUMENT_OWNERSHIP_LEVELS>, options?: fields.DataField.ValidateOptions<this> | null, ): boolean | void; } /** * A special SetField which provides additional validation and initialization behavior specific to compendium packs. */ export class PackageCompendiumPacks< ElementFieldType extends fields.DataField.Any, > extends fields.SetField<ElementFieldType> { protected override _cleanType( value: Set<fields.ArrayField.InitializedElementType<ElementFieldType>>, options?: fields.DataField.CleanOptions, ): Set<fields.ArrayField.InitializedElementType<ElementFieldType>>; // options: not null (parameter default only) override initialize( value: fields.ArrayField.PersistedElementType<ElementFieldType>[], // In Foundry itself, this field is only used in `BasePackage`, however it should be able to accept any model. // NOTE(LukeAbby): This also has been seen in a circularity `Type of property 'packs' circularly references itself in mapped type ...`. model: DataModel.Any, options?: fields.DataField.InitializeOptions, ): | Set<fields.ArrayField.InitializedElementType<ElementFieldType>> | (() => Set<fields.ArrayField.InitializedElementType<ElementFieldType>> | null); protected override _validateElements( value: AnyArray, options?: fields.DataField.ValidateOptions<fields.DataField.Any>, ): void | DataModelValidationFailure; protected override _validateElement( value: unknown, options: fields.DataField.ValidateOptions<fields.DataField.Any>, ): void | DataModelValidationFailure; } /** * The data schema used to define a Package manifest. * Specific types of packages extend this schema with additional fields. */ declare class BasePackage< // BaseWorld alters the definition of `version` PackageSchema extends BasePackage.Internal.Schema = BasePackage.Schema, > extends DataModel<PackageSchema, null> { static [__BasePackageBrand]: never; [__PackageSchema]: PackageSchema; /** * An availability code in PACKAGE_AVAILABILITY_CODES which defines whether this package can be used. */ availability: foundry.CONST.PACKAGE_AVAILABILITY_CODES; /** * A flag which tracks whether this package is currently locked. * @defaultValue `false` */ locked: boolean; /** * A flag which tracks whether this package is a free Exclusive pack * @defaultValue `false` */ exclusive: boolean; /** * A flag which tracks whether this package is owned, if it is protected. * @defaultValue `false` */ owned: boolean; /** * A set of Tags that indicate what kind of Package this is, provided by the Website * @defaultValue `[]` */ tags: string[]; /** * Define the package type in CONST.PACKAGE_TYPES that this class represents. * Each BasePackage subclass must define this attribute. * @abstract */ static type: foundry.CONST.PACKAGE_TYPES; /** * The type of this package instance. A value in CONST.PACKAGE_TYPES. */ get type(): foundry.CONST.PACKAGE_TYPES; /** * The canonical identifier for this package * @deprecated since v10, will be removed in v13 * @remarks `"You are accessing BasePackage#name which is now deprecated in favor of id."` */ get name(): GetKey<this, "id">; /** * A flag which defines whether this package is unavailable to be used. */ get unavailable(): boolean; /** * Test if a given availability is incompatible with the core version. * @param availability - The availability value to test. */ static isIncompatibleWithCoreVersion(availability: foundry.CONST.PACKAGE_AVAILABILITY_CODES): boolean; /** * The named collection to which this package type belongs */ static get collection(): "worlds" | "systems" | "modules"; static defineSchema(): BasePackage.Schema; static testAvailability( data: InexactPartial<BasePackage.PackageManifestData>, options: InexactPartial<{ /** * A specific software release for which to test availability. * Tests against the current release by default. */ release: ReleaseData; }>, ): foundry.CONST.PACKAGE_AVAILABILITY_CODES; /** * Test that the dependencies of a package are satisfied as compatible. * This method assumes that all packages in modulesCollection have already had their own availability tested. * @param modulesCollection - A collection which defines the set of available modules * @returns Are all required dependencies satisfied? */ _testRequiredDependencies(modulesCollection: Collection<foundry.packages.Module>): Promise<boolean>; /** * Test compatibility of a package's supported systems. * @param systemCollection - A collection which defines the set of available systems. * @returns True if all supported systems which are currently installed * are compatible or if the package has no supported systems. * Returns false otherwise, or if no supported systems are installed. */ _testSupportedSystems(systemCollection: Collection<foundry.packages.System>): Promise<boolean>; /** * Determine if a dependency is within the given compatibility range. * @param compatibility - The compatibility range declared for the dependency, if any * @param dependency - The known dependency package * @returns Is the dependency compatible with the required range? */ static testDependencyCompatibility(compatibility: PackageCompatibility, dependency: BasePackage): boolean; static cleanData(source?: AnyObject, options?: BasePackage.CleanDataOptions): AnyMutableObject; /** * Validate that a Package ID is allowed. * @param id - The candidate ID * @throws An error if the candidate ID is invalid */ static validateId(id: string): void; /** * A wrapper around the default compatibility warning logger which handles some package-specific interactions. * @param packageId - The package ID being logged * @param message - The warning or error being logged * @param options - Logging options passed to foundry.utils.logCompatibilityWarning */ protected static _logWarning(packageId: string, message: string, options?: BasePackage.LogOptions): void; /** * A set of package manifest keys that are migrated. */ static migratedKeys: Set<string>; /** * @remarks * Migrations: * - `name` to `id`, both at root and for any `dependencies` (since v10 until v13) * - `dependencies` to `relationships` (structural change) (since v10 until v13) * - `minimumCoreVersion` and `compatibleCoreVersion` to `compatibility.minimum` and `.verified`, respectively (since v10 until v13) * - Inside `media` entries, `link` to `url` (since v11 until v13) * - Inside `packs` entries: * - `private` to an `ownership` object with `{PLAYER: "LIMITED", ASSISTANT: "OWNER"}` (since v11 until v13) * - Slugifies the `name` if not already a valid slug (since v12, until v14) * - `entity` to `type` (since v9, no specified end) */ static override migrateData(data: AnyMutableObject, options?: BasePackage.MigrateDataOptions): AnyMutableObject; protected static _migrateNameToId(data: AnyObject, logOptions: BasePackage.LogOptions): void; protected static _migrateDependenciesNameToId(data: AnyObject, logOptions: BasePackage.LogOptions): void; protected static _migrateToRelationships(data: AnyObject, logOptions: BasePackage.LogOptions): void; protected static _migrateCompatibility(data: AnyObject, logOptions: BasePackage.LogOptions): void; protected static _migrateMediaURL(data: AnyObject, logOptions: BasePackage.LogOptions): void; protected static _migrateOwnership(data: AnyObject, logOptions: BasePackage.LogOptions): void; protected static _migratePackIDs(data: AnyObject, logOptions: Parameters<typeof BasePackage._logWarning>[2]): void; protected static _migratePackEntityToType( data: AnyObject, logOptions: Parameters<typeof BasePackage._logWarning>[2], ): void; /** * Retrieve the latest Package manifest from a provided remote location. * @param manifestUrl - A remote manifest URL to load * @param options - Additional options which affect package construction * @returns A Promise which resolves to a constructed ServerPackage instance * @throws An error if the retrieved manifest data is invalid */ static fromRemoteManifest( manifestUrl: string, options: { /** * Whether to construct the remote package strictly * @defaultValue `true` */ strict: boolean; }, ): Promise<never>; } declare abstract class AnyBasePackage extends foundry.packages.BasePackage<any> { constructor(...args: never); } export default BasePackage;