@vttforge/core 0.0.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["resolveBases","resolveDragDrop","registered","vttfError","readHooks","readConfig","applyInit"],"sources":["../src/errors/registry.ts","../src/base-actor-sheet.ts","../src/base-item-sheet.ts","../src/base-type-data-model.ts","../src/data/fields.ts","../src/errors/manifest.ts","../src/migrations/runner.ts","../src/register-module.ts","../src/register-system.ts","../src/system-config.ts","../src/index.ts"],"sourcesContent":["/**\n * VTTF-NNNN error registry — append-only, stable across majors.\n *\n * Every error VTTForge throws has a numeric code (`VTTF-NNNN`) and a PascalCase\n * `name` for stack-trace readability. Codes are URLs — `https://vttforge.dev/errors/VTTF-0001`\n * eventually links to a docs page generated from this registry.\n *\n * Never renumber an entry. To deprecate, mark with `deprecated: true` and add a\n * `replacedBy` pointer. Adding a new code: pick the next unused integer.\n */\n\nexport type VttfErrorCode = `VTTF-${string}`;\n\nexport interface VttfErrorEntry {\n readonly code: VttfErrorCode;\n readonly name: string;\n readonly summary: string;\n readonly deprecated?: boolean;\n readonly replacedBy?: VttfErrorCode;\n}\n\nconst DOCS_BASE_URL = 'https://vttforge.dev/errors';\n\nconst REGISTRY: Readonly<Record<VttfErrorCode, VttfErrorEntry>> = Object.freeze({\n 'VTTF-0001': Object.freeze({\n code: 'VTTF-0001',\n name: 'SystemAlreadyRegistered',\n summary:\n 'registerSystem() was called more than once for the same system id. This is almost always a hot-reload artefact or a duplicate import.',\n }),\n 'VTTF-0002': Object.freeze({\n code: 'VTTF-0002',\n name: 'MissingFoundryGlobals',\n summary:\n 'VTTForge code ran in an environment without Foundry globals (game, Hooks, CONFIG). Initialise inside the Foundry runtime, not in a Node test without mocks.',\n }),\n 'VTTF-0003': Object.freeze({\n code: 'VTTF-0003',\n name: 'UnknownSetting',\n summary:\n 'SystemConfig.get() / set() was called with a key that was never passed to SystemConfig.register(). Register the setting in your init hook before reading it.',\n }),\n 'VTTF-0004': Object.freeze({\n code: 'VTTF-0004',\n name: 'MigrationFailed',\n summary:\n 'A migration function passed to createMigrationRunner() threw. The original error is available on .cause. The schemaVersion setting is not advanced past the failed migration so retrying on the next world load picks up where the failure left off.',\n }),\n 'VTTF-0005': Object.freeze({\n code: 'VTTF-0005',\n name: 'WorldTooOldForMigration',\n summary:\n 'createMigrationRunner() was called on a world whose stored schemaVersion is older than the configured compatibleVersion floor. Upgrade the world to a supported intermediate version before continuing — running migrations across the gap would corrupt data.',\n }),\n});\n\n/**\n * Look up a registered entry by code. Throws if the code is unknown — the\n * registry is the source of truth, so missing codes mean a typo.\n */\nexport function getErrorEntry(code: VttfErrorCode): VttfErrorEntry {\n const entry = REGISTRY[code];\n if (entry === undefined) {\n throw new Error(`Unknown VTTForge error code: ${code}. Add it to the registry.`);\n }\n return entry;\n}\n\n/**\n * Return every entry currently in the registry. Used by codegen to emit the\n * runtime constants and the JSON manifest that powers the docs pages.\n */\nexport function listErrorEntries(): readonly VttfErrorEntry[] {\n return Object.values(REGISTRY);\n}\n\nexport function docsUrlFor(code: VttfErrorCode): string {\n return `${DOCS_BASE_URL}/${code}`;\n}\n\n/**\n * VttfError — every error VTTForge throws extends this.\n *\n * - `code` is the registry key (string-narrowed).\n * - `name` is the PascalCase name from the registry — shows up in stack traces.\n * - `docsUrl` points at the docs page.\n * - `cause` uses the native ES2022 mechanism. Multiple causes => pass an\n * `AggregateError` as the cause.\n */\nexport class VttfError extends Error {\n readonly code: VttfErrorCode;\n readonly docsUrl: string;\n\n constructor(code: VttfErrorCode, message?: string, options?: ErrorOptions) {\n const entry = getErrorEntry(code);\n const finalMessage = `[${code}] ${message ?? entry.summary}`;\n super(finalMessage, options);\n this.code = code;\n this.name = entry.name;\n this.docsUrl = docsUrlFor(code);\n }\n}\n","/**\n * BaseActorSheet — `ActorSheetV2 + HandlebarsApplicationMixin` baseline with the\n * boilerplate every shipping system copy-pastes hoisted into the SDK.\n *\n * What this adds beyond stock Foundry v13:\n *\n * - **`static DRAG_DROP`** — declare drag sources / drop targets as data, get\n * `foundry.applications.ux.DragDrop` instances wired in `_onRender` with\n * `isEditable`-gated permissions and a sensible default `_onDragStart` that\n * serialises `data-item-id` elements as `{ type: \"Item\", uuid }`.\n * - **`_prepareContext` auto-fills `context.tabs[group]`** for every group\n * declared in ApplicationV2's `static TABS`, so subclass `_prepareContext`\n * implementations stop having to call `_prepareTabs(group)` by hand.\n * - **Typed drop dispatch** — override `onDropItem(item, event)` /\n * `onDropActor(actor, event)` / `onDropFolder(folder, event)` /\n * `onDropActiveEffect(effect, event)` and skip the `fromUuid()` ceremony.\n * Returning `undefined` falls through to Foundry's default `_onDropX`\n * behaviour; return any other value to take ownership.\n *\n * Intentional non-additions:\n *\n * - `editImage` action — already shipped by `DocumentSheetV2` (inherited by\n * `ActorSheetV2`). Templates wire `<img data-edit=\"img\">` and Foundry's\n * built-in action handles the `FilePicker` flow.\n * - `_getTabs()` — ApplicationV2 already owns the tab state machine; we only\n * eliminate the `_prepareTabs` call in `_prepareContext`.\n *\n * Resolved lazily so subclasses can be declared at module load without\n * Foundry globals existing yet (test boot, ESM hoist).\n */\n\nimport { VttfError } from './errors/registry.js';\n\n// biome-ignore lint/suspicious/noExplicitAny: Foundry's ActorSheetV2 shape lives in fvtt-types (deferred to @vttforge/types v1.0)\ntype AnyConstructor = new (...args: any[]) => any;\n\n/**\n * Declarative DragDrop entry consumed by `_onRender`. Mirrors the\n * `foundry.applications.ux.DragDrop` constructor config. Permissions and\n * callbacks fall back to sensible defaults that honour `this.isEditable` and\n * the default `_onDragStart` / `_onDrop`.\n */\nexport interface DragDropConfig {\n readonly dragSelector?: string;\n readonly dropSelector?: string;\n readonly permissions?: {\n readonly dragstart?: () => boolean;\n readonly drop?: () => boolean;\n };\n // biome-ignore lint/suspicious/noExplicitAny: DragEvent payload is browser-native; consumers route to their own typed handlers\n readonly callbacks?: Record<string, (...args: any[]) => unknown>;\n}\n\n/**\n * The statics a VTTForge sheet base carries.\n *\n * The factory used to return a bare constructor, so a subclass writing\n * `super.DEFAULT_OPTIONS` — the pattern the docs show and every sheet needs —\n * failed to compile. TypeScript cannot see a static through an untyped\n * constructor. The example system never caught it because it is JavaScript.\n *\n * `DEFAULT_OPTIONS` is deliberately loose: a subclass merges its own shape\n * into it, and pinning ours would reject the merge.\n */\nexport interface SheetBaseStatics {\n // biome-ignore lint/suspicious/noExplicitAny: a subclass merges arbitrary\n // ApplicationV2 options into this; a narrower type would reject the merge.\n readonly DEFAULT_OPTIONS: Record<string, any>;\n readonly DRAG_DROP: ReadonlyArray<DragDropConfig>;\n}\n\n/**\n * What the factory hands back: something you can `extend`, whose statics the\n * compiler can see.\n */\nexport interface SheetBaseCtor extends SheetBaseStatics {\n // biome-ignore lint/suspicious/noExplicitAny: mirrors ApplicationV2's own\n // constructor arity, which subclasses pass straight through.\n new (...args: any[]): any;\n}\n\ninterface DragDropInstance {\n bind(element: HTMLElement): void;\n}\n\ninterface DragDropCtor {\n new (config: Record<string, unknown>): DragDropInstance;\n}\n\ninterface FoundryApplicationsApi {\n HandlebarsApplicationMixin?: (base: AnyConstructor) => AnyConstructor;\n}\n\ninterface FoundryApplicationsSheets {\n ActorSheetV2?: AnyConstructor;\n}\n\ninterface FoundryApplicationsUx {\n DragDrop?: DragDropCtor;\n}\n\ninterface FoundryApplications {\n api?: FoundryApplicationsApi;\n sheets?: FoundryApplicationsSheets;\n ux?: FoundryApplicationsUx;\n}\n\ninterface FoundryGlobal {\n applications?: FoundryApplications;\n}\n\nfunction resolveBases(): { Base: AnyConstructor; mixin: (b: AnyConstructor) => AnyConstructor } {\n const foundry = (globalThis as Record<string, unknown>).foundry as FoundryGlobal | undefined;\n const Base = foundry?.applications?.sheets?.ActorSheetV2;\n const mixin = foundry?.applications?.api?.HandlebarsApplicationMixin;\n if (typeof Base !== 'function' || typeof mixin !== 'function') {\n throw new VttfError(\n 'VTTF-0002',\n 'foundry.applications.sheets.ActorSheetV2 and/or foundry.applications.api.HandlebarsApplicationMixin are not available. Define your BaseActorSheet subclasses inside the Foundry runtime (or stub the global in tests).',\n );\n }\n return { Base, mixin };\n}\n\nfunction resolveDragDrop(): DragDropCtor | undefined {\n const foundry = (globalThis as Record<string, unknown>).foundry as FoundryGlobal | undefined;\n const ctor = foundry?.applications?.ux?.DragDrop;\n return typeof ctor === 'function' ? ctor : undefined;\n}\n\nasync function resolveFromUuid(uuid: string): Promise<unknown> {\n const fn = (globalThis as Record<string, unknown>).fromUuid as\n | ((u: string) => Promise<unknown>)\n | undefined;\n if (typeof fn !== 'function') return null;\n return fn(uuid);\n}\n\ninterface DropPayload {\n readonly type?: string;\n readonly uuid?: string;\n}\n\n/**\n * Marker class that consumer CSS uses for scoping. Always present on every\n * VTTForge-derived sheet so rules like `.vttforge .actor-sheet { ... }` work.\n */\nexport const VTTFORGE_SHEET_CLASS = 'vttforge';\n\n/**\n * Build the `BaseActorSheet` for the current Foundry runtime. See module\n * header for the boilerplate this base eliminates.\n *\n * @example\n * ```ts\n * class CharacterSheet extends BaseActorSheet() {\n * static DEFAULT_OPTIONS = foundry.utils.mergeObject(\n * super.DEFAULT_OPTIONS,\n * { classes: ['my-system'], position: { width: 720 } },\n * );\n * static PARTS = { ... };\n * static TABS = {\n * primary: {\n * tabs: [\n * { id: 'features', group: 'primary', label: 'Features' },\n * { id: 'inventory', group: 'primary', label: 'Inventory' },\n * ],\n * initial: 'features',\n * },\n * };\n * static DRAG_DROP = [{ dragSelector: '.item[draggable=true]', dropSelector: null }];\n * async onDropItem(item, event) {\n * if (item.type !== 'weapon') return false;\n * // …fall through to super by returning undefined.\n * }\n * }\n * ```\n */\nexport function BaseActorSheet(): SheetBaseCtor {\n const { Base, mixin } = resolveBases();\n const Mixed = mixin(Base);\n\n class VttforgeBaseActorSheet extends Mixed {\n static readonly DEFAULT_OPTIONS = {\n classes: [VTTFORGE_SHEET_CLASS],\n window: { resizable: true },\n position: { width: 600, height: 700 },\n tag: 'form',\n form: { submitOnChange: true, closeOnSubmit: false },\n actions: { vttforgeTab: VttforgeBaseActorSheet._onTab },\n } as const;\n\n /**\n * Declarative DragDrop entries. Each becomes a\n * `foundry.applications.ux.DragDrop` instance bound in `_onRender`.\n * Subclasses override by re-declaring `static DRAG_DROP = [...]`.\n */\n static readonly DRAG_DROP: ReadonlyArray<DragDropConfig> = [];\n\n /**\n * Augment ApplicationV2's context with `tabs[group]` for sheets that\n * declare **multiple** `static TABS` groups. ApplicationV2 already\n * auto-populates `context.tabs` (keyed by tab id) for single-group\n * sheets — overriding that flat shape would force every consumer to\n * either unwrap or write `context.tabs.<group>.<tabId>` in templates.\n * Multi-group sheets get nested `context.tabs.<group>.<tabId>` because\n * ApplicationV2 returns `{}` for them by default.\n */\n async _prepareContext(options: unknown): Promise<Record<string, unknown>> {\n const superPrepare = (\n Mixed.prototype as {\n _prepareContext?: (options: unknown) => Promise<Record<string, unknown>>;\n }\n )._prepareContext;\n const context =\n typeof superPrepare === 'function'\n ? ((await superPrepare.call(this, options)) as Record<string, unknown>)\n : {};\n const tabsConfig = (this.constructor as { TABS?: Record<string, unknown> }).TABS;\n if (tabsConfig && typeof tabsConfig === 'object') {\n const groups = Object.keys(tabsConfig);\n if (groups.length > 1) {\n const prepareTabs = (this as { _prepareTabs?: (group: string) => unknown })._prepareTabs;\n const tabs: Record<string, unknown> = {};\n for (const group of groups) {\n tabs[group] = typeof prepareTabs === 'function' ? prepareTabs.call(this, group) : {};\n }\n context.tabs = tabs;\n }\n }\n return context;\n }\n\n /**\n * Default `tab` action handler. ApplicationV2 doesn't ship one, so every\n * sheet that uses `<button data-action=\"tab\" data-tab=… data-group=…>`\n * has to wire its own. We toggle the `.active` class on the matching\n * nav element (`[data-action=\"tab\"][data-tab=…][data-group=…]`) and\n * on `section.tab[data-tab=…][data-group=…]`, then update\n * `sheet.tabGroups[group]` so subsequent re-renders pick the right\n * initial tab.\n *\n * ApplicationV2's action dispatcher binds `this` to the sheet instance\n * at call time even though the handler is declared `static`.\n */\n static _onTab(_event: Event, target: HTMLElement): void {\n // biome-ignore lint/complexity/noThisInStatic: ApplicationV2 binds `this` to the sheet instance at call time — wrap the cast in a single line so biome's auto-fix can't rewrite downstream references to the class name\n const sheet = this as unknown as { tabGroups: Record<string, string>; element?: HTMLElement };\n const group = target.dataset?.group;\n const tab = target.dataset?.tab;\n if (!group || !tab) return;\n sheet.tabGroups[group] = tab;\n const root = sheet.element;\n if (!root) return;\n for (const link of root.querySelectorAll<HTMLElement>(\n `[data-action=\"vttforgeTab\"][data-group=\"${group}\"]`,\n )) {\n link.classList.toggle('active', link.dataset.tab === tab);\n }\n for (const section of root.querySelectorAll<HTMLElement>(\n `section.tab[data-group=\"${group}\"]`,\n )) {\n section.classList.toggle('active', section.dataset.tab === tab);\n }\n }\n\n /**\n * Wire each `static DRAG_DROP` entry into a real `DragDrop` instance.\n * Permissions default to `this.isEditable`; callbacks default to\n * `_onDragStart` / `_onDrop`. Subclasses extending `_onRender` MUST call\n * `super._onRender(context, options)` to keep DragDrop wired.\n */\n _onRender(context: unknown, options: unknown): void {\n const superRender = (\n Mixed.prototype as { _onRender?: (context: unknown, options: unknown) => void }\n )._onRender;\n if (typeof superRender === 'function') {\n superRender.call(this, context, options);\n }\n const configs = (this.constructor as { DRAG_DROP?: ReadonlyArray<DragDropConfig> }).DRAG_DROP;\n if (!configs?.length) return;\n const DragDrop = resolveDragDrop();\n if (!DragDrop) return;\n const element = (this as { element?: HTMLElement }).element;\n if (!element) return;\n const onDragStart = (this as { _onDragStart?: (event: DragEvent) => void })._onDragStart;\n const onDrop = (this as { _onDrop?: (event: DragEvent) => void })._onDrop;\n for (const cfg of configs) {\n new DragDrop({\n dragSelector: cfg.dragSelector,\n dropSelector: cfg.dropSelector,\n permissions: {\n dragstart: cfg.permissions?.dragstart ?? (() => this.#isEditable()),\n drop: cfg.permissions?.drop ?? (() => this.#isEditable()),\n },\n callbacks: {\n ...(typeof onDragStart === 'function' ? { dragstart: onDragStart.bind(this) } : {}),\n ...(typeof onDrop === 'function' ? { drop: onDrop.bind(this) } : {}),\n ...(cfg.callbacks ?? {}),\n },\n }).bind(element);\n }\n }\n\n /**\n * Default drag handler — serialises the item identified by\n * `data-item-id` on the drag source element. Override for richer payloads\n * (Actor drags, custom UUIDs).\n */\n _onDragStart(event: DragEvent): void {\n const target = event.currentTarget as HTMLElement | null;\n const itemId = target?.dataset?.itemId;\n if (!itemId || !event.dataTransfer) return;\n const items = (\n this as { document?: { items?: { get(id: string): { uuid: string } | undefined } } }\n ).document?.items;\n const item = items?.get(itemId);\n if (!item) return;\n event.dataTransfer.setData(\n 'application/json',\n JSON.stringify({ type: 'Item', uuid: item.uuid }),\n );\n }\n\n /**\n * Typed drop sugar. Subclasses override this instead of `_onDropItem`\n * to skip the `fromUuid()` ceremony. Return `undefined` to fall through\n * to Foundry's default `_onDropItem`; return anything else to take\n * ownership of the drop.\n */\n async onDropItem(_item: unknown, _event: DragEvent): Promise<unknown> {\n return undefined;\n }\n async onDropActor(_actor: unknown, _event: DragEvent): Promise<unknown> {\n return undefined;\n }\n async onDropFolder(_folder: unknown, _event: DragEvent): Promise<unknown> {\n return undefined;\n }\n async onDropActiveEffect(_effect: unknown, _event: DragEvent): Promise<unknown> {\n return undefined;\n }\n\n async _onDropItem(event: DragEvent, data: DropPayload): Promise<unknown> {\n return this.#dispatchDrop('_onDropItem', 'onDropItem', event, data);\n }\n async _onDropActor(event: DragEvent, data: DropPayload): Promise<unknown> {\n return this.#dispatchDrop('_onDropActor', 'onDropActor', event, data);\n }\n async _onDropFolder(event: DragEvent, data: DropPayload): Promise<unknown> {\n return this.#dispatchDrop('_onDropFolder', 'onDropFolder', event, data);\n }\n async _onDropActiveEffect(event: DragEvent, data: DropPayload): Promise<unknown> {\n return this.#dispatchDrop('_onDropActiveEffect', 'onDropActiveEffect', event, data);\n }\n\n async #dispatchDrop(\n superKey: '_onDropItem' | '_onDropActor' | '_onDropFolder' | '_onDropActiveEffect',\n sugarKey: 'onDropItem' | 'onDropActor' | 'onDropFolder' | 'onDropActiveEffect',\n event: DragEvent,\n data: DropPayload,\n ): Promise<unknown> {\n const uuid = data?.uuid;\n if (uuid) {\n const doc = await resolveFromUuid(uuid);\n if (doc) {\n const result = await (\n this as unknown as Record<\n typeof sugarKey,\n (doc: unknown, event: DragEvent) => Promise<unknown>\n >\n )[sugarKey](doc, event);\n if (result !== undefined) return result;\n }\n }\n const superFn = (Mixed.prototype as Record<typeof superKey, unknown>)[superKey] as\n | ((event: DragEvent, data: DropPayload) => Promise<unknown>)\n | undefined;\n if (typeof superFn === 'function') return superFn.call(this, event, data);\n return undefined;\n }\n\n #isEditable(): boolean {\n return Boolean((this as { isEditable?: boolean }).isEditable);\n }\n }\n\n return VttforgeBaseActorSheet as unknown as SheetBaseCtor;\n}\n","/**\n * BaseItemSheet — `ItemSheetV2 + HandlebarsApplicationMixin` baseline. Mirror\n * of `BaseActorSheet` minus the typed drop dispatch (items rarely receive\n * drops; the rare case that does can override `_onDrop` directly).\n *\n * Carries the same boilerplate-eliminators:\n *\n * - `static DRAG_DROP` — declarative `foundry.applications.ux.DragDrop` wiring\n * in `_onRender`, with `isEditable`-gated permissions.\n * - `_prepareContext` auto-fills `context.tabs[group]` for every group declared\n * in ApplicationV2's `static TABS`.\n *\n * As with `BaseActorSheet`, `editImage` is intentionally not added — it ships\n * built-in on `DocumentSheetV2` (parent of `ItemSheetV2`).\n */\n\nimport type { DragDropConfig, SheetBaseCtor } from './base-actor-sheet.js';\nimport { VTTFORGE_SHEET_CLASS } from './base-actor-sheet.js';\nimport { VttfError } from './errors/registry.js';\n\n// biome-ignore lint/suspicious/noExplicitAny: Foundry's ItemSheetV2 shape lives in fvtt-types (deferred to @vttforge/types v1.0)\ntype AnyConstructor = new (...args: any[]) => any;\n\ninterface DragDropInstance {\n bind(element: HTMLElement): void;\n}\n\ninterface DragDropCtor {\n new (config: Record<string, unknown>): DragDropInstance;\n}\n\ninterface FoundryApplicationsApi {\n HandlebarsApplicationMixin?: (base: AnyConstructor) => AnyConstructor;\n}\n\ninterface FoundryApplicationsSheets {\n ItemSheetV2?: AnyConstructor;\n}\n\ninterface FoundryApplicationsUx {\n DragDrop?: DragDropCtor;\n}\n\ninterface FoundryApplications {\n api?: FoundryApplicationsApi;\n sheets?: FoundryApplicationsSheets;\n ux?: FoundryApplicationsUx;\n}\n\ninterface FoundryGlobal {\n applications?: FoundryApplications;\n}\n\nfunction resolveBases(): { Base: AnyConstructor; mixin: (b: AnyConstructor) => AnyConstructor } {\n const foundry = (globalThis as Record<string, unknown>).foundry as FoundryGlobal | undefined;\n const Base = foundry?.applications?.sheets?.ItemSheetV2;\n const mixin = foundry?.applications?.api?.HandlebarsApplicationMixin;\n if (typeof Base !== 'function' || typeof mixin !== 'function') {\n throw new VttfError(\n 'VTTF-0002',\n 'foundry.applications.sheets.ItemSheetV2 and/or foundry.applications.api.HandlebarsApplicationMixin are not available. Define your BaseItemSheet subclasses inside the Foundry runtime (or stub the global in tests).',\n );\n }\n return { Base, mixin };\n}\n\nfunction resolveDragDrop(): DragDropCtor | undefined {\n const foundry = (globalThis as Record<string, unknown>).foundry as FoundryGlobal | undefined;\n const ctor = foundry?.applications?.ux?.DragDrop;\n return typeof ctor === 'function' ? ctor : undefined;\n}\n\n/**\n * Build the `BaseItemSheet` for the current Foundry runtime.\n *\n * @example\n * ```ts\n * class WeaponSheet extends BaseItemSheet() {\n * static DEFAULT_OPTIONS = foundry.utils.mergeObject(\n * super.DEFAULT_OPTIONS,\n * { classes: ['my-system'], position: { width: 540 } },\n * );\n * static PARTS = { ... };\n * static TABS = {\n * primary: {\n * tabs: [\n * { id: 'description', group: 'primary', label: 'Description' },\n * { id: 'details', group: 'primary', label: 'Details' },\n * ],\n * initial: 'description',\n * },\n * };\n * }\n * ```\n */\nexport function BaseItemSheet(): SheetBaseCtor {\n const { Base, mixin } = resolveBases();\n const Mixed = mixin(Base);\n\n class VttforgeBaseItemSheet extends Mixed {\n static readonly DEFAULT_OPTIONS = {\n classes: [VTTFORGE_SHEET_CLASS],\n window: { resizable: true },\n position: { width: 520, height: 480 },\n tag: 'form',\n form: { submitOnChange: true, closeOnSubmit: false },\n actions: { vttforgeTab: VttforgeBaseItemSheet._onTab },\n } as const;\n\n static readonly DRAG_DROP: ReadonlyArray<DragDropConfig> = [];\n\n /**\n * Multi-group sheets get nested `context.tabs.<group>.<tabId>` because\n * ApplicationV2 returns `{}` for them by default; single-group sheets\n * use ApplicationV2's flat `context.tabs.<tabId>` shape untouched. See\n * BaseActorSheet for the long version.\n */\n async _prepareContext(options: unknown): Promise<Record<string, unknown>> {\n const superPrepare = (\n Mixed.prototype as {\n _prepareContext?: (options: unknown) => Promise<Record<string, unknown>>;\n }\n )._prepareContext;\n const context =\n typeof superPrepare === 'function'\n ? ((await superPrepare.call(this, options)) as Record<string, unknown>)\n : {};\n const tabsConfig = (this.constructor as { TABS?: Record<string, unknown> }).TABS;\n if (tabsConfig && typeof tabsConfig === 'object') {\n const groups = Object.keys(tabsConfig);\n if (groups.length > 1) {\n const prepareTabs = (this as { _prepareTabs?: (group: string) => unknown })._prepareTabs;\n const tabs: Record<string, unknown> = {};\n for (const group of groups) {\n tabs[group] = typeof prepareTabs === 'function' ? prepareTabs.call(this, group) : {};\n }\n context.tabs = tabs;\n }\n }\n return context;\n }\n\n static _onTab(_event: Event, target: HTMLElement): void {\n // biome-ignore lint/complexity/noThisInStatic: ApplicationV2 binds `this` to the sheet instance at call time\n const sheet = this as unknown as { tabGroups: Record<string, string>; element?: HTMLElement };\n const group = target.dataset?.group;\n const tab = target.dataset?.tab;\n if (!group || !tab) return;\n sheet.tabGroups[group] = tab;\n const root = sheet.element;\n if (!root) return;\n for (const link of root.querySelectorAll<HTMLElement>(\n `[data-action=\"vttforgeTab\"][data-group=\"${group}\"]`,\n )) {\n link.classList.toggle('active', link.dataset.tab === tab);\n }\n for (const section of root.querySelectorAll<HTMLElement>(\n `section.tab[data-group=\"${group}\"]`,\n )) {\n section.classList.toggle('active', section.dataset.tab === tab);\n }\n }\n\n _onRender(context: unknown, options: unknown): void {\n const superRender = (\n Mixed.prototype as { _onRender?: (context: unknown, options: unknown) => void }\n )._onRender;\n if (typeof superRender === 'function') {\n superRender.call(this, context, options);\n }\n const configs = (this.constructor as { DRAG_DROP?: ReadonlyArray<DragDropConfig> }).DRAG_DROP;\n if (!configs?.length) return;\n const DragDrop = resolveDragDrop();\n if (!DragDrop) return;\n const element = (this as { element?: HTMLElement }).element;\n if (!element) return;\n const onDragStart = (this as { _onDragStart?: (event: DragEvent) => void })._onDragStart;\n const onDrop = (this as { _onDrop?: (event: DragEvent) => void })._onDrop;\n for (const cfg of configs) {\n new DragDrop({\n dragSelector: cfg.dragSelector,\n dropSelector: cfg.dropSelector,\n permissions: {\n dragstart: cfg.permissions?.dragstart ?? (() => this.#isEditable()),\n drop: cfg.permissions?.drop ?? (() => this.#isEditable()),\n },\n callbacks: {\n ...(typeof onDragStart === 'function' ? { dragstart: onDragStart.bind(this) } : {}),\n ...(typeof onDrop === 'function' ? { drop: onDrop.bind(this) } : {}),\n ...(cfg.callbacks ?? {}),\n },\n }).bind(element);\n }\n }\n\n #isEditable(): boolean {\n return Boolean((this as { isEditable?: boolean }).isEditable);\n }\n }\n\n return VttforgeBaseItemSheet as unknown as SheetBaseCtor;\n}\n","/**\n * BaseTypeDataModel — minimal extension of `foundry.abstract.TypeDataModel`.\n *\n * Provides safe defaults that systems usually copy-paste anyway:\n *\n * - `migrateData()` calls `super.migrateData(data)` — every TypeDataModel\n * must do this so chained migrations from base classes still run.\n * - `prepareBaseData()` is a no-op stub — override to initialize fields that\n * Active Effects need to mutate (e.g. base max HP before AE bonus). Foundry\n * applies Active Effects between `prepareBaseData()` and `prepareDerivedData()`,\n * so anything you compute here is the input AEs see.\n * - `prepareDerivedData()` is a no-op stub — override for computed values\n * that depend on AE-mutated state (modifiers, percentages, totals).\n *\n * Subclasses still own `defineSchema()` because there is no useful default —\n * we never invent a schema for you.\n *\n * Resolves the base class from `globalThis.foundry.abstract.TypeDataModel` at\n * runtime. In tests, the test harness installs a stub; in Foundry, the global\n * exists by the time this module runs (we are loaded from system esmodules).\n */\n\nimport type { FieldInstance } from './data/fields.js';\nimport type { InferSchema } from './data/infer-schema.js';\nimport { VttfError } from './errors/registry.js';\n\n// biome-ignore lint/suspicious/noExplicitAny: we mix into Foundry's TypeDataModel whose shape lives in fvtt-types (deferred to @vttforge/types v1.0)\ntype AnyConstructor = new (...args: any[]) => any;\n\nfunction resolveTypeDataModelClass(): AnyConstructor {\n const foundry = (globalThis as Record<string, unknown>).foundry as\n | { abstract?: { TypeDataModel?: AnyConstructor } }\n | undefined;\n const cls = foundry?.abstract?.TypeDataModel;\n if (typeof cls !== 'function') {\n throw new VttfError(\n 'VTTF-0002',\n 'foundry.abstract.TypeDataModel is not available. Define your BaseTypeDataModel subclasses inside the Foundry runtime (or stub the global in tests).',\n );\n }\n return cls;\n}\n\n/**\n * Resolve the runtime base class, then build a mixin that adds VTTForge defaults.\n *\n * Why a function: subclasses are declared once at module load, but Foundry\n * globals may not exist yet (test boot, ESM hoist). Calling `BaseTypeDataModel()`\n * lazy-resolves the global at the moment of subclassing.\n */\n/** The two hooks this base fills in, so a subclass can omit either. */\nexport interface TypeDataModelHooks {\n prepareBaseData(): void;\n prepareDerivedData(): void;\n}\n\n/**\n * What an instance looks like when the schema is known.\n *\n * The schema's fields ARE the instance properties — inside\n * `prepareDerivedData()` you read `this.level`, not `this.system.level`, and\n * `actor.system` is this instance.\n *\n * Derived values are not in the schema, so they are not here either. Declare\n * them on the subclass:\n *\n * ```ts\n * declare armorClass: number;\n * ```\n */\nexport type TypedTypeDataModel<S extends Record<string, FieldInstance>> = InferSchema<S> &\n TypeDataModelHooks & {\n /**\n * Phantom property carrying the schema's inferred shape. Never assigned,\n * never present at runtime — it exists so the type has a name:\n *\n * ```ts\n * type CharacterSystem = CharacterData['$inferData'];\n * ```\n */\n readonly $inferData: InferSchema<S>;\n };\n\nexport interface TypedTypeDataModelCtor<S extends Record<string, FieldInstance>> {\n // biome-ignore lint/suspicious/noExplicitAny: a subclass declaring its own\n // constructor has to pass Foundry's (data, context) pair through to super.\n new (...args: any[]): TypedTypeDataModel<S>;\n defineSchema(): S;\n migrateData(data: Record<string, unknown>): Record<string, unknown>;\n}\n\n/**\n * Build a base class with no knowledge of the schema.\n *\n * `this` inside the hooks is untyped. Pass your schema function instead to\n * get the fields typed.\n */\nexport function BaseTypeDataModel(): AnyConstructor;\n/**\n * Build a base class that knows its schema.\n *\n * Hand it the function that returns your fields and it implements\n * `static defineSchema()` for you, so the schema is written once:\n *\n * ```ts\n * const defineCharacterSchema = () => {\n * const f = fields();\n * return { level: new f.NumberField({ required: true, nullable: false, initial: 1 }) };\n * };\n *\n * class CharacterData extends BaseTypeDataModel(defineCharacterSchema) {\n * declare armorClass: number;\n * prepareDerivedData() {\n * this.armorClass = 10 + this.level; // this.level is number\n * }\n * }\n * ```\n *\n * It has to be a function, not an object: `fields()` reads a Foundry global\n * that does not exist when the module is first evaluated.\n *\n * A subclass may still declare its own `static defineSchema()`; that one wins,\n * the same as any other static.\n */\nexport function BaseTypeDataModel<S extends Record<string, FieldInstance>>(\n defineSchema: () => S,\n): TypedTypeDataModelCtor<S>;\nexport function BaseTypeDataModel(\n defineSchema?: () => Record<string, FieldInstance>,\n): AnyConstructor {\n const Base = resolveTypeDataModelClass();\n\n class VttforgeBaseTypeDataModel extends Base {\n /**\n * Default no-op so subclasses can omit it when they have no value-level\n * migrations. Always end with `super.migrateData(data)` if you override.\n */\n static migrateData(data: Record<string, unknown>): Record<string, unknown> {\n const superMigrateData = (\n Base as { migrateData?: (d: Record<string, unknown>) => Record<string, unknown> }\n ).migrateData;\n if (typeof superMigrateData === 'function') {\n return superMigrateData.call(VttforgeBaseTypeDataModel, data);\n }\n return data;\n }\n\n /**\n * No-op stub. Override per type to initialize fields whose values Active\n * Effects need to consume — base max HP, base AC, etc. Foundry calls this\n * BEFORE applying Active Effects, so anything you set here is the input\n * that AE changes (`ADD`, `MULTIPLY`, `OVERRIDE`, …) operate on.\n *\n * Use `prepareDerivedData()` instead for values that depend on the\n * AE-mutated state (modifiers, percentages, totals).\n *\n * Never write to the database here — purely in-memory.\n */\n prepareBaseData(): void {\n // override me\n }\n\n /**\n * No-op stub. Override per type to compute derived values from the\n * AE-mutated state (modifiers, percentages, totals). Runs AFTER Active\n * Effects apply; use `prepareBaseData()` for values that AEs need to read.\n *\n * Never write to the database here — purely in-memory.\n */\n prepareDerivedData(): void {\n // override me\n }\n }\n\n if (defineSchema !== undefined) {\n // Assigned rather than declared in the class body so the no-argument form\n // keeps inheriting Foundry's own defineSchema instead of shadowing it\n // with one that returns nothing.\n Object.defineProperty(VttforgeBaseTypeDataModel, 'defineSchema', {\n value: defineSchema,\n writable: true,\n configurable: true,\n });\n }\n\n return VttforgeBaseTypeDataModel as unknown as AnyConstructor;\n}\n","/**\n * `fields()` — typed bag of Foundry v13 data-field constructors.\n *\n * Foundry idiom inside `defineSchema()` is `const f = foundry.data.fields`. We\n * mirror that, but routed through a factory so the import succeeds in Node\n * (tests, IDE typecheck) where the global is absent. The factory resolves\n * `globalThis.foundry.data.fields` lazily — same pattern as\n * `BaseTypeDataModel()` (see `base-type-data-model.ts:25`) and\n * `BaseActorSheet()` (see `base-actor-sheet.ts:40`).\n *\n * v0.1 covers eight fields (PRD §7): NumberField, StringField, BooleanField,\n * HTMLField, ArrayField, SchemaField, ColorField, FilePathField. The instance\n * interfaces carry a phantom `[BRAND]` tag and an `options` capture so the\n * conditional types in `./infer-schema.ts` can extract the runtime semantics\n * (e.g. `nullable: true`).\n *\n * `EmbeddedDataField`, `EmbeddedDocumentField`, `TypedSchemaField`, and the\n * full required×initial nullability matrix ship with `@vttforge/types` v1.0.\n */\n\nimport { VttfError } from '../errors/registry.js';\nimport type {\n ArrayFieldOptions,\n BooleanFieldOptions,\n ColorFieldOptions,\n FilePathFieldOptions,\n ForeignDocumentFieldOptions,\n HTMLFieldOptions,\n NumberFieldOptions,\n SchemaFieldOptions,\n SetFieldOptions,\n StringFieldOptions,\n} from './field-options.js';\n\ndeclare const BRAND: unique symbol;\n\n/**\n * Anything that satisfies the `FieldInstance` shape — used as the inner-field\n * constraint on `ArrayField` and as the value type of `SchemaField`'s child\n * map. Keeps the conditional types in `./infer-schema.ts` straightforward.\n */\nexport interface FieldInstance {\n readonly [BRAND]: string;\n readonly options: unknown;\n}\n\nexport interface NumberFieldInstance<O extends NumberFieldOptions = NumberFieldOptions>\n extends FieldInstance {\n readonly [BRAND]: 'number';\n readonly options: O;\n}\n\nexport interface StringFieldInstance<O extends StringFieldOptions = StringFieldOptions>\n extends FieldInstance {\n readonly [BRAND]: 'string';\n readonly options: O;\n}\n\nexport interface BooleanFieldInstance<O extends BooleanFieldOptions = BooleanFieldOptions>\n extends FieldInstance {\n readonly [BRAND]: 'boolean';\n readonly options: O;\n}\n\nexport interface HTMLFieldInstance<O extends HTMLFieldOptions = HTMLFieldOptions>\n extends FieldInstance {\n readonly [BRAND]: 'html';\n readonly options: O;\n}\n\nexport interface ColorFieldInstance<O extends ColorFieldOptions = ColorFieldOptions>\n extends FieldInstance {\n readonly [BRAND]: 'color';\n readonly options: O;\n}\n\nexport interface FilePathFieldInstance<O extends FilePathFieldOptions = FilePathFieldOptions>\n extends FieldInstance {\n readonly [BRAND]: 'filePath';\n readonly options: O;\n}\n\nexport interface ArrayFieldInstance<\n Inner extends FieldInstance = FieldInstance,\n O extends ArrayFieldOptions = ArrayFieldOptions,\n> extends FieldInstance {\n readonly [BRAND]: 'array';\n readonly element: Inner;\n readonly options: O;\n}\n\n/**\n * A `SetField` holds a `Set`, not an array.\n *\n * It extends `ArrayField` and validates the same way, but `initialize`\n * wraps the result in `new Set(...)` — so a schema that declares one and\n * types it as an array gets `.push` and index access from the compiler on a\n * value that has neither.\n */\nexport interface SetFieldInstance<\n Inner extends FieldInstance = FieldInstance,\n O extends SetFieldOptions = SetFieldOptions,\n> extends FieldInstance {\n readonly [BRAND]: 'set';\n readonly element: Inner;\n readonly options: O;\n}\n\n/**\n * A reference to another document, stored as its id.\n *\n * What you read back depends on `idOnly`. With it, the id string. Without\n * it, the document itself: the field resolves to a getter, so reading the\n * property looks the document up in its collection and hands back the\n * instance — or `null` when it is gone or lives in a compendium.\n *\n * The field is nullable by default, so both shapes admit `null`.\n */\nexport interface ForeignDocumentFieldInstance<\n Doc extends DocumentClass = DocumentClass,\n O extends ForeignDocumentFieldOptions = ForeignDocumentFieldOptions,\n> extends FieldInstance {\n readonly [BRAND]: 'foreignDocument';\n readonly model: Doc;\n readonly options: O;\n}\n\nexport interface SchemaFieldInstance<\n S extends Record<string, FieldInstance> = Record<string, FieldInstance>,\n O extends SchemaFieldOptions = SchemaFieldOptions,\n> extends FieldInstance {\n readonly [BRAND]: 'schema';\n readonly fields: S;\n readonly options: O;\n}\n\nexport interface NumberFieldCtor {\n new <O extends NumberFieldOptions = NumberFieldOptions>(options?: O): NumberFieldInstance<O>;\n}\n\nexport interface StringFieldCtor {\n new <O extends StringFieldOptions = StringFieldOptions>(options?: O): StringFieldInstance<O>;\n}\n\nexport interface BooleanFieldCtor {\n new <O extends BooleanFieldOptions = BooleanFieldOptions>(options?: O): BooleanFieldInstance<O>;\n}\n\nexport interface HTMLFieldCtor {\n new <O extends HTMLFieldOptions = HTMLFieldOptions>(options?: O): HTMLFieldInstance<O>;\n}\n\nexport interface ColorFieldCtor {\n new <O extends ColorFieldOptions = ColorFieldOptions>(options?: O): ColorFieldInstance<O>;\n}\n\nexport interface FilePathFieldCtor {\n new <O extends FilePathFieldOptions = FilePathFieldOptions>(\n options?: O,\n ): FilePathFieldInstance<O>;\n}\n\nexport interface ArrayFieldCtor {\n new <Inner extends FieldInstance, O extends ArrayFieldOptions = ArrayFieldOptions>(\n element: Inner,\n options?: O,\n ): ArrayFieldInstance<Inner, O>;\n}\n\nexport interface SetFieldCtor {\n new <Inner extends FieldInstance, O extends SetFieldOptions = SetFieldOptions>(\n element: Inner,\n options?: O,\n ): SetFieldInstance<Inner, O>;\n}\n\n/**\n * Any document class — what `ForeignDocumentField` takes as its first\n * argument. Declared structurally so the inference surface stays free of a\n * dependency on a Foundry type package.\n */\nexport type DocumentClass = abstract new (...args: never[]) => object;\n\nexport interface ForeignDocumentFieldCtor {\n new <\n Doc extends DocumentClass,\n O extends ForeignDocumentFieldOptions = ForeignDocumentFieldOptions,\n >(\n model: Doc,\n options?: O,\n ): ForeignDocumentFieldInstance<Doc, O>;\n}\n\nexport interface SchemaFieldCtor {\n new <S extends Record<string, FieldInstance>, O extends SchemaFieldOptions = SchemaFieldOptions>(\n fields: S,\n options?: O,\n ): SchemaFieldInstance<S, O>;\n}\n\n/**\n * Typed bag returned by `fields()`. Each property is the corresponding\n * `foundry.data.fields.*` class — the runtime value is Foundry's own\n * constructor; the type is our overlay.\n */\nexport interface FieldsApi {\n readonly NumberField: NumberFieldCtor;\n readonly StringField: StringFieldCtor;\n readonly BooleanField: BooleanFieldCtor;\n readonly HTMLField: HTMLFieldCtor;\n readonly ColorField: ColorFieldCtor;\n readonly FilePathField: FilePathFieldCtor;\n readonly ArrayField: ArrayFieldCtor;\n readonly SetField: SetFieldCtor;\n readonly ForeignDocumentField: ForeignDocumentFieldCtor;\n readonly SchemaField: SchemaFieldCtor;\n}\n\ninterface FoundryDataNamespace {\n readonly fields?: Record<string, unknown>;\n}\n\ninterface FoundryRoot {\n readonly data?: FoundryDataNamespace;\n}\n\n/**\n * Resolve `globalThis.foundry.data.fields` and return it typed as `FieldsApi`.\n *\n * Call this inside `defineSchema()` (or any code that runs after Foundry's\n * `init` hook). Calling at module scope will throw when imported from Node\n * tests — the global only exists inside the Foundry runtime.\n *\n * @throws `VttfError` with code `VTTF-0002` when `foundry.data.fields` is\n * missing.\n */\nexport function fields(): FieldsApi {\n const foundry = (globalThis as Record<string, unknown>).foundry as FoundryRoot | undefined;\n const f = foundry?.data?.fields;\n if (f === undefined || f === null) {\n throw new VttfError(\n 'VTTF-0002',\n 'foundry.data.fields is not available. Call fields() inside the Foundry runtime (or stub the global in tests).',\n );\n }\n return f as unknown as FieldsApi;\n}\n","/**\n * Typed runtime view over the VTTF-NNNN registry.\n *\n * Same data as `listErrorEntries()` — the manifest wraps it in a versioned\n * envelope so external tooling (the v0.3 docs site, IDE extensions, lint\n * rules) has a stable shape to consume. The matching JSON projection is\n * emitted to `dist/errors-manifest.json` at build time by\n * `packages/core/scripts/codegen-errors.mjs`.\n */\n\nimport { listErrorEntries, type VttfErrorEntry } from './registry.js';\n\nexport const ERROR_MANIFEST_VERSION = 1 as const;\n\nexport interface ErrorManifest {\n readonly version: typeof ERROR_MANIFEST_VERSION;\n readonly package: '@vttforge/core';\n readonly entries: ReadonlyArray<VttfErrorEntry>;\n}\n\n/**\n * Snapshot the current registry as a manifest object. Recomputed on every\n * call — cheap (the registry is a frozen literal). For the JSON projection\n * shipped with the package, see `dist/errors-manifest.json`.\n */\nexport function getErrorManifest(): ErrorManifest {\n return {\n version: ERROR_MANIFEST_VERSION,\n package: '@vttforge/core',\n entries: listErrorEntries(),\n };\n}\n","/**\n * `createMigrationRunner` — declarative schema migrations for Foundry systems.\n *\n * Replaces the copy-pasted \"schemaVersion setting + Hooks.once('ready') +\n * isNewerVersion compare + sequential await\" pattern that every system\n * eventually grows on its own. The runner owns no hooks — call\n * `register()` from your `init` hook and `run()` from your `ready` hook\n * (gated by `game.user.isGM`).\n *\n * Versions are semver strings, compared with `foundry.utils.isNewerVersion`.\n * The data lives in a per-system world setting and lines up cleanly with\n * `system.json`'s `flags.<systemId>.needsMigrationVersion` /\n * `compatibleMigrationVersion`.\n *\n * Failures advance `schemaVersion` only past migrations that *completed* — a\n * mid-sequence throw leaves the world at the last successful version so the\n * retry on the next world load picks up exactly where it failed.\n */\n\nimport { VttfError } from '../errors/registry.js';\nimport type { GameSettingsApi } from '../foundry-globals.js';\nimport type {\n Migration,\n MigrationLogger,\n MigrationRunner,\n MigrationRunnerOptions,\n} from './types.js';\n\nconst DEFAULT_SETTING_KEY = 'schemaVersion';\nconst INITIAL_VERSION = '0.0.0';\n\ninterface FoundryUtilsApi {\n isNewerVersion?: (next: string, current: string) => boolean;\n}\n\ninterface FoundryUiNotifications {\n info?: (msg: string) => unknown;\n warn?: (msg: string) => unknown;\n error?: (msg: string) => unknown;\n}\n\nfunction resolveIsNewerVersion(): (next: string, current: string) => boolean {\n const foundry = (globalThis as Record<string, unknown>).foundry as\n | { utils?: FoundryUtilsApi }\n | undefined;\n const fn = foundry?.utils?.isNewerVersion;\n if (typeof fn === 'function') return fn;\n // Last-resort fallback for non-Foundry runtimes — naive numeric semver compare.\n // Real consumers always run inside Foundry where the proper comparator exists.\n return naiveIsNewerVersion;\n}\n\nfunction naiveIsNewerVersion(next: string, current: string): boolean {\n const parse = (v: string): number[] =>\n v.split('.').map((part) => {\n const n = Number.parseInt(part, 10);\n return Number.isNaN(n) ? 0 : n;\n });\n const a = parse(next);\n const b = parse(current);\n const len = Math.max(a.length, b.length);\n for (let i = 0; i < len; i++) {\n const ai = a[i] ?? 0;\n const bi = b[i] ?? 0;\n if (ai > bi) return true;\n if (ai < bi) return false;\n }\n return false;\n}\n\nfunction resolveSettings(): GameSettingsApi {\n const game = (globalThis as Record<string, unknown>).game as\n | { settings?: GameSettingsApi }\n | undefined;\n const settings = game?.settings;\n if (\n settings === undefined ||\n typeof settings.register !== 'function' ||\n typeof settings.get !== 'function' ||\n typeof settings.set !== 'function'\n ) {\n throw new VttfError(\n 'VTTF-0002',\n 'globalThis.game.settings is not available — call createMigrationRunner().register() inside the Foundry runtime (or pass an explicit settings adapter in MigrationRunnerOptions).',\n );\n }\n return settings;\n}\n\nfunction resolveLogger(): MigrationLogger {\n const ui = (globalThis as Record<string, unknown>).ui as\n | { notifications?: FoundryUiNotifications }\n | undefined;\n const notifications = ui?.notifications;\n return {\n info(message) {\n // biome-ignore lint/suspicious/noConsole: console.info is the only Foundry-portable info-level logger\n console.info(message);\n notifications?.info?.(message);\n },\n warn(message) {\n console.warn(message);\n notifications?.warn?.(message);\n },\n error(message) {\n console.error(message);\n notifications?.error?.(message);\n },\n };\n}\n\nfunction lastVersion(migrations: ReadonlyArray<Migration>): string {\n return migrations.at(-1)?.version ?? INITIAL_VERSION;\n}\n\nfunction assertAscending(\n migrations: ReadonlyArray<Migration>,\n isNewer: (next: string, current: string) => boolean,\n): void {\n for (let i = 1; i < migrations.length; i++) {\n const prevMig = migrations[i - 1];\n const nextMig = migrations[i];\n // Loop bounds guarantee both indices are valid; the explicit guard\n // exists to satisfy TypeScript's flow analysis without a non-null\n // assertion.\n if (prevMig === undefined || nextMig === undefined) continue;\n if (!isNewer(nextMig.version, prevMig.version)) {\n throw new VttfError(\n 'VTTF-0004',\n `Migration list out of order: ${nextMig.version} must be newer than ${prevMig.version}.`,\n );\n }\n }\n}\n\n/**\n * Build a migration runner for a system. See module header for the failure\n * semantics; see `Migration` JSDoc for the per-entry shape.\n *\n * @example\n * ```ts\n * const migrations = createMigrationRunner({\n * systemId: 'my-system',\n * migrations: [\n * { version: '1.0.0', description: 'Rename bio → biography', fn: migrateV1 },\n * { version: '2.0.0', description: 'Add hp.temp', fn: migrateV2 },\n * ],\n * compatibleVersion: '0.9.0',\n * });\n *\n * registerSystem({\n * id: 'my-system',\n * onAfterInit: () => migrations.register(),\n * onReady: async () => {\n * if (!game.user.isGM) return;\n * await migrations.run();\n * },\n * });\n * ```\n */\nexport function createMigrationRunner(options: MigrationRunnerOptions): MigrationRunner {\n const settingKey = options.settingKey ?? DEFAULT_SETTING_KEY;\n const target = lastVersion(options.migrations);\n const settingsOverride = options.settings;\n const loggerOverride = options.logger;\n const isNewerOverride = options.isNewerVersion;\n\n return {\n targetVersion: target,\n\n register(): void {\n const settings = settingsOverride ?? resolveSettings();\n settings.register<string>(options.systemId, settingKey, {\n name: 'Schema Version',\n hint: 'Internal schema version for VTTForge data migration tracking. Do not edit by hand.',\n scope: 'world',\n config: false,\n type: String,\n default: INITIAL_VERSION,\n });\n },\n\n async run(): Promise<ReadonlyArray<string>> {\n if (options.migrations.length === 0) return [];\n\n const settings = settingsOverride ?? resolveSettings();\n const logger = loggerOverride ?? resolveLogger();\n const isNewer = isNewerOverride ?? resolveIsNewerVersion();\n\n assertAscending(options.migrations, isNewer);\n\n const stored = settings.get<string>(options.systemId, settingKey);\n const current = stored ?? INITIAL_VERSION;\n\n if (options.compatibleVersion !== undefined) {\n if (isNewer(options.compatibleVersion, current)) {\n throw new VttfError(\n 'VTTF-0005',\n `World schemaVersion ${current} is older than ${options.systemId}'s compatibleVersion ${options.compatibleVersion}. Upgrade through an intermediate release first.`,\n );\n }\n }\n\n const pending = options.migrations.filter((m) => isNewer(m.version, current));\n if (pending.length === 0) return [];\n\n const ran: string[] = [];\n let lastApplied = current;\n logger.warn(\n `${options.systemId} | Running ${pending.length} pending migration(s) from ${current} to ${target}.`,\n );\n\n for (const migration of pending) {\n const label = migration.description\n ? `${migration.version} — ${migration.description}`\n : migration.version;\n logger.info(`${options.systemId} | Migrating to ${label}`);\n try {\n await migration.fn();\n } catch (cause) {\n if (isNewer(lastApplied, current)) {\n await settings.set(options.systemId, settingKey, lastApplied);\n }\n throw new VttfError(\n 'VTTF-0004',\n `Migration to ${label} failed for system \"${options.systemId}\". schemaVersion left at ${lastApplied}.`,\n { cause },\n );\n }\n await settings.set(options.systemId, settingKey, migration.version);\n lastApplied = migration.version;\n ran.push(migration.version);\n }\n\n logger.info(`${options.systemId} | Migration complete. schemaVersion = ${target}.`);\n return ran;\n },\n };\n}\n","/**\n * registerModule — the module counterpart to `registerSystem`.\n *\n * A module is a guest in someone else's world, and Foundry enforces that. The\n * two differences that matter:\n *\n * - **Sub-type keys are namespaced.** A system registers `character`; a module\n * registering the same thing must register `<module-id>.character`, and the\n * manifest must declare it under `documentTypes`. Forget the prefix and the\n * type silently never appears. This function adds it for you.\n * - **A module never owns the globals.** Document classes, the initiative\n * formula and the status-effect array belong to the system. So there is no\n * option here to replace them — `statusEffects` only appends, which is what\n * a module is allowed to do.\n */\n\nimport { VttfError, type VttfErrorCode } from './errors/registry.js';\nimport type { FoundryConfig, HooksApi } from './foundry-globals.js';\n\nexport interface ModuleRegistration {\n /** Module id — must match the folder name and `module.json` `id`. */\n readonly id: string;\n\n /**\n * Actor sub-types this module contributes, keyed by the bare type name.\n * Registered under `<id>.<type>`, so declare them the same way in\n * `documentTypes.Actor` in your manifest.\n */\n readonly actorDataModels?: Readonly<Record<string, unknown>>;\n\n /** Item sub-types, same rule as `actorDataModels`. */\n readonly itemDataModels?: Readonly<Record<string, unknown>>;\n\n /**\n * Status effects to append to `CONFIG.statusEffects`.\n *\n * Appended, never assigned: the array belongs to the system, and replacing\n * it would delete conditions the world depends on.\n */\n readonly statusEffects?: readonly unknown[];\n\n /** Runs before any CONFIG mutation — the usual home for the module API. */\n readonly onBeforeInit?: () => void;\n\n /** Runs after the mutations above, inside the same `init` hook. */\n readonly onAfterInit?: () => void;\n\n /**\n * Runs once on `ready`.\n *\n * **Not GM-gated.** Guard inside your callback when the work is GM-only.\n */\n readonly onReady?: () => void | Promise<void>;\n}\n\nconst registered = new Set<string>();\n\n/** For tests — clears the in-process \"already registered\" guard. */\nexport function _resetRegisteredModulesForTests(): void {\n registered.clear();\n}\n\n/**\n * The key Foundry files a module's document sub-type under.\n *\n * Use it wherever you name the type outside `registerModule` — registering the\n * sheet, checking `actor.type`, writing `documentTypes` in the manifest. The\n * prefix is easy to get wrong by hand and fails silently when you do.\n *\n * @example\n * ```ts\n * moduleSubType('pdf-character-sheet', 'pdf'); // 'pdf-character-sheet.pdf'\n * ```\n */\nexport function moduleSubType(moduleId: string, type: string): string {\n return `${moduleId}.${type}`;\n}\n\nfunction vttfError(code: VttfErrorCode, message?: string): VttfError {\n return new VttfError(code, message);\n}\n\nfunction readHooks(): HooksApi {\n const hooks = (globalThis as Record<string, unknown>).Hooks as HooksApi | undefined;\n if (hooks === undefined || typeof hooks.once !== 'function') {\n throw vttfError(\n 'VTTF-0002',\n 'globalThis.Hooks is not available — call registerModule() inside a Foundry runtime or stub Hooks in tests',\n );\n }\n return hooks;\n}\n\nfunction readConfig(): FoundryConfig {\n const config = (globalThis as Record<string, unknown>).CONFIG as FoundryConfig | undefined;\n if (config === undefined) {\n throw vttfError(\n 'VTTF-0002',\n 'globalThis.CONFIG is not available — call registerModule() inside a Foundry runtime or stub CONFIG in tests',\n );\n }\n return config;\n}\n\nfunction assignSubTypes(\n target: Record<string, unknown>,\n moduleId: string,\n models: Readonly<Record<string, unknown>>,\n): void {\n for (const [type, model] of Object.entries(models)) {\n target[moduleSubType(moduleId, type)] = model;\n }\n}\n\n/**\n * Register a Foundry module with VTTForge.\n *\n * Calling twice with the same `id` throws VTTF-0001 — almost always a\n * hot-reload artefact or a duplicate import. The CONFIG mutations are deferred\n * until Foundry's `init` hook fires.\n */\nexport function registerModule(config: ModuleRegistration): ModuleRegistration {\n if (registered.has(config.id)) {\n throw vttfError('VTTF-0001', `Module \"${config.id}\" was already registered`);\n }\n registered.add(config.id);\n\n const hooks = readHooks();\n hooks.once('init', () => {\n applyInit(config);\n });\n if (config.onReady !== undefined) {\n hooks.once('ready', () => {\n void config.onReady?.();\n });\n }\n\n return config;\n}\n\nfunction applyInit(config: ModuleRegistration): void {\n config.onBeforeInit?.();\n const CONFIG = readConfig();\n\n if (config.actorDataModels !== undefined) {\n assignSubTypes(CONFIG.Actor.dataModels, config.id, config.actorDataModels);\n }\n if (config.itemDataModels !== undefined) {\n assignSubTypes(CONFIG.Item.dataModels, config.id, config.itemDataModels);\n }\n if (config.statusEffects !== undefined && config.statusEffects.length > 0) {\n CONFIG.statusEffects ??= [];\n CONFIG.statusEffects.push(...config.statusEffects);\n }\n\n config.onAfterInit?.();\n}\n","/**\n * registerSystem — one call that replaces the boilerplate `Hooks.once(\"init\", ...)`\n * block in every Foundry system.\n *\n * Conforms to the canonical Foundry init lifecycle:\n *\n * init → CONFIG mutations (dataModels, documentClass, statusEffects)\n * i18nInit → translate CONFIG labels\n * setup → enrichers, packs\n * ready → migrations (GM-only — consumer guards inside onReady)\n *\n * v0.1 scope: `init` + `ready`. `setup` / `i18nInit` callbacks remain v0.1.1.\n *\n * Per PRD §11 open question #1, we wrap the hook ourselves (\"explicit hook for\n * now\"); callers don't need to write `Hooks.once(\"init\", ...)` themselves.\n */\n\nimport { VttfError, type VttfErrorCode } from './errors/registry.js';\nimport type {\n ActiveEffectConfig,\n CombatConfig,\n FoundryConfig,\n HooksApi,\n} from './foundry-globals.js';\n\nexport interface SystemRegistration {\n /** System id — must match the folder name and `system.json` `id`. */\n readonly id: string;\n\n /** Map of `documentTypes.Actor` key → TypeDataModel class. */\n readonly actorDataModels?: Readonly<Record<string, unknown>>;\n\n /** Map of `documentTypes.Item` key → TypeDataModel class. */\n readonly itemDataModels?: Readonly<Record<string, unknown>>;\n\n /** Replacement for `CONFIG.Actor.documentClass`. */\n readonly actorDocumentClass?: unknown;\n\n /** Replacement for `CONFIG.Item.documentClass`. */\n readonly itemDocumentClass?: unknown;\n\n /** Global initiative formula — assigned to `CONFIG.Combat.initiative`. */\n readonly combat?: CombatConfig;\n\n /** Disables legacy Active Effect transferral. Defaults to true. */\n readonly activeEffect?: ActiveEffectConfig;\n\n /**\n * Replaces `CONFIG.statusEffects` (systems own this array — modules push).\n * If omitted, the existing array is kept untouched.\n */\n readonly statusEffects?: readonly unknown[];\n\n /**\n * Optional pre-init hook for work that has to run before any of the CONFIG\n * mutations (rare — usually used to assign `globalThis.<systemId>` API).\n */\n readonly onBeforeInit?: () => void;\n\n /** Optional post-init hook for work that depends on the mutations above. */\n readonly onAfterInit?: () => void;\n\n /**\n * Optional `ready` hook — fires once after Foundry has finished bootstrap.\n * The natural home for migration runners (`createMigrationRunner().run()`).\n *\n * **Not GM-gated.** Guard inside your callback (`if (!game.user.isGM) return;`)\n * when the work is GM-only — migrations always are.\n */\n readonly onReady?: () => void | Promise<void>;\n}\n\nconst registered = new Set<string>();\n\n/** For tests — clears the in-process \"already registered\" guard. */\nexport function _resetRegisteredSystemsForTests(): void {\n registered.clear();\n}\n\nfunction readHooks(): HooksApi {\n const hooks = (globalThis as Record<string, unknown>).Hooks as HooksApi | undefined;\n if (hooks === undefined || typeof hooks.once !== 'function') {\n throw vttfError(\n 'VTTF-0002',\n 'globalThis.Hooks is not available — call registerSystem() inside a Foundry runtime or stub Hooks in tests',\n );\n }\n return hooks;\n}\n\nfunction readConfig(): FoundryConfig {\n const config = (globalThis as Record<string, unknown>).CONFIG as FoundryConfig | undefined;\n if (config === undefined) {\n throw vttfError(\n 'VTTF-0002',\n 'globalThis.CONFIG is not available — call registerSystem() inside a Foundry runtime or stub CONFIG in tests',\n );\n }\n return config;\n}\n\nfunction vttfError(code: VttfErrorCode, message?: string): VttfError {\n return new VttfError(code, message);\n}\n\n/**\n * Register a Foundry system with VTTForge. Idempotency: the same `id` calling\n * twice throws VTTF-0001 — almost always a hot-reload or duplicate import bug.\n *\n * Returns the registration object so consumers can inspect what was applied\n * (useful in tests). The actual CONFIG mutations are deferred until Foundry's\n * `init` hook fires.\n */\nexport function registerSystem(config: SystemRegistration): SystemRegistration {\n if (registered.has(config.id)) {\n throw vttfError('VTTF-0001', `System \"${config.id}\" was already registered`);\n }\n registered.add(config.id);\n\n const hooks = readHooks();\n hooks.once('init', () => {\n applyInit(config);\n });\n if (config.onReady !== undefined) {\n hooks.once('ready', () => {\n // Foundry awaits ready-hook results, but `Hooks.once` types it as\n // `unknown` so we don't return anything ourselves — Foundry treats\n // Promise rejections as unhandled, which is the right escalation.\n void config.onReady?.();\n });\n }\n\n return config;\n}\n\nfunction applyInit(config: SystemRegistration): void {\n config.onBeforeInit?.();\n const CONFIG = readConfig();\n\n if (config.actorDataModels !== undefined) {\n Object.assign(CONFIG.Actor.dataModels, config.actorDataModels);\n }\n if (config.itemDataModels !== undefined) {\n Object.assign(CONFIG.Item.dataModels, config.itemDataModels);\n }\n if (config.actorDocumentClass !== undefined) {\n CONFIG.Actor.documentClass = config.actorDocumentClass;\n }\n if (config.itemDocumentClass !== undefined) {\n CONFIG.Item.documentClass = config.itemDocumentClass;\n }\n if (config.combat?.initiative !== undefined) {\n CONFIG.Combat.initiative = config.combat.initiative;\n }\n\n // Disable legacy Active Effect transferral by default — every modern v13\n // system wants this off (the modern AE model is opt-in via this flag).\n const legacyTransferral = config.activeEffect?.legacyTransferral ?? false;\n CONFIG.ActiveEffect.legacyTransferral = legacyTransferral;\n\n if (config.statusEffects !== undefined) {\n CONFIG.statusEffects = [...config.statusEffects];\n }\n\n config.onAfterInit?.();\n}\n","/**\n * SystemConfig — typed wrapper around `game.settings.register/get/set`.\n *\n * Eliminates the boilerplate of repeating the system id in every call:\n *\n * // before\n * game.settings.register(\"ordemparanormal\", \"homebrewRules\", { ... });\n * game.settings.get(\"ordemparanormal\", \"homebrewRules\");\n *\n * // after\n * const cfg = new SystemConfig(\"ordemparanormal\");\n * cfg.register(\"homebrewRules\", { ... });\n * cfg.get<boolean>(\"homebrewRules\");\n *\n * Also keeps a local manifest of registered keys so attempts to read an\n * unregistered key fail with VTTF-0003 instead of returning undefined.\n *\n * Registration must happen during the `init` hook; reads can happen any\n * time after.\n */\n\nimport { VttfError } from './errors/registry.js';\nimport type { GameApi, SettingConfig } from './foundry-globals.js';\n\nfunction readGame(): GameApi {\n const candidate = (globalThis as Record<string, unknown>).game as GameApi | undefined;\n if (candidate === undefined || candidate.settings === undefined) {\n throw new VttfError(\n 'VTTF-0002',\n 'game.settings is not available — call SystemConfig methods inside or after the Foundry \"init\" hook',\n );\n }\n return candidate;\n}\n\nexport class SystemConfig {\n readonly systemId: string;\n readonly #registered = new Set<string>();\n\n constructor(systemId: string) {\n this.systemId = systemId;\n }\n\n register<T>(key: string, config: SettingConfig<T>): void {\n const game = readGame();\n game.settings.register(this.systemId, key, config);\n this.#registered.add(key);\n }\n\n get<T>(key: string): T {\n if (!this.#registered.has(key)) {\n throw new VttfError(\n 'VTTF-0003',\n `SystemConfig.get(\"${key}\") was called before register(\"${key}\")`,\n );\n }\n return readGame().settings.get<T>(this.systemId, key);\n }\n\n async set<T>(key: string, value: T): Promise<T> {\n if (!this.#registered.has(key)) {\n throw new VttfError(\n 'VTTF-0003',\n `SystemConfig.set(\"${key}\") was called before register(\"${key}\")`,\n );\n }\n return readGame().settings.set<T>(this.systemId, key, value);\n }\n\n isRegistered(key: string): boolean {\n return this.#registered.has(key);\n }\n}\n","/**\n * @vttforge/core — runtime utilities for FoundryVTT v13+ systems and modules.\n *\n * v0.1 surface:\n *\n * - registerSystem() — one-call init, replaces Hooks.once(\"init\")\n * - registerModule() — the same for modules, with namespaced sub-types\n * - SystemConfig — typed wrapper around game.settings\n * - BaseTypeDataModel() — TypeDataModel with safe migrateData default\n * - BaseActorSheet() — ActorSheetV2 + HandlebarsApplicationMixin\n * - BaseItemSheet() — ItemSheetV2 + HandlebarsApplicationMixin\n * - fields() — typed bag of foundry.data.fields constructors\n * - InferSchema<T> — derive `system` shape from defineSchema()\n * - createMigrationRunner() — declarative schema migrations (register + run)\n * - VttfError + error registry — VTTF-NNNN codes with docs URLs\n *\n * Foundry classes are resolved from `globalThis.foundry` lazily so the package\n * imports cleanly in Node/tests; concrete Foundry typing arrives with\n * `@vttforge/types` in v1.0.\n */\n\nexport const VTTFORGE_CORE_VERSION = '0.2.0';\n\nexport {\n BaseActorSheet,\n type DragDropConfig,\n type SheetBaseCtor,\n type SheetBaseStatics,\n VTTFORGE_SHEET_CLASS,\n} from './base-actor-sheet.js';\nexport { BaseItemSheet } from './base-item-sheet.js';\nexport {\n BaseTypeDataModel,\n type TypeDataModelHooks,\n type TypedTypeDataModel,\n type TypedTypeDataModelCtor,\n} from './base-type-data-model.js';\nexport type {\n ArrayFieldOptions,\n BooleanFieldOptions,\n ColorFieldOptions,\n DataFieldOptions,\n FilePathFieldOptions,\n ForeignDocumentFieldOptions,\n HTMLFieldOptions,\n NumberFieldOptions,\n SchemaFieldOptions,\n SetFieldOptions,\n StringFieldOptions,\n} from './data/field-options.js';\nexport {\n type ArrayFieldCtor,\n type ArrayFieldInstance,\n type BooleanFieldCtor,\n type BooleanFieldInstance,\n type ColorFieldCtor,\n type ColorFieldInstance,\n type DocumentClass,\n type FieldInstance,\n type FieldsApi,\n type FilePathFieldCtor,\n type FilePathFieldInstance,\n type ForeignDocumentFieldCtor,\n type ForeignDocumentFieldInstance,\n fields,\n type HTMLFieldCtor,\n type HTMLFieldInstance,\n type NumberFieldCtor,\n type NumberFieldInstance,\n type SchemaFieldCtor,\n type SchemaFieldInstance,\n type SetFieldCtor,\n type SetFieldInstance,\n type StringFieldCtor,\n type StringFieldInstance,\n} from './data/fields.js';\nexport type { InferField, InferSchema, Prettify } from './data/infer-schema.js';\nexport {\n ERROR_MANIFEST_VERSION,\n type ErrorManifest,\n getErrorManifest,\n} from './errors/manifest.js';\nexport {\n docsUrlFor,\n getErrorEntry,\n listErrorEntries,\n VttfError,\n type VttfErrorCode,\n type VttfErrorEntry,\n} from './errors/registry.js';\nexport type {\n ActiveEffectConfig,\n CombatConfig,\n FoundryConfig,\n GameApi,\n GameSettingsApi,\n HookCallback,\n HooksApi,\n SettingConfig,\n SettingScope,\n} from './foundry-globals.js';\nexport { createMigrationRunner } from './migrations/runner.js';\nexport type {\n Migration,\n MigrationLogger,\n MigrationRunner,\n MigrationRunnerOptions,\n} from './migrations/types.js';\nexport {\n type ModuleRegistration,\n moduleSubType,\n registerModule,\n} from './register-module.js';\nexport { registerSystem, type SystemRegistration } from './register-system.js';\nexport { SystemConfig } from './system-config.js';\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,16 +1,61 @@
1
1
  {
2
2
  "name": "@vttforge/core",
3
- "version": "0.0.0",
4
- "description": "Runtime utilities for building FoundryVTT systems and modules. Placeholder — real release coming soon.",
5
- "keywords": ["foundryvtt", "fvtt", "vtt", "sdk", "tabletop", "ttrpg"],
3
+ "version": "0.6.0",
4
+ "description": "VTTForge core runtime: BaseTypeDataModel, BaseActorSheet, SystemConfig, registerSystem, error registry.",
5
+ "type": "module",
6
6
  "license": "MIT",
7
- "author": "Fabricio Cavalcante de Souza <fabricio.unix@gmail.com> (https://github.com/fcsouza)",
8
- "homepage": "https://github.com/vttforge/vttforge",
7
+ "homepage": "https://github.com/vttforge/vttforge#readme",
9
8
  "repository": {
10
9
  "type": "git",
11
- "url": "git+https://github.com/vttforge/vttforge.git"
10
+ "url": "git+https://github.com/vttforge/vttforge.git",
11
+ "directory": "packages/core"
12
12
  },
13
- "bugs": {
14
- "url": "https://github.com/vttforge/vttforge/issues"
13
+ "bugs": "https://github.com/vttforge/vttforge/issues",
14
+ "keywords": [
15
+ "foundryvtt",
16
+ "foundry-vtt",
17
+ "sdk",
18
+ "typescript",
19
+ "vtt"
20
+ ],
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.mts",
24
+ "import": "./dist/index.mjs"
25
+ },
26
+ "./package.json": "./package.json"
27
+ },
28
+ "main": "./dist/index.mjs",
29
+ "module": "./dist/index.mjs",
30
+ "types": "./dist/index.d.mts",
31
+ "files": [
32
+ "dist",
33
+ "README.md",
34
+ "CHANGELOG.md"
35
+ ],
36
+ "sideEffects": false,
37
+ "devDependencies": {
38
+ "@arethetypeswrong/cli": "^0.18.5",
39
+ "happy-dom": "^20.12.0",
40
+ "publint": "^0.3.24",
41
+ "tsdown": "^0.22.14",
42
+ "typescript": "^7.0.2",
43
+ "unrun": "^0.3.1",
44
+ "vitest": "^4.1.11"
45
+ },
46
+ "engines": {
47
+ "node": ">=26.0.0"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public",
51
+ "provenance": false
52
+ },
53
+ "scripts": {
54
+ "build": "tsdown",
55
+ "postbuild": "node ./scripts/codegen-errors.mjs",
56
+ "typecheck": "tsc --noEmit",
57
+ "test": "vitest run",
58
+ "publint": "publint",
59
+ "attw": "attw --pack . --profile esm-only"
15
60
  }
16
- }
61
+ }