@linxin666/dsh-pet 0.2.2 → 0.2.3
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.i18n.yaml +2 -2
- package/README.md +66 -3
- package/README.zh.md +66 -3
- package/assets/whale/pet.json +169 -20
- package/assets/whale-refined/pet.json +17 -2
- package/lib/client.js +438 -21
- package/lib/client.js.map +1 -1
- package/lib/index.js +752 -36
- package/lib/live2d-vendor.js +995 -0
- package/lib/live2d-vendor.js.map +1 -0
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +2 -1
- package/lib/types/client/PetSettingsCard.d.ts +10 -0
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +22 -1
- package/lib/types/client/PetSprite.d.ts +7 -1
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +17 -8
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +5 -0
- package/lib/types/client/locales.d.ts +10 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +10 -0
- package/lib/types/client/phase-stream.d.ts +22 -0
- package/lib/types/client/phase-stream.d.ts.map +1 -0
- package/lib/types/client/phase-stream.js +28 -0
- package/lib/types/client/renderers/PetRendererSwitch.d.ts +25 -0
- package/lib/types/client/renderers/PetRendererSwitch.d.ts.map +1 -0
- package/lib/types/client/renderers/PetRendererSwitch.js +24 -0
- package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts +22 -0
- package/lib/types/client/renderers/live2d/Live2dVisualMount.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d/Live2dVisualMount.js +75 -0
- package/lib/types/client/renderers/live2d/runtime.d.ts +89 -0
- package/lib/types/client/renderers/live2d/runtime.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d/runtime.js +63 -0
- package/lib/types/client/renderers/live2d/vendor-entry.d.ts +15 -0
- package/lib/types/client/renderers/live2d/vendor-entry.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d/vendor-entry.js +14 -0
- package/lib/types/client/renderers/live2d.d.ts +52 -0
- package/lib/types/client/renderers/live2d.d.ts.map +1 -0
- package/lib/types/client/renderers/live2d.js +180 -0
- package/lib/types/client/renderers/registry.d.ts +32 -0
- package/lib/types/client/renderers/registry.d.ts.map +1 -0
- package/lib/types/client/renderers/registry.js +49 -0
- package/lib/types/contracts/renderer.d.ts +50 -0
- package/lib/types/contracts/renderer.d.ts.map +1 -0
- package/lib/types/contracts/renderer.js +15 -0
- package/lib/types/manifest-v2.d.ts +129 -0
- package/lib/types/manifest-v2.d.ts.map +1 -0
- package/lib/types/manifest-v2.js +387 -0
- package/lib/types/model3.d.ts +26 -0
- package/lib/types/model3.d.ts.map +1 -0
- package/lib/types/model3.js +96 -0
- package/lib/types/registry.d.ts +57 -3
- package/lib/types/registry.d.ts.map +1 -1
- package/lib/types/registry.js +208 -33
- package/lib/types/routes.d.ts +39 -2
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +183 -12
- package/lib/types/service.d.ts +5 -1
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +4 -0
- package/package.json +3 -1
- package/src/client/PetDockEntry.tsx +19 -11
- package/src/client/PetSettingsCard.tsx +39 -0
- package/src/client/PetSprite.test.tsx +11 -0
- package/src/client/PetSprite.tsx +24 -9
- package/src/client/index.ts +6 -0
- package/src/client/locales.ts +10 -0
- package/src/client/phase-stream.test.ts +76 -0
- package/src/client/phase-stream.ts +39 -0
- package/src/client/renderers/PetRendererSwitch.test.tsx +66 -0
- package/src/client/renderers/PetRendererSwitch.tsx +48 -0
- package/src/client/renderers/live2d/Live2dVisualMount.tsx +98 -0
- package/src/client/renderers/live2d/runtime.test.ts +61 -0
- package/src/client/renderers/live2d/runtime.ts +119 -0
- package/src/client/renderers/live2d/vendor-entry.ts +14 -0
- package/src/client/renderers/live2d.test.ts +242 -0
- package/src/client/renderers/live2d.ts +218 -0
- package/src/client/renderers/registry.ts +58 -0
- package/src/client/settings-section.module.css +23 -0
- package/src/contracts/renderer.ts +54 -0
- package/src/manifest-v2.test.ts +251 -0
- package/src/manifest-v2.ts +414 -0
- package/src/model3.test.ts +79 -0
- package/src/model3.ts +91 -0
- package/src/registry.test.ts +215 -2
- package/src/registry.ts +246 -34
- package/src/routes.ts +202 -13
- package/src/service.ts +6 -0
package/lib/types/registry.d.ts
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pet registry — the multi-pet contract. One pet is a directory holding a
|
|
3
3
|
* 'pet.json' manifest plus an atlas image; nothing else is required, and no
|
|
4
|
-
* host or client code changes when a pet is added. The registry scans
|
|
4
|
+
* host or client code changes when a pet is added. The registry scans four
|
|
5
5
|
* sources, later sources overriding earlier ones on an id collision:
|
|
6
6
|
*
|
|
7
7
|
* 1. the package's own 'assets' subdirectories (built-in pets);
|
|
8
|
-
* 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets
|
|
9
|
-
*
|
|
8
|
+
* 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets,
|
|
9
|
+
* legacy source kept readable);
|
|
10
|
+
* 3. '$DSH_HOME/pets' subdirectories (the pet-center user directory);
|
|
11
|
+
* 4. 'PetConfig.pets' manifests composed by the embedding application
|
|
10
12
|
* (highest precedence).
|
|
11
13
|
*
|
|
14
|
+
* Manifests are parsed through manifest-v2 (pet-center M2, issue #623): v1
|
|
15
|
+
* manifests are compat-read as sprite2d, v2 manifests validate fail-closed,
|
|
16
|
+
* and structured diagnostics ride alongside the legacy warnings. Live2d
|
|
17
|
+
* entries (pet-center M3) list like any other pet: the entry carries the
|
|
18
|
+
* validated live2d block plus the model's reference closure (the servable
|
|
19
|
+
* set the asset route allows), and a model3.json that is unreadable or
|
|
20
|
+
* declares unsafe references rejects the entry with an error diagnostic.
|
|
21
|
+
*
|
|
12
22
|
* The manifest follows the Codex/hatch-pet contract (8 columns x 9 rows of
|
|
13
23
|
* 192x208 cells, the 9-state row order below). Legacy whale-girl manifests
|
|
14
24
|
* that only carry 'frames' keep working: geometry, per-row frame counts and
|
|
@@ -18,6 +28,7 @@
|
|
|
18
28
|
*/
|
|
19
29
|
import type { ActivityPhase, PetAnimation } from './state.ts';
|
|
20
30
|
import { type PetRemarks, type PetRemarksManifest } from './remarks.ts';
|
|
31
|
+
import { type PetRendererKind } from './manifest-v2.ts';
|
|
21
32
|
/** Fixed row order of the 9-state animation contract. */
|
|
22
33
|
export declare const PET_ROW_ORDER: readonly PetAnimation[];
|
|
23
34
|
/** Atlas cell size in px. */
|
|
@@ -100,11 +111,37 @@ export interface PetTrackOverride {
|
|
|
100
111
|
/** Track to switch to after a non-looping track finishes. */
|
|
101
112
|
fallback?: PetAnimation;
|
|
102
113
|
}
|
|
114
|
+
/** The live2d renderer block as served to the browser half (pet-center M3). */
|
|
115
|
+
export interface PetLive2dDefinition {
|
|
116
|
+
/** Browser URL of the .model3.json (served by the host asset route). */
|
|
117
|
+
modelUrl: string;
|
|
118
|
+
/** Manifest-relative model path (host route allow-list key). */
|
|
119
|
+
modelPath: string;
|
|
120
|
+
/** Scale multiplier over the canvas auto-fit, (0, 10]. */
|
|
121
|
+
scale?: number;
|
|
122
|
+
/** Model offset in canvas px from the center-bottom anchor. */
|
|
123
|
+
translate?: {
|
|
124
|
+
x?: number;
|
|
125
|
+
y?: number;
|
|
126
|
+
};
|
|
127
|
+
/** ActivityPhase -> motion group; unmapped phases fall back to idle. */
|
|
128
|
+
motions: Partial<Record<ActivityPhase, string>> & {
|
|
129
|
+
idle: string;
|
|
130
|
+
};
|
|
131
|
+
/** Optional ActivityPhase -> expression name layered over the motion. */
|
|
132
|
+
expressions?: Partial<Record<ActivityPhase, string>>;
|
|
133
|
+
/** Hit area names triggering the tap motion; defaults to every model HitArea. */
|
|
134
|
+
hitAreas?: string[];
|
|
135
|
+
}
|
|
103
136
|
/** A normalized pet as served to the browser half. */
|
|
104
137
|
export interface PetDefinition {
|
|
105
138
|
id: string;
|
|
106
139
|
displayName: string;
|
|
107
140
|
description: string;
|
|
141
|
+
/** The renderer this entry mounts with (pet-center M2). */
|
|
142
|
+
renderer: PetRendererKind;
|
|
143
|
+
/** Live2d render block; present exactly when renderer is 'live2d' (M3). */
|
|
144
|
+
live2d?: PetLive2dDefinition;
|
|
108
145
|
/** Atlas cell size in px. */
|
|
109
146
|
cell: PetCell;
|
|
110
147
|
/** Columns per row. */
|
|
@@ -128,6 +165,12 @@ export interface PetEntry extends PetDefinition {
|
|
|
128
165
|
dir: string;
|
|
129
166
|
/** Atlas path relative to 'dir' (declared by the manifest). */
|
|
130
167
|
spritesheetPath: string;
|
|
168
|
+
/**
|
|
169
|
+
* Manifest-relative files the asset route may serve beyond pet.json and
|
|
170
|
+
* 'previews/*' (pet-center M3): the sprite2d atlas, or the live2d model
|
|
171
|
+
* plus its model3.json reference closure.
|
|
172
|
+
*/
|
|
173
|
+
servable: readonly string[];
|
|
131
174
|
/** Normalized per-pet remark pools (manifest 'remarks'), when declared. */
|
|
132
175
|
remarks?: PetRemarks;
|
|
133
176
|
}
|
|
@@ -135,10 +178,19 @@ export interface PetEntry extends PetDefinition {
|
|
|
135
178
|
export interface PetRegistry {
|
|
136
179
|
entries: PetEntry[];
|
|
137
180
|
warnings: string[];
|
|
181
|
+
/** Structured diagnostics from the manifest-v2 parse (superset detail of warnings). */
|
|
182
|
+
diagnostics: PetRegistryDiagnostic[];
|
|
138
183
|
byId(id: string): PetEntry | undefined;
|
|
139
184
|
/** The pet an installation falls back to when the selection is unknown. */
|
|
140
185
|
defaultEntry(): PetEntry;
|
|
141
186
|
}
|
|
187
|
+
/** One structured registry diagnostic (manifest-v2 era). */
|
|
188
|
+
export interface PetRegistryDiagnostic {
|
|
189
|
+
level: 'error' | 'warning';
|
|
190
|
+
/** Where the diagnostic originates (directory or file). */
|
|
191
|
+
source: string;
|
|
192
|
+
message: string;
|
|
193
|
+
}
|
|
142
194
|
/** Registry sources. */
|
|
143
195
|
export interface PetRegistryOptions {
|
|
144
196
|
/** Absolute package root whose 'assets/*' hold built-in pets. */
|
|
@@ -147,6 +199,8 @@ export interface PetRegistryOptions {
|
|
|
147
199
|
assetPrefix?: string;
|
|
148
200
|
/** Custom pet directory (defaults to '${CODEX_HOME:-~/.codex}/pets'). */
|
|
149
201
|
petsDir?: string;
|
|
202
|
+
/** Pet-center user directory (defaults to '$DSH_HOME/pets'; '' disables). */
|
|
203
|
+
dshPetsDir?: string;
|
|
150
204
|
/** Extra manifest entries composed by the embedding application. */
|
|
151
205
|
extra?: readonly PetManifest[];
|
|
152
206
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"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"}
|
package/lib/types/registry.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pet registry — the multi-pet contract. One pet is a directory holding a
|
|
3
3
|
* 'pet.json' manifest plus an atlas image; nothing else is required, and no
|
|
4
|
-
* host or client code changes when a pet is added. The registry scans
|
|
4
|
+
* host or client code changes when a pet is added. The registry scans four
|
|
5
5
|
* sources, later sources overriding earlier ones on an id collision:
|
|
6
6
|
*
|
|
7
7
|
* 1. the package's own 'assets' subdirectories (built-in pets);
|
|
8
|
-
* 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets
|
|
9
|
-
*
|
|
8
|
+
* 2. '${CODEX_HOME:-~/.codex}/pets' subdirectories (hatch-pet custom pets,
|
|
9
|
+
* legacy source kept readable);
|
|
10
|
+
* 3. '$DSH_HOME/pets' subdirectories (the pet-center user directory);
|
|
11
|
+
* 4. 'PetConfig.pets' manifests composed by the embedding application
|
|
10
12
|
* (highest precedence).
|
|
11
13
|
*
|
|
14
|
+
* Manifests are parsed through manifest-v2 (pet-center M2, issue #623): v1
|
|
15
|
+
* manifests are compat-read as sprite2d, v2 manifests validate fail-closed,
|
|
16
|
+
* and structured diagnostics ride alongside the legacy warnings. Live2d
|
|
17
|
+
* entries (pet-center M3) list like any other pet: the entry carries the
|
|
18
|
+
* validated live2d block plus the model's reference closure (the servable
|
|
19
|
+
* set the asset route allows), and a model3.json that is unreadable or
|
|
20
|
+
* declares unsafe references rejects the entry with an error diagnostic.
|
|
21
|
+
*
|
|
12
22
|
* The manifest follows the Codex/hatch-pet contract (8 columns x 9 rows of
|
|
13
23
|
* 192x208 cells, the 9-state row order below). Legacy whale-girl manifests
|
|
14
24
|
* that only carry 'frames' keep working: geometry, per-row frame counts and
|
|
@@ -21,6 +31,9 @@ import { homedir } from 'node:os';
|
|
|
21
31
|
import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
|
|
22
32
|
import { fileURLToPath } from 'node:url';
|
|
23
33
|
import { normalizePetRemarks } from './remarks.js';
|
|
34
|
+
import { dshHome } from './dsh-home.js';
|
|
35
|
+
import { parsePetManifest } from './manifest-v2.js';
|
|
36
|
+
import { collectModel3References } from './model3.js';
|
|
24
37
|
/** Fixed row order of the 9-state animation contract. */
|
|
25
38
|
export const PET_ROW_ORDER = [
|
|
26
39
|
'idle',
|
|
@@ -115,6 +128,41 @@ function normalizeSequences(raw, id, warn) {
|
|
|
115
128
|
}
|
|
116
129
|
return Object.keys(sequences).length === 0 ? undefined : sequences;
|
|
117
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Build the fully resolved animation tracks from the contract defaults plus
|
|
133
|
+
* optional per-track overrides. Shared by the sprite2d resolver and the
|
|
134
|
+
* live2d entry builder (which fills the sprite fields with contract
|
|
135
|
+
* defaults so the flat PetDefinition shape holds for every renderer).
|
|
136
|
+
*/
|
|
137
|
+
function buildTracks(rows, columns, trackOverrides, warn) {
|
|
138
|
+
const tracks = {};
|
|
139
|
+
for (const [row, animation] of PET_ROW_ORDER.entries()) {
|
|
140
|
+
const pattern = DEFAULT_TRACK_PATTERNS[animation];
|
|
141
|
+
const override = trackOverrides[animation];
|
|
142
|
+
const durations = Array.isArray(override?.durations) && override.durations.length > 0
|
|
143
|
+
? override.durations.filter((value) => typeof value === 'number' && Number.isFinite(value) && value > 0)
|
|
144
|
+
: pattern.durations;
|
|
145
|
+
if (durations.length === 0) {
|
|
146
|
+
warn('track ' + animation + ' carries no usable durations');
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
const frameCount = Math.max(1, Math.min(rows[row], columns));
|
|
150
|
+
const sized = durations.length >= frameCount
|
|
151
|
+
? durations.slice(0, frameCount)
|
|
152
|
+
: Array.from({ length: frameCount }, (_, index) => durations[index % durations.length]);
|
|
153
|
+
tracks[animation] = {
|
|
154
|
+
frames: Array.from({ length: frameCount }, (_, index) => index),
|
|
155
|
+
durations: sized,
|
|
156
|
+
loop: typeof override?.loop === 'boolean' ? override.loop : pattern.loop,
|
|
157
|
+
...(override?.fallback === undefined
|
|
158
|
+
? pattern.fallback === undefined ? {} : { fallback: pattern.fallback }
|
|
159
|
+
: PET_ROW_ORDER.includes(override.fallback)
|
|
160
|
+
? { fallback: override.fallback }
|
|
161
|
+
: pattern.fallback === undefined ? {} : { fallback: pattern.fallback }),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return tracks;
|
|
165
|
+
}
|
|
118
166
|
/**
|
|
119
167
|
* Normalize one parsed manifest into a renderable pet entry, or undefined
|
|
120
168
|
* (with a warning recorded) when the manifest violates the contract.
|
|
@@ -164,36 +212,15 @@ export function resolvePetManifest(raw, dir, options = {}) {
|
|
|
164
212
|
const remarks = normalizePetRemarks(source.remarks, message => warn('manifest ' + id + ': ' + message));
|
|
165
213
|
const sequences = normalizeSequences(source.sequences, id, warn);
|
|
166
214
|
const trackOverrides = (typeof source.tracks === 'object' && source.tracks !== null ? source.tracks : {});
|
|
167
|
-
const tracks =
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const durations = Array.isArray(override?.durations) && override.durations.length > 0
|
|
172
|
-
? override.durations.filter((value) => typeof value === 'number' && Number.isFinite(value) && value > 0)
|
|
173
|
-
: pattern.durations;
|
|
174
|
-
if (durations.length === 0) {
|
|
175
|
-
warn('manifest ' + id + ': track ' + animation + ' carries no usable durations');
|
|
176
|
-
return undefined;
|
|
177
|
-
}
|
|
178
|
-
const frameCount = Math.max(1, Math.min(rows[row], columns));
|
|
179
|
-
const sized = durations.length >= frameCount
|
|
180
|
-
? durations.slice(0, frameCount)
|
|
181
|
-
: Array.from({ length: frameCount }, (_, index) => durations[index % durations.length]);
|
|
182
|
-
tracks[animation] = {
|
|
183
|
-
frames: Array.from({ length: frameCount }, (_, index) => index),
|
|
184
|
-
durations: sized,
|
|
185
|
-
loop: typeof override?.loop === 'boolean' ? override.loop : pattern.loop,
|
|
186
|
-
...(override?.fallback === undefined
|
|
187
|
-
? pattern.fallback === undefined ? {} : { fallback: pattern.fallback }
|
|
188
|
-
: PET_ROW_ORDER.includes(override.fallback)
|
|
189
|
-
? { fallback: override.fallback }
|
|
190
|
-
: pattern.fallback === undefined ? {} : { fallback: pattern.fallback }),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
215
|
+
const tracks = buildTracks(rows, columns, trackOverrides, message => warn('manifest ' + id + ': ' + message));
|
|
216
|
+
if (tracks === undefined)
|
|
217
|
+
return undefined;
|
|
218
|
+
const sheet = spritesheetPath.join('/');
|
|
193
219
|
return {
|
|
194
220
|
id,
|
|
195
221
|
displayName,
|
|
196
222
|
description,
|
|
223
|
+
renderer: 'sprite2d',
|
|
197
224
|
cell,
|
|
198
225
|
columns,
|
|
199
226
|
rows,
|
|
@@ -203,7 +230,121 @@ export function resolvePetManifest(raw, dir, options = {}) {
|
|
|
203
230
|
atlasUrl: assetUrl(assetPrefix, id, spritesheet),
|
|
204
231
|
manifestUrl: assetUrl(assetPrefix, id, 'pet.json'),
|
|
205
232
|
dir,
|
|
206
|
-
spritesheetPath:
|
|
233
|
+
spritesheetPath: sheet,
|
|
234
|
+
servable: [sheet],
|
|
235
|
+
...(remarks === undefined ? {} : { remarks }),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Adapt a validated v2 manifest's sprite2d block onto the legacy flat shape
|
|
240
|
+
* the established resolver consumes (pet-center M2 P2). The legacy resolver
|
|
241
|
+
* only expresses 9-row (default) and 11-row (spriteVersionNumber 2) atlases,
|
|
242
|
+
* so other atlasRows values are rejected here with a diagnostic.
|
|
243
|
+
*/
|
|
244
|
+
function flattenV2Sprite2d(manifest) {
|
|
245
|
+
const block = manifest.sprite2d;
|
|
246
|
+
if (block === undefined)
|
|
247
|
+
return undefined;
|
|
248
|
+
const legacy = {
|
|
249
|
+
id: manifest.id,
|
|
250
|
+
displayName: manifest.displayName,
|
|
251
|
+
spritesheetPath: block.spritesheetPath,
|
|
252
|
+
};
|
|
253
|
+
if (manifest.description !== undefined)
|
|
254
|
+
legacy.description = manifest.description;
|
|
255
|
+
if (block.cell !== undefined)
|
|
256
|
+
legacy.cell = block.cell;
|
|
257
|
+
if (block.columns !== undefined)
|
|
258
|
+
legacy.columns = block.columns;
|
|
259
|
+
if (block.frames !== undefined)
|
|
260
|
+
legacy.frames = block.frames;
|
|
261
|
+
if (block.tracks !== undefined)
|
|
262
|
+
legacy.tracks = block.tracks;
|
|
263
|
+
if (block.atlasRows !== undefined) {
|
|
264
|
+
if (block.atlasRows === 11)
|
|
265
|
+
legacy.spriteVersionNumber = 2;
|
|
266
|
+
else if (block.atlasRows !== DEFAULT_PET_ROW_COUNT)
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
if (manifest.sequences !== undefined)
|
|
270
|
+
legacy.sequences = manifest.sequences;
|
|
271
|
+
if (manifest.remarks !== undefined)
|
|
272
|
+
legacy.remarks = manifest.remarks;
|
|
273
|
+
return legacy;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Resolve a validated live2d manifest into a renderable entry (pet-center
|
|
277
|
+
* M3). The model3.json is read at scan time: its reference closure becomes
|
|
278
|
+
* the entry's servable set (the asset route's allow-list), and a model that
|
|
279
|
+
* is unreadable or declares unsafe references rejects the entry fail-closed
|
|
280
|
+
* with an error diagnostic. Closure files missing on disk warn but keep the
|
|
281
|
+
* entry listed — the client renderer's diagnostic card reports the broken
|
|
282
|
+
* render, matching the registry's never-throw philosophy (install-time
|
|
283
|
+
* strictness belongs to the CLI validator). The sprite fields carry contract
|
|
284
|
+
* defaults: the chrome sizes live2d pets off 'display.size', not the atlas.
|
|
285
|
+
*/
|
|
286
|
+
function resolveLive2dEntry(manifest, dir, options) {
|
|
287
|
+
const assetPrefix = options.assetPrefix ?? '/pet';
|
|
288
|
+
const record = (level, message) => {
|
|
289
|
+
options.diagnostics?.push({ level, source: dir, message });
|
|
290
|
+
options.warnings?.push(message);
|
|
291
|
+
};
|
|
292
|
+
const block = manifest.live2d;
|
|
293
|
+
if (block === undefined) {
|
|
294
|
+
record('error', 'pet ' + manifest.id + ': renderer live2d requires a live2d block');
|
|
295
|
+
return undefined;
|
|
296
|
+
}
|
|
297
|
+
let model3;
|
|
298
|
+
try {
|
|
299
|
+
model3 = JSON.parse(readFileSync(join(dir, block.model), 'utf8'));
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
record('error', 'pet ' + manifest.id + ': live2d model ' + block.model + ' is not readable: '
|
|
303
|
+
+ (error instanceof Error ? error.message : String(error)));
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
const { references, errors } = collectModel3References(model3);
|
|
307
|
+
if (errors.length > 0) {
|
|
308
|
+
for (const message of errors) {
|
|
309
|
+
record('error', 'pet ' + manifest.id + ': live2d model ' + block.model + ': ' + message);
|
|
310
|
+
}
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
for (const reference of references) {
|
|
314
|
+
if (!existsSync(join(dir, reference))) {
|
|
315
|
+
record('warning', 'pet ' + manifest.id + ': live2d closure file missing: ' + reference);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const tracks = buildTracks(DEFAULT_FRAME_COUNTS, DEFAULT_PET_COLUMNS, {}, message => record('warning', 'pet ' + manifest.id + ': ' + message));
|
|
319
|
+
if (tracks === undefined)
|
|
320
|
+
return undefined;
|
|
321
|
+
const remarks = normalizePetRemarks(manifest.remarks, message => record('warning', 'pet ' + manifest.id + ': ' + message));
|
|
322
|
+
const modelUrl = assetUrl(assetPrefix, manifest.id, block.model);
|
|
323
|
+
const live2d = {
|
|
324
|
+
modelUrl,
|
|
325
|
+
modelPath: block.model,
|
|
326
|
+
...(block.scale === undefined ? {} : { scale: block.scale }),
|
|
327
|
+
...(block.translate === undefined ? {} : { translate: block.translate }),
|
|
328
|
+
motions: block.motions,
|
|
329
|
+
...(block.expressions === undefined ? {} : { expressions: block.expressions }),
|
|
330
|
+
...(block.hitAreas === undefined ? {} : { hitAreas: block.hitAreas }),
|
|
331
|
+
};
|
|
332
|
+
return {
|
|
333
|
+
id: manifest.id,
|
|
334
|
+
displayName: manifest.displayName,
|
|
335
|
+
description: manifest.description ?? '',
|
|
336
|
+
renderer: 'live2d',
|
|
337
|
+
live2d,
|
|
338
|
+
cell: { ...DEFAULT_PET_CELL },
|
|
339
|
+
columns: DEFAULT_PET_COLUMNS,
|
|
340
|
+
rows: [...DEFAULT_FRAME_COUNTS],
|
|
341
|
+
atlasRows: DEFAULT_PET_ROW_COUNT,
|
|
342
|
+
tracks,
|
|
343
|
+
atlasUrl: modelUrl,
|
|
344
|
+
manifestUrl: assetUrl(assetPrefix, manifest.id, 'pet.json'),
|
|
345
|
+
dir,
|
|
346
|
+
spritesheetPath: block.model,
|
|
347
|
+
servable: [block.model, ...references],
|
|
207
348
|
...(remarks === undefined ? {} : { remarks }),
|
|
208
349
|
};
|
|
209
350
|
}
|
|
@@ -227,7 +368,28 @@ function scanPetDir(dir, options) {
|
|
|
227
368
|
const parsed = readPetJson(manifestFile, options.warnings);
|
|
228
369
|
if (parsed === undefined)
|
|
229
370
|
continue;
|
|
230
|
-
const
|
|
371
|
+
const entryDir = join(dir, name);
|
|
372
|
+
const verdict = parsePetManifest(parsed, entryDir);
|
|
373
|
+
for (const diagnostic of verdict.diagnostics) {
|
|
374
|
+
options.diagnostics?.push({ level: diagnostic.level, source: entryDir, message: diagnostic.message });
|
|
375
|
+
options.warnings?.push(diagnostic.message);
|
|
376
|
+
}
|
|
377
|
+
if (!verdict.ok)
|
|
378
|
+
continue;
|
|
379
|
+
if (verdict.manifest.renderer === 'live2d') {
|
|
380
|
+
const entry = resolveLive2dEntry(verdict.manifest, entryDir, options);
|
|
381
|
+
if (entry !== undefined)
|
|
382
|
+
entries.push(entry);
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const legacy = flattenV2Sprite2d(verdict.manifest);
|
|
386
|
+
if (legacy === undefined) {
|
|
387
|
+
const note = 'pet ' + verdict.manifest.id + ': sprite2d.atlasRows only supports 9 or 11 under the v1 compat resolver';
|
|
388
|
+
options.diagnostics?.push({ level: 'error', source: entryDir, message: note });
|
|
389
|
+
options.warnings?.push(note);
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
const entry = resolvePetManifest(legacy, entryDir, options);
|
|
231
393
|
if (entry !== undefined)
|
|
232
394
|
entries.push(entry);
|
|
233
395
|
}
|
|
@@ -252,9 +414,10 @@ function readPetJson(file, warnings) {
|
|
|
252
414
|
export function loadPetRegistry(options) {
|
|
253
415
|
const { packageRoot, assetPrefix = '/pet' } = options;
|
|
254
416
|
const warnings = [];
|
|
417
|
+
const diagnostics = [];
|
|
255
418
|
const byId = new Map();
|
|
256
419
|
const builtinIds = new Set();
|
|
257
|
-
for (const entry of scanPetDir(join(packageRoot, 'assets'), { assetPrefix, warnings })) {
|
|
420
|
+
for (const entry of scanPetDir(join(packageRoot, 'assets'), { assetPrefix, warnings, diagnostics })) {
|
|
258
421
|
if (byId.has(entry.id)) {
|
|
259
422
|
warnings.push('duplicate built-in pet id ' + entry.id + '; the first one wins');
|
|
260
423
|
continue;
|
|
@@ -264,12 +427,21 @@ export function loadPetRegistry(options) {
|
|
|
264
427
|
}
|
|
265
428
|
const petsDir = options.petsDir ?? codexPetsDir();
|
|
266
429
|
if (petsDir !== '') {
|
|
267
|
-
for (const entry of scanPetDir(petsDir, { assetPrefix, warnings })) {
|
|
430
|
+
for (const entry of scanPetDir(petsDir, { assetPrefix, warnings, diagnostics })) {
|
|
268
431
|
if (byId.has(entry.id))
|
|
269
432
|
warnings.push('custom pet ' + entry.id + ' overrides the built-in one');
|
|
270
433
|
byId.set(entry.id, entry);
|
|
271
434
|
}
|
|
272
435
|
}
|
|
436
|
+
// The pet-center user directory ranks above the legacy hatch-pet source.
|
|
437
|
+
const dshPetsDir = options.dshPetsDir ?? join(dshHome(), 'pets');
|
|
438
|
+
if (dshPetsDir !== '') {
|
|
439
|
+
for (const entry of scanPetDir(dshPetsDir, { assetPrefix, warnings, diagnostics })) {
|
|
440
|
+
if (byId.has(entry.id))
|
|
441
|
+
warnings.push('user pet ' + entry.id + ' overrides an earlier registration');
|
|
442
|
+
byId.set(entry.id, entry);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
273
445
|
for (const manifest of options.extra ?? []) {
|
|
274
446
|
const raw = manifest.spritesheetPath;
|
|
275
447
|
const dir = raw === undefined || isAbsolute(raw)
|
|
@@ -293,6 +465,7 @@ export function loadPetRegistry(options) {
|
|
|
293
465
|
return {
|
|
294
466
|
entries,
|
|
295
467
|
warnings,
|
|
468
|
+
diagnostics,
|
|
296
469
|
byId: (id) => byId.get(id),
|
|
297
470
|
defaultEntry: () => entries.find(entry => builtinIds.has(entry.id)) ?? entries[0],
|
|
298
471
|
};
|
|
@@ -303,6 +476,8 @@ export function petEntryView(entry) {
|
|
|
303
476
|
id: entry.id,
|
|
304
477
|
displayName: entry.displayName,
|
|
305
478
|
description: entry.description,
|
|
479
|
+
renderer: entry.renderer,
|
|
480
|
+
...(entry.live2d === undefined ? {} : { live2d: entry.live2d }),
|
|
306
481
|
cell: entry.cell,
|
|
307
482
|
columns: entry.columns,
|
|
308
483
|
rows: entry.rows,
|
package/lib/types/routes.d.ts
CHANGED
|
@@ -14,9 +14,46 @@ import type { PetService } from './service.ts';
|
|
|
14
14
|
export declare const PET_API_PREFIX = "/api/pet";
|
|
15
15
|
/** Browser-facing base path of the pet asset routes ('/pet/<id>/...'). */
|
|
16
16
|
export declare const PET_ASSET_PREFIX = "/pet";
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Per-class size ceilings for served pet assets, in bytes (pet-center M2 P3,
|
|
19
|
+
* issue #623). Constants are tested directly; makePetRoutes accepts an
|
|
20
|
+
* override so tests can exercise the 413 path with tiny caps.
|
|
21
|
+
*/
|
|
22
|
+
export declare const PET_ASSET_CAPS: {
|
|
23
|
+
/** pet.json manifest. */
|
|
24
|
+
readonly manifest: number;
|
|
25
|
+
/** Atlas, preview and Live2D texture imagery. */
|
|
26
|
+
readonly image: number;
|
|
27
|
+
/** Live2D model closure files (.moc3, motion/physics/expression JSON; M3). */
|
|
28
|
+
readonly model: number;
|
|
29
|
+
};
|
|
30
|
+
/** Size-cap profile the asset route enforces (test seam). */
|
|
31
|
+
export interface PetAssetCaps {
|
|
32
|
+
manifest: number;
|
|
33
|
+
image: number;
|
|
34
|
+
model: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* realpath containment: resolve both sides and require the candidate to stay
|
|
38
|
+
* inside the base directory. A pet directory (or an atlas/preview inside it)
|
|
39
|
+
* that is a symlink escaping its root is rejected, never followed.
|
|
40
|
+
*/
|
|
41
|
+
export declare function containedRealpath(base: string, candidate: string): string | undefined;
|
|
42
|
+
/** Browser-facing base path of the plugin runtime files (pet-center M3). */
|
|
43
|
+
export declare const PET_RUNTIME_PREFIX: string;
|
|
44
|
+
/** Size ceiling for one runtime file (the Cubism Core is ~200 KB today). */
|
|
45
|
+
export declare const PET_RUNTIME_CAP: number;
|
|
46
|
+
/** Runtime file roots (test seam; defaults resolve from the environment). */
|
|
47
|
+
export interface PetRuntimeRoots {
|
|
48
|
+
/** User-supplied runtime directory (defaults to '$DSH_HOME/pets/.runtime'). */
|
|
49
|
+
runtimeDir?: string;
|
|
50
|
+
/** Plugin vendor bundle directory (defaults to the package 'lib'). */
|
|
51
|
+
vendorDir?: string;
|
|
52
|
+
}
|
|
53
|
+
/** Build the full route family (API + assets + runtime) for one service. */
|
|
18
54
|
export declare function makePetRoutes(deps: {
|
|
19
55
|
service: PetService;
|
|
20
|
-
|
|
56
|
+
assetCaps?: PetAssetCaps;
|
|
57
|
+
} & PetRuntimeRoots): WebRoute[];
|
|
21
58
|
export { petPackageRoot } from './registry.ts';
|
|
22
59
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAM9C,+CAA+C;AAC/C,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAMtC;;;;GAIG;AACH,eAAO,MAAM,cAAc;IACzB,yBAAyB;aACzB,QAAQ;IACR,iDAAiD;aACjD,KAAK;IACL,8EAA8E;aAC9E,KAAK;CACG,CAAA;AAEV,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAWD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUrF;AAsPD,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAA8B,CAAA;AAe7D,4EAA4E;AAC5E,eAAO,MAAM,eAAe,QAAmB,CAAA;AAE/C,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAiFD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,SAAS,CAAC,EAAE,YAAY,CAAA;CAAE,GAAG,eAAe,GAAG,QAAQ,EAAE,CAkDnH;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
|