Skip to content

How schema versions and shared types work

Neil de Carteret edited this page Feb 7, 2023 · 3 revisions

Why we have shared types

INVESTIGATOR is written in TypeScript, a statically typed superset of Javascript. The types that INVESTIGATOR uses for things like presets and themes are useful for people developing addons for INVESTIGATOR.

As a result, we publish a package on npm called @lumphammer/investigator-fvtt-types. If you are using Typescript, you can pull this package in as a devDependency.

If you're not using TypeScript in your own project, then no worries - you don't need to use the shared types library either.

Why we have schema versions

The goal is to allow addons to work for as long as possible, while acknowledging that we will want to make changes to things like the formats of themes and presets.

To accomplish this, we say that every theme and preset MUST contain a field saying what schemaVersion it uses. As of the time of writing, the only schema version is "v1".

In future, we might publish a schema version "v2". This would be incompatible with v1 in some way. But any add-ons using v1 would continue to work, because INVESTIGATOR will see the "v1" and automatically apply a transformation to bring it up to v2.

It is key that INVESTIGATOR will always maintain an automated upgrade path between schema versions.

How schema version and shared types come together

The shared types library will expose types with built-in version numbers. In other words, we do NOT expose a type Preset. Instead we expose PresetV1.

We may publish updates to PresetV1, but they will always be backwards compatible. So we might e.g. add a new optional field to PresetV1, because older presets without said optional field will be fine. But won't add a new compulsory field, or change the typoe of an existing field in PresetV1, because that could break things.

If we do ever need a new compulsory field, we will do it by creating PresetV2, and defining an automatic conversion within INVESTIGATOR.

Strategery

It stands to reason that if an automatic conversion is possible for a new compulsory field, it could have been optional, right? So we should favour optional fields.

We have not yet properly released the types, so there have been some breaking changes so far. This is only while we get the types ready for launch.

Going forwards, new schema versions should be used sparingly. Noone wants to deal with 50 fighting versions. That said, as long as there is always an incremental automated upgrade for each new version, it wouldn't actually be a huge issue.

Question: could we actually make everything in V1 be optional? What would break? Anything? The way we use these bad boys is we have a default set of values (actually the Path of Cthulhu preset and theme) which is typed as Required<PresetV1> and we merge the given preset into this to find the final value.

Addendum: ThemeSeedV1 is already largely optional (because it's a "seed".)