osu-stable-db 0.1.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/README.md +141 -0
- package/dist/index.d.mts +15 -0
- package/dist/index.mjs +2 -0
- package/dist/node.d.mts +12 -0
- package/dist/node.mjs +23 -0
- package/dist/scores-7qsAMzUc.mjs +665 -0
- package/dist/types-DiZMN3fQ.d.mts +547 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# osu-stable-db
|
|
2
|
+
|
|
3
|
+
TypeScript reader and writer for osu!stable database files.
|
|
4
|
+
|
|
5
|
+
This library currently supports the latest database structure from version 20250107 onward for:
|
|
6
|
+
|
|
7
|
+
- osu!.db
|
|
8
|
+
- collection.db
|
|
9
|
+
- scores.db
|
|
10
|
+
|
|
11
|
+
The core binary and database logic is browser-compatible. A separate Node-only subpath is provided for direct file reads and writes.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
- Supports only 20250107 and later database structures
|
|
16
|
+
- Preserves null string semantics used by the stable database format
|
|
17
|
+
- Uses bigint for 64-bit values such as DateTime ticks
|
|
18
|
+
- Exposes byte-array database APIs from the main entry
|
|
19
|
+
- Exposes direct file APIs from the ./node subpath
|
|
20
|
+
|
|
21
|
+
Older stable database versions are intentionally out of scope.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add osu-stable-db
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Browser Usage
|
|
30
|
+
|
|
31
|
+
Use the main entry when you already have bytes in memory.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import {
|
|
35
|
+
readOsuDatabase,
|
|
36
|
+
writeCollectionDatabase,
|
|
37
|
+
type CollectionDatabase,
|
|
38
|
+
} from 'osu-stable-db'
|
|
39
|
+
|
|
40
|
+
const osuBytes: ArrayBuffer = bytesFromSomewhere
|
|
41
|
+
const osuDatabase = readOsuDatabase(osuBytes)
|
|
42
|
+
|
|
43
|
+
const collectionDatabase: CollectionDatabase = {
|
|
44
|
+
version: osuDatabase.version,
|
|
45
|
+
collections: [
|
|
46
|
+
{
|
|
47
|
+
name: 'Favorites',
|
|
48
|
+
beatmapMd5Hashes: ['d41d8cd98f00b204e9800998ecf8427e'],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const collectionBytes = writeCollectionDatabase(collectionDatabase)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Main entry exports:
|
|
57
|
+
|
|
58
|
+
- All public types and constants
|
|
59
|
+
- readOsuDatabase and writeOsuDatabase
|
|
60
|
+
- readCollectionDatabase and writeCollectionDatabase
|
|
61
|
+
- readScoresDatabase and writeScoresDatabase
|
|
62
|
+
|
|
63
|
+
## Node Usage
|
|
64
|
+
|
|
65
|
+
Use the Node subpath when you want direct file reads and writes through node:fs/promises.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import {
|
|
69
|
+
readOsuDatabaseFile,
|
|
70
|
+
writeCollectionDatabaseFile,
|
|
71
|
+
} from 'osu-stable-db/node'
|
|
72
|
+
|
|
73
|
+
const osuDatabase = await readOsuDatabaseFile('path/to/osu!.db')
|
|
74
|
+
|
|
75
|
+
await writeCollectionDatabaseFile(
|
|
76
|
+
'path/to/collection.db',
|
|
77
|
+
{
|
|
78
|
+
version: osuDatabase.version,
|
|
79
|
+
collections: [],
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Node subpath exports:
|
|
85
|
+
|
|
86
|
+
- readOsuDatabaseFile and writeOsuDatabaseFile
|
|
87
|
+
- readCollectionDatabaseFile and writeCollectionDatabaseFile
|
|
88
|
+
- readScoresDatabaseFile and writeScoresDatabaseFile
|
|
89
|
+
|
|
90
|
+
## Types And Time Values
|
|
91
|
+
|
|
92
|
+
- Date-like 64-bit values are exposed as DateTimeTicks, backed by bigint
|
|
93
|
+
- Helper functions for DateTimeTicks and mod flags live in [src/core/utils.ts](src/core/utils.ts)
|
|
94
|
+
|
|
95
|
+
JavaScript Date is not used as the storage type because it loses sub-millisecond tick precision.
|
|
96
|
+
|
|
97
|
+
## AI Disclosure
|
|
98
|
+
|
|
99
|
+
This project is 100% AI-generated.
|
|
100
|
+
|
|
101
|
+
## Tests And Fixtures
|
|
102
|
+
|
|
103
|
+
Committed minimal fixtures live in [tests/files](tests/files).
|
|
104
|
+
|
|
105
|
+
Large real-world local fixtures can be placed in:
|
|
106
|
+
|
|
107
|
+
- [tests/files/local](tests/files/local)
|
|
108
|
+
|
|
109
|
+
That directory is git-ignored. When those files are present, the test suite will:
|
|
110
|
+
|
|
111
|
+
- parse them
|
|
112
|
+
- verify byte-for-byte round-trip for osu!.db, collection.db, and scores.db
|
|
113
|
+
|
|
114
|
+
You can also generate a local inspection report for a specific beatmap identifier with:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
pnpm run local:inspect -- 5288868
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The generated report is written to:
|
|
121
|
+
|
|
122
|
+
- [tests/files/local/reports](tests/files/local/reports)
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pnpm install
|
|
128
|
+
pnpm run typecheck
|
|
129
|
+
pnpm test -- --run
|
|
130
|
+
pnpm run build
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Notes On Validation
|
|
134
|
+
|
|
135
|
+
Local validation also passes against private real-world database files in [tests/files/local](tests/files/local):
|
|
136
|
+
|
|
137
|
+
- osu!.db: 58,295,932 bytes, 72,038 beatmaps
|
|
138
|
+
- collection.db: 195,402 bytes, 11 collections, 5,743 stored beatmap references
|
|
139
|
+
- scores.db: 3,714,272 bytes, 11,331 beatmap score groups, 26,481 scores
|
|
140
|
+
|
|
141
|
+
Those local tests passed with parsing and byte-for-byte round-trip verification enabled.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { C as UserPermissionFlags, S as UserPermission, _ as ScoreAdditionalModInfo, a as GameplayMode, b as ScoresDatabase, c as Grades, d as Mod, f as ModFlags, g as RankedStatuses, h as RankedStatus, i as DateTimeTicks, l as IntFloatPair, m as OsuDatabase, n as CollectionDatabase, o as GameplayModes, p as Mods, r as CollectionEntry, s as Grade, t as BeatmapEntry, u as MINIMUM_SUPPORTED_VERSION, v as ScoreEntry, w as UserPermissions, x as TimingPoint, y as ScoresBeatmapEntry } from "./types-DiZMN3fQ.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/db/collection.d.ts
|
|
4
|
+
declare function readCollectionDatabase(input: ArrayBuffer | Uint8Array): CollectionDatabase;
|
|
5
|
+
declare function writeCollectionDatabase(database: CollectionDatabase): Uint8Array;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/db/osu.d.ts
|
|
8
|
+
declare function readOsuDatabase(input: ArrayBuffer | Uint8Array): OsuDatabase;
|
|
9
|
+
declare function writeOsuDatabase(database: OsuDatabase): Uint8Array;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/db/scores.d.ts
|
|
12
|
+
declare function readScoresDatabase(input: ArrayBuffer | Uint8Array): ScoresDatabase;
|
|
13
|
+
declare function writeScoresDatabase(database: ScoresDatabase): Uint8Array;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { BeatmapEntry, CollectionDatabase, CollectionEntry, DateTimeTicks, GameplayMode, GameplayModes, Grade, Grades, IntFloatPair, MINIMUM_SUPPORTED_VERSION, Mod, ModFlags, Mods, OsuDatabase, RankedStatus, RankedStatuses, ScoreAdditionalModInfo, ScoreEntry, ScoresBeatmapEntry, ScoresDatabase, TimingPoint, UserPermission, UserPermissionFlags, UserPermissions, readCollectionDatabase, readOsuDatabase, readScoresDatabase, writeCollectionDatabase, writeOsuDatabase, writeScoresDatabase };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as readCollectionDatabase, c as Grades, d as RankedStatuses, f as UserPermissions, i as writeOsuDatabase, l as MINIMUM_SUPPORTED_VERSION, n as writeScoresDatabase, o as writeCollectionDatabase, r as readOsuDatabase, s as GameplayModes, t as readScoresDatabase, u as Mods } from "./scores-7qsAMzUc.mjs";
|
|
2
|
+
export { GameplayModes, Grades, MINIMUM_SUPPORTED_VERSION, Mods, RankedStatuses, UserPermissions, readCollectionDatabase, readOsuDatabase, readScoresDatabase, writeCollectionDatabase, writeOsuDatabase, writeScoresDatabase };
|
package/dist/node.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { b as ScoresDatabase, m as OsuDatabase, n as CollectionDatabase } from "./types-DiZMN3fQ.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/node.d.ts
|
|
4
|
+
type DatabaseFilePath = string | URL;
|
|
5
|
+
declare function readOsuDatabaseFile(path: DatabaseFilePath): Promise<OsuDatabase>;
|
|
6
|
+
declare function writeOsuDatabaseFile(path: DatabaseFilePath, database: OsuDatabase): Promise<void>;
|
|
7
|
+
declare function readCollectionDatabaseFile(path: DatabaseFilePath): Promise<CollectionDatabase>;
|
|
8
|
+
declare function writeCollectionDatabaseFile(path: DatabaseFilePath, database: CollectionDatabase): Promise<void>;
|
|
9
|
+
declare function readScoresDatabaseFile(path: DatabaseFilePath): Promise<ScoresDatabase>;
|
|
10
|
+
declare function writeScoresDatabaseFile(path: DatabaseFilePath, database: ScoresDatabase): Promise<void>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { DatabaseFilePath, readCollectionDatabaseFile, readOsuDatabaseFile, readScoresDatabaseFile, writeCollectionDatabaseFile, writeOsuDatabaseFile, writeScoresDatabaseFile };
|
package/dist/node.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { a as readCollectionDatabase, i as writeOsuDatabase, n as writeScoresDatabase, o as writeCollectionDatabase, r as readOsuDatabase, t as readScoresDatabase } from "./scores-7qsAMzUc.mjs";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
//#region src/node.ts
|
|
4
|
+
async function readOsuDatabaseFile(path) {
|
|
5
|
+
return readOsuDatabase(new Uint8Array(await readFile(path)));
|
|
6
|
+
}
|
|
7
|
+
async function writeOsuDatabaseFile(path, database) {
|
|
8
|
+
await writeFile(path, writeOsuDatabase(database));
|
|
9
|
+
}
|
|
10
|
+
async function readCollectionDatabaseFile(path) {
|
|
11
|
+
return readCollectionDatabase(new Uint8Array(await readFile(path)));
|
|
12
|
+
}
|
|
13
|
+
async function writeCollectionDatabaseFile(path, database) {
|
|
14
|
+
await writeFile(path, writeCollectionDatabase(database));
|
|
15
|
+
}
|
|
16
|
+
async function readScoresDatabaseFile(path) {
|
|
17
|
+
return readScoresDatabase(new Uint8Array(await readFile(path)));
|
|
18
|
+
}
|
|
19
|
+
async function writeScoresDatabaseFile(path, database) {
|
|
20
|
+
await writeFile(path, writeScoresDatabase(database));
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { readCollectionDatabaseFile, readOsuDatabaseFile, readScoresDatabaseFile, writeCollectionDatabaseFile, writeOsuDatabaseFile, writeScoresDatabaseFile };
|