promidas 2.0.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/LICENSE +21 -0
- package/README.md +179 -0
- package/dist/builder.d.ts +158 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +255 -0
- package/dist/builder.js.map +1 -0
- package/dist/factory.d.ts +154 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +243 -0
- package/dist/factory.js.map +1 -0
- package/dist/fetcher/client/config.d.ts +140 -0
- package/dist/fetcher/client/config.d.ts.map +1 -0
- package/dist/fetcher/client/config.js +2 -0
- package/dist/fetcher/client/config.js.map +1 -0
- package/dist/fetcher/client/fetch-with-progress.d.ts +156 -0
- package/dist/fetcher/client/fetch-with-progress.d.ts.map +1 -0
- package/dist/fetcher/client/fetch-with-progress.js +313 -0
- package/dist/fetcher/client/fetch-with-progress.js.map +1 -0
- package/dist/fetcher/client/fetch-with-timeout.d.ts +6 -0
- package/dist/fetcher/client/fetch-with-timeout.d.ts.map +1 -0
- package/dist/fetcher/client/fetch-with-timeout.js +48 -0
- package/dist/fetcher/client/fetch-with-timeout.js.map +1 -0
- package/dist/fetcher/client/protopedia-api-custom-client.d.ts +141 -0
- package/dist/fetcher/client/protopedia-api-custom-client.d.ts.map +1 -0
- package/dist/fetcher/client/protopedia-api-custom-client.js +268 -0
- package/dist/fetcher/client/protopedia-api-custom-client.js.map +1 -0
- package/dist/fetcher/client/select-custom-fetch.d.ts +58 -0
- package/dist/fetcher/client/select-custom-fetch.d.ts.map +1 -0
- package/dist/fetcher/client/select-custom-fetch.js +58 -0
- package/dist/fetcher/client/select-custom-fetch.js.map +1 -0
- package/dist/fetcher/errors/fetcher-error.d.ts +10 -0
- package/dist/fetcher/errors/fetcher-error.d.ts.map +1 -0
- package/dist/fetcher/errors/fetcher-error.js +15 -0
- package/dist/fetcher/errors/fetcher-error.js.map +1 -0
- package/dist/fetcher/index.d.ts +73 -0
- package/dist/fetcher/index.d.ts.map +1 -0
- package/dist/fetcher/index.js +70 -0
- package/dist/fetcher/index.js.map +1 -0
- package/dist/fetcher/types/index.d.ts +9 -0
- package/dist/fetcher/types/index.d.ts.map +1 -0
- package/dist/fetcher/types/index.js +7 -0
- package/dist/fetcher/types/index.js.map +1 -0
- package/dist/fetcher/types/progress-event.types.d.ts +221 -0
- package/dist/fetcher/types/progress-event.types.d.ts.map +1 -0
- package/dist/fetcher/types/progress-event.types.js +10 -0
- package/dist/fetcher/types/progress-event.types.js.map +1 -0
- package/dist/fetcher/types/prototype-api.types.d.ts +106 -0
- package/dist/fetcher/types/prototype-api.types.d.ts.map +1 -0
- package/dist/fetcher/types/prototype-api.types.js +2 -0
- package/dist/fetcher/types/prototype-api.types.js.map +1 -0
- package/dist/fetcher/types/result.types.d.ts +75 -0
- package/dist/fetcher/types/result.types.d.ts.map +1 -0
- package/dist/fetcher/types/result.types.js +2 -0
- package/dist/fetcher/types/result.types.js.map +1 -0
- package/dist/fetcher/utils/create-client-fetch.d.ts +63 -0
- package/dist/fetcher/utils/create-client-fetch.d.ts.map +1 -0
- package/dist/fetcher/utils/create-client-fetch.js +89 -0
- package/dist/fetcher/utils/create-client-fetch.js.map +1 -0
- package/dist/fetcher/utils/create-fetch-with-stripped-headers.d.ts +6 -0
- package/dist/fetcher/utils/create-fetch-with-stripped-headers.d.ts.map +1 -0
- package/dist/fetcher/utils/create-fetch-with-stripped-headers.js +40 -0
- package/dist/fetcher/utils/create-fetch-with-stripped-headers.js.map +1 -0
- package/dist/fetcher/utils/errors/handler.d.ts +58 -0
- package/dist/fetcher/utils/errors/handler.d.ts.map +1 -0
- package/dist/fetcher/utils/errors/handler.js +243 -0
- package/dist/fetcher/utils/errors/handler.js.map +1 -0
- package/dist/fetcher/utils/errors/messages.d.ts +75 -0
- package/dist/fetcher/utils/errors/messages.d.ts.map +1 -0
- package/dist/fetcher/utils/errors/messages.js +88 -0
- package/dist/fetcher/utils/errors/messages.js.map +1 -0
- package/dist/fetcher/utils/index.d.ts +13 -0
- package/dist/fetcher/utils/index.d.ts.map +1 -0
- package/dist/fetcher/utils/index.js +12 -0
- package/dist/fetcher/utils/index.js.map +1 -0
- package/dist/fetcher/utils/log-timestamp-normalization-warnings.d.ts +10 -0
- package/dist/fetcher/utils/log-timestamp-normalization-warnings.d.ts.map +1 -0
- package/dist/fetcher/utils/log-timestamp-normalization-warnings.js +32 -0
- package/dist/fetcher/utils/log-timestamp-normalization-warnings.js.map +1 -0
- package/dist/fetcher/utils/normalize-protopedia-timestamp.d.ts +59 -0
- package/dist/fetcher/utils/normalize-protopedia-timestamp.d.ts.map +1 -0
- package/dist/fetcher/utils/normalize-protopedia-timestamp.js +81 -0
- package/dist/fetcher/utils/normalize-protopedia-timestamp.js.map +1 -0
- package/dist/fetcher/utils/normalize-prototype.d.ts +56 -0
- package/dist/fetcher/utils/normalize-prototype.d.ts.map +1 -0
- package/dist/fetcher/utils/normalize-prototype.js +113 -0
- package/dist/fetcher/utils/normalize-prototype.js.map +1 -0
- package/dist/fetcher/utils/sanitize-options.d.ts +14 -0
- package/dist/fetcher/utils/sanitize-options.d.ts.map +1 -0
- package/dist/fetcher/utils/sanitize-options.js +16 -0
- package/dist/fetcher/utils/sanitize-options.js.map +1 -0
- package/dist/fetcher/utils/string-parsers.d.ts +45 -0
- package/dist/fetcher/utils/string-parsers.d.ts.map +1 -0
- package/dist/fetcher/utils/string-parsers.js +53 -0
- package/dist/fetcher/utils/string-parsers.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/console-logger.d.ts +74 -0
- package/dist/logger/console-logger.d.ts.map +1 -0
- package/dist/logger/console-logger.js +113 -0
- package/dist/logger/console-logger.js.map +1 -0
- package/dist/logger/factory.d.ts +88 -0
- package/dist/logger/factory.d.ts.map +1 -0
- package/dist/logger/factory.js +94 -0
- package/dist/logger/factory.js.map +1 -0
- package/dist/logger/index.d.ts +42 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +41 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/logger.types.d.ts +49 -0
- package/dist/logger/logger.types.d.ts.map +1 -0
- package/dist/logger/logger.types.js +2 -0
- package/dist/logger/logger.types.js.map +1 -0
- package/dist/repository/errors/validation-error.d.ts +24 -0
- package/dist/repository/errors/validation-error.d.ts.map +1 -0
- package/dist/repository/errors/validation-error.js +26 -0
- package/dist/repository/errors/validation-error.js.map +1 -0
- package/dist/repository/index.d.ts +122 -0
- package/dist/repository/index.d.ts.map +1 -0
- package/dist/repository/index.js +44 -0
- package/dist/repository/index.js.map +1 -0
- package/dist/repository/protopedia-in-memory-repository.d.ts +560 -0
- package/dist/repository/protopedia-in-memory-repository.d.ts.map +1 -0
- package/dist/repository/protopedia-in-memory-repository.js +929 -0
- package/dist/repository/protopedia-in-memory-repository.js.map +1 -0
- package/dist/repository/schemas/index.d.ts +9 -0
- package/dist/repository/schemas/index.d.ts.map +1 -0
- package/dist/repository/schemas/index.js +11 -0
- package/dist/repository/schemas/index.js.map +1 -0
- package/dist/repository/schemas/params.d.ts +44 -0
- package/dist/repository/schemas/params.d.ts.map +1 -0
- package/dist/repository/schemas/params.js +44 -0
- package/dist/repository/schemas/params.js.map +1 -0
- package/dist/repository/schemas/serializable-snapshot.d.ts +33 -0
- package/dist/repository/schemas/serializable-snapshot.d.ts.map +1 -0
- package/dist/repository/schemas/serializable-snapshot.js +45 -0
- package/dist/repository/schemas/serializable-snapshot.js.map +1 -0
- package/dist/repository/types/analysis.types.d.ts +89 -0
- package/dist/repository/types/analysis.types.d.ts.map +1 -0
- package/dist/repository/types/analysis.types.js +2 -0
- package/dist/repository/types/analysis.types.js.map +1 -0
- package/dist/repository/types/index.d.ts +12 -0
- package/dist/repository/types/index.d.ts.map +1 -0
- package/dist/repository/types/index.js +7 -0
- package/dist/repository/types/index.js.map +1 -0
- package/dist/repository/types/repository-events.types.d.ts +110 -0
- package/dist/repository/types/repository-events.types.d.ts.map +1 -0
- package/dist/repository/types/repository-events.types.js +2 -0
- package/dist/repository/types/repository-events.types.js.map +1 -0
- package/dist/repository/types/repository.types.d.ts +330 -0
- package/dist/repository/types/repository.types.d.ts.map +1 -0
- package/dist/repository/types/repository.types.js +2 -0
- package/dist/repository/types/repository.types.js.map +1 -0
- package/dist/repository/types/result.types.d.ts +55 -0
- package/dist/repository/types/result.types.d.ts.map +1 -0
- package/dist/repository/types/result.types.js +2 -0
- package/dist/repository/types/result.types.js.map +1 -0
- package/dist/repository/types/serialization.types.d.ts +61 -0
- package/dist/repository/types/serialization.types.d.ts.map +1 -0
- package/dist/repository/types/serialization.types.js +2 -0
- package/dist/repository/types/serialization.types.js.map +1 -0
- package/dist/repository/types/snapshot-operation.types.d.ts +140 -0
- package/dist/repository/types/snapshot-operation.types.d.ts.map +1 -0
- package/dist/repository/types/snapshot-operation.types.js +2 -0
- package/dist/repository/types/snapshot-operation.types.js.map +1 -0
- package/dist/repository/utils/convert-fetch-result.d.ts +46 -0
- package/dist/repository/utils/convert-fetch-result.d.ts.map +1 -0
- package/dist/repository/utils/convert-fetch-result.js +59 -0
- package/dist/repository/utils/convert-fetch-result.js.map +1 -0
- package/dist/repository/utils/convert-store-result.d.ts +36 -0
- package/dist/repository/utils/convert-store-result.d.ts.map +1 -0
- package/dist/repository/utils/convert-store-result.js +36 -0
- package/dist/repository/utils/convert-store-result.js.map +1 -0
- package/dist/repository/utils/emit-repository-event-safely.d.ts +5 -0
- package/dist/repository/utils/emit-repository-event-safely.d.ts.map +1 -0
- package/dist/repository/utils/emit-repository-event-safely.js +17 -0
- package/dist/repository/utils/emit-repository-event-safely.js.map +1 -0
- package/dist/repository/utils/index.d.ts +3 -0
- package/dist/repository/utils/index.d.ts.map +1 -0
- package/dist/repository/utils/index.js +3 -0
- package/dist/repository/utils/index.js.map +1 -0
- package/dist/repository/validation/index.d.ts +9 -0
- package/dist/repository/validation/index.d.ts.map +1 -0
- package/dist/repository/validation/index.js +10 -0
- package/dist/repository/validation/index.js.map +1 -0
- package/dist/repository/validation/params-validators.d.ts +46 -0
- package/dist/repository/validation/params-validators.d.ts.map +1 -0
- package/dist/repository/validation/params-validators.js +68 -0
- package/dist/repository/validation/params-validators.js.map +1 -0
- package/dist/repository/validation/serializable-snapshot.d.ts +47 -0
- package/dist/repository/validation/serializable-snapshot.d.ts.map +1 -0
- package/dist/repository/validation/serializable-snapshot.js +104 -0
- package/dist/repository/validation/serializable-snapshot.js.map +1 -0
- package/dist/schemas/index.d.ts +8 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +8 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/normalized-prototype.d.ts +56 -0
- package/dist/schemas/normalized-prototype.d.ts.map +1 -0
- package/dist/schemas/normalized-prototype.js +123 -0
- package/dist/schemas/normalized-prototype.js.map +1 -0
- package/dist/store/errors/store-error.d.ts +148 -0
- package/dist/store/errors/store-error.d.ts.map +1 -0
- package/dist/store/errors/store-error.js +156 -0
- package/dist/store/errors/store-error.js.map +1 -0
- package/dist/store/index.d.ts +84 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +83 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/store.d.ts +295 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +411 -0
- package/dist/store/store.js.map +1 -0
- package/dist/store/types/index.d.ts +2 -0
- package/dist/store/types/index.d.ts.map +1 -0
- package/dist/store/types/index.js +2 -0
- package/dist/store/types/index.js.map +1 -0
- package/dist/store/types/result.types.d.ts +67 -0
- package/dist/store/types/result.types.d.ts.map +1 -0
- package/dist/store/types/result.types.js +2 -0
- package/dist/store/types/result.types.js.map +1 -0
- package/dist/types/codes.d.ts +44 -0
- package/dist/types/codes.d.ts.map +1 -0
- package/dist/types/codes.js +9 -0
- package/dist/types/codes.js.map +1 -0
- package/dist/types/index.d.ts +61 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +60 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/normalized-prototype.d.ts +95 -0
- package/dist/types/normalized-prototype.d.ts.map +1 -0
- package/dist/types/normalized-prototype.js +2 -0
- package/dist/types/normalized-prototype.js.map +1 -0
- package/dist/utils/converters/index.d.ts +15 -0
- package/dist/utils/converters/index.d.ts.map +1 -0
- package/dist/utils/converters/index.js +15 -0
- package/dist/utils/converters/index.js.map +1 -0
- package/dist/utils/converters/license-type.d.ts +23 -0
- package/dist/utils/converters/license-type.d.ts.map +1 -0
- package/dist/utils/converters/license-type.js +38 -0
- package/dist/utils/converters/license-type.js.map +1 -0
- package/dist/utils/converters/release-flag.d.ts +24 -0
- package/dist/utils/converters/release-flag.d.ts.map +1 -0
- package/dist/utils/converters/release-flag.js +40 -0
- package/dist/utils/converters/release-flag.js.map +1 -0
- package/dist/utils/converters/status.d.ts +23 -0
- package/dist/utils/converters/status.d.ts.map +1 -0
- package/dist/utils/converters/status.js +40 -0
- package/dist/utils/converters/status.js.map +1 -0
- package/dist/utils/converters/thanks-flag.d.ts +25 -0
- package/dist/utils/converters/thanks-flag.d.ts.map +1 -0
- package/dist/utils/converters/thanks-flag.js +41 -0
- package/dist/utils/converters/thanks-flag.js.map +1 -0
- package/dist/utils/deep-merge.d.ts +38 -0
- package/dist/utils/deep-merge.d.ts.map +1 -0
- package/dist/utils/deep-merge.js +85 -0
- package/dist/utils/deep-merge.js.map +1 -0
- package/dist/utils/index.d.ts +80 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +85 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger-utils.d.ts +100 -0
- package/dist/utils/logger-utils.d.ts.map +1 -0
- package/dist/utils/logger-utils.js +265 -0
- package/dist/utils/logger-utils.js.map +1 -0
- package/dist/utils/time/constants.d.ts +14 -0
- package/dist/utils/time/constants.d.ts.map +1 -0
- package/dist/utils/time/constants.js +14 -0
- package/dist/utils/time/constants.js.map +1 -0
- package/dist/utils/time/index.d.ts +28 -0
- package/dist/utils/time/index.d.ts.map +1 -0
- package/dist/utils/time/index.js +28 -0
- package/dist/utils/time/index.js.map +1 -0
- package/dist/utils/time/parser.d.ts +91 -0
- package/dist/utils/time/parser.d.ts.map +1 -0
- package/dist/utils/time/parser.js +143 -0
- package/dist/utils/time/parser.js.map +1 -0
- package/dist/utils/validation/index.d.ts +8 -0
- package/dist/utils/validation/index.d.ts.map +1 -0
- package/dist/utils/validation/index.js +7 -0
- package/dist/utils/validation/index.js.map +1 -0
- package/dist/utils/validation/normalized-prototype.d.ts +64 -0
- package/dist/utils/validation/normalized-prototype.d.ts.map +1 -0
- package/dist/utils/validation/normalized-prototype.js +97 -0
- package/dist/utils/validation/normalized-prototype.js.map +1 -0
- package/dist/utils/validation/types.d.ts +62 -0
- package/dist/utils/validation/types.d.ts.map +1 -0
- package/dist/utils/validation/types.js +8 -0
- package/dist/utils/validation/types.js.map +1 -0
- package/dist/version.d.ts +6 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/package.json +138 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { ConsoleLogger, createConsoleLogger, } from '../logger/index.js';
|
|
2
|
+
import { sanitizeDataForLogging } from '../utils/index.js';
|
|
3
|
+
import { ConfigurationError, DataSizeExceededError, SizeEstimationError, } from './errors/store-error.js';
|
|
4
|
+
const DEFAULT_TTL_MS = 30 * 60 * 1_000; // 30 minutes
|
|
5
|
+
const DEFAULT_DATA_SIZE_BYTES = 10 * 1024 * 1024; // 10 MiB
|
|
6
|
+
/**
|
|
7
|
+
* Hard limit for data size in bytes for storing snapshots.
|
|
8
|
+
* Attempting to configure a store with a size larger than this will throw an error.
|
|
9
|
+
*/
|
|
10
|
+
export const LIMIT_DATA_SIZE_BYTES = 30 * 1024 * 1024; // 30 MiB
|
|
11
|
+
/**
|
|
12
|
+
* In-memory store that keeps the full set of normalized prototypes with an ID-based index.
|
|
13
|
+
*
|
|
14
|
+
* The store accepts full snapshots (`setAll`) and exposes O(1) lookups by prototype id
|
|
15
|
+
* via an internal index. When TTL expires, data remains readable while callers kick off
|
|
16
|
+
* background refresh tasks using {@link runExclusive} to avoid redundant upstream calls.
|
|
17
|
+
*/
|
|
18
|
+
export class PrototypeInMemoryStore {
|
|
19
|
+
logger;
|
|
20
|
+
logLevel;
|
|
21
|
+
ttlMs;
|
|
22
|
+
maxDataSizeBytes;
|
|
23
|
+
prototypeIdIndex = new Map();
|
|
24
|
+
prototypes = [];
|
|
25
|
+
cachedAt = null;
|
|
26
|
+
dataSizeBytes = 0;
|
|
27
|
+
refreshPromise = null;
|
|
28
|
+
/**
|
|
29
|
+
* Create a new PrototypeInMemoryStore instance.
|
|
30
|
+
*
|
|
31
|
+
* Initializes an in-memory cache for normalized prototypes with configurable
|
|
32
|
+
* TTL and size limits. The store manages snapshot expiration, refresh state,
|
|
33
|
+
* and provides type-safe read-only access to cached data.
|
|
34
|
+
*
|
|
35
|
+
* @param config - Configuration options for the store
|
|
36
|
+
* @param config.ttlMs - Time-to-live in milliseconds for cached snapshots.
|
|
37
|
+
* Defaults to 30 minutes (1,800,000ms). After this duration, the snapshot
|
|
38
|
+
* is considered expired and should be refreshed.
|
|
39
|
+
* @param config.maxDataSizeBytes - Maximum allowed size for cached data in bytes.
|
|
40
|
+
* Defaults to 10 MiB (10,485,760 bytes). Must not exceed 30 MiB.
|
|
41
|
+
* If a snapshot exceeds this limit, setAll() will reject it.
|
|
42
|
+
* @param config.logger - Optional custom logger instance. If not provided,
|
|
43
|
+
* a default ConsoleLogger is created.
|
|
44
|
+
* @param config.logLevel - Log level for the logger. When `logger` is not provided,
|
|
45
|
+
* creates a ConsoleLogger with this level. When `logger` is provided and mutable,
|
|
46
|
+
* updates the logger's level property.
|
|
47
|
+
*
|
|
48
|
+
* @throws {ConfigurationError} When maxDataSizeBytes exceeds LIMIT_DATA_SIZE_BYTES (30 MiB)
|
|
49
|
+
*/
|
|
50
|
+
constructor({ ttlMs = DEFAULT_TTL_MS, maxDataSizeBytes = DEFAULT_DATA_SIZE_BYTES, logger, logLevel, } = {}) {
|
|
51
|
+
this.ttlMs = ttlMs;
|
|
52
|
+
this.maxDataSizeBytes = maxDataSizeBytes;
|
|
53
|
+
// Fastify-style logger configuration
|
|
54
|
+
if (logger) {
|
|
55
|
+
// Custom logger provided
|
|
56
|
+
this.logger = logger;
|
|
57
|
+
this.logLevel = logLevel ?? 'info';
|
|
58
|
+
// If logLevel is specified, update logger's level property (if mutable)
|
|
59
|
+
if (logLevel !== undefined && 'level' in logger) {
|
|
60
|
+
logger.level = logLevel;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// No custom logger → create ConsoleLogger with logLevel
|
|
65
|
+
const resolvedLogLevel = logLevel ?? 'info';
|
|
66
|
+
this.logger = new ConsoleLogger(resolvedLogLevel);
|
|
67
|
+
this.logLevel = resolvedLogLevel;
|
|
68
|
+
}
|
|
69
|
+
this.logger.info('PrototypeInMemoryStore constructor called', {
|
|
70
|
+
ttlMs,
|
|
71
|
+
maxDataSizeBytes,
|
|
72
|
+
logger: logger ? 'custom' : undefined,
|
|
73
|
+
logLevel,
|
|
74
|
+
});
|
|
75
|
+
// Throw if maxDataSizeBytes exceeds the hard limit
|
|
76
|
+
if (maxDataSizeBytes > LIMIT_DATA_SIZE_BYTES) {
|
|
77
|
+
const maxMiB = (LIMIT_DATA_SIZE_BYTES / (1024 * 1024)).toFixed(0);
|
|
78
|
+
throw new ConfigurationError(`PrototypeInMemoryStore maxDataSizeBytes must be <= ${LIMIT_DATA_SIZE_BYTES} bytes (${maxMiB} MiB) to prevent oversized data`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Retrieve the configuration used to initialize this store.
|
|
83
|
+
*
|
|
84
|
+
* Returns the resolved configuration values (TTL and max payload size) that were
|
|
85
|
+
* set during instantiation. These values are immutable after construction.
|
|
86
|
+
*/
|
|
87
|
+
getConfig() {
|
|
88
|
+
return {
|
|
89
|
+
ttlMs: this.ttlMs,
|
|
90
|
+
maxDataSizeBytes: this.maxDataSizeBytes,
|
|
91
|
+
logLevel: this.logLevel,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Count of prototypes currently kept in the in-memory store. */
|
|
95
|
+
get size() {
|
|
96
|
+
return this.prototypeIdIndex.size;
|
|
97
|
+
}
|
|
98
|
+
/** Timestamp representing when the snapshot was last refreshed. */
|
|
99
|
+
getCachedAt() {
|
|
100
|
+
return this.cachedAt;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Calculate elapsed time in milliseconds since the snapshot was cached.
|
|
104
|
+
* Returns 0 if no data is cached.
|
|
105
|
+
*/
|
|
106
|
+
getElapsedTime() {
|
|
107
|
+
if (!this.cachedAt) {
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
return Date.now() - this.cachedAt.getTime();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Calculate remaining time in milliseconds until expiration.
|
|
114
|
+
* Returns 0 if already expired or no data is cached.
|
|
115
|
+
*/
|
|
116
|
+
getRemainingTtl() {
|
|
117
|
+
if (!this.cachedAt) {
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
const elapsed = this.getElapsedTime();
|
|
121
|
+
const remaining = this.ttlMs - elapsed;
|
|
122
|
+
return Math.max(0, remaining);
|
|
123
|
+
}
|
|
124
|
+
/** Determine whether the snapshot is stale based on the configured TTL. */
|
|
125
|
+
isExpired() {
|
|
126
|
+
if (!this.cachedAt) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
return this.getElapsedTime() > this.ttlMs;
|
|
130
|
+
}
|
|
131
|
+
/** Report whether a background refresh is currently in flight. */
|
|
132
|
+
isRefreshInFlight() {
|
|
133
|
+
return this.refreshPromise !== null;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Provide statistics describing cache health and runtime state.
|
|
137
|
+
*
|
|
138
|
+
* Returns metadata about the current snapshot including size, expiration status,
|
|
139
|
+
* and refresh state. For configuration values like TTL, use {@link getConfig}.
|
|
140
|
+
*/
|
|
141
|
+
getStats() {
|
|
142
|
+
return {
|
|
143
|
+
size: this.prototypeIdIndex.size,
|
|
144
|
+
cachedAt: this.cachedAt,
|
|
145
|
+
isExpired: this.isExpired(),
|
|
146
|
+
remainingTtlMs: this.getRemainingTtl(),
|
|
147
|
+
dataSizeBytes: this.dataSizeBytes,
|
|
148
|
+
refreshInFlight: this.isRefreshInFlight(),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Estimates the JSON payload size of an array of NormalizedPrototypes in bytes.
|
|
153
|
+
*
|
|
154
|
+
* This method calculates the size by iteratively serializing each item and summing their byte lengths,
|
|
155
|
+
* along with the overhead for array brackets and commas. This approach minimizes memory usage
|
|
156
|
+
* by avoiding the creation of a single large JSON string for the entire array, thus reducing
|
|
157
|
+
* the risk of out-of-memory errors, especially with large datasets.
|
|
158
|
+
*
|
|
159
|
+
* @param data - The array of NormalizedPrototypes to estimate the size for.
|
|
160
|
+
* @returns The estimated size in bytes of the JSON-serialized data.
|
|
161
|
+
* @throws {SizeEstimationError} When JSON serialization fails (e.g., circular references).
|
|
162
|
+
*/
|
|
163
|
+
estimateSize(data) {
|
|
164
|
+
try {
|
|
165
|
+
if (data.length === 0) {
|
|
166
|
+
return 2; // "[]"
|
|
167
|
+
}
|
|
168
|
+
// Start with 2 bytes for "[]" and 1 byte for each comma (N-1 commas)
|
|
169
|
+
let totalBytes = 2 + (data.length - 1);
|
|
170
|
+
if (typeof Buffer !== 'undefined') {
|
|
171
|
+
for (const item of data) {
|
|
172
|
+
totalBytes += Buffer.byteLength(JSON.stringify(item), 'utf8');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else if (typeof TextEncoder !== 'undefined') {
|
|
176
|
+
const encoder = new TextEncoder();
|
|
177
|
+
for (const item of data) {
|
|
178
|
+
totalBytes += encoder.encode(JSON.stringify(item)).length;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// Fallback for environments without Buffer/TextEncoder (should not happen in Node.js)
|
|
183
|
+
this.logger.warn('Neither Buffer nor TextEncoder found for size estimation. Returning 0.', {});
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
return totalBytes;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
this.logger.error('Failed to estimate payload size', {
|
|
190
|
+
error: sanitizeDataForLogging(error),
|
|
191
|
+
});
|
|
192
|
+
throw new SizeEstimationError('UNKNOWN', error instanceof Error ? error : undefined);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Execute a refresh task while preventing concurrent execution.
|
|
197
|
+
*
|
|
198
|
+
* @returns Promise resolved when the task completes; callers may ignore it for background refreshes.
|
|
199
|
+
*/
|
|
200
|
+
runExclusive(task) {
|
|
201
|
+
if (this.refreshPromise) {
|
|
202
|
+
return this.refreshPromise;
|
|
203
|
+
}
|
|
204
|
+
this.refreshPromise = (async () => {
|
|
205
|
+
try {
|
|
206
|
+
await task();
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
this.logger.error('PrototypeInMemoryStore refresh task failed', {
|
|
210
|
+
error: sanitizeDataForLogging(error),
|
|
211
|
+
});
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
this.refreshPromise = null;
|
|
216
|
+
}
|
|
217
|
+
})();
|
|
218
|
+
return this.refreshPromise;
|
|
219
|
+
}
|
|
220
|
+
/** Reset the store to an empty state and clear all metadata. */
|
|
221
|
+
clear() {
|
|
222
|
+
const previousSize = this.prototypeIdIndex.size;
|
|
223
|
+
this.prototypeIdIndex.clear();
|
|
224
|
+
this.prototypes = [];
|
|
225
|
+
this.cachedAt = null;
|
|
226
|
+
this.dataSizeBytes = 0;
|
|
227
|
+
this.logger.info('PrototypeInMemoryStore cleared', { previousSize });
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Store the provided snapshot if it fits within the configured payload limit.
|
|
231
|
+
* Creates a shallow copy of the input array to prevent external mutations.
|
|
232
|
+
*
|
|
233
|
+
* @param prototypes - Array of normalized prototypes to store (array will be copied)
|
|
234
|
+
* @returns Metadata about the stored snapshot including the exact data size in bytes
|
|
235
|
+
* @throws {SizeEstimationError} When data size estimation fails
|
|
236
|
+
* @throws {DataSizeExceededError} When the payload exceeds the configured maximum size limit
|
|
237
|
+
*
|
|
238
|
+
* @remarks
|
|
239
|
+
* **Error Handling**: When an error is thrown, the store is NOT modified.
|
|
240
|
+
* Any previously stored snapshot remains intact and accessible. This ensures
|
|
241
|
+
* that applications can continue serving data from the last successful snapshot
|
|
242
|
+
* even when new data cannot be stored.
|
|
243
|
+
*
|
|
244
|
+
* The method creates a shallow copy of the input array to ensure the store's
|
|
245
|
+
* internal state cannot be corrupted by external mutations of the array.
|
|
246
|
+
* However, the prototype objects themselves are not cloned. Callers must not
|
|
247
|
+
* mutate the prototype objects after passing them to this method.
|
|
248
|
+
*
|
|
249
|
+
* Size calculation is performed AFTER deduplication to ensure accurate size checking.
|
|
250
|
+
* If duplicate IDs are present in the input array, only the last occurrence is kept.
|
|
251
|
+
*/
|
|
252
|
+
setAll(prototypes) {
|
|
253
|
+
// Build O(1) lookup index by prototype ID first to deduplicate
|
|
254
|
+
// Note: If duplicate IDs are present in the input array, the last one wins.
|
|
255
|
+
const uniqueMap = new Map(prototypes.map((prototype) => [prototype.id, prototype]));
|
|
256
|
+
// Warn if duplicate IDs were detected in the input array
|
|
257
|
+
if (uniqueMap.size !== prototypes.length) {
|
|
258
|
+
this.logger.warn('Duplicate prototype IDs detected in snapshot', {
|
|
259
|
+
inputCount: prototypes.length,
|
|
260
|
+
storedCount: uniqueMap.size,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
// Reconstruct prototypes array from the map to ensure consistency and uniqueness by ID.
|
|
264
|
+
// This will also ensure that `getAll().length` matches `this.size`.
|
|
265
|
+
const uniquePrototypes = Array.from(uniqueMap.values());
|
|
266
|
+
// Validate payload size AFTER deduplication
|
|
267
|
+
const dataSizeBytes = (() => {
|
|
268
|
+
try {
|
|
269
|
+
return this.estimateSize(uniquePrototypes);
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
// At this point, store data is unchanged (estimation failed before any store updates)
|
|
273
|
+
if (error instanceof SizeEstimationError) {
|
|
274
|
+
throw new SizeEstimationError('UNCHANGED', error.cause);
|
|
275
|
+
}
|
|
276
|
+
// Re-throw unexpected errors
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
})();
|
|
280
|
+
if (dataSizeBytes > this.maxDataSizeBytes) {
|
|
281
|
+
this.logger.warn('Snapshot rejected: data exceeds maximum size', {
|
|
282
|
+
dataSizeBytes,
|
|
283
|
+
maxDataSizeBytes: this.maxDataSizeBytes,
|
|
284
|
+
inputCount: prototypes.length,
|
|
285
|
+
uniqueCount: uniqueMap.size,
|
|
286
|
+
});
|
|
287
|
+
throw new DataSizeExceededError('UNCHANGED', dataSizeBytes, this.maxDataSizeBytes);
|
|
288
|
+
}
|
|
289
|
+
// Store the deduplicated data
|
|
290
|
+
this.prototypeIdIndex = uniqueMap;
|
|
291
|
+
this.prototypes = uniquePrototypes;
|
|
292
|
+
// Update cache metadata
|
|
293
|
+
this.cachedAt = new Date();
|
|
294
|
+
this.dataSizeBytes = dataSizeBytes;
|
|
295
|
+
this.logger.info('PrototypeInMemoryStore snapshot updated', {
|
|
296
|
+
count: this.prototypeIdIndex.size,
|
|
297
|
+
dataSizeBytes,
|
|
298
|
+
});
|
|
299
|
+
return { dataSizeBytes };
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Retrieve the latest fetched prototypes in their original order.
|
|
303
|
+
*
|
|
304
|
+
* Returns type-level readonly reference to the internal prototypes array.
|
|
305
|
+
* The readonly type provides compile-time safety but not runtime protection.
|
|
306
|
+
*
|
|
307
|
+
* @returns Type-level readonly array of prototypes
|
|
308
|
+
*
|
|
309
|
+
* @remarks
|
|
310
|
+
* **Type Safety**: This method returns a readonly-typed reference without
|
|
311
|
+
* runtime immutability enforcement (no Object.freeze or defensive copying).
|
|
312
|
+
* Callers must honor the readonly contract and not cast it away.
|
|
313
|
+
*
|
|
314
|
+
* **Performance**: Direct reference with zero overhead - suitable for
|
|
315
|
+
* high-frequency reads of large datasets.
|
|
316
|
+
*/
|
|
317
|
+
getAll() {
|
|
318
|
+
return this.prototypes;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Return a lightweight structure containing the cached data and metadata.
|
|
322
|
+
*
|
|
323
|
+
* Useful for callers that want to inspect expiry state without mutating the store.
|
|
324
|
+
*/
|
|
325
|
+
getSnapshot() {
|
|
326
|
+
return {
|
|
327
|
+
data: this.getAll(),
|
|
328
|
+
cachedAt: this.cachedAt,
|
|
329
|
+
isExpired: this.isExpired(),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Retrieve a single prototype by its numeric identifier.
|
|
334
|
+
*
|
|
335
|
+
* Uses the internal prototypeIdIndex for O(1) constant-time lookup, providing
|
|
336
|
+
* exceptional performance even with thousands of cached prototypes. This is
|
|
337
|
+
* significantly faster than linear search alternatives (approximately 12,500x
|
|
338
|
+
* faster for 5,000 items).
|
|
339
|
+
*
|
|
340
|
+
* The index-based implementation adds minimal memory overhead (~230KB for 5,000
|
|
341
|
+
* items, or ~0.8% of total cache size) while delivering constant-time access
|
|
342
|
+
* regardless of cache size.
|
|
343
|
+
*
|
|
344
|
+
* @param prototypeId - The numeric ID of the prototype to retrieve
|
|
345
|
+
* @returns The prototype with type-level immutability, or null if not found
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```typescript
|
|
349
|
+
* const proto = store.getByPrototypeId(123);
|
|
350
|
+
* if (proto) {
|
|
351
|
+
* console.log(proto.prototypeNm);
|
|
352
|
+
* }
|
|
353
|
+
* ```
|
|
354
|
+
*
|
|
355
|
+
* @performance
|
|
356
|
+
* - Time complexity: O(1) - constant time regardless of cache size
|
|
357
|
+
* - Measured: ~0.0002ms per lookup (10,000 items)
|
|
358
|
+
* - Memory overhead: ~40 bytes per entry (including index metadata and hash table)
|
|
359
|
+
*/
|
|
360
|
+
getByPrototypeId(prototypeId) {
|
|
361
|
+
const prototype = this.prototypeIdIndex.get(prototypeId) ?? null;
|
|
362
|
+
return prototype;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Return an array of all cached prototype IDs.
|
|
366
|
+
*
|
|
367
|
+
* This method provides efficient access to prototype IDs without copying the
|
|
368
|
+
* entire prototype objects. Useful for operations that only need IDs, such as
|
|
369
|
+
* ID-based filtering, statistics, or exporting ID lists.
|
|
370
|
+
*
|
|
371
|
+
* @returns Read-only array of prototype IDs in insertion order
|
|
372
|
+
*
|
|
373
|
+
* @performance
|
|
374
|
+
* - Time complexity: O(n) - must iterate through all Map keys
|
|
375
|
+
* - Memory: Creates a new array of numbers (~40 bytes per ID)
|
|
376
|
+
* - Lighter than getAll() which copies full objects (~300+ bytes each)
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```typescript
|
|
380
|
+
* // ✅ Good: Call once and reuse
|
|
381
|
+
* const ids = store.getPrototypeIds();
|
|
382
|
+
* const count = ids.length;
|
|
383
|
+
* const maxId = Math.max(...ids);
|
|
384
|
+
*
|
|
385
|
+
* // ✅ Good: Single-use cases
|
|
386
|
+
* return { availableIds: store.getPrototypeIds() };
|
|
387
|
+
*
|
|
388
|
+
* // ❌ Bad: Repeated calls in loops
|
|
389
|
+
* for (let i = 0; i < 1000; i++) {
|
|
390
|
+
* const ids = store.getPrototypeIds(); // O(n) × 1000 = very slow!
|
|
391
|
+
* const id = ids[Math.floor(Math.random() * ids.length)];
|
|
392
|
+
* }
|
|
393
|
+
*
|
|
394
|
+
* // ✅ Better: Use getAll() once for repeated access
|
|
395
|
+
* const all = store.getAll();
|
|
396
|
+
* for (let i = 0; i < 1000; i++) {
|
|
397
|
+
* const item = all[Math.floor(Math.random() * all.length)];
|
|
398
|
+
* }
|
|
399
|
+
* ```
|
|
400
|
+
*
|
|
401
|
+
* @remarks
|
|
402
|
+
* **Performance Warning**: This method creates a new array on every call.
|
|
403
|
+
* For high-frequency operations (loops, repeated random access), prefer
|
|
404
|
+
* calling {@link getAll} once and reusing the result. The O(n) cost per
|
|
405
|
+
* call makes this unsuitable for tight loops.
|
|
406
|
+
*/
|
|
407
|
+
getPrototypeIds() {
|
|
408
|
+
return Array.from(this.prototypeIdIndex.keys());
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../lib/store/store.ts"],"names":[],"mappings":"AASA,OAAO,EACL,aAAa,EAGb,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,aAAa;AACrD,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,SAAS;AAE3D;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,SAAS;AAuEhE;;;;;;GAMG;AACH,MAAM,OAAO,sBAAsB;IAChB,MAAM,CAAS;IAEf,QAAQ,CAAW;IAEnB,KAAK,CAAS;IAEd,gBAAgB,CAAS;IAElC,gBAAgB,GAAG,IAAI,GAAG,EAA+B,CAAC;IAE1D,UAAU,GAA0B,EAAE,CAAC;IAEvC,QAAQ,GAAgB,IAAI,CAAC;IAE7B,aAAa,GAAG,CAAC,CAAC;IAElB,cAAc,GAAyB,IAAI,CAAC;IAEpD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,YAAY,EACV,KAAK,GAAG,cAAc,EACtB,gBAAgB,GAAG,uBAAuB,EAC1C,MAAM,EACN,QAAQ,MACwB,EAAE;QAClC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QAEzC,qCAAqC;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,yBAAyB;YACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,MAAM,CAAC;YACnC,wEAAwE;YACxE,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;gBAC/C,MAA8B,CAAC,KAAK,GAAG,QAAQ,CAAC;YACnD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,wDAAwD;YACxD,MAAM,gBAAgB,GAAG,QAAQ,IAAI,MAAM,CAAC;YAC5C,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC,gBAAgB,CAAC,CAAC;YAClD,IAAI,CAAC,QAAQ,GAAG,gBAAgB,CAAC;QACnC,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2CAA2C,EAAE;YAC5D,KAAK;YACL,gBAAgB;YAChB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YACrC,QAAQ;SACT,CAAC,CAAC;QAEH,mDAAmD;QACnD,IAAI,gBAAgB,GAAG,qBAAqB,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,CAAC,qBAAqB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAClE,MAAM,IAAI,kBAAkB,CAC1B,sDAAsD,qBAAqB,WAAW,MAAM,iCAAiC,CAC9H,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,SAAS;QACP,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC;IACJ,CAAC;IAED,iEAAiE;IACjE,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;IACpC,CAAC;IAED,mEAAmE;IACnE,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;OAGG;IACK,cAAc;QACpB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACK,eAAe;QACrB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;QACvC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,2EAA2E;IAC3E,SAAS;QACP,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;IAC5C,CAAC;IAED,kEAAkE;IAClE,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC;IACtC,CAAC;IAED;;;;;OAKG;IACH,QAAQ;QACN,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI;YAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;YAC3B,cAAc,EAAE,IAAI,CAAC,eAAe,EAAE;YACtC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,eAAe,EAAE,IAAI,CAAC,iBAAiB,EAAE;SAC1C,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;OAWG;IACK,YAAY,CAAC,IAAoC;QACvD,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,CAAC,CAAC,OAAO;YACnB,CAAC;YAED,qEAAqE;YACrE,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAEvC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;gBAClC,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;oBACxB,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;gBAChE,CAAC;YACH,CAAC;iBAAM,IAAI,OAAO,WAAW,KAAK,WAAW,EAAE,CAAC;gBAC9C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;gBAClC,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;oBACxB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC5D,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,sFAAsF;gBACtF,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,wEAAwE,EACxE,EAAE,CACH,CAAC;gBACF,OAAO,CAAC,CAAC;YACX,CAAC;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;gBACnD,KAAK,EAAE,sBAAsB,CAAC,KAAK,CAAC;aACrC,CAAC,CAAC;YACH,MAAM,IAAI,mBAAmB,CAC3B,SAAS,EACT,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAC3C,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,IAAiB;QAC5B,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,cAAc,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,CAAC,KAAK,IAAI,EAAE;YAChC,IAAI,CAAC;gBACH,MAAM,IAAI,EAAE,CAAC;YACf,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,EAAE;oBAC9D,KAAK,EAAE,sBAAsB,CAAC,KAAK,CAAC;iBACrC,CAAC,CAAC;gBACH,MAAM,KAAK,CAAC;YACd,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED,gEAAgE;IAChE,KAAK;QACH,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;QAChD,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IACvE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,UAAiC;QACtC,+DAA+D;QAC/D,4EAA4E;QAC5E,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CACzD,CAAC;QAEF,yDAAyD;QACzD,IAAI,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,EAAE;gBAC/D,UAAU,EAAE,UAAU,CAAC,MAAM;gBAC7B,WAAW,EAAE,SAAS,CAAC,IAAI;aAC5B,CAAC,CAAC;QACL,CAAC;QAED,wFAAwF;QACxF,oEAAoE;QACpE,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;QAExD,4CAA4C;QAC5C,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE;YAC1B,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;YAC7C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,sFAAsF;gBACtF,IAAI,KAAK,YAAY,mBAAmB,EAAE,CAAC;oBACzC,MAAM,IAAI,mBAAmB,CAAC,WAAW,EAAE,KAAK,CAAC,KAAc,CAAC,CAAC;gBACnE,CAAC;gBACD,6BAA6B;gBAC7B,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,IAAI,aAAa,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,EAAE;gBAC/D,aAAa;gBACb,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;gBACvC,UAAU,EAAE,UAAU,CAAC,MAAM;gBAC7B,WAAW,EAAE,SAAS,CAAC,IAAI;aAC5B,CAAC,CAAC;YACH,MAAM,IAAI,qBAAqB,CAC7B,WAAW,EACX,aAAa,EACb,IAAI,CAAC,gBAAgB,CACtB,CAAC;QACJ,CAAC;QAED,8BAA8B;QAC9B,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,gBAAgB,CAAC;QAEnC,wBAAwB;QACxB,IAAI,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,EAAE;YAC1D,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI;YACjC,aAAa;SACd,CAAC,CAAC;QAEH,OAAO,EAAE,aAAa,EAAE,CAAC;IAC3B,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,UAA0D,CAAC;IACzE,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;SAC5B,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,gBAAgB,CACd,WAAmB;QAEnB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC;QACjE,OAAO,SAAqD,CAAC;IAC/D,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACH,eAAe;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/store/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/store/types/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { StoreDataState } from '../errors/store-error.js';
|
|
2
|
+
import type { PrototypeInMemoryStats } from '../store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Failure kinds specific to store operations.
|
|
5
|
+
*
|
|
6
|
+
* - `storage_limit`: Store capacity exceeded
|
|
7
|
+
* - `serialization`: JSON serialization failed during size estimation
|
|
8
|
+
* - `unknown`: Unexpected store error
|
|
9
|
+
*/
|
|
10
|
+
export type StoreFailureKind = 'storage_limit' | 'serialization' | 'unknown';
|
|
11
|
+
/**
|
|
12
|
+
* Error codes for store-originated failures.
|
|
13
|
+
*
|
|
14
|
+
* - `STORE_CAPACITY_EXCEEDED`: Data size exceeds configured limit
|
|
15
|
+
* - `STORE_SERIALIZATION_FAILED`: Failed to serialize data for size estimation
|
|
16
|
+
* - `STORE_UNKNOWN`: Unexpected error from store
|
|
17
|
+
*/
|
|
18
|
+
export type StoreErrorCode = 'STORE_CAPACITY_EXCEEDED' | 'STORE_SERIALIZATION_FAILED' | 'STORE_UNKNOWN';
|
|
19
|
+
/**
|
|
20
|
+
* Successful result from setAll operation.
|
|
21
|
+
*/
|
|
22
|
+
export type SetSuccess = {
|
|
23
|
+
/** Indicates successful operation. */
|
|
24
|
+
ok: true;
|
|
25
|
+
/** Statistics about the current snapshot after storing. */
|
|
26
|
+
stats: PrototypeInMemoryStats;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Failed result from setAll operation.
|
|
30
|
+
*
|
|
31
|
+
* Contains store-specific error information.
|
|
32
|
+
*/
|
|
33
|
+
export type SetFailure = {
|
|
34
|
+
/** Indicates failed operation. */
|
|
35
|
+
ok: false;
|
|
36
|
+
/** Always store-originated. */
|
|
37
|
+
origin: 'store';
|
|
38
|
+
/** Coarse-grained classification of the failure cause. */
|
|
39
|
+
kind: StoreFailureKind;
|
|
40
|
+
/** Canonical error code from the store. */
|
|
41
|
+
code: StoreErrorCode;
|
|
42
|
+
/** Human-readable error message. */
|
|
43
|
+
message: string;
|
|
44
|
+
/** State of the store's data when the error occurred. */
|
|
45
|
+
dataState: StoreDataState;
|
|
46
|
+
/** Underlying cause of the error (for serialization failures). */
|
|
47
|
+
cause?: unknown;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Result from setAll operation.
|
|
51
|
+
*
|
|
52
|
+
* Returns either success with stats or failure with store-specific error details.
|
|
53
|
+
* This type maintains symmetry with FetchPrototypesResult at the operation boundary,
|
|
54
|
+
* allowing fetchAndStore to handle both fetch and store operations uniformly.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const result = storeSnapshot(data);
|
|
59
|
+
* if (result.ok) {
|
|
60
|
+
* console.log('Stored:', result.stats.size);
|
|
61
|
+
* } else {
|
|
62
|
+
* console.error('Store failed:', result.kind, result.code);
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export type SetResult = SetSuccess | SetFailure;
|
|
67
|
+
//# sourceMappingURL=result.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.types.d.ts","sourceRoot":"","sources":["../../../lib/store/types/result.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,eAAe,GAAG,SAAS,CAAC;AAE7E;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GACtB,yBAAyB,GACzB,4BAA4B,GAC5B,eAAe,CAAC;AAEpB;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,sCAAsC;IACtC,EAAE,EAAE,IAAI,CAAC;IACT,2DAA2D;IAC3D,KAAK,EAAE,sBAAsB,CAAC;CAC/B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,kCAAkC;IAClC,EAAE,EAAE,KAAK,CAAC;IACV,+BAA+B;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,0DAA0D;IAC1D,IAAI,EAAE,gBAAgB,CAAC;IACvB,2CAA2C;IAC3C,IAAI,EAAE,cAAc,CAAC;IACrB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,SAAS,EAAE,cAAc,CAAC;IAC1B,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.types.js","sourceRoot":"","sources":["../../../lib/store/types/result.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for ProtoPedia field value codes.
|
|
3
|
+
*
|
|
4
|
+
* These types define the valid numeric values for various ProtoPedia fields.
|
|
5
|
+
*
|
|
6
|
+
* @module types
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Valid status code values.
|
|
10
|
+
*
|
|
11
|
+
* - 1: 'アイデア' (Idea)
|
|
12
|
+
* - 2: '開発中' (In Development)
|
|
13
|
+
* - 3: '完成' (Completed)
|
|
14
|
+
* - 4: '供養' (Retired/Memorial)
|
|
15
|
+
*
|
|
16
|
+
* All four status values appear in public API responses.
|
|
17
|
+
*/
|
|
18
|
+
export type StatusCode = 1 | 2 | 3 | 4;
|
|
19
|
+
/**
|
|
20
|
+
* Valid release flag code values.
|
|
21
|
+
*
|
|
22
|
+
* - 1: '下書き保存' (Draft) - Not accessible via public API
|
|
23
|
+
* - 2: '一般公開' (Public) - Only this value appears in API responses
|
|
24
|
+
* - 3: '限定共有' (Limited Sharing) - Not accessible via public API
|
|
25
|
+
*/
|
|
26
|
+
export type ReleaseFlagCode = 1 | 2 | 3;
|
|
27
|
+
/**
|
|
28
|
+
* Valid license type code values.
|
|
29
|
+
*
|
|
30
|
+
* - 0: 'なし' (None) - Not observed in API responses
|
|
31
|
+
* - 1: '表示(CC:BY)' (Display with CC BY license) - All API responses have this value
|
|
32
|
+
*/
|
|
33
|
+
export type LicenseTypeCode = 0 | 1;
|
|
34
|
+
/**
|
|
35
|
+
* Valid thanks flag code values.
|
|
36
|
+
*
|
|
37
|
+
* - 0: (Implicit) Message not yet shown - Rarely or never seen in API responses
|
|
38
|
+
* - 1: '初回表示済' ("Thank you for posting" message shown) - Most common value
|
|
39
|
+
* - undefined: Field not present in older prototypes (pre-thanksFlg era, ~3.26% of data)
|
|
40
|
+
*
|
|
41
|
+
* Note: Historical data may not include this field. Always handle undefined case.
|
|
42
|
+
*/
|
|
43
|
+
export type ThanksFlagCode = 0 | 1 | undefined;
|
|
44
|
+
//# sourceMappingURL=codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../../lib/types/codes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAExC;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,CAAC,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codes.js","sourceRoot":"","sources":["../../lib/types/codes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for the library.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the core data structures used throughout the library.
|
|
5
|
+
* It serves as the single source of truth for type definitions, ensuring
|
|
6
|
+
* consistency across all layers (Fetcher, Store, Repository).
|
|
7
|
+
*
|
|
8
|
+
* ## Main Exports
|
|
9
|
+
*
|
|
10
|
+
* - {@link NormalizedPrototype} — The standardized shape of a prototype
|
|
11
|
+
* after normalization from ProtoPedia API responses.
|
|
12
|
+
* - {@link StatusCode} — Type for prototype status codes (1-4)
|
|
13
|
+
* - {@link ReleaseFlagCode} — Type for release flag codes (1-3)
|
|
14
|
+
* - {@link LicenseTypeCode} — Type for license type codes (0-1)
|
|
15
|
+
* - {@link ThanksFlagCode} — Type for thanks flag codes (0, 1, or undefined)
|
|
16
|
+
*
|
|
17
|
+
* ## Type Characteristics
|
|
18
|
+
*
|
|
19
|
+
* - **Type Safety**: Strongly typed with clear required/optional field distinction
|
|
20
|
+
* - **Normalization**: Pipe-separated strings converted to arrays, timestamps to UTC ISO 8601
|
|
21
|
+
* - **Strict Typing**: Compatible with TypeScript's `exactOptionalPropertyTypes: true`
|
|
22
|
+
* - **Cross-Layer Consistency**: Used uniformly across Fetcher, Store, and Repository
|
|
23
|
+
*
|
|
24
|
+
* ## Usage
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import type { NormalizedPrototype, StatusCode } from 'promidas/types';
|
|
29
|
+
*
|
|
30
|
+
* function processPrototype(prototype: NormalizedPrototype) {
|
|
31
|
+
* // Required fields are always accessible
|
|
32
|
+
* console.log(prototype.id, prototype.prototypeNm);
|
|
33
|
+
*
|
|
34
|
+
* // Array fields are type-safe
|
|
35
|
+
* prototype.tags.forEach(tag => console.log(tag)); // tag is string
|
|
36
|
+
*
|
|
37
|
+
* // Optional fields require undefined checks
|
|
38
|
+
* if (prototype.releaseDate !== undefined) {
|
|
39
|
+
* console.log(new Date(prototype.releaseDate));
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* // Code types are available
|
|
43
|
+
* const status: StatusCode = prototype.status as StatusCode;
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* ## Data Transformation
|
|
48
|
+
*
|
|
49
|
+
* This type represents data after normalization:
|
|
50
|
+
*
|
|
51
|
+
* - **Raw API data** (`UpstreamPrototype`) → `normalizePrototype()` → **Normalized data** (`NormalizedPrototype`)
|
|
52
|
+
* - Pipe-separated strings (`"tag1|tag2"`) → Arrays (`["tag1", "tag2"]`)
|
|
53
|
+
* - JST timestamps (`"2025-12-12 09:00:00.0"`) → UTC ISO 8601 (`"2025-12-12T00:00:00.000Z"`)
|
|
54
|
+
*
|
|
55
|
+
* @module
|
|
56
|
+
* @see {@link NormalizedPrototype} for detailed field documentation
|
|
57
|
+
* @see {@link ../fetcher/index.js} for normalization utilities
|
|
58
|
+
*/
|
|
59
|
+
export type { NormalizedPrototype } from './normalized-prototype.js';
|
|
60
|
+
export type { StatusCode, ReleaseFlagCode, LicenseTypeCode, ThanksFlagCode, } from './codes.js';
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EACV,UAAU,EACV,eAAe,EACf,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC"}
|