gcm-database-local 0.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.
Files changed (46) hide show
  1. package/dist/chunithm/chart.d.ts +16 -0
  2. package/dist/chunithm/chart.js +3 -0
  3. package/dist/chunithm/chart.js.map +1 -0
  4. package/dist/chunithm/database.d.ts +36 -0
  5. package/dist/chunithm/database.js +115 -0
  6. package/dist/chunithm/database.js.map +1 -0
  7. package/dist/chunithm/presence.d.ts +36 -0
  8. package/dist/chunithm/presence.js +3 -0
  9. package/dist/chunithm/presence.js.map +1 -0
  10. package/dist/chunithm.d.ts +3 -0
  11. package/dist/chunithm.js +6 -0
  12. package/dist/chunithm.js.map +1 -0
  13. package/dist/lib/cache.d.ts +24 -0
  14. package/dist/lib/cache.js +80 -0
  15. package/dist/lib/cache.js.map +1 -0
  16. package/dist/lib/getInternalLevelFromPresences.d.ts +4 -0
  17. package/dist/lib/getInternalLevelFromPresences.js +21 -0
  18. package/dist/lib/getInternalLevelFromPresences.js.map +1 -0
  19. package/dist/lib/logger.d.ts +2 -0
  20. package/dist/lib/logger.js +16 -0
  21. package/dist/lib/logger.js.map +1 -0
  22. package/dist/maimai/chart.d.ts +19 -0
  23. package/dist/maimai/chart.js +3 -0
  24. package/dist/maimai/chart.js.map +1 -0
  25. package/dist/maimai/database.d.ts +37 -0
  26. package/dist/maimai/database.js +118 -0
  27. package/dist/maimai/database.js.map +1 -0
  28. package/dist/maimai/presence.d.ts +52 -0
  29. package/dist/maimai/presence.js +3 -0
  30. package/dist/maimai/presence.js.map +1 -0
  31. package/dist/maimai.d.ts +3 -0
  32. package/dist/maimai.js +6 -0
  33. package/dist/maimai.js.map +1 -0
  34. package/dist/ongeki/chart.d.ts +16 -0
  35. package/dist/ongeki/chart.js +3 -0
  36. package/dist/ongeki/chart.js.map +1 -0
  37. package/dist/ongeki/database.d.ts +44 -0
  38. package/dist/ongeki/database.js +140 -0
  39. package/dist/ongeki/database.js.map +1 -0
  40. package/dist/ongeki/presence.d.ts +36 -0
  41. package/dist/ongeki/presence.js +3 -0
  42. package/dist/ongeki/presence.js.map +1 -0
  43. package/dist/ongeki.d.ts +3 -0
  44. package/dist/ongeki.js +6 -0
  45. package/dist/ongeki.js.map +1 -0
  46. package/package.json +51 -0
@@ -0,0 +1,16 @@
1
+ import type { Chart as BaseChart } from "gcm-database/chunithm";
2
+ import type { Presences } from "./presence";
3
+ export interface Chart extends BaseChart {
4
+ optionalData: Partial<{
5
+ bpm: number[];
6
+ notes: {
7
+ tap: number;
8
+ hold: number;
9
+ slide: number;
10
+ air: number;
11
+ flick?: number;
12
+ };
13
+ designer: string;
14
+ presences: Presences[];
15
+ }>;
16
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart.js","sourceRoot":"","sources":["../../src/chunithm/chart.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ import type { Database as BaseDatabase, Difficulty } from "gcm-database/chunithm";
2
+ import type { Chart } from "./chart";
3
+ export declare class Database implements BaseDatabase<Chart> {
4
+ private _localDatabasePath;
5
+ constructor(_localDatabasePath: string);
6
+ setLocalDatabasePath(path: string): boolean;
7
+ hasLocalDatabase(): boolean;
8
+ private cache;
9
+ getJacket(identifier: string, variant?: "DX" | "EX" | "CN"): Promise<{
10
+ data: Buffer<ArrayBuffer> | Buffer<any>;
11
+ err?: undefined;
12
+ } | {
13
+ err: string;
14
+ data?: undefined;
15
+ }>;
16
+ getChart(identifier: string, difficulty: Difficulty): Promise<{
17
+ data: any;
18
+ err?: undefined;
19
+ } | {
20
+ err: string;
21
+ data?: undefined;
22
+ }>;
23
+ private getAllCharts;
24
+ searchChart(payload: {
25
+ title: string;
26
+ level: number;
27
+ difficulty: Difficulty;
28
+ }, options?: Partial<{
29
+ maxResultCount: number;
30
+ }>): Promise<{
31
+ data: {
32
+ chart: Chart;
33
+ weight: number;
34
+ }[];
35
+ }>;
36
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Database = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const cache_1 = require("../lib/cache");
10
+ const getInternalLevelFromPresences_1 = require("../lib/getInternalLevelFromPresences");
11
+ class Database {
12
+ _localDatabasePath;
13
+ constructor(_localDatabasePath) {
14
+ this._localDatabasePath = _localDatabasePath;
15
+ }
16
+ setLocalDatabasePath(path) {
17
+ if (node_fs_1.default.existsSync(path)) {
18
+ this._localDatabasePath = path;
19
+ return true;
20
+ }
21
+ else {
22
+ return false;
23
+ }
24
+ }
25
+ hasLocalDatabase() {
26
+ return node_fs_1.default.existsSync(this._localDatabasePath);
27
+ }
28
+ cache = new cache_1.Cache("gcm-database-local/chunithm");
29
+ async getJacket(identifier, variant) {
30
+ const cacheKey = `jacket-${identifier}${variant ? `-${variant}` : ""}`;
31
+ const cached = await this.cache.get(cacheKey);
32
+ if (cached instanceof Buffer) {
33
+ return { data: cached };
34
+ }
35
+ else {
36
+ const songId = identifier.slice(-4);
37
+ if (variant) {
38
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "chunithm", "jackets", `${songId.padStart(6, "0")}-${variant}.png`);
39
+ if (node_fs_1.default.existsSync(localFilePath)) {
40
+ return { data: node_fs_1.default.readFileSync(localFilePath) };
41
+ }
42
+ }
43
+ // Falls back to normal jacket if a variant cannot be found.
44
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "chunithm", "jackets", `${songId.padStart(6, "0")}.png`);
45
+ const jacket = node_fs_1.default.existsSync(localFilePath) && node_fs_1.default.readFileSync(localFilePath);
46
+ if (jacket) {
47
+ this.cache.put(cacheKey, jacket, 5 * 1000); // 5 seconds.
48
+ return { data: jacket };
49
+ }
50
+ else {
51
+ return { err: `Cannot find the jacket of ${identifier}.` };
52
+ }
53
+ }
54
+ }
55
+ async getChart(identifier, difficulty) {
56
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "chunithm", "charts", `${identifier.padStart(6, "0")}`);
57
+ if (node_fs_1.default.existsSync(node_path_1.default.join(localFilePath, difficulty))) {
58
+ try {
59
+ return {
60
+ data: JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(localFilePath, difficulty), "utf-8")),
61
+ };
62
+ }
63
+ catch {
64
+ return {
65
+ err: `Failed to parse ${identifier} ${difficulty}.`,
66
+ };
67
+ }
68
+ }
69
+ return {
70
+ err: `Cannot find a chart with identifier ${identifier}.`,
71
+ };
72
+ }
73
+ async getAllCharts() {
74
+ const cached = await this.cache.get("all-charts");
75
+ if (cached)
76
+ return cached;
77
+ const localFolderPath = node_path_1.default.join(this._localDatabasePath, "assets", "chunithm", "charts");
78
+ const chartFolders = node_fs_1.default.readdirSync(localFolderPath);
79
+ const songs = [];
80
+ for (const folder of chartFolders) {
81
+ const charts = node_fs_1.default.readdirSync(node_path_1.default.join(localFolderPath, folder));
82
+ for (const chart of charts) {
83
+ try {
84
+ songs.push(require(node_path_1.default.join(localFolderPath, folder, chart)));
85
+ }
86
+ catch { }
87
+ }
88
+ }
89
+ await this.cache.put("all-charts", songs, 15 * 60 * 1000); // 15 minutes.
90
+ return songs;
91
+ }
92
+ async searchChart(payload, options) {
93
+ const allSongs = await this.getAllCharts();
94
+ const sortedCandidates = allSongs
95
+ .filter((v) => v.title === payload.title &&
96
+ v.difficulty === payload.difficulty)
97
+ .map((v) => {
98
+ if (v.optionalData.presences) {
99
+ const internalLevel = (0, getInternalLevelFromPresences_1.getInternalLevelFromPresences)(v.optionalData.presences);
100
+ if (internalLevel) {
101
+ return {
102
+ chart: v,
103
+ weight: Math.abs(internalLevel - payload.level),
104
+ };
105
+ }
106
+ }
107
+ return { chart: v };
108
+ })
109
+ .filter((v) => !!v.weight)
110
+ .sort((a, b) => a.weight - b.weight);
111
+ return { data: sortedCandidates.slice(options?.maxResultCount || 20) };
112
+ }
113
+ }
114
+ exports.Database = Database;
115
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/chunithm/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ interface BasePresence {
2
+ type: string;
3
+ data?: unknown;
4
+ version: Version;
5
+ }
6
+ export interface Existence extends BasePresence {
7
+ type: "existence";
8
+ data: {
9
+ level: number;
10
+ };
11
+ }
12
+ export interface Absence extends BasePresence {
13
+ type: "absence";
14
+ }
15
+ export interface Removal extends BasePresence {
16
+ type: "removal";
17
+ }
18
+ export type Presences = Existence | Absence | Removal;
19
+ export interface Version {
20
+ /**
21
+ * Full name of the version.
22
+ * @example "CHUNITHM X-VERSE-X"
23
+ */
24
+ name: string;
25
+ /**
26
+ * Version number as it is used internally.
27
+ * Formatted as `{major}.{minor}.{patch}`.
28
+ */
29
+ gameVersion: {
30
+ major: number;
31
+ minor: number;
32
+ release?: number;
33
+ };
34
+ region: "JPN" | "INT" | "CHN";
35
+ }
36
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=presence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presence.js","sourceRoot":"","sources":["../../src/chunithm/presence.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export { Chart } from "./chunithm/chart";
2
+ export { Database } from "./chunithm/database";
3
+ export { Absence, Existence, Presences, Removal, Version, } from "./chunithm/presence";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Database = void 0;
4
+ var database_1 = require("./chunithm/database");
5
+ Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return database_1.Database; } });
6
+ //# sourceMappingURL=chunithm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunithm.js","sourceRoot":"","sources":["../src/chunithm.ts"],"names":[],"mappings":";;;AACA,+CAA8C;AAArC,oGAAA,QAAQ,OAAA"}
@@ -0,0 +1,24 @@
1
+ export declare class Cache<T> {
2
+ private namespace;
3
+ private logger;
4
+ private memCache;
5
+ private redisClient;
6
+ private isRedisAvailable;
7
+ constructor(namespace: string);
8
+ private getKey;
9
+ /**
10
+ * Get a value from cache.
11
+ *
12
+ * @param key Cache key.
13
+ * @returns Cache value.
14
+ */
15
+ get(key: string): Promise<any>;
16
+ /**
17
+ * Put a value into cache.
18
+ *
19
+ * @param key Cache key.
20
+ * @param value Cache value.
21
+ * @param ttl Cache TTL in milliseconds.
22
+ */
23
+ put(key: string, value: T, ttl: number): Promise<void>;
24
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Cache = void 0;
4
+ const memory_cache_1 = require("memory-cache");
5
+ const redis_1 = require("redis");
6
+ const logger_1 = require("./logger");
7
+ class Cache {
8
+ namespace;
9
+ logger;
10
+ memCache;
11
+ redisClient;
12
+ isRedisAvailable = true;
13
+ constructor(namespace) {
14
+ this.namespace = namespace;
15
+ this.logger = logger_1.logger.child().withGroup(`${this.namespace}:cache`);
16
+ this.memCache = new memory_cache_1.Cache();
17
+ this.redisClient = (0, redis_1.createClient)();
18
+ this.redisClient.on("error", async () => {
19
+ this.logger.error("Redis connection error, using memory-cache");
20
+ this.isRedisAvailable = false;
21
+ this.redisClient.destroy();
22
+ });
23
+ this.redisClient.connect();
24
+ }
25
+ getKey(key) {
26
+ return `${this.namespace}:${key}`;
27
+ }
28
+ /**
29
+ * Get a value from cache.
30
+ *
31
+ * @param key Cache key.
32
+ * @returns Cache value.
33
+ */
34
+ async get(key) {
35
+ if (this.isRedisAvailable) {
36
+ const redisValue = await this.redisClient.get(this.getKey(key));
37
+ if (redisValue) {
38
+ try {
39
+ return JSON.parse(redisValue);
40
+ }
41
+ catch {
42
+ return Buffer.from(redisValue, "base64");
43
+ }
44
+ }
45
+ }
46
+ else
47
+ return this.memCache.get(this.getKey(key));
48
+ }
49
+ /**
50
+ * Put a value into cache.
51
+ *
52
+ * @param key Cache key.
53
+ * @param value Cache value.
54
+ * @param ttl Cache TTL in milliseconds.
55
+ */
56
+ async put(key, value, ttl) {
57
+ if (this.isRedisAvailable) {
58
+ if (Buffer.isBuffer(value)) {
59
+ await this.redisClient.set(this.getKey(key), value.toString("base64"), {
60
+ expiration: {
61
+ type: "EX",
62
+ value: Math.trunc(ttl / 1000),
63
+ },
64
+ });
65
+ }
66
+ else {
67
+ await this.redisClient.set(this.getKey(key), JSON.stringify(value), {
68
+ expiration: {
69
+ type: "EX",
70
+ value: Math.trunc(ttl / 1000),
71
+ },
72
+ });
73
+ }
74
+ }
75
+ else
76
+ this.memCache.put(this.getKey(key), value, ttl);
77
+ }
78
+ }
79
+ exports.Cache = Cache;
80
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/lib/cache.ts"],"names":[],"mappings":";;;AAAA,+CAAiD;AACjD,iCAAqC;AACrC,qCAAkC;AAElC,MAAa,KAAK;IAOM;IANZ,MAAM,CAAC;IAEP,QAAQ,CAAC;IACT,WAAW,CAAC;IAEZ,gBAAgB,GAAG,IAAI,CAAC;IAChC,YAAoB,SAAiB;QAAjB,cAAS,GAAT,SAAS,CAAQ;QACjC,IAAI,CAAC,MAAM,GAAG,eAAM,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,QAAQ,CAAC,CAAC;QAClE,IAAI,CAAC,QAAQ,GAAG,IAAI,oBAAQ,EAAa,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,IAAA,oBAAY,GAAE,CAAC;QAClC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;YACpC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;YAC9B,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IAC/B,CAAC;IACO,MAAM,CAAC,GAAW;QACtB,OAAO,GAAG,IAAI,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC;IACtC,CAAC;IACD;;;;;OAKG;IACI,KAAK,CAAC,GAAG,CAAC,GAAW;QACxB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,IAAI,UAAU,EAAE,CAAC;gBACb,IAAI,CAAC;oBACD,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAClC,CAAC;gBAAC,MAAM,CAAC;oBACL,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBAC7C,CAAC;YACL,CAAC;QACL,CAAC;;YAAM,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,CAAC;IACD;;;;;;OAMG;IACI,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,GAAW;QAC/C,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CACtB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAChB,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EACxB;oBACI,UAAU,EAAE;wBACR,IAAI,EAAE,IAAI;wBACV,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC;qBAChC;iBACJ,CACJ,CAAC;YACN,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CACtB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAChB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EACrB;oBACI,UAAU,EAAE;wBACR,IAAI,EAAE,IAAI;wBACV,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC;qBAChC;iBACJ,CACJ,CAAC;YACN,CAAC;QACL,CAAC;;YAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAC3D,CAAC;CACJ;AAzED,sBAyEC"}
@@ -0,0 +1,4 @@
1
+ import type { Presences as ChunithmPresences } from "../chunithm/presence";
2
+ import type { Presences as MaimaiPresences } from "../maimai/presence";
3
+ import type { Presences as OngekiPresences } from "../ongeki/presence";
4
+ export declare function getInternalLevelFromPresences(presences: (MaimaiPresences | ChunithmPresences | OngekiPresences)[]): number | null;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getInternalLevelFromPresences = getInternalLevelFromPresences;
4
+ function getInternalLevelFromPresences(presences) {
5
+ let latestPresence;
6
+ for (const presence of presences) {
7
+ if (!latestPresence ||
8
+ (presence.type === "existence" &&
9
+ presence.version.gameVersion.major >=
10
+ latestPresence.version.gameVersion.major &&
11
+ presence.version.gameVersion.minor >=
12
+ latestPresence.version.gameVersion.minor)) {
13
+ latestPresence = presence;
14
+ }
15
+ }
16
+ if (latestPresence) {
17
+ return latestPresence.data.level;
18
+ }
19
+ return null;
20
+ }
21
+ //# sourceMappingURL=getInternalLevelFromPresences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getInternalLevelFromPresences.js","sourceRoot":"","sources":["../../src/lib/getInternalLevelFromPresences.ts"],"names":[],"mappings":";;AAeA,sEAoBC;AApBD,SAAgB,6BAA6B,CACzC,SAAoE;IAEpE,IAAI,cAAwC,CAAC;IAC7C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC/B,IACI,CAAC,cAAc;YACf,CAAC,QAAQ,CAAC,IAAI,KAAK,WAAW;gBAC1B,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK;oBAC9B,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK;gBAC5C,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK;oBAC9B,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,EACnD,CAAC;YACC,cAAc,GAAG,QAAwB,CAAC;QAC9C,CAAC;IACL,CAAC;IACD,IAAI,cAAc,EAAE,CAAC;QACjB,OAAO,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { LogLayer } from "loglayer";
2
+ export declare const logger: LogLayer;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = void 0;
4
+ const log_level_manager_global_1 = require("@loglayer/log-level-manager-global");
5
+ const transport_pino_1 = require("@loglayer/transport-pino");
6
+ const loglayer_1 = require("loglayer");
7
+ const pino_1 = require("pino");
8
+ const p = (0, pino_1.pino)({
9
+ level: "trace", // Enable all log levels
10
+ });
11
+ exports.logger = new loglayer_1.LogLayer({
12
+ transport: new transport_pino_1.PinoTransport({
13
+ logger: p,
14
+ }),
15
+ }).withLogLevelManager(new log_level_manager_global_1.GlobalLogLevelManager());
16
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":";;;AAAA,iFAA2E;AAC3E,6DAAyD;AACzD,uCAAoC;AACpC,+BAA4B;AAE5B,MAAM,CAAC,GAAG,IAAA,WAAI,EAAC;IACX,KAAK,EAAE,OAAO,EAAE,wBAAwB;CAC3C,CAAC,CAAC;AAEU,QAAA,MAAM,GAAG,IAAI,mBAAQ,CAAC;IAC/B,SAAS,EAAE,IAAI,8BAAa,CAAC;QACzB,MAAM,EAAE,CAAC;KACZ,CAAC;CACL,CAAC,CAAC,mBAAmB,CAAC,IAAI,gDAAqB,EAAE,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Chart as BaseChart } from "gcm-database/maimai";
2
+ import type { Presences } from "./presence";
3
+ export interface Chart extends BaseChart {
4
+ optionalData: Partial<{
5
+ bpm: number[];
6
+ notes: {
7
+ tap: number;
8
+ hold: number;
9
+ slide: number;
10
+ touch: number;
11
+ break: number;
12
+ };
13
+ designer: {
14
+ id: number;
15
+ name: string;
16
+ };
17
+ presences: Presences[];
18
+ }>;
19
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart.js","sourceRoot":"","sources":["../../src/maimai/chart.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import type { Database as BaseDatabase, Difficulty, Type } from "gcm-database/maimai";
2
+ import type { Chart } from "./chart";
3
+ export declare class Database implements BaseDatabase<Chart> {
4
+ private _localDatabasePath;
5
+ constructor(_localDatabasePath: string);
6
+ setLocalDatabasePath(path: string): boolean;
7
+ hasLocalDatabase(): boolean;
8
+ private cache;
9
+ getJacket(identifier: string, variant?: "DX" | "EX" | "CN"): Promise<{
10
+ data: Buffer<ArrayBuffer> | Buffer<any>;
11
+ err?: undefined;
12
+ } | {
13
+ err: string;
14
+ data?: undefined;
15
+ }>;
16
+ getChart(identifier: string, difficulty: Difficulty): Promise<{
17
+ data: any;
18
+ err?: undefined;
19
+ } | {
20
+ err: string;
21
+ data?: undefined;
22
+ }>;
23
+ private getAllCharts;
24
+ searchChart(payload: {
25
+ title: string;
26
+ level: number;
27
+ difficulty: Difficulty;
28
+ type: Type;
29
+ }, options?: Partial<{
30
+ maxResultCount: number;
31
+ }>): Promise<{
32
+ data: {
33
+ chart: Chart;
34
+ weight: number;
35
+ }[];
36
+ }>;
37
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Database = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const cache_1 = require("../lib/cache");
10
+ const getInternalLevelFromPresences_1 = require("../lib/getInternalLevelFromPresences");
11
+ class Database {
12
+ _localDatabasePath;
13
+ constructor(_localDatabasePath) {
14
+ this._localDatabasePath = _localDatabasePath;
15
+ }
16
+ setLocalDatabasePath(path) {
17
+ if (node_fs_1.default.existsSync(path)) {
18
+ this._localDatabasePath = path;
19
+ return true;
20
+ }
21
+ else {
22
+ return false;
23
+ }
24
+ }
25
+ hasLocalDatabase() {
26
+ return node_fs_1.default.existsSync(this._localDatabasePath);
27
+ }
28
+ cache = new cache_1.Cache("gcm-database-local/maimai");
29
+ async getJacket(identifier, variant) {
30
+ const cacheKey = `jacket-${identifier}${variant ? `-${variant}` : ""}`;
31
+ const cached = await this.cache.get(cacheKey);
32
+ if (cached instanceof Buffer) {
33
+ return { data: cached };
34
+ }
35
+ else {
36
+ const songId = identifier.slice(-4);
37
+ if (variant) {
38
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "maimai", "jackets", `${songId.padStart(6, "0")}-${variant}.png`);
39
+ if (node_fs_1.default.existsSync(localFilePath)) {
40
+ return { data: node_fs_1.default.readFileSync(localFilePath) };
41
+ }
42
+ }
43
+ // Falls back to normal jacket if a variant cannot be found.
44
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "maimai", "jackets", `${songId.padStart(6, "0")}.png`);
45
+ const jacket = node_fs_1.default.existsSync(localFilePath) && node_fs_1.default.readFileSync(localFilePath);
46
+ if (jacket) {
47
+ this.cache.put(cacheKey, jacket, 5 * 1000); // 5 seconds.
48
+ return { data: jacket };
49
+ }
50
+ else {
51
+ return { err: `Cannot find the jacket of ${identifier}.` };
52
+ }
53
+ }
54
+ }
55
+ async getChart(identifier, difficulty) {
56
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "maimai", "charts", `${identifier.padStart(6, "0")}`);
57
+ if (node_fs_1.default.existsSync(node_path_1.default.join(localFilePath, difficulty))) {
58
+ try {
59
+ return {
60
+ data: JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(localFilePath, difficulty), "utf-8")),
61
+ };
62
+ }
63
+ catch {
64
+ return {
65
+ err: `Failed to parse ${identifier} ${difficulty}.`,
66
+ };
67
+ }
68
+ }
69
+ return {
70
+ err: `Cannot find a chart with identifier ${identifier}.`,
71
+ };
72
+ }
73
+ async getAllCharts() {
74
+ const cached = await this.cache.get("all-charts");
75
+ if (cached)
76
+ return cached;
77
+ const localFolderPath = node_path_1.default.join(this._localDatabasePath, "assets", "maimai", "charts");
78
+ const chartFolders = node_fs_1.default.readdirSync(localFolderPath);
79
+ const songs = [];
80
+ for (const folder of chartFolders) {
81
+ const charts = node_fs_1.default.readdirSync(node_path_1.default.join(localFolderPath, folder));
82
+ for (const chart of charts) {
83
+ try {
84
+ songs.push(require(node_path_1.default.join(localFolderPath, folder, chart)));
85
+ }
86
+ catch { }
87
+ }
88
+ }
89
+ await this.cache.put("all-charts", songs, 15 * 60 * 1000); // 15 minutes.
90
+ return songs;
91
+ }
92
+ async searchChart(payload, options) {
93
+ const allSongs = await this.getAllCharts();
94
+ const sortedCandidates = allSongs
95
+ .filter((v) => v.title === payload.title &&
96
+ v.type === payload.type &&
97
+ v.difficulty === payload.difficulty)
98
+ .map((v) => {
99
+ if (v.optionalData.presences) {
100
+ if (v.optionalData.presences) {
101
+ const internalLevel = (0, getInternalLevelFromPresences_1.getInternalLevelFromPresences)(v.optionalData.presences);
102
+ if (internalLevel) {
103
+ return {
104
+ chart: v,
105
+ weight: Math.abs(internalLevel - payload.level),
106
+ };
107
+ }
108
+ }
109
+ }
110
+ return { chart: v };
111
+ })
112
+ .filter((v) => !!v.weight)
113
+ .sort((a, b) => a.weight - b.weight);
114
+ return { data: sortedCandidates.slice(options?.maxResultCount || 20) };
115
+ }
116
+ }
117
+ exports.Database = Database;
118
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/maimai/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ interface BasePresence {
2
+ type: string;
3
+ data?: unknown;
4
+ version: Version;
5
+ }
6
+ export interface Existence extends BasePresence {
7
+ type: "existence";
8
+ data: {
9
+ level: number;
10
+ };
11
+ }
12
+ export interface Absence extends BasePresence {
13
+ type: "absence";
14
+ }
15
+ export interface Removal extends BasePresence {
16
+ type: "removal";
17
+ }
18
+ export interface UsaLock extends BasePresence {
19
+ type: "usa_lock";
20
+ }
21
+ export type Presences = Existence | Absence | Removal | UsaLock;
22
+ export interface Version {
23
+ /**
24
+ * Full name of the version.
25
+ * @example "maimai でらっくす PRiSM PLUS"
26
+ */
27
+ name: string;
28
+ /**
29
+ * Version number as it is used internally.
30
+ * Formatted as `{major}.{minor}.{patch}`.
31
+ *
32
+ * @example "1.40" for "1.40"
33
+ * @example "1.99" for "1.99"
34
+ * @example "2.41.7" for "DX1.41-G"
35
+ * @example "2.55.0" for "DX1.55"
36
+ */
37
+ gameVersion: {
38
+ /**
39
+ * maimai FiNALE and earlier: `1`
40
+ *
41
+ * maimai DX and later: `2`
42
+ */
43
+ major: number;
44
+ minor: number;
45
+ release?: number;
46
+ };
47
+ /**
48
+ * Events before maimai DX is always `DX`
49
+ */
50
+ region: "DX" | "EX" | "CN";
51
+ }
52
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=presence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presence.js","sourceRoot":"","sources":["../../src/maimai/presence.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export { Chart } from "./maimai/chart";
2
+ export { Database } from "./maimai/database";
3
+ export { Absence, Existence, Presences, Removal, Version, } from "./maimai/presence";
package/dist/maimai.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Database = void 0;
4
+ var database_1 = require("./maimai/database");
5
+ Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return database_1.Database; } });
6
+ //# sourceMappingURL=maimai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maimai.js","sourceRoot":"","sources":["../src/maimai.ts"],"names":[],"mappings":";;;AACA,6CAA4C;AAAnC,oGAAA,QAAQ,OAAA"}
@@ -0,0 +1,16 @@
1
+ import type { Chart as BaseChart } from "gcm-database/ongeki";
2
+ import type { Presences } from "./presence";
3
+ export interface Chart extends BaseChart {
4
+ optionalData: Partial<{
5
+ bpm: number[];
6
+ notes: {
7
+ tap: number;
8
+ hold: number;
9
+ side: number;
10
+ flick: number;
11
+ bell: number;
12
+ };
13
+ designer: string;
14
+ presences: Presences[];
15
+ }>;
16
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart.js","sourceRoot":"","sources":["../../src/ongeki/chart.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ import type { Database as BaseDatabase, Difficulty } from "gcm-database/ongeki";
2
+ import type { Chart } from "./chart";
3
+ export declare class Database implements BaseDatabase<Chart> {
4
+ private _localDatabasePath;
5
+ private readonly logger;
6
+ constructor(_localDatabasePath: string);
7
+ setLocalDatabasePath(path: string): boolean;
8
+ hasLocalDatabase(): boolean;
9
+ private cache;
10
+ getJacket(identifier: string, variant?: "DX" | "EX" | "CN"): Promise<{
11
+ data: Buffer<ArrayBuffer> | Buffer<any>;
12
+ err?: undefined;
13
+ } | {
14
+ err: string;
15
+ data?: undefined;
16
+ }>;
17
+ getChart(identifier: string, difficulty: Difficulty): Promise<{
18
+ data: any;
19
+ err?: undefined;
20
+ } | {
21
+ err: string;
22
+ data?: undefined;
23
+ }>;
24
+ private getAllCharts;
25
+ searchChart(payload: {
26
+ title: string;
27
+ level: number;
28
+ difficulty: Difficulty;
29
+ }, options?: Partial<{
30
+ maxResultCount: number;
31
+ }>): Promise<{
32
+ data: {
33
+ chart: Chart;
34
+ weight: number;
35
+ }[];
36
+ }>;
37
+ getBossCard(chart: Chart): Promise<{
38
+ data: Buffer<ArrayBuffer> | Buffer<any>;
39
+ err?: undefined;
40
+ } | {
41
+ err: string;
42
+ data?: undefined;
43
+ }>;
44
+ }
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Database = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const cache_1 = require("../lib/cache");
10
+ const getInternalLevelFromPresences_1 = require("../lib/getInternalLevelFromPresences");
11
+ const logger_1 = require("../lib/logger");
12
+ class Database {
13
+ _localDatabasePath;
14
+ logger = logger_1.logger
15
+ .child()
16
+ .withGroup("gcm-database-local/ongeki");
17
+ constructor(_localDatabasePath) {
18
+ this._localDatabasePath = _localDatabasePath;
19
+ }
20
+ setLocalDatabasePath(path) {
21
+ if (node_fs_1.default.existsSync(path)) {
22
+ this._localDatabasePath = path;
23
+ return true;
24
+ }
25
+ else {
26
+ return false;
27
+ }
28
+ }
29
+ hasLocalDatabase() {
30
+ return node_fs_1.default.existsSync(this._localDatabasePath);
31
+ }
32
+ cache = new cache_1.Cache("gcm-database-local/ongeki");
33
+ async getJacket(identifier, variant) {
34
+ const cacheKey = `jacket-${identifier}${variant ? `-${variant}` : ""}`;
35
+ const cached = await this.cache.get(cacheKey);
36
+ if (cached instanceof Buffer) {
37
+ return { data: cached };
38
+ }
39
+ else {
40
+ const songId = identifier.slice(-4);
41
+ if (variant) {
42
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "ongeki", "jackets", `${songId.padStart(6, "0")}-${variant}.png`);
43
+ if (node_fs_1.default.existsSync(localFilePath)) {
44
+ return { data: node_fs_1.default.readFileSync(localFilePath) };
45
+ }
46
+ }
47
+ // Falls back to normal jacket if a variant cannot be found.
48
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "ongeki", "jackets", `${songId.padStart(6, "0")}.png`);
49
+ const jacket = node_fs_1.default.existsSync(localFilePath) && node_fs_1.default.readFileSync(localFilePath);
50
+ if (jacket) {
51
+ this.cache.put(cacheKey, jacket, 5 * 1000); // 5 seconds.
52
+ return { data: jacket };
53
+ }
54
+ else {
55
+ return { err: `Cannot find the jacket of ${identifier}.` };
56
+ }
57
+ }
58
+ }
59
+ async getChart(identifier, difficulty) {
60
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "ongeki", "charts", `${identifier.padStart(6, "0")}`);
61
+ if (node_fs_1.default.existsSync(node_path_1.default.join(localFilePath, difficulty))) {
62
+ try {
63
+ return {
64
+ data: JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(localFilePath, difficulty), "utf-8")),
65
+ };
66
+ }
67
+ catch {
68
+ return {
69
+ err: `Failed to parse ${identifier} ${difficulty}.`,
70
+ };
71
+ }
72
+ }
73
+ return {
74
+ err: `Cannot find a chart with identifier ${identifier}.`,
75
+ };
76
+ }
77
+ async getAllCharts() {
78
+ const cached = await this.cache.get("all-charts");
79
+ if (cached)
80
+ return cached;
81
+ const localFolderPath = node_path_1.default.join(this._localDatabasePath, "assets", "ongeki", "charts");
82
+ const chartFolders = node_fs_1.default.readdirSync(localFolderPath);
83
+ const songs = [];
84
+ for (const folder of chartFolders) {
85
+ const charts = node_fs_1.default.readdirSync(node_path_1.default.join(localFolderPath, folder));
86
+ for (const chart of charts) {
87
+ try {
88
+ songs.push(require(node_path_1.default.join(localFolderPath, folder, chart)));
89
+ }
90
+ catch { }
91
+ }
92
+ }
93
+ await this.cache.put("all-charts", songs, 15 * 60 * 1000); // 15 minutes.
94
+ return songs;
95
+ }
96
+ async searchChart(payload, options) {
97
+ const allSongs = await this.getAllCharts();
98
+ const sortedCandidates = allSongs
99
+ .filter((v) => v.title === payload.title &&
100
+ v.difficulty === payload.difficulty)
101
+ .map((v) => {
102
+ if (v.optionalData.presences) {
103
+ const internalLevel = (0, getInternalLevelFromPresences_1.getInternalLevelFromPresences)(v.optionalData.presences);
104
+ if (internalLevel) {
105
+ return {
106
+ chart: v,
107
+ weight: Math.abs(internalLevel - payload.level),
108
+ };
109
+ }
110
+ }
111
+ return { chart: v };
112
+ })
113
+ .filter((v) => !!v.weight)
114
+ .sort((a, b) => a.weight - b.weight);
115
+ return { data: sortedCandidates.slice(options?.maxResultCount || 20) };
116
+ }
117
+ async getBossCard(chart) {
118
+ const identifier = chart.boss.character.card;
119
+ const cacheKey = `boss-card-${identifier}`;
120
+ const cached = await this.cache.get(cacheKey);
121
+ if (cached instanceof Buffer) {
122
+ this.logger.trace(`GET Card-${identifier}-image, cache HIT`);
123
+ return { data: cached };
124
+ }
125
+ else {
126
+ this.logger.trace(`GET Card-${identifier}-image, cache MISS`);
127
+ const localFilePath = node_path_1.default.join(this._localDatabasePath, "assets", "ongeki", "cards", "images", `${identifier.padStart(6, "0")}.png`);
128
+ if (node_fs_1.default.existsSync(localFilePath)) {
129
+ this.logger.trace(`GET Card-${identifier}-image, database HIT`);
130
+ const card = node_fs_1.default.readFileSync(localFilePath);
131
+ if (card)
132
+ this.cache.put(cacheKey, card, 5 * 1000); // 5 seconds
133
+ return { data: card };
134
+ }
135
+ }
136
+ return { err: "Cannot find the card of this character." };
137
+ }
138
+ }
139
+ exports.Database = Database;
140
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/ongeki/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ interface BasePresence {
2
+ type: string;
3
+ data?: unknown;
4
+ version: Version;
5
+ }
6
+ export interface Existence extends BasePresence {
7
+ type: "existence";
8
+ data: {
9
+ level: number;
10
+ };
11
+ }
12
+ export interface Absence extends BasePresence {
13
+ type: "absence";
14
+ }
15
+ export interface Removal extends BasePresence {
16
+ type: "removal";
17
+ }
18
+ export type Presences = Existence | Absence | Removal;
19
+ export interface Version {
20
+ /**
21
+ * Full name of the version.
22
+ * @example "オンゲキ Re:Fresh"
23
+ */
24
+ name: string;
25
+ /**
26
+ * Version number as it is used internally.
27
+ * Formatted as `{major}.{minor}.{patch}`.
28
+ */
29
+ gameVersion: {
30
+ major: number;
31
+ minor: number;
32
+ release?: number;
33
+ };
34
+ region: "JPN";
35
+ }
36
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=presence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presence.js","sourceRoot":"","sources":["../../src/ongeki/presence.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export { Chart } from "./ongeki/chart";
2
+ export { Database } from "./ongeki/database";
3
+ export { Absence, Existence, Presences, Removal, Version, } from "./ongeki/presence";
package/dist/ongeki.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Database = void 0;
4
+ var database_1 = require("./ongeki/database");
5
+ Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return database_1.Database; } });
6
+ //# sourceMappingURL=ongeki.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ongeki.js","sourceRoot":"","sources":["../src/ongeki.ts"],"names":[],"mappings":";;;AACA,6CAA4C;AAAnC,oGAAA,QAAQ,OAAA"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "gcm-database-local",
3
+ "version": "0.0.1",
4
+ "description": "A GekiChuMai Metadata database",
5
+ "homepage": "https://github.com/saltcute/gcm-database-local#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/saltcute/gcm-database-local/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/saltcute/gcm-database-local.git"
12
+ },
13
+ "license": "MIT",
14
+ "author": "saltcute",
15
+ "type": "commonjs",
16
+ "exports": {
17
+ "./maimai": "./dist/maimai.js",
18
+ "./chunithm": "./dist/chunithm.js",
19
+ "./ongeki": "./dist/ongeki.js"
20
+ },
21
+ "files": [
22
+ "dist/"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc && tsc-alias",
26
+ "clean": "rimraf dist/*",
27
+ "format": "biome format --write",
28
+ "lint": "biome lint --write",
29
+ "make": "npm run clean && npm run format && npm run lint && npm run build",
30
+ "test": "export LOG_LEVEL=debug && npm run make && node ./test/test.js"
31
+ },
32
+ "devDependencies": {
33
+ "@biomejs/biome": "^2.5.0",
34
+ "@types/memory-cache": "^0.2.6",
35
+ "@types/node": "^25.9.3",
36
+ "rimraf": "^6.1.3",
37
+ "tsc-alias": "^1.8.17",
38
+ "typescript": "^6.0.3"
39
+ },
40
+ "dependencies": {
41
+ "@loglayer/log-level-manager-global": "^2.2.0",
42
+ "@loglayer/transport-pino": "^3.2.0",
43
+ "loglayer": "^9.3.0",
44
+ "memory-cache": "^0.2.0",
45
+ "pino": "^10.3.1",
46
+ "redis": "^6.0.0"
47
+ },
48
+ "peerDependencies": {
49
+ "gcm-database": "^0.0.6"
50
+ }
51
+ }