@optolith/database-schema 0.68.1 → 0.69.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 +13 -0
- package/lib/cache/index.d.ts +4 -1
- package/lib/cache/index.js +5 -2
- package/lib/cache/tradeSecrets.d.ts +23 -0
- package/lib/cache/tradeSecrets.js +126 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
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.69.0](https://github.com/Optolith/database-schema/compare/v0.68.1...v0.69.0) (2026-09-27)
|
|
6
|
+
|
|
7
|
+
### ⚠ BREAKING CHANGES
|
|
8
|
+
|
|
9
|
+
* ancestor blood advantage cache name typo
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* derived trade secrets cache ([18e1ea8](https://github.com/Optolith/database-schema/commit/18e1ea889894108647f3b844c6f84f19beb8eac1))
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* ancestor blood advantage cache name typo ([b7d2592](https://github.com/Optolith/database-schema/commit/b7d2592cf6f8542761fa0f46b76630f57011047e))
|
|
5
18
|
## [0.68.1](https://github.com/Optolith/database-schema/compare/v0.68.0...v0.68.1) (2026-09-27)
|
|
6
19
|
|
|
7
20
|
### Features
|
package/lib/cache/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
22
|
+
ancestorBloodAdvantages: AncestorBloodAdvantagesCache;
|
|
23
|
+
derivedTradeSecrets: DerivedTradeSecretsCache;
|
|
21
24
|
magicalAndBlessedAdvantagesAndDisadvantages: MagicalAndBlessedAdvantagesAndDisadvantagesCache;
|
|
22
25
|
newApplicationsAndUses: NewApplicationsAndUsesCache;
|
|
23
26
|
};
|
package/lib/cache/index.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optolith/database-schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.69.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",
|