@xivdyetools/core 2.7.0 → 4.0.1
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/README.md +85 -67
- package/dist/blending/blending.d.ts +22 -0
- package/dist/blending/blending.d.ts.map +1 -0
- package/dist/blending/blending.js +129 -0
- package/dist/blending/blending.js.map +1 -0
- package/dist/blending/conversions.d.ts +53 -0
- package/dist/blending/conversions.d.ts.map +1 -0
- package/dist/blending/conversions.js +256 -0
- package/dist/blending/conversions.js.map +1 -0
- package/dist/blending/index.d.ts +8 -0
- package/dist/blending/index.d.ts.map +1 -0
- package/dist/blending/index.js +3 -0
- package/dist/blending/index.js.map +1 -0
- package/dist/blending/types.d.ts +36 -0
- package/dist/blending/types.d.ts.map +1 -0
- package/dist/blending/types.js +21 -0
- package/dist/blending/types.js.map +1 -0
- package/dist/config/band-calibration.d.ts +68 -0
- package/dist/config/band-calibration.d.ts.map +1 -0
- package/dist/config/band-calibration.js +196 -0
- package/dist/config/band-calibration.js.map +1 -0
- package/dist/config/band-vocabulary.d.ts +82 -0
- package/dist/config/band-vocabulary.d.ts.map +1 -0
- package/dist/config/band-vocabulary.js +117 -0
- package/dist/config/band-vocabulary.js.map +1 -0
- package/dist/config/consolidated-ids.js +2 -2
- package/dist/config/consolidated-ids.js.map +1 -1
- package/dist/config/dye-vocabulary.d.ts +45 -0
- package/dist/config/dye-vocabulary.d.ts.map +1 -0
- package/dist/config/dye-vocabulary.js +58 -0
- package/dist/config/dye-vocabulary.js.map +1 -0
- package/dist/config/facewear.d.ts +24 -0
- package/dist/config/facewear.d.ts.map +1 -0
- package/dist/config/facewear.js +35 -0
- package/dist/config/facewear.js.map +1 -0
- package/dist/config/learn-links.d.ts +70 -0
- package/dist/config/learn-links.d.ts.map +1 -0
- package/dist/config/learn-links.js +171 -0
- package/dist/config/learn-links.js.map +1 -0
- package/dist/config/product-links.d.ts +44 -0
- package/dist/config/product-links.d.ts.map +1 -0
- package/dist/config/product-links.js +44 -0
- package/dist/config/product-links.js.map +1 -0
- package/dist/constants/index.d.ts +14 -1
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +38 -22
- package/dist/constants/index.js.map +1 -1
- package/dist/data/character_colors/race_specific/hair_colors.json +1 -1
- package/dist/data/character_colors/race_specific/skin_colors.json +1 -1
- package/dist/data/dyes.json +1127 -0
- package/dist/data/facewear_colors.json +57 -0
- package/dist/data/locales/de.json +4 -50
- package/dist/data/locales/en.json +4 -50
- package/dist/data/locales/fr.json +4 -50
- package/dist/data/locales/ja.json +4 -50
- package/dist/data/locales/ko.json +4 -50
- package/dist/data/locales/zh.json +4 -50
- package/dist/data/presets.json +59 -301
- package/dist/index.d.ts +156 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +114 -10
- package/dist/index.js.map +1 -1
- package/dist/services/APIService.d.ts +7 -61
- package/dist/services/APIService.d.ts.map +1 -1
- package/dist/services/APIService.js +43 -154
- package/dist/services/APIService.js.map +1 -1
- package/dist/services/CharacterColorService.d.ts +4 -36
- package/dist/services/CharacterColorService.d.ts.map +1 -1
- package/dist/services/CharacterColorService.js +16 -68
- package/dist/services/CharacterColorService.js.map +1 -1
- package/dist/services/ColorService.d.ts +55 -68
- package/dist/services/ColorService.d.ts.map +1 -1
- package/dist/services/ColorService.js +86 -94
- package/dist/services/ColorService.js.map +1 -1
- package/dist/services/DyeService.d.ts +10 -103
- package/dist/services/DyeService.d.ts.map +1 -1
- package/dist/services/DyeService.js +13 -156
- package/dist/services/DyeService.js.map +1 -1
- package/dist/services/LocalizationService.d.ts +1 -33
- package/dist/services/LocalizationService.d.ts.map +1 -1
- package/dist/services/LocalizationService.js +0 -44
- package/dist/services/LocalizationService.js.map +1 -1
- package/dist/services/PaletteService.d.ts +8 -9
- package/dist/services/PaletteService.d.ts.map +1 -1
- package/dist/services/PaletteService.js +2 -21
- package/dist/services/PaletteService.js.map +1 -1
- package/dist/services/PresetService.d.ts +2 -34
- package/dist/services/PresetService.d.ts.map +1 -1
- package/dist/services/PresetService.js +12 -59
- package/dist/services/PresetService.js.map +1 -1
- package/dist/services/chara/chara-models.d.ts +68 -0
- package/dist/services/chara/chara-models.d.ts.map +1 -0
- package/dist/services/chara/chara-models.js +87 -0
- package/dist/services/chara/chara-models.js.map +1 -0
- package/dist/services/chara/chara-parser.d.ts +95 -0
- package/dist/services/chara/chara-parser.d.ts.map +1 -0
- package/dist/services/chara/chara-parser.js +299 -0
- package/dist/services/chara/chara-parser.js.map +1 -0
- package/dist/services/chara/chara-resolver.d.ts +103 -0
- package/dist/services/chara/chara-resolver.d.ts.map +1 -0
- package/dist/services/chara/chara-resolver.js +233 -0
- package/dist/services/chara/chara-resolver.js.map +1 -0
- package/dist/services/color/ColorConverter.d.ts +107 -35
- package/dist/services/color/ColorConverter.d.ts.map +1 -1
- package/dist/services/color/ColorConverter.js +159 -48
- package/dist/services/color/ColorConverter.js.map +1 -1
- package/dist/services/color/ColorManipulator.d.ts +11 -0
- package/dist/services/color/ColorManipulator.d.ts.map +1 -1
- package/dist/services/color/ColorManipulator.js +14 -0
- package/dist/services/color/ColorManipulator.js.map +1 -1
- package/dist/services/color/ColorblindnessSimulator.d.ts +17 -0
- package/dist/services/color/ColorblindnessSimulator.d.ts.map +1 -1
- package/dist/services/color/ColorblindnessSimulator.js +53 -1
- package/dist/services/color/ColorblindnessSimulator.js.map +1 -1
- package/dist/services/color/SpectralMixer.d.ts +0 -34
- package/dist/services/color/SpectralMixer.d.ts.map +1 -1
- package/dist/services/color/SpectralMixer.js +0 -73
- package/dist/services/color/SpectralMixer.js.map +1 -1
- package/dist/services/dye/DyeDatabase.d.ts +0 -21
- package/dist/services/dye/DyeDatabase.d.ts.map +1 -1
- package/dist/services/dye/DyeDatabase.js +78 -103
- package/dist/services/dye/DyeDatabase.js.map +1 -1
- package/dist/services/dye/DyeSearch.d.ts +17 -31
- package/dist/services/dye/DyeSearch.d.ts.map +1 -1
- package/dist/services/dye/DyeSearch.js +31 -67
- package/dist/services/dye/DyeSearch.js.map +1 -1
- package/dist/services/dye/HarmonyGenerator.d.ts +11 -18
- package/dist/services/dye/HarmonyGenerator.d.ts.map +1 -1
- package/dist/services/dye/HarmonyGenerator.js +24 -35
- package/dist/services/dye/HarmonyGenerator.js.map +1 -1
- package/dist/services/localization/LocaleLoader.d.ts.map +1 -1
- package/dist/services/localization/LocaleLoader.js +0 -1
- package/dist/services/localization/LocaleLoader.js.map +1 -1
- package/dist/services/localization/TranslationProvider.d.ts +1 -42
- package/dist/services/localization/TranslationProvider.d.ts.map +1 -1
- package/dist/services/localization/TranslationProvider.js +4 -82
- package/dist/services/localization/TranslationProvider.js.map +1 -1
- package/dist/types/index.d.ts +39 -52
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +50 -10
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +35 -122
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +45 -422
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/kd-tree.d.ts +0 -4
- package/dist/utils/kd-tree.d.ts.map +1 -1
- package/dist/utils/kd-tree.js +0 -6
- package/dist/utils/kd-tree.js.map +1 -1
- package/package.json +19 -10
- package/dist/data/character_colors/index.json +0 -40
- package/dist/data/colors_xiv.json +0 -3538
- package/dist/version.d.ts +0 -11
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -11
- package/dist/version.js.map +0 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
// @xivdyetools/core — public barrel.
|
|
2
|
+
//
|
|
3
|
+
// A `@public` JSDoc tag on a specifier below means: published API, deliberately
|
|
4
|
+
// kept even though no workspace in this monorepo imports it. The root
|
|
5
|
+
// `knip.jsonc` gate (`pnpm run lint:dead`, part of `lint`) reports every
|
|
6
|
+
// untagged barrel export that nothing consumes, so a new export must either
|
|
7
|
+
// gain a consumer or be tagged on purpose — see the package CLAUDE.md.
|
|
1
8
|
// Services
|
|
2
9
|
export { ColorService } from './services/ColorService.js';
|
|
3
|
-
export { ColorConverter } from './services/color/ColorConverter.js';
|
|
10
|
+
export { /** @public */ ColorConverter } from './services/color/ColorConverter.js';
|
|
4
11
|
export { DyeService } from './services/DyeService.js';
|
|
5
|
-
export { APIService, MemoryCacheBackend } from './services/APIService.js';
|
|
6
|
-
export { LocalizationService, SUPPORTED_LOCALES, extractLocaleCode,
|
|
12
|
+
export { APIService, /** @public */ MemoryCacheBackend } from './services/APIService.js';
|
|
13
|
+
export { LocalizationService, SUPPORTED_LOCALES, extractLocaleCode,
|
|
14
|
+
/** @public */
|
|
15
|
+
resolveLocaleFromPreference, } from './services/LocalizationService.js';
|
|
7
16
|
// Localization internals — exported for stateless callers (e.g., og-worker)
|
|
8
17
|
// that prefer explicit-locale APIs over the singleton + setLocale pattern.
|
|
9
18
|
export { LocaleLoader } from './services/localization/LocaleLoader.js';
|
|
@@ -15,17 +24,112 @@ export { CharacterColorService, } from './services/CharacterColorService.js';
|
|
|
15
24
|
// Dye filtering
|
|
16
25
|
export { isDyeExcluded, filterDyes, hasActiveFilters, EXPENSIVE_DYE_IDS, VENDOR_ACQUISITIONS, CRAFT_ACQUISITIONS, } from './services/dye/DyeFilter.js';
|
|
17
26
|
export {
|
|
18
|
-
//
|
|
19
|
-
|
|
27
|
+
// 5.0 matching vocabulary (one list suite-wide, dE2000 default)
|
|
28
|
+
MATCHING_METHODS, DEFAULT_MATCHING_METHOD, MATCHING_METHOD_TAGS, LEGACY_MATCHING_METHOD_MAP, isMatchingMethod, normalizeMatchingMethod, } from './types/index.js';
|
|
20
29
|
// Dye consolidation (Patch 7.5)
|
|
21
30
|
export { CONSOLIDATED_IDS, CONSOLIDATED_DYES, isConsolidationActive, getMarketItemID, getConsolidatedDyeName, } from './config/consolidated-ids.js';
|
|
31
|
+
// Dye vocabulary (closed value sets + acquisition → price/currency coupling)
|
|
32
|
+
export {
|
|
33
|
+
/** @public */
|
|
34
|
+
DYE_CATEGORIES,
|
|
35
|
+
/** @public */
|
|
36
|
+
DYE_ACQUISITIONS,
|
|
37
|
+
/** @public */
|
|
38
|
+
ACQUISITION_META,
|
|
39
|
+
/** @public */
|
|
40
|
+
METALLIC_STAIN_IDS, } from './config/dye-vocabulary.js';
|
|
41
|
+
// Band vocabulary (5.0 calibrated per-method tier boundaries)
|
|
42
|
+
export { BAND_VOCABULARY, BAND_METHOD_DP,
|
|
43
|
+
/** @public */
|
|
44
|
+
RATIO_BANDS, classifyBandTier,
|
|
45
|
+
/** @public */
|
|
46
|
+
classifyBandTierWithCuts,
|
|
47
|
+
/** @public */
|
|
48
|
+
deriveDistinguishCuts, roundToBandDisplay, } from './config/band-vocabulary.js';
|
|
49
|
+
export { SOCIAL_LINKS, PRODUCT_LINKS } from './config/product-links.js';
|
|
50
|
+
// .chara character-file import (5.0 Swatch Matcher; parse rules live in core)
|
|
51
|
+
export { parseCharaFile } from './services/chara/chara-parser.js';
|
|
52
|
+
export { resolveCharaColors,
|
|
53
|
+
/** @public */ OFF_GRID_DELTA_E2000, } from './services/chara/chara-resolver.js';
|
|
54
|
+
// Equipment model identity (packing helpers shared by api-worker's resolver
|
|
55
|
+
// and the web-app client; the parser emits the keys, nothing in core resolves)
|
|
56
|
+
export {
|
|
57
|
+
/** @public */ gearModelKey,
|
|
58
|
+
/** @public */ weaponModelKey, charaModelKey, formatCharaModelLabel, CHARA_SLOT_SEARCH_FIELD,
|
|
59
|
+
/** @public */ CHARA_WEAPON_SLOTS, isCharaWeaponSlot, isWornCharaModel, } from './services/chara/chara-models.js';
|
|
60
|
+
// /manual topics + learn-more links (shared data for web, bot, og-worker)
|
|
61
|
+
export { MANUAL_TOPICS,
|
|
62
|
+
/** @public */
|
|
63
|
+
LODESTONE_BY_REGION,
|
|
64
|
+
/** @public */
|
|
65
|
+
XIVDYETOOLS_DOCS_URL, getLearnLink, getLodestoneLink, } from './config/learn-links.js';
|
|
66
|
+
// Facewear colors (split out of the dye database in schema v2)
|
|
67
|
+
export {
|
|
68
|
+
/** @public */
|
|
69
|
+
facewearColors,
|
|
70
|
+
/** @public */
|
|
71
|
+
LEGACY_FACEWEAR_ITEM_IDS,
|
|
72
|
+
/** @public */
|
|
73
|
+
getFacewearColor, getFacewearColorByLegacyItemID, } from './config/facewear.js';
|
|
22
74
|
// Constants
|
|
23
|
-
export {
|
|
75
|
+
export {
|
|
76
|
+
/** @public */
|
|
77
|
+
RGB_MIN,
|
|
78
|
+
/** @public */
|
|
79
|
+
RGB_MAX,
|
|
80
|
+
/** @public */
|
|
81
|
+
HUE_MIN,
|
|
82
|
+
/** @public */
|
|
83
|
+
HUE_MAX,
|
|
84
|
+
/** @public */
|
|
85
|
+
SATURATION_MIN,
|
|
86
|
+
/** @public */
|
|
87
|
+
SATURATION_MAX,
|
|
88
|
+
/** @public */
|
|
89
|
+
VALUE_MIN,
|
|
90
|
+
/** @public */
|
|
91
|
+
VALUE_MAX,
|
|
92
|
+
/** @public */
|
|
93
|
+
BRETTEL_MATRICES,
|
|
94
|
+
/** @public */
|
|
95
|
+
MACHADO_MATRICES,
|
|
96
|
+
/** @public */
|
|
97
|
+
PATTERNS, UNIVERSALIS_API_BASE,
|
|
98
|
+
/** @public */
|
|
99
|
+
UNIVERSALIS_API_TIMEOUT,
|
|
100
|
+
/** @public */
|
|
101
|
+
UNIVERSALIS_API_RETRY_COUNT,
|
|
102
|
+
/** @public */
|
|
103
|
+
UNIVERSALIS_API_RETRY_DELAY,
|
|
104
|
+
/** @public */
|
|
105
|
+
API_CACHE_TTL,
|
|
106
|
+
/** @public */
|
|
107
|
+
API_CACHE_VERSION,
|
|
108
|
+
/** @public */
|
|
109
|
+
API_MAX_RESPONSE_SIZE,
|
|
110
|
+
/** @public */
|
|
111
|
+
API_RATE_LIMIT_DELAY, } from './constants/index.js';
|
|
24
112
|
// Utils
|
|
25
|
-
export {
|
|
113
|
+
export {
|
|
114
|
+
/** @public */
|
|
115
|
+
clamp,
|
|
116
|
+
/** @public */
|
|
117
|
+
round,
|
|
118
|
+
/** @public */
|
|
119
|
+
isValidHexColor,
|
|
120
|
+
/** @public */
|
|
121
|
+
isValidRGB,
|
|
122
|
+
/** @public */
|
|
123
|
+
isValidHSV,
|
|
124
|
+
/** @public */
|
|
125
|
+
sleep,
|
|
126
|
+
/** @public */
|
|
127
|
+
retry,
|
|
128
|
+
/** @public */
|
|
129
|
+
isAbortError,
|
|
130
|
+
/** @public */
|
|
131
|
+
generateChecksum, abbreviateDyeName, } from './utils/index.js';
|
|
26
132
|
// Data (for browser environments - to be injected)
|
|
27
|
-
export { default as dyeDatabase } from './data/
|
|
133
|
+
export { default as dyeDatabase } from './data/dyes.json' with { type: 'json' };
|
|
28
134
|
export { default as presetData } from './data/presets.json' with { type: 'json' };
|
|
29
|
-
// Version (auto-generated from package.json during build)
|
|
30
|
-
export { VERSION } from './version.js';
|
|
31
135
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -174,7 +174,7 @@ export interface APIServiceOptions {
|
|
|
174
174
|
* baseUrl: 'https://universalis.app/api/v2'
|
|
175
175
|
*
|
|
176
176
|
* // Through CORS proxy (browser clients)
|
|
177
|
-
* baseUrl: 'https://
|
|
177
|
+
* baseUrl: 'https://data.xivdyetools.app/universalis'
|
|
178
178
|
*/
|
|
179
179
|
baseUrl?: string;
|
|
180
180
|
}
|
|
@@ -190,15 +190,15 @@ export interface APIServiceOptions {
|
|
|
190
190
|
*
|
|
191
191
|
* // With custom cache backend (e.g., Redis)
|
|
192
192
|
* const redisCache = new RedisCacheBackend(redisClient);
|
|
193
|
-
* const apiService = new APIService(redisCache);
|
|
193
|
+
* const apiService = new APIService({ cacheBackend: redisCache });
|
|
194
194
|
*
|
|
195
195
|
* // With custom fetch client for testing
|
|
196
196
|
* const mockFetch = new MockFetchClient();
|
|
197
|
-
* const apiService = new APIService(
|
|
197
|
+
* const apiService = new APIService({ fetchClient: mockFetch });
|
|
198
198
|
*
|
|
199
199
|
* // With custom rate limiter (e.g., no rate limiting for tests)
|
|
200
200
|
* const noRateLimit = new NoOpRateLimiter();
|
|
201
|
-
* const apiService = new APIService(
|
|
201
|
+
* const apiService = new APIService({ rateLimiter: noRateLimit });
|
|
202
202
|
*
|
|
203
203
|
* // Fetch price data
|
|
204
204
|
* const priceData = await apiService.getPriceData(itemID, worldID, dataCenterID);
|
|
@@ -209,25 +209,9 @@ export interface APIServiceOptions {
|
|
|
209
209
|
*
|
|
210
210
|
* // With custom base URL (e.g., CORS proxy for browser clients)
|
|
211
211
|
* const apiService = new APIService({
|
|
212
|
-
* baseUrl: 'https://
|
|
212
|
+
* baseUrl: 'https://data.xivdyetools.app/universalis'
|
|
213
213
|
* });
|
|
214
214
|
*/
|
|
215
|
-
/**
|
|
216
|
-
* Cache performance metrics
|
|
217
|
-
* Tracks hit/miss/eviction/error counts for observability (OPT-002)
|
|
218
|
-
*/
|
|
219
|
-
export interface CacheMetrics {
|
|
220
|
-
/** Number of cache hits (valid cached data returned) */
|
|
221
|
-
hits: number;
|
|
222
|
-
/** Number of cache misses (no cached data found) */
|
|
223
|
-
misses: number;
|
|
224
|
-
/** Number of cache evictions (expired, version mismatch, or corrupted entries removed) */
|
|
225
|
-
evictions: number;
|
|
226
|
-
/** Number of cache backend errors */
|
|
227
|
-
errors: number;
|
|
228
|
-
/** Timestamp (ms) when metrics were last reset */
|
|
229
|
-
lastReset: number;
|
|
230
|
-
}
|
|
231
215
|
export declare class APIService {
|
|
232
216
|
private cache;
|
|
233
217
|
private fetchClient;
|
|
@@ -241,18 +225,11 @@ export declare class APIService {
|
|
|
241
225
|
private pendingBatchRequests;
|
|
242
226
|
private readonly logger;
|
|
243
227
|
private readonly baseUrl;
|
|
244
|
-
/** OPT-002: Cache performance counters */
|
|
245
|
-
private metrics;
|
|
246
228
|
/**
|
|
247
229
|
* Constructor with optional dependency injection
|
|
248
|
-
* @param options Configuration options
|
|
230
|
+
* @param options Configuration options
|
|
249
231
|
*/
|
|
250
|
-
constructor(options?:
|
|
251
|
-
/**
|
|
252
|
-
* Type guard to check if the options parameter is an APIServiceOptions object
|
|
253
|
-
* Checks for any known property of APIServiceOptions
|
|
254
|
-
*/
|
|
255
|
-
private isOptionsObject;
|
|
232
|
+
constructor(options?: APIServiceOptions);
|
|
256
233
|
/**
|
|
257
234
|
* Get price from cache if available and not expired
|
|
258
235
|
* Validates cache version and checksum
|
|
@@ -276,18 +253,6 @@ export declare class APIService {
|
|
|
276
253
|
* Clear cache
|
|
277
254
|
*/
|
|
278
255
|
clearCache(): Promise<void>;
|
|
279
|
-
/**
|
|
280
|
-
* Get cache stats including performance metrics (OPT-002)
|
|
281
|
-
*/
|
|
282
|
-
getCacheStats(): Promise<{
|
|
283
|
-
size: number;
|
|
284
|
-
keys: string[];
|
|
285
|
-
metrics: CacheMetrics;
|
|
286
|
-
}>;
|
|
287
|
-
/**
|
|
288
|
-
* Reset cache performance metrics counters
|
|
289
|
-
*/
|
|
290
|
-
resetMetrics(): void;
|
|
291
256
|
/**
|
|
292
257
|
* Fetch price data for a dye from Universalis API
|
|
293
258
|
* Implements caching, debouncing, and retry logic
|
|
@@ -352,17 +317,6 @@ export declare class APIService {
|
|
|
352
317
|
* This prevents crafted dataCenterID values from colliding with other key patterns
|
|
353
318
|
*/
|
|
354
319
|
private buildCacheKey;
|
|
355
|
-
/**
|
|
356
|
-
* Fetch prices for multiple items (global/universal pricing)
|
|
357
|
-
* PERFORMANCE: Uses batched API requests to minimize rate limiting
|
|
358
|
-
*
|
|
359
|
-
* Strategy:
|
|
360
|
-
* 1. Check cache for each item
|
|
361
|
-
* 2. Collect uncached items
|
|
362
|
-
* 3. Fetch uncached items in a single batched request
|
|
363
|
-
* 4. Store fetched items in cache
|
|
364
|
-
*/
|
|
365
|
-
getPricesForItems(itemIDs: number[]): Promise<Map<number, PriceData>>;
|
|
366
320
|
/**
|
|
367
321
|
* Fetch prices for dyes in a specific data center
|
|
368
322
|
* PERFORMANCE: Uses batched API requests to minimize rate limiting
|
|
@@ -390,14 +344,6 @@ export declare class APIService {
|
|
|
390
344
|
* Format price for display (FFXIV Gil format: 69,420G)
|
|
391
345
|
*/
|
|
392
346
|
static formatPrice(price: number): string;
|
|
393
|
-
/**
|
|
394
|
-
* Calculate price trend (simplified)
|
|
395
|
-
*/
|
|
396
|
-
static getPriceTrend(currentPrice: number, previousPrice: number): {
|
|
397
|
-
trend: 'up' | 'down' | 'stable';
|
|
398
|
-
change: number;
|
|
399
|
-
changePercent: number;
|
|
400
|
-
};
|
|
401
347
|
}
|
|
402
348
|
export {};
|
|
403
349
|
//# sourceMappingURL=APIService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"APIService.d.ts","sourceRoot":"","sources":["../../src/services/APIService.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"APIService.d.ts","sourceRoot":"","sources":["../../src/services/APIService.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAkB1D;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC9D;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,WAAW;IAC9C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;CAGnE;AAMD;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B;;OAEG;IACH,aAAa,IAAI,IAAI,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,KAAK;aAEhB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM;CAKlB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK5D;AAED;;;;;;GAMG;AACH,qBAAa,kBAAmB,YAAW,WAAW;IAOxC,OAAO,CAAC,QAAQ;IAN5B,OAAO,CAAC,aAAa,CAAa;IAElC;;;OAGG;gBACiB,QAAQ,GAAE,MAA6B;IAErD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAUnC,aAAa,IAAI,IAAI;CAItB;AAMD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAEvF;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAErE;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAE1C;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAE9B;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CACtC;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,aAAa;IACtD,OAAO,CAAC,KAAK,CAAiD;IAE9D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI;IAI9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI;IAIpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,MAAM,EAAE;CAGjB;AAMD;;GAEG;AACH,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,UAAU,cAAc;IACtB,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;GAEG;AACH,UAAU,WAAW;IACnB,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,EAAE,CAAC,EAAE,WAAW,CAAC;CAClB;AAmDD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC;IAE7B;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,eAAe,CAAqD;IAC5E;;;;OAIG;IACH,OAAO,CAAC,oBAAoB,CAA2D;IACvF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC;;;OAGG;gBACS,OAAO,GAAE,iBAAsB;IAY3C;;;;;;OAMG;YACW,cAAc;IA6C5B;;OAEG;YACW,cAAc;IAW5B;;;;;OAKG;YACW,iBAAiB;IAU/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC;;;;;;;;OAQG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAgE5B;;OAEG;YACW,cAAc;IAyC5B;;;;;;;OAOG;YACW,mBAAmB;IAoEjC;;;;OAIG;YACW,gBAAgB;IAqD9B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAmDxB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAuD7B;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAgCxB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAsBrB;;;;;;;;;OASG;IACG,sBAAsB,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAmElC;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IASxC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAiBtE;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAS1C"}
|
|
@@ -129,6 +129,40 @@ function extractPriceFromApiItem(result) {
|
|
|
129
129
|
}
|
|
130
130
|
return { price, worldId };
|
|
131
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Service for Universalis API integration
|
|
134
|
+
* Handles price data fetching with caching and debouncing
|
|
135
|
+
*
|
|
136
|
+
* Refactored for testability: Supports dependency injection of cache, fetch client, and rate limiter
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* // With default implementations (memory cache, global fetch, standard rate limiting)
|
|
140
|
+
* const apiService = new APIService();
|
|
141
|
+
*
|
|
142
|
+
* // With custom cache backend (e.g., Redis)
|
|
143
|
+
* const redisCache = new RedisCacheBackend(redisClient);
|
|
144
|
+
* const apiService = new APIService({ cacheBackend: redisCache });
|
|
145
|
+
*
|
|
146
|
+
* // With custom fetch client for testing
|
|
147
|
+
* const mockFetch = new MockFetchClient();
|
|
148
|
+
* const apiService = new APIService({ fetchClient: mockFetch });
|
|
149
|
+
*
|
|
150
|
+
* // With custom rate limiter (e.g., no rate limiting for tests)
|
|
151
|
+
* const noRateLimit = new NoOpRateLimiter();
|
|
152
|
+
* const apiService = new APIService({ rateLimiter: noRateLimit });
|
|
153
|
+
*
|
|
154
|
+
* // Fetch price data
|
|
155
|
+
* const priceData = await apiService.getPriceData(itemID, worldID, dataCenterID);
|
|
156
|
+
*
|
|
157
|
+
* // With custom logger for debugging
|
|
158
|
+
* import { ConsoleLogger } from 'xivdyetools-core';
|
|
159
|
+
* const apiService = new APIService({ logger: ConsoleLogger });
|
|
160
|
+
*
|
|
161
|
+
* // With custom base URL (e.g., CORS proxy for browser clients)
|
|
162
|
+
* const apiService = new APIService({
|
|
163
|
+
* baseUrl: 'https://data.xivdyetools.app/universalis'
|
|
164
|
+
* });
|
|
165
|
+
*/
|
|
132
166
|
export class APIService {
|
|
133
167
|
cache;
|
|
134
168
|
fetchClient;
|
|
@@ -142,52 +176,16 @@ export class APIService {
|
|
|
142
176
|
pendingBatchRequests = new Map();
|
|
143
177
|
logger;
|
|
144
178
|
baseUrl;
|
|
145
|
-
/** OPT-002: Cache performance counters */
|
|
146
|
-
metrics = {
|
|
147
|
-
hits: 0,
|
|
148
|
-
misses: 0,
|
|
149
|
-
evictions: 0,
|
|
150
|
-
errors: 0,
|
|
151
|
-
lastReset: Date.now(),
|
|
152
|
-
};
|
|
153
179
|
/**
|
|
154
180
|
* Constructor with optional dependency injection
|
|
155
|
-
* @param options Configuration options
|
|
181
|
+
* @param options Configuration options
|
|
156
182
|
*/
|
|
157
|
-
constructor(options
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
this.cache = opts.cacheBackend ?? new MemoryCacheBackend();
|
|
164
|
-
this.fetchClient = opts.fetchClient ?? new DefaultFetchClient();
|
|
165
|
-
this.rateLimiter = opts.rateLimiter ?? new DefaultRateLimiter();
|
|
166
|
-
this.logger = opts.logger ?? NoOpLogger;
|
|
167
|
-
this.baseUrl = opts.baseUrl ?? UNIVERSALIS_API_BASE;
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
// Legacy positional arguments API
|
|
171
|
-
this.cache = options ?? new MemoryCacheBackend();
|
|
172
|
-
this.fetchClient = fetchClient ?? new DefaultFetchClient();
|
|
173
|
-
this.rateLimiter = rateLimiter ?? new DefaultRateLimiter();
|
|
174
|
-
this.logger = NoOpLogger;
|
|
175
|
-
this.baseUrl = UNIVERSALIS_API_BASE;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Type guard to check if the options parameter is an APIServiceOptions object
|
|
180
|
-
* Checks for any known property of APIServiceOptions
|
|
181
|
-
*/
|
|
182
|
-
isOptionsObject(options) {
|
|
183
|
-
if (!options || typeof options !== 'object')
|
|
184
|
-
return false;
|
|
185
|
-
const obj = options;
|
|
186
|
-
return ('logger' in obj ||
|
|
187
|
-
'cacheBackend' in obj ||
|
|
188
|
-
'baseUrl' in obj ||
|
|
189
|
-
'fetchClient' in obj ||
|
|
190
|
-
'rateLimiter' in obj);
|
|
183
|
+
constructor(options = {}) {
|
|
184
|
+
this.cache = options.cacheBackend ?? new MemoryCacheBackend();
|
|
185
|
+
this.fetchClient = options.fetchClient ?? new DefaultFetchClient();
|
|
186
|
+
this.rateLimiter = options.rateLimiter ?? new DefaultRateLimiter();
|
|
187
|
+
this.logger = options.logger ?? NoOpLogger;
|
|
188
|
+
this.baseUrl = options.baseUrl ?? UNIVERSALIS_API_BASE;
|
|
191
189
|
}
|
|
192
190
|
// ============================================================================
|
|
193
191
|
// Cache Management
|
|
@@ -207,24 +205,20 @@ export class APIService {
|
|
|
207
205
|
catch (error) {
|
|
208
206
|
// ERROR-001: Log cache backend error and fall through to API fetch
|
|
209
207
|
// This distinguishes "cache broken" from "cache miss" in logs
|
|
210
|
-
this.metrics.errors++;
|
|
211
208
|
this.logger.error(`Cache backend error for key ${cacheKey}: ${error instanceof Error ? error.message : 'Unknown error'}. Falling through to API fetch.`);
|
|
212
209
|
return null;
|
|
213
210
|
}
|
|
214
211
|
if (!cached) {
|
|
215
|
-
this.metrics.misses++;
|
|
216
212
|
return null;
|
|
217
213
|
}
|
|
218
214
|
// Check cache version
|
|
219
215
|
if (cached.version && cached.version !== API_CACHE_VERSION) {
|
|
220
|
-
this.metrics.evictions++;
|
|
221
216
|
// OPT-003: Fire-and-forget — cache cleanup is best-effort, don't block request path
|
|
222
217
|
void this.cache.delete(cacheKey);
|
|
223
218
|
return null;
|
|
224
219
|
}
|
|
225
220
|
// Check if cache has expired
|
|
226
221
|
if (Date.now() - cached.timestamp > cached.ttl) {
|
|
227
|
-
this.metrics.evictions++;
|
|
228
222
|
// OPT-003: Fire-and-forget — cache cleanup is best-effort, don't block request path
|
|
229
223
|
void this.cache.delete(cacheKey);
|
|
230
224
|
return null;
|
|
@@ -233,14 +227,12 @@ export class APIService {
|
|
|
233
227
|
if (cached.checksum) {
|
|
234
228
|
const computedChecksum = generateChecksum(cached.data);
|
|
235
229
|
if (computedChecksum !== cached.checksum) {
|
|
236
|
-
this.metrics.evictions++;
|
|
237
230
|
this.logger.warn(`Cache corruption detected for key: ${cacheKey}`);
|
|
238
231
|
// OPT-003: Fire-and-forget — cache cleanup is best-effort, don't block request path
|
|
239
232
|
void this.cache.delete(cacheKey);
|
|
240
233
|
return null;
|
|
241
234
|
}
|
|
242
235
|
}
|
|
243
|
-
this.metrics.hits++;
|
|
244
236
|
return cached.data;
|
|
245
237
|
}
|
|
246
238
|
/**
|
|
@@ -267,7 +259,6 @@ export class APIService {
|
|
|
267
259
|
await this.setCachedPrice(cacheKey, data);
|
|
268
260
|
}
|
|
269
261
|
catch (error) {
|
|
270
|
-
this.metrics.errors++;
|
|
271
262
|
this.logger.error(`Cache write failed for ${cacheKey}: ${error instanceof Error ? error.message : String(error)}`);
|
|
272
263
|
}
|
|
273
264
|
}
|
|
@@ -276,28 +267,8 @@ export class APIService {
|
|
|
276
267
|
*/
|
|
277
268
|
async clearCache() {
|
|
278
269
|
await this.cache.clear();
|
|
279
|
-
this.resetMetrics();
|
|
280
270
|
this.logger.info('Price cache cleared');
|
|
281
271
|
}
|
|
282
|
-
/**
|
|
283
|
-
* Get cache stats including performance metrics (OPT-002)
|
|
284
|
-
*/
|
|
285
|
-
async getCacheStats() {
|
|
286
|
-
const keys = await this.cache.keys();
|
|
287
|
-
return { size: keys.length, keys, metrics: { ...this.metrics } };
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Reset cache performance metrics counters
|
|
291
|
-
*/
|
|
292
|
-
resetMetrics() {
|
|
293
|
-
this.metrics = {
|
|
294
|
-
hits: 0,
|
|
295
|
-
misses: 0,
|
|
296
|
-
evictions: 0,
|
|
297
|
-
errors: 0,
|
|
298
|
-
lastReset: Date.now(),
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
272
|
// ============================================================================
|
|
302
273
|
// API Calls
|
|
303
274
|
// ============================================================================
|
|
@@ -374,8 +345,7 @@ export class APIService {
|
|
|
374
345
|
// Build API URL
|
|
375
346
|
const url = this.buildApiUrl(itemID, worldID, dataCenterID);
|
|
376
347
|
try {
|
|
377
|
-
const data = await retry(() => this.fetchWithTimeout(url, UNIVERSALIS_API_TIMEOUT), UNIVERSALIS_API_RETRY_COUNT, UNIVERSALIS_API_RETRY_DELAY, this.logger, isRetryableHttpError
|
|
378
|
-
);
|
|
348
|
+
const data = await retry(() => this.fetchWithTimeout(url, UNIVERSALIS_API_TIMEOUT), UNIVERSALIS_API_RETRY_COUNT, UNIVERSALIS_API_RETRY_DELAY, this.logger, isRetryableHttpError);
|
|
379
349
|
if (!data) {
|
|
380
350
|
return null;
|
|
381
351
|
}
|
|
@@ -433,8 +403,7 @@ export class APIService {
|
|
|
433
403
|
// Build batch API URL — safe: length ≤ 100 and IDs validated above
|
|
434
404
|
const url = this.buildBatchApiUrl(validItemIDs, dataCenterID);
|
|
435
405
|
try {
|
|
436
|
-
const data = await retry(() => this.fetchWithTimeout(url, UNIVERSALIS_API_TIMEOUT), UNIVERSALIS_API_RETRY_COUNT, UNIVERSALIS_API_RETRY_DELAY, this.logger, isRetryableHttpError
|
|
437
|
-
);
|
|
406
|
+
const data = await retry(() => this.fetchWithTimeout(url, UNIVERSALIS_API_TIMEOUT), UNIVERSALIS_API_RETRY_COUNT, UNIVERSALIS_API_RETRY_DELAY, this.logger, isRetryableHttpError);
|
|
438
407
|
if (!data) {
|
|
439
408
|
return new Map();
|
|
440
409
|
}
|
|
@@ -652,68 +621,6 @@ export class APIService {
|
|
|
652
621
|
// ============================================================================
|
|
653
622
|
// Batch Operations
|
|
654
623
|
// ============================================================================
|
|
655
|
-
/**
|
|
656
|
-
* Fetch prices for multiple items (global/universal pricing)
|
|
657
|
-
* PERFORMANCE: Uses batched API requests to minimize rate limiting
|
|
658
|
-
*
|
|
659
|
-
* Strategy:
|
|
660
|
-
* 1. Check cache for each item
|
|
661
|
-
* 2. Collect uncached items
|
|
662
|
-
* 3. Fetch uncached items in a single batched request
|
|
663
|
-
* 4. Store fetched items in cache
|
|
664
|
-
*/
|
|
665
|
-
async getPricesForItems(itemIDs) {
|
|
666
|
-
const results = new Map();
|
|
667
|
-
const uncachedItemIDs = [];
|
|
668
|
-
// Step 1: Check cache for each item (in parallel for async backends)
|
|
669
|
-
const cacheChecks = await Promise.all(itemIDs.map(async (itemID) => {
|
|
670
|
-
const cacheKey = this.buildCacheKey(itemID);
|
|
671
|
-
const cached = await this.getCachedPrice(cacheKey);
|
|
672
|
-
return { itemID, cached };
|
|
673
|
-
}));
|
|
674
|
-
for (const { itemID, cached } of cacheChecks) {
|
|
675
|
-
if (cached) {
|
|
676
|
-
results.set(itemID, cached);
|
|
677
|
-
}
|
|
678
|
-
else {
|
|
679
|
-
uncachedItemIDs.push(itemID);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
// Step 2: If all items are cached, return immediately
|
|
683
|
-
if (uncachedItemIDs.length === 0) {
|
|
684
|
-
this.logger.debug(`All ${itemIDs.length} items found in cache`);
|
|
685
|
-
return results;
|
|
686
|
-
}
|
|
687
|
-
this.logger.debug(`Fetching ${uncachedItemIDs.length} uncached items (${results.size} cached)`);
|
|
688
|
-
// Step 3+4: Fetch uncached items and write them to cache.
|
|
689
|
-
// OPT-001 (2026-07-18 audit): identical in-flight batches are coalesced so
|
|
690
|
-
// N concurrent cold-cache callers produce one upstream request, mirroring
|
|
691
|
-
// the single-item pendingRequests dedupe. The entry is removed on settle.
|
|
692
|
-
// BUG-011: cache writes are best-effort — one failed write must not throw
|
|
693
|
-
// away the whole fetched batch.
|
|
694
|
-
const batchKey = [...uncachedItemIDs].sort((a, b) => a - b).join(',') + ':universal';
|
|
695
|
-
let batchPromise = this.pendingBatchRequests.get(batchKey);
|
|
696
|
-
if (!batchPromise) {
|
|
697
|
-
batchPromise = (async () => {
|
|
698
|
-
const batchResults = await this.fetchBatchPriceData(uncachedItemIDs);
|
|
699
|
-
const cacheWrites = [];
|
|
700
|
-
for (const [itemID, priceData] of batchResults) {
|
|
701
|
-
const cacheKey = this.buildCacheKey(itemID);
|
|
702
|
-
cacheWrites.push(this.trySetCachedPrice(cacheKey, priceData));
|
|
703
|
-
}
|
|
704
|
-
await Promise.all(cacheWrites);
|
|
705
|
-
return batchResults;
|
|
706
|
-
})().finally(() => {
|
|
707
|
-
this.pendingBatchRequests.delete(batchKey);
|
|
708
|
-
});
|
|
709
|
-
this.pendingBatchRequests.set(batchKey, batchPromise);
|
|
710
|
-
}
|
|
711
|
-
const batchResults = await batchPromise;
|
|
712
|
-
for (const [itemID, priceData] of batchResults) {
|
|
713
|
-
results.set(itemID, priceData);
|
|
714
|
-
}
|
|
715
|
-
return results;
|
|
716
|
-
}
|
|
717
624
|
/**
|
|
718
625
|
* Fetch prices for dyes in a specific data center
|
|
719
626
|
* PERFORMANCE: Uses batched API requests to minimize rate limiting
|
|
@@ -820,23 +727,5 @@ export class APIService {
|
|
|
820
727
|
// Return with small "G" suffix
|
|
821
728
|
return `${formattedNumber}G`;
|
|
822
729
|
}
|
|
823
|
-
/**
|
|
824
|
-
* Calculate price trend (simplified)
|
|
825
|
-
*/
|
|
826
|
-
static getPriceTrend(currentPrice, previousPrice) {
|
|
827
|
-
const change = currentPrice - previousPrice;
|
|
828
|
-
const changePercent = previousPrice === 0 ? 0 : (change / previousPrice) * 100;
|
|
829
|
-
let trend;
|
|
830
|
-
if (change > previousPrice * 0.05) {
|
|
831
|
-
trend = 'up';
|
|
832
|
-
}
|
|
833
|
-
else if (change < -previousPrice * 0.05) {
|
|
834
|
-
trend = 'down';
|
|
835
|
-
}
|
|
836
|
-
else {
|
|
837
|
-
trend = 'stable';
|
|
838
|
-
}
|
|
839
|
-
return { trend, change, changePercent: Math.round(changePercent * 100) / 100 };
|
|
840
|
-
}
|
|
841
730
|
}
|
|
842
731
|
//# sourceMappingURL=APIService.js.map
|