@randomplay/data 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.
- package/LICENSE +21 -0
- package/README.md +26 -0
- package/cleaned/audit/mihoyo-buhflipexplode.source-conflicts.json +282 -0
- package/cleaned/audit/nicole.acceptance.json +45 -0
- package/cleaned/audit/v1-agent-source-candidates.json +467 -0
- package/cleaned/audit/yanagi.acceptance.json +102 -0
- package/cleaned/golden/v1-replay-report.json +399 -0
- package/dist/index.d.mts +173 -0
- package/dist/index.mjs +223 -0
- package/dist/source-manifest-pBseE3aE.d.mts +41 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +1 -0
- package/package.json +53 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { parseGameData, sourceDocumentSchema, sourceRefSchema } from "@randomplay/core";
|
|
2
|
+
//#region src/adapters.ts
|
|
3
|
+
function createDiscoveryOnlyAdapter(descriptor) {
|
|
4
|
+
return {
|
|
5
|
+
sourceId: descriptor.id,
|
|
6
|
+
async fetch() {
|
|
7
|
+
throw new Error(`Data source ${descriptor.id} is discovery-only; implement a real fetcher after source review.`);
|
|
8
|
+
},
|
|
9
|
+
async parse() {
|
|
10
|
+
return {
|
|
11
|
+
sourceId: descriptor.id,
|
|
12
|
+
sourceVersion: "discovery-only",
|
|
13
|
+
formalDataReady: false,
|
|
14
|
+
records: [],
|
|
15
|
+
notes: ["No formal data was parsed because this adapter is a skeleton."]
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/ingest.ts
|
|
22
|
+
function createEmptyGameData(options) {
|
|
23
|
+
return parseGameData({
|
|
24
|
+
schemaVersion: options.schemaVersion ?? "game-data-v1",
|
|
25
|
+
gameVersion: options.gameVersion,
|
|
26
|
+
dataVersion: options.dataVersion,
|
|
27
|
+
sourceVersion: options.sourceVersion,
|
|
28
|
+
generatedAt: options.generatedAt,
|
|
29
|
+
sources: [...options.sources],
|
|
30
|
+
agents: {},
|
|
31
|
+
skills: {},
|
|
32
|
+
wEngines: {},
|
|
33
|
+
driveDiscs: {},
|
|
34
|
+
enemies: {},
|
|
35
|
+
resonium: {},
|
|
36
|
+
modifiers: {},
|
|
37
|
+
rules: {},
|
|
38
|
+
aliases: {
|
|
39
|
+
fields: {},
|
|
40
|
+
enumValues: {},
|
|
41
|
+
sourceTerms: {}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function assertDiscoveryOnlyGameData(gameData) {
|
|
46
|
+
const formalRecordCounts = {
|
|
47
|
+
agents: Object.keys(gameData.agents).length,
|
|
48
|
+
skills: Object.keys(gameData.skills).length,
|
|
49
|
+
wEngines: Object.keys(gameData.wEngines).length,
|
|
50
|
+
driveDiscs: Object.keys(gameData.driveDiscs).length,
|
|
51
|
+
enemies: Object.keys(gameData.enemies).length,
|
|
52
|
+
resonium: Object.keys(gameData.resonium).length,
|
|
53
|
+
modifiers: Object.keys(gameData.modifiers).length,
|
|
54
|
+
rules: Object.keys(gameData.rules).length,
|
|
55
|
+
"aliases.fields": Object.keys(gameData.aliases.fields).length,
|
|
56
|
+
"aliases.enumValues": Object.keys(gameData.aliases.enumValues).length,
|
|
57
|
+
"aliases.sourceTerms": Object.keys(gameData.aliases.sourceTerms).length
|
|
58
|
+
};
|
|
59
|
+
const populated = Object.entries(formalRecordCounts).filter(([, count]) => count > 0);
|
|
60
|
+
if (populated.length > 0) {
|
|
61
|
+
const details = populated.map(([name, count]) => `${name}=${count}`).join(", ");
|
|
62
|
+
throw new Error(`Discovery-only GameData must not contain formal data: ${details}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/metadata.ts
|
|
67
|
+
const DATA_SOURCE_SKELETON_PARSER_VERSION = "@randomplay/data-source-skeleton-v0.1.0";
|
|
68
|
+
function buildSourceDocument(descriptor, options) {
|
|
69
|
+
const candidate = {
|
|
70
|
+
id: descriptor.id,
|
|
71
|
+
kind: descriptor.kind,
|
|
72
|
+
sourceVersion: options.sourceVersion,
|
|
73
|
+
parsedAt: options.parsedAt,
|
|
74
|
+
parserVersion: options.parserVersion ?? "@randomplay/data-source-skeleton-v0.1.0"
|
|
75
|
+
};
|
|
76
|
+
if (descriptor.url !== void 0) candidate.url = descriptor.url;
|
|
77
|
+
if (options.fileName !== void 0) candidate.fileName = options.fileName;
|
|
78
|
+
if (options.gameVersion !== void 0) candidate.gameVersion = options.gameVersion;
|
|
79
|
+
if (options.fetchedAt !== void 0) candidate.fetchedAt = options.fetchedAt;
|
|
80
|
+
if (options.licenseNote !== void 0) candidate.licenseNote = options.licenseNote;
|
|
81
|
+
return sourceDocumentSchema.parse(candidate);
|
|
82
|
+
}
|
|
83
|
+
function buildSourceRef(descriptor, options = {}) {
|
|
84
|
+
const candidate = { sourceId: descriptor.id };
|
|
85
|
+
if (options.sourceVersion !== void 0) candidate.sourceVersion = options.sourceVersion;
|
|
86
|
+
if (options.sourceAnchor !== void 0) candidate.sourceAnchor = options.sourceAnchor;
|
|
87
|
+
if (options.dataPath !== void 0) candidate.dataPath = options.dataPath;
|
|
88
|
+
return sourceRefSchema.parse(candidate);
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/sources.ts
|
|
92
|
+
const dataSourceDescriptors = [
|
|
93
|
+
{
|
|
94
|
+
id: "lo-user-excel",
|
|
95
|
+
kind: "excel",
|
|
96
|
+
label: "lo-user provided ZZZ data workbook",
|
|
97
|
+
fileNameHint: "data/source/excel/data.xlsx",
|
|
98
|
+
status: "readyForAdapter",
|
|
99
|
+
formalDataReady: false,
|
|
100
|
+
parserTargets: [
|
|
101
|
+
"agent skill multipliers",
|
|
102
|
+
"daze multipliers",
|
|
103
|
+
"W-Engine passives",
|
|
104
|
+
"Drive Disc set effects",
|
|
105
|
+
"agent enhancement / potential activation fields"
|
|
106
|
+
],
|
|
107
|
+
sourceVersionStrategy: "Use the retained workbook hash plus the workbook-provided version marker from 首页!A1.",
|
|
108
|
+
discoveredAssets: [
|
|
109
|
+
"data/source/excel/data.xlsx",
|
|
110
|
+
"data/source/excel/META.md",
|
|
111
|
+
"data/source/excel/workbook-audit.json"
|
|
112
|
+
],
|
|
113
|
+
fetchPolicy: {
|
|
114
|
+
mode: "manualUpload",
|
|
115
|
+
maxRequestsPerMinute: 0,
|
|
116
|
+
cacheRequired: true,
|
|
117
|
+
conditionalRequestsPreferred: false,
|
|
118
|
+
requiresUserAgent: false
|
|
119
|
+
},
|
|
120
|
+
compliance: {
|
|
121
|
+
robotsTxt: "notApplicable",
|
|
122
|
+
termsStatus: "requiresHumanReview",
|
|
123
|
+
redistribution: "cleanedDataOnly",
|
|
124
|
+
notes: [
|
|
125
|
+
"The workbook is retained in git under data/source/excel/ as a raw/source archive.",
|
|
126
|
+
"The workbook and derived audit artifacts must not be published in the @randomplay/data package.",
|
|
127
|
+
"Use workbook-audit.json for sheet/column discovery; do not infer typed modifiers from text without deterministic parser support or manual acceptance."
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: "mihoyo-zzz-critical-assault",
|
|
133
|
+
kind: "mihoyoWiki",
|
|
134
|
+
label: "Mihoyo ZZZ wiki Critical Assault map",
|
|
135
|
+
url: "https://baike.mihoyo.com/zzz/wiki/channel/map/13/108",
|
|
136
|
+
status: "readyForAdapter",
|
|
137
|
+
formalDataReady: false,
|
|
138
|
+
parserTargets: [
|
|
139
|
+
"Deadly Assault period list",
|
|
140
|
+
"three selectable period buffs",
|
|
141
|
+
"three boss room detail texts and challenge targets",
|
|
142
|
+
"official Chinese labels and descriptions",
|
|
143
|
+
"Mihoyo/buhflipexplode zh/en source-text anchors"
|
|
144
|
+
],
|
|
145
|
+
sourceVersionStrategy: "Use the retained snapshot id plus fetch-manifest hashes for the channel and entry_page API payloads.",
|
|
146
|
+
discoveredAssets: [
|
|
147
|
+
"data/source/raw/mihoyo/zzz-da/2026-05-05T0850Z/channel-108/periods.json",
|
|
148
|
+
"data/source/raw/mihoyo/zzz-da/2026-05-05T0850Z/parsed/period-details.json",
|
|
149
|
+
"data/source/raw/mihoyo/zzz-da/2026-05-05T0850Z/alignment/mihoyo-buhflipexplode.json",
|
|
150
|
+
"data/source/raw/mihoyo/zzz-da/2026-05-05T0850Z/fetch-manifest.json"
|
|
151
|
+
],
|
|
152
|
+
fetchPolicy: {
|
|
153
|
+
mode: "httpGet",
|
|
154
|
+
maxRequestsPerMinute: 12,
|
|
155
|
+
cacheRequired: true,
|
|
156
|
+
conditionalRequestsPreferred: true,
|
|
157
|
+
requiresUserAgent: true
|
|
158
|
+
},
|
|
159
|
+
compliance: {
|
|
160
|
+
robotsTxt: "notFound",
|
|
161
|
+
termsStatus: "requiresHumanReview",
|
|
162
|
+
redistribution: "cleanedDataOnly",
|
|
163
|
+
notes: [
|
|
164
|
+
"robots.txt returned HTTP 404 on 2026-05-05.",
|
|
165
|
+
"The target page returned HTTP 200 with cache-control max-age=300.",
|
|
166
|
+
"The rendered Nuxt page shell does not contain detail content; use public JSON API payloads and parse embedded rich-text HTML fragments.",
|
|
167
|
+
"entry_page requests must include x-rpc-wiki_app: zzz to avoid cross-namespace content_id collisions.",
|
|
168
|
+
"Do not crawl authenticated or private APIs; use public wiki responses only."
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "buhflipexplode-zzz-da",
|
|
174
|
+
kind: "thirdPartySite",
|
|
175
|
+
label: "buhflipexplode Deadly Assault data",
|
|
176
|
+
url: "https://www.buhflipexplode.org/zzz/da/",
|
|
177
|
+
status: "readyForAdapter",
|
|
178
|
+
formalDataReady: false,
|
|
179
|
+
parserTargets: [
|
|
180
|
+
"deadly assault version entries",
|
|
181
|
+
"enemy HP/daze/anomaly multipliers",
|
|
182
|
+
"boss buff metadata",
|
|
183
|
+
"Deadly Assault score / HP display algorithm evidence",
|
|
184
|
+
"algorithm drift manifest"
|
|
185
|
+
],
|
|
186
|
+
sourceVersionStrategy: "Use the accepted raw snapshot id plus fetch-manifest and algorithm-manifest hashes.",
|
|
187
|
+
discoveredAssets: [
|
|
188
|
+
"data/source/raw/buhflipexplode/2026-05-05T0445Z/da/da-versions.live.json",
|
|
189
|
+
"data/source/raw/buhflipexplode/2026-05-05T0445Z/assets/zzz/enemies.live.json",
|
|
190
|
+
"data/source/raw/buhflipexplode/2026-05-05T0445Z/assets/zzz/buffs.live.json",
|
|
191
|
+
"data/source/raw/buhflipexplode/2026-05-05T0445Z/da/da.js",
|
|
192
|
+
"data/source/raw/buhflipexplode/2026-05-05T0445Z/algorithm-manifest.json"
|
|
193
|
+
],
|
|
194
|
+
fetchPolicy: {
|
|
195
|
+
mode: "httpGet",
|
|
196
|
+
maxRequestsPerMinute: 12,
|
|
197
|
+
cacheRequired: true,
|
|
198
|
+
conditionalRequestsPreferred: true,
|
|
199
|
+
requiresUserAgent: true
|
|
200
|
+
},
|
|
201
|
+
compliance: {
|
|
202
|
+
robotsTxt: "notFound",
|
|
203
|
+
termsStatus: "requiresHumanReview",
|
|
204
|
+
redistribution: "cleanedDataOnly",
|
|
205
|
+
notes: [
|
|
206
|
+
"robots.txt returned HTTP 404 on 2026-05-05.",
|
|
207
|
+
"The site describes itself as fan-created and non-commercial.",
|
|
208
|
+
"The about page links source code at https://github.com/spiritfxxxx/buhflipexplode-src.",
|
|
209
|
+
"The source repository has a GPL-3.0 LICENSE for code; do not copy GPL JS into Fairy runtime packages.",
|
|
210
|
+
"The about page says most images/data are officially sourced from in-game and public fandoms.",
|
|
211
|
+
"D-12 locks option B: retain GPL JS for audit only; runtime implementation must remain independent MIT code.",
|
|
212
|
+
"Retained JSON payloads are filtered to live versions only; non-live / beta / leaks config is excluded."
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
];
|
|
217
|
+
function getDataSourceDescriptor(id) {
|
|
218
|
+
const descriptor = dataSourceDescriptors.find((source) => source.id === id);
|
|
219
|
+
if (descriptor === void 0) throw new Error(`Unknown data source descriptor: ${id}`);
|
|
220
|
+
return descriptor;
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
export { DATA_SOURCE_SKELETON_PARSER_VERSION, assertDiscoveryOnlyGameData, buildSourceDocument, buildSourceRef, createDiscoveryOnlyAdapter, createEmptyGameData, dataSourceDescriptors, getDataSourceDescriptor };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { GameData } from "@randomplay/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types/cleaned-data.d.ts
|
|
4
|
+
type CleanedDataKind = "gameData" | "gameLabelI18n" | "sourceManifest";
|
|
5
|
+
interface CleanedDataArtifact<TData = unknown> {
|
|
6
|
+
kind: CleanedDataKind;
|
|
7
|
+
schemaVersion: string;
|
|
8
|
+
dataVersion: string;
|
|
9
|
+
generatedAt: string;
|
|
10
|
+
sourceManifestPath: string;
|
|
11
|
+
data: TData;
|
|
12
|
+
}
|
|
13
|
+
type CleanedGameDataArtifact = CleanedDataArtifact<GameData>;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/types/source-manifest.d.ts
|
|
16
|
+
interface DistributionPolicy {
|
|
17
|
+
rawSourceArchive: "versioned-in-git-not-packaged";
|
|
18
|
+
publishedArtifacts: "cleaned-json-and-types-only";
|
|
19
|
+
}
|
|
20
|
+
interface SourceManifestEntry {
|
|
21
|
+
id: string;
|
|
22
|
+
kind: "excel" | "referenceGuide" | "rawHttpSnapshot";
|
|
23
|
+
path: string;
|
|
24
|
+
sha256: string;
|
|
25
|
+
bytes: number;
|
|
26
|
+
receivedAt?: string;
|
|
27
|
+
fetchedAt?: string;
|
|
28
|
+
providedBy?: string;
|
|
29
|
+
attachmentId?: string;
|
|
30
|
+
metadataPath?: string;
|
|
31
|
+
distribution: "raw-retained-not-packaged" | "reference-retained-not-packaged" | "cleaned-publishable";
|
|
32
|
+
usage: string;
|
|
33
|
+
}
|
|
34
|
+
interface SourceManifest {
|
|
35
|
+
schemaVersion: "source-manifest-v1";
|
|
36
|
+
generatedAt: string;
|
|
37
|
+
distributionPolicy: DistributionPolicy;
|
|
38
|
+
sources: SourceManifestEntry[];
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { CleanedDataKind as a, CleanedDataArtifact as i, SourceManifest as n, CleanedGameDataArtifact as o, SourceManifestEntry as r, DistributionPolicy as t };
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as CleanedDataKind, i as CleanedDataArtifact, n as SourceManifest, o as CleanedGameDataArtifact, r as SourceManifestEntry, t as DistributionPolicy } from "./source-manifest-pBseE3aE.mjs";
|
|
2
|
+
export { CleanedDataArtifact, CleanedDataKind, CleanedGameDataArtifact, DistributionPolicy, SourceManifest, SourceManifestEntry };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@randomplay/data",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/LoTwT/fairy.git",
|
|
9
|
+
"directory": "packages/data"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"import": "./dist/index.mjs"
|
|
15
|
+
},
|
|
16
|
+
"./types": {
|
|
17
|
+
"types": "./dist/types.d.mts",
|
|
18
|
+
"import": "./dist/types.mjs"
|
|
19
|
+
},
|
|
20
|
+
"./cleaned/*": "./cleaned/*"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"cleaned",
|
|
25
|
+
"README.md",
|
|
26
|
+
"package.json"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@randomplay/core": "0.0.1"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"cheerio": "^1.2.0",
|
|
36
|
+
"tsx": "^4.21.0",
|
|
37
|
+
"xlsx": "^0.18.5"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"audit:excel": "node scripts/excel-source.mjs audit --generated-at 2026-05-05T17:40:00+08:00",
|
|
41
|
+
"audit:golden-v1": "tsx scripts/golden-v1-replay.ts audit --generated-at 2026-05-05T18:20:00+08:00",
|
|
42
|
+
"build": "tsdown src/index.ts src/types.ts --format esm --dts --clean --out-dir dist",
|
|
43
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
44
|
+
"fetch:buhflipexplode-da": "node scripts/buhflipexplode-da-source.mjs fetch",
|
|
45
|
+
"fetch:mihoyo-da": "node scripts/mihoyo-da-source.mjs fetch",
|
|
46
|
+
"sync-cleaned": "node scripts/sync-cleaned.mjs",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"verify:buhflipexplode-da": "node scripts/buhflipexplode-da-source.mjs verify --snapshot 2026-05-05T0445Z",
|
|
49
|
+
"verify:excel": "node scripts/excel-source.mjs verify",
|
|
50
|
+
"verify:golden-v1": "tsx scripts/golden-v1-replay.ts verify",
|
|
51
|
+
"verify:mihoyo-da": "node scripts/mihoyo-da-source.mjs verify --snapshot 2026-05-05T0850Z"
|
|
52
|
+
}
|
|
53
|
+
}
|