@optolith/database-schema 0.68.1 → 0.70.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 CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
+ ## [0.70.0](https://github.com/Optolith/database-schema/compare/v0.69.0...v0.70.0) (2026-09-27)
6
+
7
+ ### ⚠ BREAKING CHANGES
8
+
9
+ * plant adjustments
10
+
11
+ ### Features
12
+
13
+ * plant adjustments ([8dcd08b](https://github.com/Optolith/database-schema/commit/8dcd08b1a3492686703fbdee7f5f12c992a5d2c5)), references [#195](https://github.com/Optolith/database-schema/issues/195)
14
+ ## [0.69.0](https://github.com/Optolith/database-schema/compare/v0.68.1...v0.69.0) (2026-09-27)
15
+
16
+ ### ⚠ BREAKING CHANGES
17
+
18
+ * ancestor blood advantage cache name typo
19
+
20
+ ### Features
21
+
22
+ * derived trade secrets cache ([18e1ea8](https://github.com/Optolith/database-schema/commit/18e1ea889894108647f3b844c6f84f19beb8eac1))
23
+
24
+ ### Bug Fixes
25
+
26
+ * ancestor blood advantage cache name typo ([b7d2592](https://github.com/Optolith/database-schema/commit/b7d2592cf6f8542761fa0f46b76630f57011047e))
5
27
  ## [0.68.1](https://github.com/Optolith/database-schema/compare/v0.68.0...v0.68.1) (2026-09-27)
6
28
 
7
29
  ### Features
package/gen/types.d.ts CHANGED
@@ -25756,7 +25756,7 @@ export interface HerbalAid {
25756
25756
  /**
25757
25757
  * The difficulty for this aid to craft.
25758
25758
  */
25759
- crafting_difficulty: number
25759
+ crafting_difficulty?: number
25760
25760
 
25761
25761
  /**
25762
25762
  * AP value and prerequisites of the herbal aid�s trade secret.
@@ -25768,6 +25768,11 @@ export interface HerbalAid {
25768
25768
  */
25769
25769
  combatUse?: HerbalAidCombatUse
25770
25770
 
25771
+ /**
25772
+ * How long this herbal aid lasts.
25773
+ */
25774
+ longevity?: HerbalPreservationLongevity
25775
+
25771
25776
  /**
25772
25777
  * References to where in which publications this entry has been defined. Entries may also be added or removed in later printings.
25773
25778
  */
@@ -25795,7 +25800,7 @@ export interface HerbalAidTranslation {
25795
25800
  /**
25796
25801
  * The herbal aid's description.
25797
25802
  */
25798
- description: string
25803
+ description?: string
25799
25804
 
25800
25805
  /**
25801
25806
  * The ingredients used to craft this herbal aid.
@@ -25818,6 +25823,44 @@ export type HerbalAidCombatUse =
25818
25823
  Armor: Armor_ID
25819
25824
  }
25820
25825
 
25826
+ export interface HerbalPreservationLongevity {
25827
+ /**
25828
+ * An expression that evaluates to the duration.
25829
+ */
25830
+ value: HerbalPreservationLongevityExpression
25831
+
25832
+ /**
25833
+ * The duration unit.
25834
+ */
25835
+ unit: DurationUnit
25836
+
25837
+ /**
25838
+ * All translations for the entry, identified by IETF language tag (BCP47).
25839
+ */
25840
+ translations?: {
25841
+ [localeId: string]: HerbalPreservationLongevityTranslation
25842
+ }
25843
+ }
25844
+
25845
+ export interface HerbalPreservationLongevityTranslation {
25846
+ /**
25847
+ * A replacement string.
25848
+ */
25849
+ replacement: ResponsiveTextReplace
25850
+ }
25851
+
25852
+ export type HerbalPreservationLongevityExpression = MathOperation<HerbalPreservationLongevityValue>
25853
+
25854
+ export type HerbalPreservationLongevityValue =
25855
+ | {
25856
+ kind: "Constant"
25857
+ Constant: number
25858
+ }
25859
+ | {
25860
+ kind: "Dice"
25861
+ Dice: Dice
25862
+ }
25863
+
25821
25864
  export interface HerbalPreservation {
25822
25865
  /**
25823
25866
  * The types of this preservation.
@@ -25864,44 +25907,6 @@ export interface HerbalPreservationTranslation {
25864
25907
  alternative_effect: string
25865
25908
  }
25866
25909
 
25867
- export interface HerbalPreservationLongevity {
25868
- /**
25869
- * An expression that evaluates to the duration.
25870
- */
25871
- value: HerbalPreservationLongevityExpression
25872
-
25873
- /**
25874
- * The duration unit.
25875
- */
25876
- unit: DurationUnit
25877
-
25878
- /**
25879
- * All translations for the entry, identified by IETF language tag (BCP47).
25880
- */
25881
- translations?: {
25882
- [localeId: string]: HerbalPreservationLongevityTranslation
25883
- }
25884
- }
25885
-
25886
- export interface HerbalPreservationLongevityTranslation {
25887
- /**
25888
- * A replacement string.
25889
- */
25890
- replacement: ResponsiveTextReplace
25891
- }
25892
-
25893
- export type HerbalPreservationLongevityExpression = MathOperation<HerbalPreservationLongevityValue>
25894
-
25895
- export type HerbalPreservationLongevityValue =
25896
- | {
25897
- kind: "Constant"
25898
- Constant: number
25899
- }
25900
- | {
25901
- kind: "Dice"
25902
- Dice: Dice
25903
- }
25904
-
25905
25910
  export interface HomunculusType {
25906
25911
  /**
25907
25912
  * All translations for the entry, identified by IETF language tag (BCP47).
@@ -26355,7 +26360,7 @@ export interface PlantLongevity {
26355
26360
  /**
26356
26361
  * All translations for the entry, identified by IETF language tag (BCP47).
26357
26362
  */
26358
- translations: {
26363
+ translations?: {
26359
26364
  [localeId: string]: PlantLongevityTranslation
26360
26365
  }
26361
26366
  }
@@ -26364,7 +26369,7 @@ export interface PlantLongevityTranslation {
26364
26369
  /**
26365
26370
  * The longevity of the raw plant
26366
26371
  */
26367
- raw: string
26372
+ raw?: string
26368
26373
 
26369
26374
  /**
26370
26375
  * The longevity of the preserved plant
@@ -4,11 +4,13 @@ import { type ActivatableSelectOptionsCache, type ResolvedSelectOption, type Res
4
4
  import { type AncestorBloodAdvantagesCache } from "./ancestorBloodAdvantages.ts";
5
5
  import { type MagicalAndBlessedAdvantagesAndDisadvantagesCache } from "./magicalAndBlessedAdvantagesAndDisadvantages.ts";
6
6
  import { type NewApplicationsAndUsesCache, type ResolvedNewSkillApplication, type ResolvedSkillUse } from "./newApplicationsAndUses.ts";
7
+ import { type DerivedTradeSecretsCache } from "./tradeSecrets.ts";
7
8
  /**
8
9
  * Identifiers of specific entries in the database that are used for creating the cache.
9
10
  */
10
11
  export type IdMap = {
11
12
  Advantage: Record<"Blessed" | "Spellcaster", string>;
13
+ GeneralSpecialAbility: Record<"Weaponsmith" | "Armorer", string>;
12
14
  MagicalSpecialAbility: Record<"PropertyKnowledge", string>;
13
15
  KarmaSpecialAbility: Record<"AspectKnowledge", string>;
14
16
  };
@@ -17,7 +19,8 @@ export type IdMap = {
17
19
  */
18
20
  export type Cache = {
19
21
  activatableSelectOptions: ActivatableSelectOptionsCache;
20
- sncestorBloodAdvantages: AncestorBloodAdvantagesCache;
22
+ ancestorBloodAdvantages: AncestorBloodAdvantagesCache;
23
+ derivedTradeSecrets: DerivedTradeSecretsCache;
21
24
  magicalAndBlessedAdvantagesAndDisadvantages: MagicalAndBlessedAdvantagesAndDisadvantagesCache;
22
25
  newApplicationsAndUses: NewApplicationsAndUsesCache;
23
26
  };
@@ -2,6 +2,7 @@ import { activatableSelectOptionsCacheBuilder, } from "./activatableSelectOption
2
2
  import { buildAncestorBloodAdvantagesCache, } from "./ancestorBloodAdvantages.js";
3
3
  import { buildMagicalAndBlessedAdvantagesAndDisadvantagesCache, } from "./magicalAndBlessedAdvantagesAndDisadvantages.js";
4
4
  import { buildNewApplicationsAndUsesCache, } from "./newApplicationsAndUses.js";
5
+ import { buildDerivedTradeSecretsCache } from "./tradeSecrets.js";
5
6
  /**
6
7
  * Creates the cache by precomputing all necessary data from the database.
7
8
  * @param db The TSONDB instance containing the database.
@@ -10,12 +11,14 @@ import { buildNewApplicationsAndUsesCache, } from "./newApplicationsAndUses.js";
10
11
  */
11
12
  export const createCache = (db, idMap) => {
12
13
  const activatableSelectOptions = activatableSelectOptionsCacheBuilder(db, idMap);
13
- const sncestorBloodAdvantages = buildAncestorBloodAdvantagesCache(db, idMap);
14
+ const ancestorBloodAdvantages = buildAncestorBloodAdvantagesCache(db, idMap);
15
+ const derivedTradeSecrets = buildDerivedTradeSecretsCache(db, idMap);
14
16
  const magicalAndBlessedAdvantagesAndDisadvantages = buildMagicalAndBlessedAdvantagesAndDisadvantagesCache(db, idMap);
15
17
  const newApplicationsAndUses = buildNewApplicationsAndUsesCache(db, idMap, activatableSelectOptions);
16
18
  return {
17
19
  activatableSelectOptions,
18
- sncestorBloodAdvantages,
20
+ ancestorBloodAdvantages,
21
+ derivedTradeSecrets,
19
22
  magicalAndBlessedAdvantagesAndDisadvantages,
20
23
  newApplicationsAndUses,
21
24
  };
@@ -0,0 +1,23 @@
1
+ import { Case } from "tsondb/schema/gen";
2
+ import type { ArmorComplexity, Complexity, EntityMap, EquipmentIdentifier, TradeSecret } from "../../gen/types.js";
3
+ import type { CacheBuilder } from "./internal.ts";
4
+ type EquipmentEntitiesWithComplexities = {
5
+ [K in EquipmentIdentifier["kind"]]: EntityMap[K] extends {
6
+ complexity?: Complexity | ArmorComplexity;
7
+ } ? K : never;
8
+ }[EquipmentIdentifier["kind"]];
9
+ type HerbaryEntitiesWithTradeSecrets = "Disease" | "Elixir" | "HerbalAid" | "Poison";
10
+ export type DerivedTradeSecretsCache = {
11
+ equipment: {
12
+ [K in EquipmentEntitiesWithComplexities]: Record<string, TradeSecret>;
13
+ };
14
+ herbary: {
15
+ [K in HerbaryEntitiesWithTradeSecrets]: Record<string, TradeSecret>;
16
+ };
17
+ all: {
18
+ id: Case<"TradeSecret" | EquipmentEntitiesWithComplexities | HerbaryEntitiesWithTradeSecrets, string>;
19
+ content: TradeSecret;
20
+ }[];
21
+ };
22
+ export declare const buildDerivedTradeSecretsCache: CacheBuilder<DerivedTradeSecretsCache>;
23
+ export {};
@@ -0,0 +1,126 @@
1
+ import { assertExhaustive } from "@elyukai/utils/typeSafety";
2
+ import { Case } from "tsondb/schema/gen";
3
+ const emptyDerivedEquipmentTradeSecretsCache = {
4
+ Armor: {},
5
+ BandageOrRemedy: {},
6
+ Book: {},
7
+ CeremonialItem: {},
8
+ Clothes: {},
9
+ Container: {},
10
+ IlluminationLightSource: {},
11
+ IlluminationRefillOrSupply: {},
12
+ Jewelry: {},
13
+ Laboratory: {},
14
+ Liebesspielzeug: {},
15
+ LuxuryGood: {},
16
+ MagicalArtifact: {},
17
+ MusicalInstrument: {},
18
+ OrienteeringAid: {},
19
+ RopeOrChain: {},
20
+ Stationery: {},
21
+ ThievesTool: {},
22
+ ToolOfTheTrade: {},
23
+ TravelGearOrTool: {},
24
+ Vehicle: {},
25
+ Weapon: {},
26
+ WeaponAccessory: {},
27
+ };
28
+ const emptyDerivedHerbaryTradeSecretsCache = {
29
+ Disease: {},
30
+ Elixir: {},
31
+ HerbalAid: {},
32
+ Poison: {},
33
+ };
34
+ export const buildDerivedTradeSecretsCache = (database, idMap) => {
35
+ const cache = {
36
+ equipment: emptyDerivedEquipmentTradeSecretsCache,
37
+ herbary: emptyDerivedHerbaryTradeSecretsCache,
38
+ all: database.getAllInstanceContainersOfEntity("TradeSecret").map(container => ({
39
+ id: Case("TradeSecret", container.id),
40
+ content: container.content,
41
+ })),
42
+ };
43
+ for (const entity of Object.keys(cache.equipment)) {
44
+ for (const container of database.getAllInstanceContainersOfEntity(entity)) {
45
+ if (container.content.complexity && container.content.complexity.kind === "Complex") {
46
+ const derivedTradeSecret = {
47
+ ap_value: Case("Fixed", container.content.complexity.Complex.ap_value),
48
+ is_secret_knowledge: false,
49
+ prerequisites: entity === "Weapon"
50
+ ? [
51
+ Case("Single", Case("Activatable", {
52
+ id: Case("GeneralSpecialAbility", idMap.GeneralSpecialAbility.Weaponsmith),
53
+ active: true,
54
+ })),
55
+ ]
56
+ : entity === "Armor"
57
+ ? [
58
+ Case("Single", Case("Activatable", {
59
+ id: Case("GeneralSpecialAbility", idMap.GeneralSpecialAbility.Armorer),
60
+ active: true,
61
+ })),
62
+ ]
63
+ : undefined,
64
+ src: container.content.complexity.Complex.src ?? container.content.src,
65
+ translations: Object.fromEntries(Object.entries(container.content.translations).map(([lang, translation]) => [
66
+ lang,
67
+ {
68
+ name: translation.name,
69
+ },
70
+ ])),
71
+ };
72
+ cache.equipment[entity][container.id] = derivedTradeSecret;
73
+ cache.all.push({
74
+ id: Case(entity, container.id),
75
+ content: derivedTradeSecret,
76
+ });
77
+ }
78
+ }
79
+ }
80
+ const addTradeSecretToHerbaryCache = (entity, container, tradeSecret) => {
81
+ const derivedTradeSecret = {
82
+ ap_value: Case("Fixed", tradeSecret.ap_value),
83
+ is_secret_knowledge: false,
84
+ prerequisites: tradeSecret.prerequisites,
85
+ src: tradeSecret.src ?? container.content.src,
86
+ translations: Object.fromEntries(Object.entries(container.content.translations).map(([lang, translation]) => [
87
+ lang,
88
+ {
89
+ name: translation.name,
90
+ },
91
+ ])),
92
+ };
93
+ cache.herbary[entity][container.id] = derivedTradeSecret;
94
+ cache.all.push({
95
+ id: Case(entity, container.id),
96
+ content: derivedTradeSecret,
97
+ });
98
+ };
99
+ for (const entity of Object.keys(emptyDerivedHerbaryTradeSecretsCache)) {
100
+ switch (entity) {
101
+ case "Disease":
102
+ case "Elixir":
103
+ case "HerbalAid":
104
+ for (const container of database.getAllInstanceContainersOfEntity(entity)) {
105
+ if (container.content.trade_secret) {
106
+ addTradeSecretToHerbaryCache(entity, container, container.content.trade_secret);
107
+ }
108
+ }
109
+ break;
110
+ case "Poison":
111
+ for (const container of database.getAllInstanceContainersOfEntity(entity)) {
112
+ if (container.content.source_type.kind === "AlchemicalPoison") {
113
+ addTradeSecretToHerbaryCache(entity, container, container.content.source_type.AlchemicalPoison.trade_secret);
114
+ }
115
+ else if (container.content.source_type.kind == "AnimalVenom" &&
116
+ container.content.source_type.AnimalVenom.complexity?.kind === "Complex") {
117
+ addTradeSecretToHerbaryCache(entity, container, container.content.source_type.AnimalVenom.complexity.Complex);
118
+ }
119
+ }
120
+ break;
121
+ default:
122
+ return assertExhaustive(entity);
123
+ }
124
+ }
125
+ return cache;
126
+ };
@@ -9,7 +9,7 @@ export declare const HerbalAid: DB.Entity<"HerbalAid", {
9
9
  Defensive: DB.EnumCase<null>;
10
10
  Supernatural: DB.EnumCase<null>;
11
11
  }, []>>>, true>;
12
- crafting_difficulty: DB.MemberDecl<DB.Integer, true>;
12
+ crafting_difficulty: DB.MemberDecl<DB.Integer, false>;
13
13
  trade_secret: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"RecipeTradeSecret", DB.Object<{
14
14
  ap_value: DB.MemberDecl<DB.Integer, true>;
15
15
  prerequisites: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"PlainGeneralPrerequisites", DB.IncludeIdentifier<DB.Param<string, DB.Type>[], DB.TypeAlias<"PlainPrerequisites", DB.Array<DB.IncludeIdentifier<DB.Param<string, DB.Type>[], DB.Enum<"PrerequisitesElement", {
@@ -82,6 +82,38 @@ export declare const HerbalAid: DB.Entity<"HerbalAid", {
82
82
  Weapon: DB.EnumCase<DB.ReferenceIdentifier>;
83
83
  Armor: DB.EnumCase<DB.ReferenceIdentifier>;
84
84
  }, []>>, false>;
85
+ longevity: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"HerbalPreservationLongevity", DB.Object<{
86
+ value: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"HerbalPreservationLongevityExpression", DB.IncludeIdentifier<DB.Param<string, DB.Type>[], import("../../_MathExpression.ts").MathOperation>, []>>, true>;
87
+ unit: DB.MemberDecl<DB.IncludeIdentifier<[], DB.Enum<"DurationUnit", {
88
+ Seconds: DB.EnumCase<null>;
89
+ Minutes: DB.EnumCase<null>;
90
+ Hours: DB.EnumCase<null>;
91
+ Days: DB.EnumCase<null>;
92
+ Weeks: DB.EnumCase<null>;
93
+ Months: DB.EnumCase<null>;
94
+ Years: DB.EnumCase<null>;
95
+ Decades: DB.EnumCase<null>;
96
+ Centuries: DB.EnumCase<null>;
97
+ Actions: DB.EnumCase<null>;
98
+ CombatRounds: DB.EnumCase<null>;
99
+ Custom: DB.EnumCase<DB.IncludeIdentifier<[], DB.TypeAlias<"CustomDurationUnit", DB.Object<{
100
+ translations: DB.MemberDecl<DB.NestedEntityMap<"CustomDurationUnitTranslation", {
101
+ name: DB.MemberDecl<DB.String, true>;
102
+ fullNumber: DB.MemberDecl<DB.String, true>;
103
+ full: DB.MemberDecl<DB.String, true>;
104
+ symbol: DB.MemberDecl<DB.String, true>;
105
+ compressedNumber: DB.MemberDecl<DB.String, true>;
106
+ compressed: DB.MemberDecl<DB.String, true>;
107
+ }>, true>;
108
+ }>, []>>>;
109
+ }, []>>, true>;
110
+ translations: DB.MemberDecl<DB.NestedEntityMap<"HerbalPreservationLongevityTranslation", {
111
+ replacement: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"ResponsiveTextReplace", DB.Object<{
112
+ full: DB.MemberDecl<DB.String, true>;
113
+ compressed: DB.MemberDecl<DB.String, true>;
114
+ }>, []>>, true>;
115
+ }>, false>;
116
+ }>, []>>, false>;
85
117
  src: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"PublicationRefs", DB.Array<DB.IncludeIdentifier<[], DB.TypeAlias<"PublicationRef", DB.Object<{
86
118
  id: DB.MemberDecl<DB.ReferenceIdentifier, true>;
87
119
  occurrences: DB.MemberDecl<DB.NestedEntityMap<string, {
@@ -125,7 +157,7 @@ export declare const HerbalAid: DB.Entity<"HerbalAid", {
125
157
  }>, []>>>, []>>, true>;
126
158
  translations: DB.MemberDecl<DB.NestedEntityMap<"HerbalAidTranslation", {
127
159
  name: DB.MemberDecl<DB.String, true>;
128
- description: DB.MemberDecl<DB.String, true>;
160
+ description: DB.MemberDecl<DB.String, false>;
129
161
  ingredients: DB.MemberDecl<DB.Array<DB.String>, true>;
130
162
  typical_tools: DB.MemberDecl<DB.Array<DB.String>, false>;
131
163
  }>, true>;
@@ -3,6 +3,7 @@ import { src } from "../../source/_PublicationRef.js";
3
3
  import { NestedTranslationMap } from "../../Locale.js";
4
4
  import { WeaponIdentifier, ArmorIdentifier } from "../../_Identifier.js";
5
5
  import { EffectType, RecipeTradeSecret } from "./_Herbary.js";
6
+ import { HerbalPreservationLongevity } from "./HerbalPreservation.js";
6
7
  export const HerbalAid = DB.Entity(import.meta.url, {
7
8
  name: "HerbalAid",
8
9
  namePlural: "HerbalAids",
@@ -11,7 +12,7 @@ export const HerbalAid = DB.Entity(import.meta.url, {
11
12
  comment: "The plant types this aid belongs to.",
12
13
  type: DB.Array(DB.IncludeIdentifier(EffectType), { minItems: 1, uniqueItems: true }),
13
14
  }),
14
- crafting_difficulty: DB.Required({
15
+ crafting_difficulty: DB.Optional({
15
16
  comment: "The difficulty for this aid to craft.",
16
17
  type: DB.Integer(),
17
18
  }),
@@ -23,13 +24,17 @@ export const HerbalAid = DB.Entity(import.meta.url, {
23
24
  comment: "The armor or weapon this herbal aid represents.",
24
25
  type: DB.IncludeIdentifier(HerbalAidCombatUse),
25
26
  }),
27
+ longevity: DB.Optional({
28
+ comment: "How long this herbal aid lasts.",
29
+ type: DB.IncludeIdentifier(HerbalPreservationLongevity),
30
+ }),
26
31
  src,
27
32
  translations: NestedTranslationMap(DB.Required, "HerbalAid", DB.Object({
28
33
  name: DB.Required({
29
34
  comment: "The herbal aid's name.",
30
35
  type: DB.String({ minLength: 1 }),
31
36
  }),
32
- description: DB.Required({
37
+ description: DB.Optional({
33
38
  comment: "The herbal aid's description.",
34
39
  type: DB.String({ minLength: 1, markdown: "block" }),
35
40
  }),
@@ -157,9 +157,9 @@ export declare const Plant: DB.Entity<"Plant", {
157
157
  longevity: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"PlantLongevity", DB.Object<{
158
158
  preservations: DB.MemberDecl<DB.Array<DB.ReferenceIdentifier>, false>;
159
159
  translations: DB.MemberDecl<DB.NestedEntityMap<"PlantLongevityTranslation", {
160
- raw: DB.MemberDecl<DB.String, true>;
160
+ raw: DB.MemberDecl<DB.String, false>;
161
161
  preserved: DB.MemberDecl<DB.String, false>;
162
- }>, true>;
162
+ }>, false>;
163
163
  }>, []>>, false>;
164
164
  src: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"PublicationRefs", DB.Array<DB.IncludeIdentifier<[], DB.TypeAlias<"PublicationRef", DB.Object<{
165
165
  id: DB.MemberDecl<DB.ReferenceIdentifier, true>;
@@ -270,8 +270,8 @@ const PlantLongevity = DB.TypeAlias(import.meta.url, {
270
270
  comment: "The preservations with alternative effect of this preserved plant",
271
271
  type: DB.Array(HerbalPreservationIdentifier(), { minItems: 1, uniqueItems: true }),
272
272
  }),
273
- translations: NestedTranslationMap(DB.Required, "PlantLongevity", DB.Object({
274
- raw: DB.Required({
273
+ translations: NestedTranslationMap(DB.Optional, "PlantLongevity", DB.Object({
274
+ raw: DB.Optional({
275
275
  comment: "The longevity of the raw plant",
276
276
  type: DB.String({ minLength: 1, markdown: "block" }),
277
277
  }),
@@ -279,6 +279,6 @@ const PlantLongevity = DB.TypeAlias(import.meta.url, {
279
279
  comment: "The longevity of the preserved plant",
280
280
  type: DB.String({ minLength: 1, markdown: "block" }),
281
281
  }),
282
- })),
283
- }),
282
+ }, { minProperties: 1 })),
283
+ }, { minProperties: 1 }),
284
284
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optolith/database-schema",
3
- "version": "0.68.1",
3
+ "version": "0.70.0",
4
4
  "description": "Definitions and utilities for the flat-file database of Optolith, a character creation tool for the Pen and Paper RPG “The Dark Eye 5”, and its external integrations into other software.",
5
5
  "keywords": [
6
6
  "tde",