@linxin666/dsh-pet 0.1.15 → 0.1.16
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 +73 -38
- package/README.zh.md +91 -55
- package/assets/whale/pet.json +12 -1
- package/cordis.patch.yml +4 -4
- package/lib/client.js +270 -334
- package/lib/client.js.map +1 -1
- package/lib/index.js +641 -87
- package/lib/types/client/PetDockEntry.d.ts +14 -12
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +13 -8
- package/lib/types/client/PetSettingsCard.d.ts +22 -9
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +42 -7
- package/lib/types/client/{WhalePet.d.ts → PetSprite.d.ts} +21 -20
- package/lib/types/client/PetSprite.d.ts.map +1 -0
- package/lib/types/client/{WhalePet.js → PetSprite.js} +44 -67
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +3 -1
- package/lib/types/client/index.d.ts +11 -8
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +30 -12
- package/lib/types/client/locales.d.ts +10 -10
- package/lib/types/client/locales.js +10 -10
- package/lib/types/client/pet-store.d.ts +5 -0
- package/lib/types/client/pet-store.d.ts.map +1 -1
- package/lib/types/client/pet-store.js +4 -0
- package/lib/types/client/settings-form.d.ts +62 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +61 -12
- package/lib/types/client/spritesheet.d.ts +14 -48
- package/lib/types/client/spritesheet.d.ts.map +1 -1
- package/lib/types/client/spritesheet.js +13 -81
- package/lib/types/index.d.ts +24 -11
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +53 -33
- package/lib/types/ledger.d.ts +4 -2
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +11 -4
- package/lib/types/persist.d.ts +10 -3
- package/lib/types/persist.d.ts.map +1 -1
- package/lib/types/persist.js +32 -5
- package/lib/types/registry.d.ts +158 -0
- package/lib/types/registry.d.ts.map +1 -0
- package/lib/types/registry.js +276 -0
- package/lib/types/routes.d.ts +10 -10
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +169 -51
- package/lib/types/service.d.ts +46 -13
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +73 -16
- package/package.json +2 -2
- package/src/client/PetDockEntry.tsx +34 -26
- package/src/client/PetSettingsCard.tsx +67 -22
- package/src/client/{WhalePet.test.tsx → PetSprite.test.tsx} +56 -8
- package/src/client/{WhalePet.tsx → PetSprite.tsx} +55 -73
- package/src/client/PluginSettingsCard.tsx +7 -1
- package/src/client/index.ts +36 -14
- package/src/client/locales.ts +10 -10
- package/src/client/pet-store.ts +9 -0
- package/src/client/settings-card.module.css +3 -0
- package/src/client/settings-form.ts +114 -12
- package/src/client/spritesheet.ts +16 -92
- package/src/index.test.ts +23 -0
- package/src/index.ts +89 -45
- package/src/ledger.test.ts +5 -3
- package/src/ledger.ts +11 -4
- package/src/persist.test.ts +52 -3
- package/src/persist.ts +42 -8
- package/src/registry.test.ts +132 -0
- package/src/registry.ts +400 -0
- package/src/routes.ts +166 -53
- package/src/service.ts +102 -20
- package/lib/types/client/WhalePet.d.ts.map +0 -1
package/src/service.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* the pure event projection (`event-projection`) onto the state machine,
|
|
4
4
|
* delegates the affinity economy to the ledger (`ledger`), and routes
|
|
5
5
|
* persistence through `persist`. The API gateway maps these methods onto
|
|
6
|
-
* `pet.state` / `pet.
|
|
7
|
-
* browser consumers.
|
|
6
|
+
* `pet.state` / `pet.pets` / `pet.interact` / `pet.setVisible` /
|
|
7
|
+
* `pet.setConfig` / `pet.setName` / `pet.setPet` for browser consumers.
|
|
8
8
|
* @module @linxin666/dsh-pet/service
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from './event-projection.ts'
|
|
22
22
|
import { PetLedger, type LedgerConfig, type LedgerInteractionResult } from './ledger.ts'
|
|
23
23
|
import {
|
|
24
|
+
DEFAULT_PET_NAME,
|
|
24
25
|
DISPLAY_INSET_MAX,
|
|
25
26
|
DISPLAY_SIZE_MAX,
|
|
26
27
|
DISPLAY_SIZE_MIN,
|
|
@@ -31,6 +32,14 @@ import {
|
|
|
31
32
|
type PetDisplayConfig,
|
|
32
33
|
type PetPersist,
|
|
33
34
|
} from './persist.ts'
|
|
35
|
+
import {
|
|
36
|
+
loadPetRegistry,
|
|
37
|
+
petEntryView,
|
|
38
|
+
petPackageRoot,
|
|
39
|
+
type PetDefinition,
|
|
40
|
+
type PetManifest,
|
|
41
|
+
type PetRegistry,
|
|
42
|
+
} from './registry.ts'
|
|
34
43
|
import {
|
|
35
44
|
defaultPetStateConfig,
|
|
36
45
|
PetStateMachine,
|
|
@@ -51,14 +60,22 @@ export interface PetConfig {
|
|
|
51
60
|
persistDir?: string
|
|
52
61
|
/** Master switch for the plugin (browser half + host routes). */
|
|
53
62
|
enabled?: boolean
|
|
63
|
+
/** Prebuilt registry (tests); defaults to scanning the package + user dirs. */
|
|
64
|
+
registry?: PetRegistry
|
|
65
|
+
/** Extra manifest entries composed by the embedding application. */
|
|
66
|
+
pets?: readonly PetManifest[]
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
/**
|
|
57
|
-
* The pet's settings-namespace section: the
|
|
58
|
-
* settings surface edits. `right`/`bottom` are also updated by drag
|
|
70
|
+
* The pet's settings-namespace section: the pet selection and display fields
|
|
71
|
+
* the web settings surface edits. `right`/`bottom` are also updated by drag
|
|
59
72
|
* interactions, which keep the settings document in sync through the service.
|
|
73
|
+
* Naming is per pet and lives outside the settings document (the hover-panel
|
|
74
|
+
* rename targets the selected pet).
|
|
60
75
|
*/
|
|
61
76
|
export interface PetSettingsSection {
|
|
77
|
+
/** Selected pet id (a registry entry; the service clamps stale values). */
|
|
78
|
+
petId?: string
|
|
62
79
|
/** Master switch. */
|
|
63
80
|
visible: boolean
|
|
64
81
|
/** Scale of the rendered pet in px (sprite cell height). */
|
|
@@ -67,8 +84,6 @@ export interface PetSettingsSection {
|
|
|
67
84
|
right: number
|
|
68
85
|
/** Vertical inset from the viewport bottom edge, px. */
|
|
69
86
|
bottom: number
|
|
70
|
-
/** User-customizable pet display name. */
|
|
71
|
-
name: string
|
|
72
87
|
/** Master switch for the plugin (browser half + host routes). */
|
|
73
88
|
enabled?: boolean
|
|
74
89
|
}
|
|
@@ -86,7 +101,16 @@ export interface PetStateView {
|
|
|
86
101
|
affinity: PetAffinityView
|
|
87
102
|
/** Display configuration. */
|
|
88
103
|
display: PetDisplayConfig
|
|
89
|
-
/**
|
|
104
|
+
/** The selected pet's registry identity. */
|
|
105
|
+
pet: {
|
|
106
|
+
/** Registry id. */
|
|
107
|
+
id: string
|
|
108
|
+
/** Manifest display name (unrenamed default). */
|
|
109
|
+
displayName: string
|
|
110
|
+
/** Manifest description. */
|
|
111
|
+
description: string
|
|
112
|
+
}
|
|
113
|
+
/** The selected pet's display name (user rename or manifest default). */
|
|
90
114
|
name: string
|
|
91
115
|
/** Treat (小鱼干) stock snapshot. */
|
|
92
116
|
treats: {
|
|
@@ -117,6 +141,7 @@ export class PetService extends Service {
|
|
|
117
141
|
|
|
118
142
|
private readonly machine: PetStateMachine
|
|
119
143
|
private readonly ledger: PetLedger
|
|
144
|
+
private readonly registry: PetRegistry
|
|
120
145
|
private readonly persistDir: string
|
|
121
146
|
private enabled: boolean
|
|
122
147
|
private disposeActivity: (() => void) | undefined
|
|
@@ -127,8 +152,22 @@ export class PetService extends Service {
|
|
|
127
152
|
constructor(ctx: Context, config: PetConfig = {}) {
|
|
128
153
|
super(ctx, 'pet')
|
|
129
154
|
this.persistDir = config.persistDir ?? petHomeDir()
|
|
155
|
+
this.registry = config.registry
|
|
156
|
+
?? loadPetRegistry({
|
|
157
|
+
packageRoot: petPackageRoot(import.meta.url),
|
|
158
|
+
...(config.pets === undefined ? {} : { extra: config.pets }),
|
|
159
|
+
})
|
|
160
|
+
if (this.registry.entries.length === 0) {
|
|
161
|
+
throw new Error('[dsh-pet] no valid pet manifests found; nothing to render')
|
|
162
|
+
}
|
|
163
|
+
let persist = loadPetPersist(this.persistDir)
|
|
164
|
+
if (this.registry.byId(persist.petId) === undefined) {
|
|
165
|
+
// The selected pet no longer exists (removed or a fresh install with a
|
|
166
|
+
// copied pet.json): fall back to the registry default.
|
|
167
|
+
persist = { ...persist, petId: this.registry.defaultEntry().id }
|
|
168
|
+
}
|
|
130
169
|
const ledgerConfig: LedgerConfig = { affinity: config.affinity, treats: config.treats }
|
|
131
|
-
this.ledger = new PetLedger(
|
|
170
|
+
this.ledger = new PetLedger(persist, ledgerConfig)
|
|
132
171
|
this.machine = new PetStateMachine({
|
|
133
172
|
...defaultPetStateConfig,
|
|
134
173
|
...(config.state ?? {}),
|
|
@@ -153,9 +192,41 @@ export class PetService extends Service {
|
|
|
153
192
|
return { ...this.ledger.snapshot.display }
|
|
154
193
|
}
|
|
155
194
|
|
|
156
|
-
/**
|
|
157
|
-
|
|
158
|
-
return this.
|
|
195
|
+
/** RPC: the registry entries the browser half renders and selects from. */
|
|
196
|
+
async pets(): Promise<PetDefinition[]> {
|
|
197
|
+
return this.registry.entries.map(petEntryView)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** The loaded registry (the asset routes serve its entries). */
|
|
201
|
+
registrySnapshot(): PetRegistry {
|
|
202
|
+
return this.registry
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** The selected pet's registry entry. */
|
|
206
|
+
activeEntry(): NonNullable<PetRegistry['entries'][number]> {
|
|
207
|
+
return this.registry.byId(this.selectedPetId()) ?? this.registry.defaultEntry()
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Currently selected pet id (persisted). */
|
|
211
|
+
selectedPetId(): string {
|
|
212
|
+
return this.ledger.snapshot.petId
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** The display name of one pet (user rename or manifest displayName). */
|
|
216
|
+
petName(petId: string = this.selectedPetId()): string {
|
|
217
|
+
const stored = this.ledger.snapshot.names[petId]
|
|
218
|
+
if (stored !== undefined && stored.trim() !== '') return stored
|
|
219
|
+
return this.registry.byId(petId)?.displayName ?? DEFAULT_PET_NAME
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** RPC: switch the selected pet (persisted, settings document mirrored). */
|
|
223
|
+
async setPetId(petId: string): Promise<{ ok: true; petId: string } | { ok: false; error: string }> {
|
|
224
|
+
const entry = this.registry.byId(petId)
|
|
225
|
+
if (entry === undefined) return { ok: false, error: 'unknown-pet' }
|
|
226
|
+
this.ledger.setPetId(entry.id)
|
|
227
|
+
this.flush()
|
|
228
|
+
this.syncSettingsFromPet()
|
|
229
|
+
return { ok: true, petId: entry.id }
|
|
159
230
|
}
|
|
160
231
|
|
|
161
232
|
/** Start or stop the session-activity listeners that drive the pet. */
|
|
@@ -257,31 +328,36 @@ export class PetService extends Service {
|
|
|
257
328
|
return { ok: true, display: this.ledger.snapshot.display }
|
|
258
329
|
}
|
|
259
330
|
|
|
260
|
-
/** RPC: rename the pet (trimmed, 1–20 chars). */
|
|
331
|
+
/** RPC: rename the selected pet (trimmed, 1–20 chars, per-pet storage). */
|
|
261
332
|
async setName(name: string): Promise<{ ok: true; name: string } | { ok: false; error: string }> {
|
|
262
333
|
const trimmed = name.trim()
|
|
263
334
|
if (trimmed === '') return { ok: false, error: 'name-empty' }
|
|
264
335
|
if (trimmed.length > PET_NAME_MAX_LENGTH) return { ok: false, error: 'name-too-long' }
|
|
265
|
-
this.ledger.
|
|
336
|
+
this.ledger.setPetName(this.selectedPetId(), trimmed)
|
|
266
337
|
this.flush()
|
|
267
|
-
this.syncSettingsFromPet()
|
|
268
338
|
return { ok: true, name: trimmed }
|
|
269
339
|
}
|
|
270
340
|
|
|
271
341
|
/**
|
|
272
|
-
* Apply a committed settings section to the persisted
|
|
273
|
-
* by the settings surface on every change; values are
|
|
274
|
-
* the setConfig RPC so both write paths converge.
|
|
342
|
+
* Apply a committed settings section to the persisted selection and display
|
|
343
|
+
* config. Called by the settings surface on every change; values are
|
|
344
|
+
* clamped exactly like the setConfig RPC so both write paths converge.
|
|
275
345
|
* @param section - the resolved settings section.
|
|
276
346
|
*/
|
|
277
347
|
applySettingsSection(section: PetSettingsSection): void {
|
|
348
|
+
if (typeof section.petId === 'string' && this.registry.byId(section.petId) !== undefined) {
|
|
349
|
+
this.ledger.setPetId(section.petId)
|
|
350
|
+
} else if (section.petId !== undefined) {
|
|
351
|
+
// The stored selection names a pet the registry no longer has: keep the
|
|
352
|
+
// current selection and repair the settings document.
|
|
353
|
+
this.syncSettingsFromPet()
|
|
354
|
+
}
|
|
278
355
|
const next = { ...this.ledger.snapshot.display }
|
|
279
356
|
next.visible = section.visible && (section.enabled ?? true)
|
|
280
357
|
next.size = Math.round(Math.min(DISPLAY_SIZE_MAX, Math.max(DISPLAY_SIZE_MIN, section.size)))
|
|
281
358
|
next.right = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, section.right)))
|
|
282
359
|
next.bottom = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, section.bottom)))
|
|
283
360
|
this.ledger.setDisplay(next)
|
|
284
|
-
this.ledger.setName(section.name.trim())
|
|
285
361
|
this.flush()
|
|
286
362
|
}
|
|
287
363
|
|
|
@@ -295,7 +371,7 @@ export class PetService extends Service {
|
|
|
295
371
|
size: snapshot.display.size,
|
|
296
372
|
right: snapshot.display.right,
|
|
297
373
|
bottom: snapshot.display.bottom,
|
|
298
|
-
|
|
374
|
+
petId: snapshot.petId,
|
|
299
375
|
}).catch(() => {
|
|
300
376
|
// A settings write failure must not break the pet's own persistence.
|
|
301
377
|
})
|
|
@@ -313,6 +389,7 @@ export class PetService extends Service {
|
|
|
313
389
|
|
|
314
390
|
private view(): PetStateView {
|
|
315
391
|
const snapshot = this.machine.render()
|
|
392
|
+
const entry = this.activeEntry()
|
|
316
393
|
// Read-only: the ledger settles on economic events only, never on a read,
|
|
317
394
|
// so polling the state cannot trigger pet.json writes.
|
|
318
395
|
return {
|
|
@@ -322,7 +399,12 @@ export class PetService extends Service {
|
|
|
322
399
|
sessionActive: snapshot.sessionActive,
|
|
323
400
|
affinity: this.ledger.affinityView(Date.now()),
|
|
324
401
|
display: { ...this.ledger.snapshot.display },
|
|
325
|
-
|
|
402
|
+
pet: {
|
|
403
|
+
id: entry.id,
|
|
404
|
+
displayName: entry.displayName,
|
|
405
|
+
description: entry.description,
|
|
406
|
+
},
|
|
407
|
+
name: this.petName(),
|
|
326
408
|
treats: {
|
|
327
409
|
stocked: this.ledger.snapshot.treats.treats,
|
|
328
410
|
max: this.ledger.treatMax,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WhalePet.d.ts","sourceRoot":"","sources":["../../../src/client/WhalePet.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAqC,WAAW,EAAE,MAAM,OAAO,CAAA;AAE3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAGjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,gCAAgC,CAAA;AAEhE,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,wBAAwB,CAAA;AAErD,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,qDAAqD;IACrD,OAAO,EAAE,gBAAgB,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,kCAAkC;IAClC,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,8CAA8C;IAC9C,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,2DAA2D;IAC3D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,+CAA+C;IAC/C,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,WAAW,CAyT1D"}
|