@vttforge/core 0.0.0 → 0.7.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.
- package/CHANGELOG.md +308 -0
- package/LICENSE +21 -0
- package/README.md +9 -6
- package/dist/errors-manifest.json +32 -0
- package/dist/index.d.mts +1049 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +911 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +54 -9
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# @vttforge/core
|
|
2
|
+
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- dcd07d5: Type the three embedded fields, and turn `checkJs` back on for the example.
|
|
8
|
+
|
|
9
|
+
- `EmbeddedDataField` is the model instance, not a plain object — the field builds a schema from the model's own `defineSchema()`, but initializing constructs the model, so derived data and methods come with it.
|
|
10
|
+
- `EmbeddedDocumentField` is the same for a Document class, and nullable out of the box.
|
|
11
|
+
- `TypedSchemaField` is a discriminated union. The field supplies a `type` string validated to equal each entry's key when the entry does not declare one, which is what makes narrowing on `type` work.
|
|
12
|
+
|
|
13
|
+
The example system now compiles with `checkJs: true`, which is what proves any of this against real JavaScript rather than only against type tests.
|
|
14
|
+
|
|
15
|
+
## 0.6.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- c24b2e9: Fix two things `InferSchema` got wrong about a field's runtime type.
|
|
20
|
+
|
|
21
|
+
`ColorField` inferred as `string`. It stores a CSS string but initializes
|
|
22
|
+
into a `Color` instance, so `system.tint` is an object with `.css`, `.rgb`
|
|
23
|
+
and friends — and the old typing made every property access on it a lie the
|
|
24
|
+
compiler accepted. It is also nullable by default, unlike the other
|
|
25
|
+
string-backed fields: the field's own defaults are `nullable: true,
|
|
26
|
+
initial: null`, so reading `.css` off a fresh document was a real crash the
|
|
27
|
+
types allowed. It now infers as `Color | null`, and drops the null when
|
|
28
|
+
`nullable: false` is set.
|
|
29
|
+
|
|
30
|
+
Presence was half-implemented. Only `nullable: true` widened the type;
|
|
31
|
+
`required: false` did not. A field that resolves to `undefined` when absent
|
|
32
|
+
was typed as always present. The rule now follows how a field actually
|
|
33
|
+
resolves a missing value: an explicit `initial` always fills, so it never
|
|
34
|
+
widens; otherwise `required: false` admits `undefined` and `nullable: true`
|
|
35
|
+
admits `null`, and the two compose.
|
|
36
|
+
|
|
37
|
+
`Color` is described structurally rather than imported, so the inference
|
|
38
|
+
surface still carries no dependency on a Foundry type package.
|
|
39
|
+
- 3f09683: Add `registerModule()` for modules that contribute document sub-types.
|
|
40
|
+
|
|
41
|
+
Foundry files a module's sub-type under `<module-id>.<type>`. Register the bare name and there is no error — the type just never appears. `registerModule()` adds the prefix, and `moduleSubType(id, type)` gives you the same string wherever else you need it (registering the sheet, checking `actor.type`, writing `documentTypes` in the manifest).
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
registerModule({
|
|
45
|
+
id: 'pdf-character-sheet',
|
|
46
|
+
itemDataModels: { pdf: PdfItemData }, // → CONFIG.Item.dataModels['pdf-character-sheet.pdf']
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`registerSystem()` was the only option before, and it is the wrong shape for a module: it writes bare keys and also replaces the document classes, the initiative formula, and the status-effect array — all of which belong to the system. There is no option to replace them here, and `statusEffects` appends instead of assigning.
|
|
51
|
+
- 98b742c: Give each field its own defaults when inferring a schema.
|
|
52
|
+
|
|
53
|
+
Every field class picks its own defaults, and they disagree. The inference treated them as if they agreed, so three fields were typed as shapes they cannot hold:
|
|
54
|
+
|
|
55
|
+
- `NumberField` is optional and nullable out of the box. `new fields.NumberField()` is `number | null | undefined`, not `number`.
|
|
56
|
+
- `StringField` is optional. A bare one is `string | undefined`.
|
|
57
|
+
- `FilePathField` starts at `null`, the way `ColorField` does. A bare one is `string | null`.
|
|
58
|
+
|
|
59
|
+
The rest were already right, for reasons worth naming: booleans and HTML fields are required and supply their own initial; arrays, sets and schemas are required and build their own empty value; document references are required but nullable.
|
|
60
|
+
|
|
61
|
+
This will surface errors in schemas that leave the options off. The fix is to declare what you meant — `{ required: true, nullable: false, initial: 0 }` — which is what the field needed all along.
|
|
62
|
+
- 8657721: Let `BaseTypeDataModel` learn your schema.
|
|
63
|
+
|
|
64
|
+
Hand it the function that returns your fields and it implements `static defineSchema()` for you. The schema is written once, and `this` inside `prepareDerivedData()` knows its own fields:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
class CharacterData extends BaseTypeDataModel(defineCharacterSchema) {
|
|
68
|
+
declare armorClass: number;
|
|
69
|
+
prepareDerivedData() {
|
|
70
|
+
this.armorClass = 10 + this.level; // this.level is number
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type CharacterSystem = CharacterData['$inferData'];
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Derived values are not in the schema, so declare them on the subclass.
|
|
78
|
+
|
|
79
|
+
Calling `BaseTypeDataModel()` with no arguments works exactly as before.
|
|
80
|
+
- f11b1f4: Type `SetField` and `ForeignDocumentField` in `InferSchema`.
|
|
81
|
+
|
|
82
|
+
A `SetField` holds a `Set`, not an array. Inferring it as an array handed you `push` and index access on a value that has neither, and the compiler agreed.
|
|
83
|
+
|
|
84
|
+
A `ForeignDocumentField` reads back as the document itself — the data model installs the field as a getter, so the property gives you the instance, not the function that fetched it. Under `idOnly` it stays the id string. Both admit `null` unless the schema sets `nullable: false`.
|
|
85
|
+
|
|
86
|
+
Also exported: `SetFieldInstance`, `SetFieldCtor`, `SetFieldOptions`, `ForeignDocumentFieldInstance`, `ForeignDocumentFieldCtor`, `ForeignDocumentFieldOptions`, and `DocumentClass`.
|
|
87
|
+
- 74c4126: Type the statics on `BaseActorSheet()` and `BaseItemSheet()`.
|
|
88
|
+
|
|
89
|
+
Both returned a bare constructor, so a subclass writing `super.DEFAULT_OPTIONS` — the pattern the docs show and every sheet needs — failed to compile. TypeScript cannot see a static through an untyped constructor. The example system is JavaScript, so nothing caught it.
|
|
90
|
+
|
|
91
|
+
They now return `SheetBaseCtor`, which carries `DEFAULT_OPTIONS` and `DRAG_DROP`. A subclass declaring either needs the `override` modifier, which is TypeScript correctly seeing the inherited static.
|
|
92
|
+
|
|
93
|
+
## 0.5.0
|
|
94
|
+
|
|
95
|
+
### Minor Changes
|
|
96
|
+
|
|
97
|
+
- 9462144: Require Node 26.
|
|
98
|
+
|
|
99
|
+
The floor moves from `>=22.14.0` to `>=26.0.0` across every package and the
|
|
100
|
+
four scaffolding templates, and the bundler target for the Node-side
|
|
101
|
+
packages moves from `node22` to `node26`.
|
|
102
|
+
|
|
103
|
+
Node 22 entered maintenance in October 2025 and receives security fixes
|
|
104
|
+
only. Node 26 becomes the active LTS line on 2026-10-28.
|
|
105
|
+
|
|
106
|
+
This is breaking for anyone on Node 22 or 24. It is marked `minor` rather
|
|
107
|
+
than `major` on purpose: these packages are still on 0.x, where a minor
|
|
108
|
+
signals the break, and a major would push every package to 1.0.0 — a claim
|
|
109
|
+
of API stability that has not been audited, on packages two of which are
|
|
110
|
+
still stubs.
|
|
111
|
+
|
|
112
|
+
The templates move to the versions this release publishes. On 0.x a caret
|
|
113
|
+
pins the minor, so their old ranges would not have matched.
|
|
114
|
+
|
|
115
|
+
CI now pins Node through `actions/setup-node` instead of inheriting whatever
|
|
116
|
+
the runner image ships, so the version the packages declare is the version
|
|
117
|
+
they are tested on. It was not before: the workflow took the image's Node,
|
|
118
|
+
and nothing enforced the declared floor because `engine-strict` is not set.
|
|
119
|
+
|
|
120
|
+
## 0.4.0
|
|
121
|
+
|
|
122
|
+
### Minor Changes
|
|
123
|
+
|
|
124
|
+
- 50721f9: fix: align with Foundry v13 manifest schema and add `prepareBaseData` hook
|
|
125
|
+
|
|
126
|
+
Three coordinated changes:
|
|
127
|
+
|
|
128
|
+
**`@vttforge/core`** — `BaseTypeDataModel()` now ships a `prepareBaseData()`
|
|
129
|
+
no-op stub alongside `prepareDerivedData()`. Use `prepareBaseData()` to
|
|
130
|
+
initialize fields that Active Effects need to mutate (base max HP, base AC),
|
|
131
|
+
since AEs apply between `prepareBaseData()` and `prepareDerivedData()`.
|
|
132
|
+
`prepareDerivedData()` stays the place for values that depend on the
|
|
133
|
+
AE-mutated state.
|
|
134
|
+
|
|
135
|
+
The misleading `_addDataFieldMigrations()` static stub is removed. The real
|
|
136
|
+
field-rename API is `_addDataFieldMigration(source, oldKey, newKey, apply?)`
|
|
137
|
+
called inside a `static migrateData(source)` override — consumers who need
|
|
138
|
+
it can call it directly on the Foundry-provided base via `super`.
|
|
139
|
+
|
|
140
|
+
**`@vttforge/vite-plugin`** — emits the canonical v13 `styles` form
|
|
141
|
+
(`[{ src: "styles/foo.css" }]`) in the built manifest. Still accepts the
|
|
142
|
+
legacy string form (`["styles/foo.css"]`) and the v13 object form as input,
|
|
143
|
+
so existing consumers don't need to change their source manifest. Additional
|
|
144
|
+
metadata declared on object entries (e.g. `layer` for cascade layer
|
|
145
|
+
placement) is preserved through the rewrite — only `src` is rewritten to
|
|
146
|
+
point at the bundled output.
|
|
147
|
+
|
|
148
|
+
**`@vttforge-examples/simple-system`** — manifest aligned with v13 schema:
|
|
149
|
+
`gridDistance` / `gridUnits` collapsed into the `grid` object; `styles`
|
|
150
|
+
declared in object form; `flags.hotReload` declared at the root of `flags`
|
|
151
|
+
(not under the package namespace) and switched to the object form
|
|
152
|
+
(`{ extensions, paths }`) that Foundry's runtime hot-reload watcher
|
|
153
|
+
actually reads. The previous shape was a double no-op — wrong location AND
|
|
154
|
+
wrong form, so the watcher silently exited without registering any
|
|
155
|
+
extensions.
|
|
156
|
+
|
|
157
|
+
Hot-reload enablement on the Foundry server side is deferred — runtime
|
|
158
|
+
configuration changes interact with felddy's `CONTAINER_PRESERVE_CONFIG`
|
|
159
|
+
flag in ways that require a dedicated design pass. That work is tracked
|
|
160
|
+
separately and will land alongside the developer-facing hot-reload bridge.
|
|
161
|
+
|
|
162
|
+
## 0.3.0
|
|
163
|
+
|
|
164
|
+
### Minor Changes
|
|
165
|
+
|
|
166
|
+
- 234a4b2: Extend `BaseActorSheet` and add `BaseItemSheet` — the boilerplate every shipping
|
|
167
|
+
system copy-pastes is now hoisted into the SDK.
|
|
168
|
+
- `static DRAG_DROP` — declare drag sources / drop targets as data; the base
|
|
169
|
+
wires real `foundry.applications.ux.DragDrop` instances in `_onRender` with
|
|
170
|
+
`isEditable`-gated permissions and a default `_onDragStart` that serialises
|
|
171
|
+
`data-item-id` elements as `{ type: "Item", uuid }`.
|
|
172
|
+
- `_prepareContext` auto-fills `context.tabs[group]` for every group declared
|
|
173
|
+
in ApplicationV2's `static TABS`, eliminating manual `_prepareTabs(group)`
|
|
174
|
+
calls in subclass `_prepareContext`.
|
|
175
|
+
- Typed drop dispatch: override `onDropItem(item, event)` / `onDropActor(...)` /
|
|
176
|
+
`onDropFolder(...)` / `onDropActiveEffect(...)` and skip the `fromUuid()`
|
|
177
|
+
ceremony. Returning `undefined` falls through to Foundry's default
|
|
178
|
+
`_onDropX`; return anything else to take ownership.
|
|
179
|
+
- New `BaseItemSheet()` mirror with the same `static DRAG_DROP` + tab
|
|
180
|
+
auto-population, minus the drop dispatch (items rarely receive drops).
|
|
181
|
+
- Exports new `DragDropConfig` type for typed `static DRAG_DROP` declarations.
|
|
182
|
+
|
|
183
|
+
`editImage` is intentionally not reinvented — it already ships on
|
|
184
|
+
`DocumentSheetV2` (inherited by both `ActorSheetV2` and `ItemSheetV2`).
|
|
185
|
+
Templates wire `<img data-edit="img">` and Foundry's built-in action handles
|
|
186
|
+
the `FilePicker` flow.
|
|
187
|
+
|
|
188
|
+
- 4fd5a07: Error registry codegen — `docsUrl` now resolves to a real page.
|
|
189
|
+
|
|
190
|
+
`postbuild` hook (`packages/core/scripts/codegen-errors.mjs`) reads the
|
|
191
|
+
just-built `dist/index.mjs`, calls `listErrorEntries()`, and emits:
|
|
192
|
+
- `dist/errors-manifest.json` — versioned JSON catalogue shipped in the
|
|
193
|
+
tarball alongside the bundled JS/types. Stable shape (`version`,
|
|
194
|
+
`package`, `packageVersion`, `entries[]`) so external tooling (the v0.3
|
|
195
|
+
docs site, IDE extensions, lint rules) has a single source of truth.
|
|
196
|
+
- `docs/errors/VTTF-NNNN.md` at the repo root — one Markdown stub per code,
|
|
197
|
+
committed so the `docsUrl` already resolves while the full VitePress site
|
|
198
|
+
is being built in v0.3.
|
|
199
|
+
|
|
200
|
+
New runtime helper: `getErrorManifest()` returns the same data as
|
|
201
|
+
`listErrorEntries()`, wrapped in a typed `ErrorManifest` envelope with a
|
|
202
|
+
stable `version: 1` field for future format migrations.
|
|
203
|
+
|
|
204
|
+
Plan deviation: the codegen runs as `postbuild` (not `prebuild`) so the
|
|
205
|
+
script imports the just-built ESM directly instead of needing
|
|
206
|
+
`tsx`/`unrun` to load the TS source. Documented inline in the codegen
|
|
207
|
+
script.
|
|
208
|
+
|
|
209
|
+
- 0896bb0: Add `createMigrationRunner()` for declarative schema migrations, plus
|
|
210
|
+
`onReady` lifecycle on `registerSystem()`.
|
|
211
|
+
|
|
212
|
+
`createMigrationRunner({ systemId, migrations, ... })` returns `{ register(),
|
|
213
|
+
run(), targetVersion }`. Call `register()` from `init` to register the
|
|
214
|
+
`schemaVersion` setting; call `run()` from `ready` (gated by
|
|
215
|
+
`game.user.isGM`) to execute every pending migration in order. Migrations use
|
|
216
|
+
semver versions and `foundry.utils.isNewerVersion` for comparison — the same
|
|
217
|
+
contract `system.json`'s `flags.<systemId>.needsMigrationVersion` /
|
|
218
|
+
`compatibleMigrationVersion` use, matching the dnd5e production pattern.
|
|
219
|
+
|
|
220
|
+
Failure semantics: `schemaVersion` is committed per-migration, so a
|
|
221
|
+
mid-sequence throw leaves the world at the last successful version and the
|
|
222
|
+
retry on the next world load picks up exactly where it failed. Migration
|
|
223
|
+
errors are wrapped in `VttfError VTTF-0004` with the original error on
|
|
224
|
+
`.cause`; calling `run()` against a world older than `compatibleVersion`
|
|
225
|
+
throws `VttfError VTTF-0005`.
|
|
226
|
+
|
|
227
|
+
`registerSystem()` gains `onReady?: () => void | Promise<void>` — the natural
|
|
228
|
+
place to wire `migrationRunner.run()`. Not GM-gated; consumer guards inside
|
|
229
|
+
their callback.
|
|
230
|
+
|
|
231
|
+
New error codes (append-only): `VTTF-0004 MigrationFailed`,
|
|
232
|
+
`VTTF-0005 WorldTooOldForMigration`.
|
|
233
|
+
|
|
234
|
+
- 49a8718: Fix `BaseActorSheet` / `BaseItemSheet` tab handling so sheets work without
|
|
235
|
+
per-consumer workarounds.
|
|
236
|
+
|
|
237
|
+
Two issues surfaced when running the example sheet inside a live Foundry v13:
|
|
238
|
+
- **`context.tabs` double-wrap on single-group sheets.** The previous
|
|
239
|
+
`_prepareContext` override unconditionally set `context.tabs[group]`,
|
|
240
|
+
even when ApplicationV2 already populated a flat
|
|
241
|
+
`context.tabs[tabId]` for single-group sheets. The collision forced
|
|
242
|
+
consumers to either unwrap manually or write `context.tabs.<group>.<tabId>`
|
|
243
|
+
in every template. Fixed: BaseActorSheet/BaseItemSheet now only fill
|
|
244
|
+
`context.tabs[group]` for **multi-group** sheets (single-group sheets
|
|
245
|
+
see ApplicationV2's flat shape untouched).
|
|
246
|
+
|
|
247
|
+
- **No default `tab`-style action handler.** ApplicationV2 doesn't ship a
|
|
248
|
+
built-in handler for `data-action="…"` tab navigation buttons, and the
|
|
249
|
+
bare name `tab` is reserved by the framework (custom handlers under that
|
|
250
|
+
name never fire). Fixed: both base sheets now ship a `vttforgeTab`
|
|
251
|
+
action that toggles `.active` on the matching nav button
|
|
252
|
+
(`[data-action="vttforgeTab"][data-group=…][data-tab=…]`) and content
|
|
253
|
+
section (`section.tab[data-group=…][data-tab=…]`) and updates
|
|
254
|
+
`sheet.tabGroups[group]`. Templates that already used the old per-sheet
|
|
255
|
+
workaround need to rename `data-action="tab"` → `data-action="vttforgeTab"`.
|
|
256
|
+
|
|
257
|
+
Discovered during development testing — not derived from any external
|
|
258
|
+
source.
|
|
259
|
+
|
|
260
|
+
Patch bump for the example: drops the `_prepareContext` unwrap workaround
|
|
261
|
+
and the per-sheet `_onTab` static handlers added in the previous PR,
|
|
262
|
+
since both now live in the SDK.
|
|
263
|
+
|
|
264
|
+
## 0.2.0
|
|
265
|
+
|
|
266
|
+
### Minor Changes
|
|
267
|
+
|
|
268
|
+
- 5dd98c1: Add `fields()` factory and `InferSchema<T>` for typed `defineSchema()` outputs.
|
|
269
|
+
|
|
270
|
+
Covers the v0.1 partial scope from PRD §7: `NumberField`, `StringField`,
|
|
271
|
+
`BooleanField`, `HTMLField`, `ArrayField`, `SchemaField`, `ColorField`,
|
|
272
|
+
`FilePathField`. Calling `fields()` lazy-resolves `globalThis.foundry.data.fields`
|
|
273
|
+
and throws `VttfError VTTF-0002` outside the Foundry runtime — same pattern as
|
|
274
|
+
`BaseTypeDataModel()` / `BaseActorSheet()`.
|
|
275
|
+
|
|
276
|
+
`InferSchema<S>` derives the `system` shape from a `defineSchema()` return value,
|
|
277
|
+
recursing through `ArrayField` and `SchemaField` and honouring the single
|
|
278
|
+
nullability rule `nullable: true` → `T | null`. Full class-level inference
|
|
279
|
+
(`BaseTypeDataModel<typeof Schema>`), `$inferData`, `EmbeddedDataField`,
|
|
280
|
+
`EmbeddedDocumentField`, `TypedSchemaField`, and the full required×initial
|
|
281
|
+
nullability matrix remain v1.0 scope and will ship from `@vttforge/types`.
|
|
282
|
+
|
|
283
|
+
## 0.1.0
|
|
284
|
+
|
|
285
|
+
### Minor Changes
|
|
286
|
+
|
|
287
|
+
- 4900e83: Foundation MVP (PR 4 of 4) — `@vttforge/core` ships its first runtime surface (registerSystem, SystemConfig, BaseTypeDataModel, BaseActorSheet, VttfError + VTTF-NNNN registry) and `@vttforge/styles` ships its first `--vttf-*` token set wrapped in the `vttforge.tokens` cascade layer.
|
|
288
|
+
|
|
289
|
+
Both packages have working consumer entrypoints (verified by an external smoke test loading the built `.mjs` from a throwaway dir) and the SDK contracts match the canonical Foundry v13 patterns (TypeDataModel migration, ActorSheetV2 + HandlebarsApplicationMixin, staged init hooks, marker classes).
|
|
290
|
+
|
|
291
|
+
Status remains pre-1.0 and APIs are explicitly unstable — these are the first releases that have real code instead of placeholder `export {}`.
|
|
292
|
+
|
|
293
|
+
## 0.0.1
|
|
294
|
+
|
|
295
|
+
Initial functional release (v0.1 MVP slice). Foundry v13+ system runtime helpers.
|
|
296
|
+
|
|
297
|
+
### Added
|
|
298
|
+
|
|
299
|
+
- `registerSystem({ id, actorDataModels, itemDataModels, actorDocumentClass, itemDocumentClass, combat, statusEffects, onBeforeInit, onAfterInit })` — one-call boot that schedules CONFIG mutations via `Hooks.once("init", ...)`. Idempotent per `id` (throws `VTTF-0001` on duplicate). Sets `CONFIG.ActiveEffect.legacyTransferral = false` by default.
|
|
300
|
+
- `SystemConfig` — typed wrapper around `game.settings.register/get/set`. Tracks registered keys locally; reads/writes against an unregistered key throw `VTTF-0003` instead of returning `undefined`.
|
|
301
|
+
- `BaseTypeDataModel()` — mixin over `foundry.abstract.TypeDataModel` providing a safe default `migrateData` that delegates to `super` (chained-migration guard), a stub `_addDataFieldMigrations`, and a no-op `prepareDerivedData`.
|
|
302
|
+
- `BaseActorSheet()` — mixin over `HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2)` with `DEFAULT_OPTIONS` that ship the `vttforge` marker class so consumers can scope CSS without specificity wars.
|
|
303
|
+
- `VttfError` + `VTTF-NNNN` registry — central, append-only error codes (`VTTF-0001` SystemAlreadyRegistered, `VTTF-0002` MissingFoundryGlobals, `VTTF-0003` UnknownSetting), each with a `name`, `summary`, and `docsUrl` pointing at `https://vttforge.dev/errors/VTTF-NNNN`. Supports native ES2022 `cause` and `AggregateError`.
|
|
304
|
+
|
|
305
|
+
### Verified
|
|
306
|
+
|
|
307
|
+
- 32 Vitest unit tests across 5 files, all passing on Node 22.14 and Node 24.
|
|
308
|
+
- External consumer smoke test (importing the published `.mjs` from a throwaway dir) confirms every exported symbol behaves as designed when Foundry globals are present or absent.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fabricio Cavalcante de Souza and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# @vttforge/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Core runtime utilities for VTTForge — the modern SDK for building [FoundryVTT](https://foundryvtt.com) v13+ systems and modules.
|
|
4
4
|
|
|
5
|
-
>
|
|
5
|
+
> **Status:** v0.0.1 placeholder. Real APIs land in v0.1.0.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Planned API surface (v0.1.0)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
- `BaseTypeDataModel` — eliminates stub `migrateData()` and centralises `InferSchema<T>` inference.
|
|
10
|
+
- `BaseActorSheet` / `BaseItemSheet` — declarative replacements for `_getTabs`, DragDrop wiring, `_onEditImage`, `_onDrop`.
|
|
11
|
+
- `SystemConfig` — typed wrapper around `game.settings`, eliminates hardcoded system-ID strings.
|
|
12
|
+
- `registerSystem()` — one-call init that replaces the manual `Hooks.once("init", …)` block.
|
|
13
|
+
- `createMigrationRunner` — declarative data migrations with version gates.
|
|
14
|
+
- Error registry — `VttfError` + central `VTTF-NNNN` codes with `docsUrl` pointing at `vttforge.dev/errors/`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"package": "@vttforge/core",
|
|
4
|
+
"packageVersion": "0.7.0",
|
|
5
|
+
"entries": [
|
|
6
|
+
{
|
|
7
|
+
"code": "VTTF-0001",
|
|
8
|
+
"name": "SystemAlreadyRegistered",
|
|
9
|
+
"summary": "registerSystem() was called more than once for the same system id. This is almost always a hot-reload artefact or a duplicate import."
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"code": "VTTF-0002",
|
|
13
|
+
"name": "MissingFoundryGlobals",
|
|
14
|
+
"summary": "VTTForge code ran in an environment without Foundry globals (game, Hooks, CONFIG). Initialise inside the Foundry runtime, not in a Node test without mocks."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"code": "VTTF-0003",
|
|
18
|
+
"name": "UnknownSetting",
|
|
19
|
+
"summary": "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."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"code": "VTTF-0004",
|
|
23
|
+
"name": "MigrationFailed",
|
|
24
|
+
"summary": "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."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"code": "VTTF-0005",
|
|
28
|
+
"name": "WorldTooOldForMigration",
|
|
29
|
+
"summary": "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."
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|