@xivdyetools/core 4.0.1 → 4.2.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.
Files changed (47) hide show
  1. package/dist/blending/conversions.d.ts +24 -0
  2. package/dist/blending/conversions.d.ts.map +1 -1
  3. package/dist/blending/conversions.js +36 -3
  4. package/dist/blending/conversions.js.map +1 -1
  5. package/dist/constants/index.d.ts +24 -0
  6. package/dist/constants/index.d.ts.map +1 -1
  7. package/dist/constants/index.js +38 -0
  8. package/dist/constants/index.js.map +1 -1
  9. package/dist/index.d.ts +10 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/services/APIService.d.ts.map +1 -1
  14. package/dist/services/APIService.js +23 -9
  15. package/dist/services/APIService.js.map +1 -1
  16. package/dist/services/CharacterColorService.d.ts +4 -0
  17. package/dist/services/CharacterColorService.d.ts.map +1 -1
  18. package/dist/services/CharacterColorService.js +17 -2
  19. package/dist/services/CharacterColorService.js.map +1 -1
  20. package/dist/services/LocalizationService.d.ts +8 -0
  21. package/dist/services/LocalizationService.d.ts.map +1 -1
  22. package/dist/services/LocalizationService.js +9 -1
  23. package/dist/services/LocalizationService.js.map +1 -1
  24. package/dist/services/PaletteService.d.ts +6 -1
  25. package/dist/services/PaletteService.d.ts.map +1 -1
  26. package/dist/services/PaletteService.js +7 -2
  27. package/dist/services/PaletteService.js.map +1 -1
  28. package/dist/services/chara/chara-parser.d.ts +7 -1
  29. package/dist/services/chara/chara-parser.d.ts.map +1 -1
  30. package/dist/services/chara/chara-parser.js.map +1 -1
  31. package/dist/services/dye/HarmonyGenerator.d.ts +3 -1
  32. package/dist/services/dye/HarmonyGenerator.d.ts.map +1 -1
  33. package/dist/services/dye/HarmonyGenerator.js +41 -8
  34. package/dist/services/dye/HarmonyGenerator.js.map +1 -1
  35. package/dist/services/dye/HarmonySelector.d.ts +107 -0
  36. package/dist/services/dye/HarmonySelector.d.ts.map +1 -0
  37. package/dist/services/dye/HarmonySelector.js +176 -0
  38. package/dist/services/dye/HarmonySelector.js.map +1 -0
  39. package/dist/services/localization/TranslationProvider.d.ts +11 -6
  40. package/dist/services/localization/TranslationProvider.d.ts.map +1 -1
  41. package/dist/services/localization/TranslationProvider.js +33 -28
  42. package/dist/services/localization/TranslationProvider.js.map +1 -1
  43. package/dist/types/index.d.ts +13 -0
  44. package/dist/types/index.d.ts.map +1 -1
  45. package/dist/types/index.js +14 -1
  46. package/dist/types/index.js.map +1 -1
  47. package/package.json +8 -8
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Harmony slot selection — the one implementation every surface uses.
3
+ *
4
+ * ## Why this exists
5
+ *
6
+ * The web app and the Discord bot used to answer "which dyes make a triadic
7
+ * harmony with this one?" through completely different code, and they
8
+ * disagreed for **89–100 % of base dyes on every harmony type** (measured
9
+ * 2026-09-03 over all 125 dyes):
10
+ *
11
+ * - the page walked `HARMONY_OFFSETS`, built each target by carrying the base
12
+ * dye's SATURATION AND VALUE onto the rotated hue, and ranked candidates by
13
+ * the user's configured ΔE method;
14
+ * - the bot called a named `DyeService.find*Dyes()` per type, which rotates hue
15
+ * without preserving S/V — and `findComplementaryPair` did not rotate at all,
16
+ * it took an RGB `invert()`.
17
+ *
18
+ * For a desaturated base the difference is not subtle: `/harmony analogous` on
19
+ * Snow White returned Neon Green and Kobold Brown, where the page shows Pure
20
+ * White and Pearl White.
21
+ *
22
+ * This module is the page's algorithm, lifted verbatim so the page's output is
23
+ * unchanged and every other surface now matches it. `HARMONY_OFFSETS` supplies
24
+ * the geometry, so a harmony type is a row in a table rather than a method —
25
+ * which is why `compound` and `shades` work here without any new code.
26
+ *
27
+ * @module services/dye/HarmonySelector
28
+ */
29
+ import { HARMONY_OFFSETS } from '../../constants/index.js';
30
+ import { ColorService } from '../ColorService.js';
31
+ /**
32
+ * The single definition of "how far is this dye from the slot's target".
33
+ *
34
+ * BUG-064: everything that scores a harmony row goes through here, so a panel
35
+ * can never mix ΔE units with degrees of hue — which is exactly what it used to
36
+ * do when a filtered-out companion's replacement was scored differently from
37
+ * its neighbours.
38
+ */
39
+ function devianceFor(dye, targetHue, targetHex, config) {
40
+ if (config.usePerceptualMatching) {
41
+ return ColorService.getDistanceForMethod(targetHex, dye.hex, config.matchingMethod);
42
+ }
43
+ const dyeHue = ColorService.hexToHsv(dye.hex).h;
44
+ const hueDiff = Math.abs(dyeHue - targetHue);
45
+ return Math.min(hueDiff, 360 - hueDiff);
46
+ }
47
+ /** Every candidate scored against one slot's ideal, nearest first. */
48
+ function rankCandidates(candidates, targetHue, targetHex, config) {
49
+ const scored = [];
50
+ for (const dye of candidates) {
51
+ // Facewear carries generic names ("Red", "Blue") and is not a dye since
52
+ // schema v2; it must never surface as a harmony match.
53
+ if (dye.category === 'Facewear')
54
+ continue;
55
+ scored.push({ dye, deviance: devianceFor(dye, targetHue, targetHex, config) });
56
+ }
57
+ scored.sort((a, b) => a.deviance - b.deviance);
58
+ return scored;
59
+ }
60
+ /**
61
+ * Whether `harmonyType` is one this module can build.
62
+ *
63
+ * Every key of `HARMONY_OFFSETS` works, which is the point: a type is a row in
64
+ * that table, not a bespoke method, so the ten the page offers are the ten
65
+ * every surface can offer.
66
+ */
67
+ export function isKnownHarmonyType(harmonyType) {
68
+ return Object.hasOwn(HARMONY_OFFSETS, harmonyType);
69
+ }
70
+ /**
71
+ * Choose a dye for every slot of a harmony.
72
+ *
73
+ * Callers filter `candidates` themselves — this function does not know about
74
+ * anyone's dye-filter shape, and pre-filtering is what makes "the nearest
75
+ * ALLOWED dye to the ideal" the answer, rather than "the nearest allowed dye to
76
+ * a dye that was thrown away".
77
+ *
78
+ * @param baseHex the colour the harmony is built around; supplies H, S and V
79
+ * @param harmonyType a key of `HARMONY_OFFSETS`
80
+ * @param candidates the pool to choose from, already filtered
81
+ * @param config ranking and de-duplication behaviour
82
+ * @param options dyes to exclude, and any slots the caller has pinned
83
+ * @returns one slot per offset; `dye` is `null` for a slot with no candidate
84
+ */
85
+ export function generateHarmonySlots(baseHex, harmonyType, candidates, config, options) {
86
+ // Own-property check, not a truthiness one: `HARMONY_OFFSETS['toString']`
87
+ // returns Object.prototype.toString, which is TRUTHY, so a `!offsets` guard
88
+ // sails past it and the `.forEach` below throws. The web app reads this type
89
+ // straight out of a share URL (`?harmony=`), so the key really can be
90
+ // arbitrary.
91
+ if (!isKnownHarmonyType(harmonyType))
92
+ return [];
93
+ const offsets = HARMONY_OFFSETS[harmonyType];
94
+ const baseHsv = ColorService.hexToHsv(baseHex);
95
+ const companionCount = config.companionCount ?? 0;
96
+ const preventDuplicates = config.preventDuplicates ?? false;
97
+ // Two different questions, and they were one set until 2026-09-03.
98
+ //
99
+ // `excluded` is "must never be chosen" — normally the base dye itself, which
100
+ // is never a member of its own harmony. A custom colour has no dye to
101
+ // exclude, which is why this is a list rather than a required base dye:
102
+ // `/harmony color:#FF0000` has a hex and nothing else.
103
+ //
104
+ // `used` is "already on screen", and only matters when the caller asked for
105
+ // no repeats.
106
+ //
107
+ // Seeding `used` with the exclusions conflated them, and `used` is read only
108
+ // on the `preventDuplicates` branch — so with duplicates allowed the
109
+ // exclusions did nothing at all, against this function's own documented
110
+ // contract. bot-logic defaults `preventDuplicates` to false, so `/harmony
111
+ // monochromatic` (a single `[0]` offset, whose ideal IS the base colour)
112
+ // answered the base dye as its own harmony at deltaE 0, and `/harmony
113
+ // analogous` on a near-grey answered the base twice.
114
+ const excluded = new Set(options?.excludeItemIDs ?? []);
115
+ const used = new Set();
116
+ const slots = [];
117
+ offsets.forEach((offset, index) => {
118
+ const normalisedOffset = ((offset % 360) + 360) % 360;
119
+ const targetHue = (baseHsv.h + normalisedOffset) % 360;
120
+ // The ideal carries the BASE's saturation and value onto the rotated hue.
121
+ // That is the whole reason a desaturated base finds desaturated dyes, and
122
+ // the single biggest difference from the per-type find*Dyes() methods.
123
+ const targetHex = ColorService.hsvToHex(targetHue, baseHsv.s, baseHsv.v);
124
+ const ranked = rankCandidates(candidates, targetHue, targetHex, config);
125
+ const pin = options?.pinned?.get(index);
126
+ // Every branch below assigns, so no initialiser: an unread `= null` here
127
+ // would be one more place for a future edit to leave a slot silently empty.
128
+ let chosen;
129
+ if (pin) {
130
+ // An explicit hand-swap wins its slot outright, exclusions included: the
131
+ // user naming a dye outranks our guess about which dyes are eligible.
132
+ chosen = { dye: pin, deviance: devianceFor(pin, targetHue, targetHex, config) };
133
+ }
134
+ else if (preventDuplicates) {
135
+ // First eligible-and-unused, else the nearest eligible even if already
136
+ // shown: a slot with a dye repeated beats a slot left blank. An excluded
137
+ // dye is not a fallback in either case.
138
+ chosen =
139
+ ranked.find((c) => !excluded.has(c.dye.itemID) && !used.has(c.dye.itemID)) ??
140
+ ranked.find((c) => !excluded.has(c.dye.itemID)) ??
141
+ null;
142
+ }
143
+ else {
144
+ chosen = ranked.find((c) => !excluded.has(c.dye.itemID)) ?? null;
145
+ }
146
+ if (chosen)
147
+ used.add(chosen.dye.itemID);
148
+ const companions = [];
149
+ if (companionCount > 0) {
150
+ for (const candidate of ranked) {
151
+ if (companions.length >= companionCount)
152
+ break;
153
+ if (excluded.has(candidate.dye.itemID))
154
+ continue;
155
+ if (chosen && candidate.dye.itemID === chosen.dye.itemID)
156
+ continue;
157
+ if (preventDuplicates && used.has(candidate.dye.itemID))
158
+ continue;
159
+ companions.push(candidate.dye);
160
+ if (preventDuplicates)
161
+ used.add(candidate.dye.itemID);
162
+ }
163
+ }
164
+ slots.push({
165
+ index,
166
+ offset: normalisedOffset,
167
+ targetHue,
168
+ targetHex,
169
+ dye: chosen?.dye ?? null,
170
+ deviance: chosen?.deviance ?? 0,
171
+ companions,
172
+ });
173
+ });
174
+ return slots;
175
+ }
176
+ //# sourceMappingURL=HarmonySelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HarmonySelector.js","sourceRoot":"","sources":["../../../src/services/dye/HarmonySelector.ts"],"names":[],"mappings":"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"}
@@ -13,12 +13,17 @@ import type { LocaleRegistry } from './LocaleRegistry.js';
13
13
  *
14
14
  * Fallback chain: requested locale → English → formatted key / original value
15
15
  *
16
- * BUG-007: All lookup methods use truthiness checks (e.g., `if (localeData?.labels[key])`)
17
- * which treats empty strings ("") as missing translations, falling back to English.
18
- * This is intentional — empty strings in locale files indicate untranslated entries.
19
- * Korean and Chinese locales are manually sourced and may have incomplete coverage;
20
- * the truthiness check ensures seamless fallback for any missing or empty entries.
21
- * For detecting incomplete locale files at build time, see `build-locales.ts`.
16
+ * BUG-007: every lookup keeps a truthiness check, which treats an empty string
17
+ * ("") as a missing translation and falls back to English. That is intentional —
18
+ * an empty string in a locale file means "not translated yet", and the Korean
19
+ * and Chinese locales are manually sourced with incomplete coverage. For
20
+ * detecting incomplete locale files at build time, see `build-locales.ts`.
21
+ *
22
+ * BUG-105: every lookup is ALSO guarded with `Object.hasOwn`, because a bare
23
+ * truthiness check on a plain object resolves through `Object.prototype` — a
24
+ * key of `'constructor'` or `'toString'` is truthy and returns a FUNCTION where
25
+ * a localized string is expected. FINDING-027 added that guard to `getLabel`
26
+ * alone; its ten siblings went without one until this pass.
22
27
  */
23
28
  export declare class TranslationProvider {
24
29
  private registry;
@@ -1 +1 @@
1
- {"version":3,"file":"TranslationProvider.d.ts","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,UAAU,EACV,OAAO,EACP,QAAQ,EACR,OAAO,EACP,OAAO,EACR,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;GAWG;AACH,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,cAAc;IAE5C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAqBzD;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IA+B7D;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBzD;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB/D;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBzD;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB/D;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB1D;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiB3D;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiBrD;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiBvD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBjD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBjD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS;CAMlB"}
1
+ {"version":3,"file":"TranslationProvider.d.ts","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,UAAU,EACV,OAAO,EACP,QAAQ,EACR,OAAO,EACP,OAAO,EACR,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,cAAc;IAE5C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAqBzD;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IA+B7D;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBzD;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB/D;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBzD;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB/D;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoB1D;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiB3D;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiBrD;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAiBvD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBjD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAoBjD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS;CAMlB"}
@@ -12,12 +12,17 @@ import { CONSOLIDATED_DYES, CONSOLIDATED_IDS, } from '../../config/consolidated-
12
12
  *
13
13
  * Fallback chain: requested locale → English → formatted key / original value
14
14
  *
15
- * BUG-007: All lookup methods use truthiness checks (e.g., `if (localeData?.labels[key])`)
16
- * which treats empty strings ("") as missing translations, falling back to English.
17
- * This is intentional — empty strings in locale files indicate untranslated entries.
18
- * Korean and Chinese locales are manually sourced and may have incomplete coverage;
19
- * the truthiness check ensures seamless fallback for any missing or empty entries.
20
- * For detecting incomplete locale files at build time, see `build-locales.ts`.
15
+ * BUG-007: every lookup keeps a truthiness check, which treats an empty string
16
+ * ("") as a missing translation and falls back to English. That is intentional —
17
+ * an empty string in a locale file means "not translated yet", and the Korean
18
+ * and Chinese locales are manually sourced with incomplete coverage. For
19
+ * detecting incomplete locale files at build time, see `build-locales.ts`.
20
+ *
21
+ * BUG-105: every lookup is ALSO guarded with `Object.hasOwn`, because a bare
22
+ * truthiness check on a plain object resolves through `Object.prototype` — a
23
+ * key of `'constructor'` or `'toString'` is truthy and returns a FUNCTION where
24
+ * a localized string is expected. FINDING-027 added that guard to `getLabel`
25
+ * alone; its ten siblings went without one until this pass.
21
26
  */
22
27
  export class TranslationProvider {
23
28
  registry;
@@ -71,13 +76,13 @@ export class TranslationProvider {
71
76
  const localeData = this.registry.getLocale(locale);
72
77
  const idStr = String(itemID);
73
78
  // Try requested locale
74
- if (localeData?.dyeNames[idStr]) {
79
+ if (localeData?.dyeNames && Object.hasOwn(localeData.dyeNames, idStr) && localeData?.dyeNames[idStr]) {
75
80
  return localeData.dyeNames[idStr];
76
81
  }
77
82
  // Fallback to English
78
83
  if (locale !== 'en') {
79
84
  const englishData = this.registry.getLocale('en');
80
- if (englishData?.dyeNames[idStr]) {
85
+ if (englishData?.dyeNames && Object.hasOwn(englishData.dyeNames, idStr) && englishData?.dyeNames[idStr]) {
81
86
  return englishData.dyeNames[idStr];
82
87
  }
83
88
  }
@@ -109,13 +114,13 @@ export class TranslationProvider {
109
114
  getCategory(category, locale) {
110
115
  const localeData = this.registry.getLocale(locale);
111
116
  // Try requested locale
112
- if (localeData?.categories[category]) {
117
+ if (localeData?.categories && Object.hasOwn(localeData.categories, category) && localeData?.categories[category]) {
113
118
  return localeData.categories[category];
114
119
  }
115
120
  // Fallback to English
116
121
  if (locale !== 'en') {
117
122
  const englishData = this.registry.getLocale('en');
118
- if (englishData?.categories[category]) {
123
+ if (englishData?.categories && Object.hasOwn(englishData.categories, category) && englishData?.categories[category]) {
119
124
  return englishData.categories[category];
120
125
  }
121
126
  }
@@ -138,13 +143,13 @@ export class TranslationProvider {
138
143
  getAcquisition(acquisition, locale) {
139
144
  const localeData = this.registry.getLocale(locale);
140
145
  // Try requested locale
141
- if (localeData?.acquisitions[acquisition]) {
146
+ if (localeData?.acquisitions && Object.hasOwn(localeData.acquisitions, acquisition) && localeData?.acquisitions[acquisition]) {
142
147
  return localeData.acquisitions[acquisition];
143
148
  }
144
149
  // Fallback to English
145
150
  if (locale !== 'en') {
146
151
  const englishData = this.registry.getLocale('en');
147
- if (englishData?.acquisitions[acquisition]) {
152
+ if (englishData?.acquisitions && Object.hasOwn(englishData.acquisitions, acquisition) && englishData?.acquisitions[acquisition]) {
148
153
  return englishData.acquisitions[acquisition];
149
154
  }
150
155
  }
@@ -167,13 +172,13 @@ export class TranslationProvider {
167
172
  getCurrency(currency, locale) {
168
173
  const localeData = this.registry.getLocale(locale);
169
174
  // Try requested locale
170
- if (localeData?.currencies?.[currency]) {
175
+ if (localeData?.currencies && Object.hasOwn(localeData.currencies, currency) && localeData.currencies[currency]) {
171
176
  return localeData.currencies[currency];
172
177
  }
173
178
  // Fallback to English
174
179
  if (locale !== 'en') {
175
180
  const englishData = this.registry.getLocale('en');
176
- if (englishData?.currencies?.[currency]) {
181
+ if (englishData?.currencies && Object.hasOwn(englishData.currencies, currency) && englishData.currencies[currency]) {
177
182
  return englishData.currencies[currency];
178
183
  }
179
184
  }
@@ -196,13 +201,13 @@ export class TranslationProvider {
196
201
  getHarmonyType(key, locale) {
197
202
  const localeData = this.registry.getLocale(locale);
198
203
  // Try requested locale
199
- if (localeData?.harmonyTypes[key]) {
204
+ if (localeData?.harmonyTypes && Object.hasOwn(localeData.harmonyTypes, key) && localeData?.harmonyTypes[key]) {
200
205
  return localeData.harmonyTypes[key];
201
206
  }
202
207
  // Fallback to English
203
208
  if (locale !== 'en') {
204
209
  const englishData = this.registry.getLocale('en');
205
- if (englishData?.harmonyTypes[key]) {
210
+ if (englishData?.harmonyTypes && Object.hasOwn(englishData.harmonyTypes, key) && englishData?.harmonyTypes[key]) {
206
211
  return englishData.harmonyTypes[key];
207
212
  }
208
213
  }
@@ -225,13 +230,13 @@ export class TranslationProvider {
225
230
  getVisionType(key, locale) {
226
231
  const localeData = this.registry.getLocale(locale);
227
232
  // Try requested locale
228
- if (localeData?.visionTypes[key]) {
233
+ if (localeData?.visionTypes && Object.hasOwn(localeData.visionTypes, key) && localeData?.visionTypes[key]) {
229
234
  return localeData.visionTypes[key];
230
235
  }
231
236
  // Fallback to English
232
237
  if (locale !== 'en') {
233
238
  const englishData = this.registry.getLocale('en');
234
- if (englishData?.visionTypes[key]) {
239
+ if (englishData?.visionTypes && Object.hasOwn(englishData.visionTypes, key) && englishData?.visionTypes[key]) {
235
240
  return englishData.visionTypes[key];
236
241
  }
237
242
  }
@@ -257,12 +262,12 @@ export class TranslationProvider {
257
262
  */
258
263
  getVisionShort(key, locale) {
259
264
  const localeData = this.registry.getLocale(locale);
260
- if (localeData?.visions?.[key]) {
265
+ if (localeData?.visions && Object.hasOwn(localeData.visions, key) && localeData.visions[key]) {
261
266
  return localeData.visions[key];
262
267
  }
263
268
  if (locale !== 'en') {
264
269
  const englishData = this.registry.getLocale('en');
265
- if (englishData?.visions?.[key]) {
270
+ if (englishData?.visions && Object.hasOwn(englishData.visions, key) && englishData.visions[key]) {
266
271
  return englishData.visions[key];
267
272
  }
268
273
  }
@@ -286,12 +291,12 @@ export class TranslationProvider {
286
291
  */
287
292
  getToolName(key, locale) {
288
293
  const localeData = this.registry.getLocale(locale);
289
- if (localeData?.tools?.[key]) {
294
+ if (localeData?.tools && Object.hasOwn(localeData.tools, key) && localeData.tools[key]) {
290
295
  return localeData.tools[key];
291
296
  }
292
297
  if (locale !== 'en') {
293
298
  const englishData = this.registry.getLocale('en');
294
- if (englishData?.tools?.[key]) {
299
+ if (englishData?.tools && Object.hasOwn(englishData.tools, key) && englishData.tools[key]) {
295
300
  return englishData.tools[key];
296
301
  }
297
302
  }
@@ -315,12 +320,12 @@ export class TranslationProvider {
315
320
  */
316
321
  getSheetName(key, locale) {
317
322
  const localeData = this.registry.getLocale(locale);
318
- if (localeData?.sheets?.[key]) {
323
+ if (localeData?.sheets && Object.hasOwn(localeData.sheets, key) && localeData.sheets[key]) {
319
324
  return localeData.sheets[key];
320
325
  }
321
326
  if (locale !== 'en') {
322
327
  const englishData = this.registry.getLocale('en');
323
- if (englishData?.sheets?.[key]) {
328
+ if (englishData?.sheets && Object.hasOwn(englishData.sheets, key) && englishData.sheets[key]) {
324
329
  return englishData.sheets[key];
325
330
  }
326
331
  }
@@ -342,13 +347,13 @@ export class TranslationProvider {
342
347
  getRace(key, locale) {
343
348
  const localeData = this.registry.getLocale(locale);
344
349
  // Try requested locale
345
- if (localeData?.races?.[key]) {
350
+ if (localeData?.races && Object.hasOwn(localeData.races, key) && localeData.races[key]) {
346
351
  return localeData.races[key];
347
352
  }
348
353
  // Fallback to English
349
354
  if (locale !== 'en') {
350
355
  const englishData = this.registry.getLocale('en');
351
- if (englishData?.races?.[key]) {
356
+ if (englishData?.races && Object.hasOwn(englishData.races, key) && englishData.races[key]) {
352
357
  return englishData.races[key];
353
358
  }
354
359
  }
@@ -371,13 +376,13 @@ export class TranslationProvider {
371
376
  getClan(key, locale) {
372
377
  const localeData = this.registry.getLocale(locale);
373
378
  // Try requested locale
374
- if (localeData?.clans?.[key]) {
379
+ if (localeData?.clans && Object.hasOwn(localeData.clans, key) && localeData.clans[key]) {
375
380
  return localeData.clans[key];
376
381
  }
377
382
  // Fallback to English
378
383
  if (locale !== 'en') {
379
384
  const englishData = this.registry.getLocale('en');
380
- if (englishData?.clans?.[key]) {
385
+ if (englishData?.clans && Object.hasOwn(englishData.clans, key) && englishData.clans[key]) {
381
386
  return englishData.clans[key];
382
387
  }
383
388
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TranslationProvider.js","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TranslationProvider.js","sourceRoot":"","sources":["../../../src/services/localization/TranslationProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAYH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GAEjB,MAAM,kCAAkC,CAAC;AAG1C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,mBAAmB;IACV;IAApB,YAAoB,QAAwB;QAAxB,aAAQ,GAAR,QAAQ,CAAgB;IAAG,CAAC;IAEhD;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,GAAmB,EAAE,MAAkB;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,0EAA0E;QAC1E,8DAA8D;QAC9D,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAClF,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrF,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,sDAAsD;QACtD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,MAAc,EAAE,MAAkB;QAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAE7B,uBAAuB;QACvB,IAAI,UAAU,EAAE,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACrG,OAAO,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxG,OAAO,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;QAED,uEAAuE;QACvE,sEAAsE;QACtE,mEAAmE;QACnE,sDAAsD;QACtD,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAiD,EAAE,CAAC;YACnF,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC;gBACtC,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;gBAC5C,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACnC,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAgB,EAAE,MAAkB;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,uBAAuB;QACvB,IAAI,UAAU,EAAE,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjH,OAAO,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,WAAW,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpH,OAAO,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,2CAA2C;QAC3C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,WAAmB,EAAE,MAAkB;QACpD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,uBAAuB;QACvB,IAAI,UAAU,EAAE,YAAY,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,WAAW,CAAC,IAAI,UAAU,EAAE,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7H,OAAO,UAAU,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAC9C,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,YAAY,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC,IAAI,WAAW,EAAE,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC;gBAChI,OAAO,WAAW,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;QAED,8CAA8C;QAC9C,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,QAAgB,EAAE,MAAkB;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,uBAAuB;QACvB,IAAI,UAAU,EAAE,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChH,OAAO,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnH,OAAO,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,2CAA2C;QAC3C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,GAAmB,EAAE,MAAkB;QACpD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,uBAAuB;QACvB,IAAI,UAAU,EAAE,YAAY,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7G,OAAO,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,YAAY,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,WAAW,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChH,OAAO,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,GAAe,EAAE,MAAkB;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,uBAAuB;QACvB,IAAI,UAAU,EAAE,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1G,OAAO,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7G,OAAO,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,GAAe,EAAE,MAAkB;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,IAAI,UAAU,EAAE,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7F,OAAO,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChG,OAAO,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,GAAY,EAAE,MAAkB;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,IAAI,UAAU,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACvF,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1F,OAAO,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,GAAa,EAAE,MAAkB;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,IAAI,UAAU,EAAE,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1F,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7F,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAY,EAAE,MAAkB;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,uBAAuB;QACvB,IAAI,UAAU,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACvF,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1F,OAAO,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,GAAY,EAAE,MAAkB;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAEnD,uBAAuB;QACvB,IAAI,UAAU,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACvF,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1F,OAAO,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;OAYG;IACK,SAAS,CAAC,GAAW;QAC3B,OAAO,GAAG;aACP,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;aAC1B,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;aACzC,IAAI,EAAE,CAAC;IACZ,CAAC;CACF"}
@@ -53,5 +53,18 @@ export declare function isMatchingMethod(value: unknown): value is MatchingMetho
53
53
  * URL `algo` param, API body) into the 5.0 vocabulary: current values pass
54
54
  * through, retired values map, anything else falls back to the default.
55
55
  */
56
+ /**
57
+ * BUG-011: `value in OBJ` and `OBJ[value]` both walk `Object.prototype`, so
58
+ * `'constructor'`, `'toString'` and `'__proto__'` looked like legacy method
59
+ * names and returned a FUNCTION typed as a `MatchingMethod`. This normalizer is
60
+ * applied at every ingress — KV preference, localStorage, the URL `algo` param,
61
+ * API bodies — and its whole contract is "anything else falls back to the
62
+ * default", so a crafted value propagated a function into the matching method
63
+ * and `getDistanceForMethod`'s exhaustive switch then returned `undefined`.
64
+ *
65
+ * `Object.hasOwn` is the fix rather than a `Map` because
66
+ * `LEGACY_MATCHING_METHOD_MAP` is a published export; changing its type would
67
+ * be a breaking change for a defect that needs a guard, not a new shape.
68
+ */
56
69
  export declare function normalizeMatchingMethod(value: unknown): MatchingMethod;
57
70
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,CAAC;AAEjG,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAOrD,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,EAAE,cAA4B,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,EAAE,MAAM,CAQzE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAKrE,CAAC;AAEF,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAMtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,CAAC;AAEjG,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAOrD,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,EAAE,cAA4B,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,cAAc,GAAG,OAAO,EAAE,MAAM,CAQzE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAKrE,CAAC;AAEF,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE;AAED;;;;GAIG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAMtE"}
@@ -51,10 +51,23 @@ export function isMatchingMethod(value) {
51
51
  * URL `algo` param, API body) into the 5.0 vocabulary: current values pass
52
52
  * through, retired values map, anything else falls back to the default.
53
53
  */
54
+ /**
55
+ * BUG-011: `value in OBJ` and `OBJ[value]` both walk `Object.prototype`, so
56
+ * `'constructor'`, `'toString'` and `'__proto__'` looked like legacy method
57
+ * names and returned a FUNCTION typed as a `MatchingMethod`. This normalizer is
58
+ * applied at every ingress — KV preference, localStorage, the URL `algo` param,
59
+ * API bodies — and its whole contract is "anything else falls back to the
60
+ * default", so a crafted value propagated a function into the matching method
61
+ * and `getDistanceForMethod`'s exhaustive switch then returned `undefined`.
62
+ *
63
+ * `Object.hasOwn` is the fix rather than a `Map` because
64
+ * `LEGACY_MATCHING_METHOD_MAP` is a published export; changing its type would
65
+ * be a breaking change for a defect that needs a guard, not a new shape.
66
+ */
54
67
  export function normalizeMatchingMethod(value) {
55
68
  if (isMatchingMethod(value))
56
69
  return value;
57
- if (typeof value === 'string' && value in LEGACY_MATCHING_METHOD_MAP) {
70
+ if (typeof value === 'string' && Object.hasOwn(LEGACY_MATCHING_METHOD_MAP, value)) {
58
71
  return LEGACY_MATCHING_METHOD_MAP[value];
59
72
  }
60
73
  return DEFAULT_MATCHING_METHOD;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA+BH,qFAAqF;AACrF,MAAM,CAAC,MAAM,gBAAgB,GAA8B;IACzD,WAAW;IACX,OAAO;IACP,OAAO;IACP,SAAS;IACT,KAAK;IACL,aAAa;CACd,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAmB,WAAW,CAAC;AAEnE;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,SAAS,EAAE,QAAQ;IACnB,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,UAAU;IACf,WAAW,EAAE,eAAe;IAC5B,KAAK,EAAE,OAAO;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAmC;IACxE,IAAI,EAAE,WAAW;IACjB,gBAAgB,EAAE,WAAW;IAC7B,kEAAkE;IAClE,SAAS,EAAE,KAAK;CACjB,CAAC;AAEF,yCAAyC;AACzC,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,0BAA0B,EAAE,CAAC;QACrE,OAAO,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,uBAAuB,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA+BH,qFAAqF;AACrF,MAAM,CAAC,MAAM,gBAAgB,GAA8B;IACzD,WAAW;IACX,OAAO;IACP,OAAO;IACP,SAAS;IACT,KAAK;IACL,aAAa;CACd,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAmB,WAAW,CAAC;AAEnE;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,SAAS,EAAE,QAAQ;IACnB,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,UAAU;IACf,WAAW,EAAE,eAAe;IAC5B,KAAK,EAAE,OAAO;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAmC;IACxE,IAAI,EAAE,WAAW;IACjB,gBAAgB,EAAE,WAAW;IAC7B,kEAAkE;IAClE,SAAS,EAAE,KAAK;CACjB,CAAC;AAEF,yCAAyC;AACzC,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,0BAA0B,EAAE,KAAK,CAAC,EAAE,CAAC;QAClF,OAAO,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,uBAAuB,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xivdyetools/core",
3
- "version": "4.0.1",
3
+ "version": "4.2.0",
4
4
  "description": "Core color algorithms and dye database for XIV Dye Tools",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,15 +46,15 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "spectral.js": "^3.0.0",
49
- "@xivdyetools/types": "2.0.0",
50
- "@xivdyetools/logger": "2.1.0"
49
+ "@xivdyetools/logger": "2.2.0",
50
+ "@xivdyetools/types": "3.0.0"
51
51
  },
52
52
  "devDependencies": {
53
- "@types/node": "^26.1.2",
54
- "@vitest/coverage-v8": "^4.1.10",
55
- "csv-parse": "^7.0.1",
56
- "tsx": "^4.23.1",
57
- "vitest": "^4.1.10",
53
+ "@types/node": "^26.4.0",
54
+ "@vitest/coverage-v8": "^4.1.11",
55
+ "csv-parse": "^7.0.2",
56
+ "tsx": "^4.23.12",
57
+ "vitest": "^4.1.11",
58
58
  "yaml": "^2.9.0"
59
59
  },
60
60
  "engines": {