@linxin666/dsh-pet 0.3.24 → 0.3.25
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 +4 -3
- package/README.zh.md +4 -3
- package/icon.svg +3 -0
- package/lib/client.js +522 -194
- package/lib/client.js.map +1 -1
- package/lib/index.js +706 -422
- package/lib/live2d-vendor.js +96 -96
- package/lib/live2d-vendor.js.map +1 -1
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +1 -1
- package/lib/types/client/PetSettingsCard.d.ts +20 -9
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +116 -5
- package/lib/types/client/PetSprite.d.ts +6 -0
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +95 -0
- package/lib/types/client/PluginSettingsCard.d.ts +4 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +3 -2
- package/lib/types/client/gameplay-hud.d.ts +10 -1
- package/lib/types/client/gameplay-hud.d.ts.map +1 -1
- package/lib/types/client/gameplay-hud.js +137 -23
- package/lib/types/client/index.d.ts +8 -5
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +61 -27
- package/lib/types/client/main-session.d.ts +33 -0
- package/lib/types/client/main-session.d.ts.map +1 -0
- package/lib/types/client/main-session.js +34 -0
- package/lib/types/client/settings-form.d.ts +17 -17
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +30 -27
- package/lib/types/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +5 -3
- package/lib/types/gameplay.d.ts +79 -5
- package/lib/types/gameplay.d.ts.map +1 -1
- package/lib/types/gameplay.js +212 -17
- package/lib/types/http.d.ts +18 -1
- package/lib/types/http.d.ts.map +1 -1
- package/lib/types/http.js +22 -1
- package/lib/types/index.d.ts +100 -29
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +113 -64
- package/lib/types/persist.d.ts.map +1 -1
- package/lib/types/persist.js +3 -1
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +3 -1
- package/lib/types/service.d.ts +8 -3
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +26 -4
- package/package.json +46 -26
- package/src/client/PetDockEntry.tsx +1 -0
- package/src/client/PetSettingsCard.test.tsx +103 -0
- package/src/client/PetSettingsCard.tsx +129 -26
- package/src/client/PetSprite.tsx +96 -0
- package/src/client/PluginSettingsCard.tsx +7 -2
- package/src/client/gameplay-hud.test.tsx +106 -8
- package/src/client/gameplay-hud.tsx +143 -28
- package/src/client/index.test.tsx +37 -4
- package/src/client/index.ts +74 -34
- package/src/client/main-session.ts +43 -0
- package/src/client/settings-form.ts +34 -31
- package/src/event-projection.ts +5 -3
- package/src/gameplay.test.ts +138 -1
- package/src/gameplay.ts +253 -16
- package/src/http.ts +23 -1
- package/src/index.test.ts +107 -11
- package/src/index.ts +162 -73
- package/src/persist.ts +3 -1
- package/src/registry.test.ts +3 -2
- package/src/routes.ts +3 -1
- package/src/service.ts +27 -5
|
@@ -10,7 +10,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
10
10
|
* @module @linxin666/dsh-pet/client/GameplayHud
|
|
11
11
|
*/
|
|
12
12
|
import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
13
|
-
import { touchZoneAt } from "../gameplay.js";
|
|
13
|
+
import { declaredModes, modeStateOf, PET_ROAM_DIRECTIONS, touchZoneAt } from "../gameplay.js";
|
|
14
14
|
import styles from './pet.module.css';
|
|
15
15
|
let floatSeq = 0;
|
|
16
16
|
/** The gameplay overlay for one frames2d pet that declares 'gameplay'. */
|
|
@@ -19,7 +19,6 @@ export function GameplayHud(props) {
|
|
|
19
19
|
const ui = useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
20
20
|
const def = definition.gameplay;
|
|
21
21
|
const view = ui.snapshot?.gameplay;
|
|
22
|
-
const phase = ui.snapshot?.phase ?? 'idle';
|
|
23
22
|
// Host-persisted skin selection for this pet (undefined = default look).
|
|
24
23
|
const persistedSkin = ui.snapshot?.skin;
|
|
25
24
|
const [open, setOpen] = useState(false);
|
|
@@ -34,12 +33,19 @@ export function GameplayHud(props) {
|
|
|
34
33
|
// Mutable driver state (refs so intervals never re-arm on a poll tick).
|
|
35
34
|
const modeRef = useRef(view?.mode ?? null);
|
|
36
35
|
modeRef.current = view?.mode ?? null;
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
/** Live gameplay view for the interval loops (def identity is stable, view is not). */
|
|
37
|
+
const viewRef = useRef(view);
|
|
38
|
+
viewRef.current = view;
|
|
39
39
|
const draggingRef = useRef(false);
|
|
40
40
|
const touchLockUntilRef = useRef(0);
|
|
41
41
|
const missRef = useRef(0);
|
|
42
42
|
const busyRef = useRef(false);
|
|
43
|
+
/** A roam walk owns the visual right now (the idle director must not steal it). */
|
|
44
|
+
const roamHeldRef = useRef(false);
|
|
45
|
+
/** A one-shot idle-director act owns the visual right now (the roam must not cut in). */
|
|
46
|
+
const actHeldRef = useRef(false);
|
|
47
|
+
/** Pending release of the roam's walk track (cleared when another owner takes it). */
|
|
48
|
+
const roamTimerRef = useRef(0);
|
|
43
49
|
// Dynamic-key lookups (stat ids / currency ids are manifest data).
|
|
44
50
|
const tr = props.t;
|
|
45
51
|
const statLabel = (name) => tr('pet.gameplay.stat.' + name);
|
|
@@ -55,6 +61,19 @@ export function GameplayHud(props) {
|
|
|
55
61
|
if (result.view !== undefined)
|
|
56
62
|
store.actions.setGameplayView(result.view);
|
|
57
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* Give up the roam's claim on the shared track-override slot. Every other
|
|
66
|
+
* owner (a mode, a touch reaction, a drag) calls this before it takes the
|
|
67
|
+
* slot, so a walk that is still in flight can never release someone else's
|
|
68
|
+
* track when its own hold window elapses.
|
|
69
|
+
*/
|
|
70
|
+
const yieldRoam = () => {
|
|
71
|
+
if (roamTimerRef.current !== 0) {
|
|
72
|
+
window.clearTimeout(roamTimerRef.current);
|
|
73
|
+
roamTimerRef.current = 0;
|
|
74
|
+
}
|
|
75
|
+
roamHeldRef.current = false;
|
|
76
|
+
};
|
|
58
77
|
// Tap handling (registered on the bus; PetSprite reports sprite-box
|
|
59
78
|
// fractions). Sleep wakes on tap; work blocks taps; a held touch
|
|
60
79
|
// animation turns taps into the plain-click boost.
|
|
@@ -69,6 +88,7 @@ export function GameplayHud(props) {
|
|
|
69
88
|
// consecutive taps cannot retrigger mid-play (skin click actions and
|
|
70
89
|
// default touch-zone reactions share this path).
|
|
71
90
|
const holdTrack = (track, holdMs) => {
|
|
91
|
+
yieldRoam();
|
|
72
92
|
bus.setTrack?.(track);
|
|
73
93
|
touchLockUntilRef.current = Date.now() + holdMs;
|
|
74
94
|
window.setTimeout(() => {
|
|
@@ -86,7 +106,9 @@ export function GameplayHud(props) {
|
|
|
86
106
|
// base idle, so holding the lock for the full loop is unnecessary).
|
|
87
107
|
const trackDuration = (track) => definition.frames2d?.tracks[track]?.durations.reduce((sum, ms) => sum + ms, 0) ?? 0;
|
|
88
108
|
bus.tap = (fx, fy) => {
|
|
89
|
-
|
|
109
|
+
// Any non-work mode ends on a tap (sleep wakes up, a bath steps out);
|
|
110
|
+
// work keeps swallowing taps while its round is running.
|
|
111
|
+
if (modeRef.current !== null && modeRef.current !== 'work') {
|
|
90
112
|
void api.setMode(null).then(applyResult, () => undefined);
|
|
91
113
|
return;
|
|
92
114
|
}
|
|
@@ -180,21 +202,25 @@ export function GameplayHud(props) {
|
|
|
180
202
|
return () => { window.removeEventListener('resize', place); };
|
|
181
203
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- one placement per open/page change
|
|
182
204
|
}, [open, page]);
|
|
183
|
-
// Drag gestures
|
|
184
|
-
// feeds the idle director's suppression check.
|
|
205
|
+
// Drag gestures end any non-work mode (sleep wakes, a bath steps out); the
|
|
206
|
+
// drag stream also feeds the idle director's suppression check.
|
|
185
207
|
useEffect(() => {
|
|
186
208
|
return props.drag.subscribe((dragging) => {
|
|
187
209
|
draggingRef.current = dragging;
|
|
188
|
-
if (dragging
|
|
210
|
+
if (dragging)
|
|
211
|
+
yieldRoam();
|
|
212
|
+
if (dragging && modeRef.current !== null && modeRef.current !== 'work') {
|
|
189
213
|
void api.setMode(null).then(applyResult, () => undefined);
|
|
190
214
|
}
|
|
191
215
|
});
|
|
192
216
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- one subscription per drag stream
|
|
193
217
|
}, [props.drag]);
|
|
194
218
|
// Idle director: weighted rolls between staying idle and playing an act.
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
//
|
|
219
|
+
// Rolls in every phase -- an ambient act is not a waiting-room performance,
|
|
220
|
+
// and the idle phase only appears when neither the agent nor the user is busy
|
|
221
|
+
// -- but only while nothing else owns the visual: no mode, no drag, no held
|
|
222
|
+
// touch animation, no roam walk and no act already playing. maxMiss forces an
|
|
223
|
+
// act after too many idle rolls in a row.
|
|
198
224
|
useEffect(() => {
|
|
199
225
|
const director = def?.idleDirector;
|
|
200
226
|
if (def === undefined || director === undefined)
|
|
@@ -202,13 +228,16 @@ export function GameplayHud(props) {
|
|
|
202
228
|
const total = director.idleWeight + director.acts.reduce((sum, act) => sum + act.weight, 0);
|
|
203
229
|
if (total <= 0)
|
|
204
230
|
return undefined;
|
|
231
|
+
let actTimer = 0;
|
|
205
232
|
const timer = window.setInterval(() => {
|
|
206
|
-
if (phaseRef.current !== 'idle')
|
|
207
|
-
return;
|
|
208
233
|
if (modeRef.current !== null || draggingRef.current)
|
|
209
234
|
return;
|
|
210
235
|
if (Date.now() < touchLockUntilRef.current)
|
|
211
236
|
return;
|
|
237
|
+
if (roamHeldRef.current)
|
|
238
|
+
return; // a roam walk owns the visual
|
|
239
|
+
if (actHeldRef.current)
|
|
240
|
+
return; // the previous act is still playing
|
|
212
241
|
let pickedAct;
|
|
213
242
|
if (missRef.current >= director.maxMiss) {
|
|
214
243
|
// Forced act: pick among the acts only.
|
|
@@ -237,14 +266,24 @@ export function GameplayHud(props) {
|
|
|
237
266
|
return;
|
|
238
267
|
}
|
|
239
268
|
missRef.current = 0;
|
|
269
|
+
actHeldRef.current = true;
|
|
240
270
|
bus.setTrack?.(pickedAct.track);
|
|
271
|
+
// A one-shot act owns the visual until its own duration elapses (the
|
|
272
|
+
// renderer then falls back to the phase map); the roam must not cut in.
|
|
273
|
+
const holdMs = definition.frames2d?.tracks[pickedAct.track]?.durations.reduce((sum, ms) => sum + ms, 0) ?? 0;
|
|
274
|
+
window.clearTimeout(actTimer);
|
|
275
|
+
actTimer = window.setTimeout(() => { actHeldRef.current = false; }, holdMs > 0 ? holdMs : 3000);
|
|
241
276
|
// Acts with a phrase pool speak one line while they play (miku parity).
|
|
242
277
|
if (pickedAct.phrases !== undefined && pickedAct.phrases.length > 0) {
|
|
243
278
|
const phrase = pickedAct.phrases[Math.floor(Math.random() * pickedAct.phrases.length)];
|
|
244
279
|
store.actions.setFeedback({ text: phrase, kind: 'none', at: Date.now() });
|
|
245
280
|
}
|
|
246
281
|
}, director.intervalMs);
|
|
247
|
-
return () =>
|
|
282
|
+
return () => {
|
|
283
|
+
window.clearInterval(timer);
|
|
284
|
+
window.clearTimeout(actTimer);
|
|
285
|
+
actHeldRef.current = false;
|
|
286
|
+
};
|
|
248
287
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- one director per pet definition
|
|
249
288
|
}, [definition.id, def]);
|
|
250
289
|
// Work loop: hold the work track, adjudicate one round per tick, play the
|
|
@@ -290,24 +329,99 @@ export function GameplayHud(props) {
|
|
|
290
329
|
};
|
|
291
330
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- the loop keys on the mode and the selected skin
|
|
292
331
|
}, [definition.id, def, view?.mode, skinId]);
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
332
|
+
// Mode loop: hold the active non-work mode's track (sleep, a bath, any
|
|
333
|
+
// extra 'modes' entry). The stat restore is host-side (lazy settle). While a
|
|
334
|
+
// skin with a matching gameplayTracks override is selected, the skin's own
|
|
335
|
+
// track replaces the default one (e.g. a skin-specific doze).
|
|
296
336
|
useEffect(() => {
|
|
297
|
-
const
|
|
298
|
-
if (def === undefined ||
|
|
337
|
+
const active = view?.mode;
|
|
338
|
+
if (def === undefined || active === undefined || active === null || active === 'work')
|
|
339
|
+
return undefined;
|
|
340
|
+
const hold = modeStateOf(def, active);
|
|
341
|
+
if (hold === undefined)
|
|
299
342
|
return undefined;
|
|
300
343
|
const skinGameplay = definition.frames2d?.skins?.find(skin => skin.id === skinIdRef.current)?.gameplayTracks;
|
|
301
|
-
|
|
302
|
-
bus.setTrack?.(hold);
|
|
344
|
+
yieldRoam();
|
|
345
|
+
bus.setTrack?.(skinGameplay?.[active] ?? hold);
|
|
303
346
|
return () => bus.setTrack?.(undefined);
|
|
304
347
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- the loop keys on the mode value
|
|
305
348
|
}, [definition.id, def, view?.mode, skinId]);
|
|
349
|
+
// Random roaming (manifest 'roam'): on a slow interval -- in any phase, as long
|
|
350
|
+
// as no mode, drag, touch animation or director act owns the pet -- roll a
|
|
351
|
+
// wander. The chrome walks the sprite and persists the new spot; this side
|
|
352
|
+
// holds the walk track for exactly the travel time.
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
const roam = def?.roam;
|
|
355
|
+
if (def === undefined || roam === undefined)
|
|
356
|
+
return undefined;
|
|
357
|
+
const roll = () => {
|
|
358
|
+
// Every phase: a wandering pet is ambient, not a performance, so she
|
|
359
|
+
// keeps walking while the agent works (the idle director's acts stay
|
|
360
|
+
// idle-only). A mode, a drag, a touch animation and a director
|
|
361
|
+
// act all still own the pet and suppress the roll.
|
|
362
|
+
if (modeRef.current !== null || draggingRef.current)
|
|
363
|
+
return;
|
|
364
|
+
if (Date.now() < touchLockUntilRef.current)
|
|
365
|
+
return;
|
|
366
|
+
if (roamHeldRef.current || actHeldRef.current)
|
|
367
|
+
return;
|
|
368
|
+
if (Math.random() >= roam.probability)
|
|
369
|
+
return;
|
|
370
|
+
const span = roam.distanceMax - roam.distanceMin;
|
|
371
|
+
const distance = roam.distanceMin + Math.random() * span;
|
|
372
|
+
const directions = roam.directions ?? PET_ROAM_DIRECTIONS;
|
|
373
|
+
const direction = directions[Math.floor(Math.random() * directions.length)] ?? 'left';
|
|
374
|
+
const travelled = bus.walk?.(direction, distance, roam.speed) ?? 0;
|
|
375
|
+
if (travelled === 0)
|
|
376
|
+
return;
|
|
377
|
+
roamHeldRef.current = true;
|
|
378
|
+
bus.setTrack?.(roam.state);
|
|
379
|
+
roamTimerRef.current = window.setTimeout(() => {
|
|
380
|
+
roamTimerRef.current = 0;
|
|
381
|
+
if (!roamHeldRef.current)
|
|
382
|
+
return; // another owner already took the slot
|
|
383
|
+
roamHeldRef.current = false;
|
|
384
|
+
bus.setTrack?.(undefined);
|
|
385
|
+
}, Math.max(150, (Math.abs(travelled) / roam.speed) * 1000));
|
|
386
|
+
};
|
|
387
|
+
// The two decision timers must never share a tick. The roam starts half an
|
|
388
|
+
// interval late, so its ticks interleave with the idle director's instead
|
|
389
|
+
// of landing on the same instant (10 s and 15 s coincide every 30 s).
|
|
390
|
+
let timer = 0;
|
|
391
|
+
const lead = window.setTimeout(() => {
|
|
392
|
+
roll();
|
|
393
|
+
timer = window.setInterval(roll, roam.intervalMs);
|
|
394
|
+
}, Math.round(roam.intervalMs / 2));
|
|
395
|
+
return () => {
|
|
396
|
+
window.clearTimeout(lead);
|
|
397
|
+
window.clearInterval(timer);
|
|
398
|
+
yieldRoam();
|
|
399
|
+
};
|
|
400
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- one director per pet definition
|
|
401
|
+
}, [definition.id, def]);
|
|
306
402
|
if (def === undefined || view === undefined)
|
|
307
403
|
return null;
|
|
308
404
|
const mode = view.mode;
|
|
309
405
|
const stats = def.stats ?? {};
|
|
310
406
|
const shop = def.shop;
|
|
407
|
+
// Every menu mode beyond work: sleep plus any extra 'modes' the pet declares.
|
|
408
|
+
const menuModes = declaredModes(def);
|
|
409
|
+
/** Action-button label for one mode (active = the button that leaves it). */
|
|
410
|
+
const modeLabel = (name, active) => {
|
|
411
|
+
if (name === 'sleep')
|
|
412
|
+
return tr(active ? 'pet.gameplay.wake' : 'pet.gameplay.sleep');
|
|
413
|
+
const declared = def.modes?.[name];
|
|
414
|
+
return (active ? declared?.activeLabel ?? declared?.label : declared?.label) ?? tr('pet.gameplay.' + name);
|
|
415
|
+
};
|
|
416
|
+
/** Chip label for the mode the pet is in right now. */
|
|
417
|
+
const modeChip = (name) => {
|
|
418
|
+
if (name === 'work')
|
|
419
|
+
return tr('pet.gameplay.working');
|
|
420
|
+
if (name === 'sleep')
|
|
421
|
+
return tr('pet.gameplay.sleeping');
|
|
422
|
+
const declared = def.modes?.[name];
|
|
423
|
+
return declared?.activeLabel ?? declared?.label ?? tr('pet.gameplay.' + name);
|
|
424
|
+
};
|
|
311
425
|
const buy = (itemId) => {
|
|
312
426
|
void api.buy(itemId).then((result) => {
|
|
313
427
|
applyResult(result);
|
|
@@ -362,8 +476,8 @@ export function GameplayHud(props) {
|
|
|
362
476
|
restore();
|
|
363
477
|
}, restore);
|
|
364
478
|
};
|
|
365
|
-
return (_jsxs("div", { ref: hudRef, className: styles.gameplayHud, "data-dsh-pet-gameplay": definition.id, children: [floats.map(entry => (_jsx("div", { className: styles.gameplayFloat, children: entry.text }, entry.id))), mode !== null && (_jsx("div", { className: styles.gameplayModeChip, children:
|
|
479
|
+
return (_jsxs("div", { ref: hudRef, className: styles.gameplayHud, "data-dsh-pet-gameplay": definition.id, children: [floats.map(entry => (_jsx("div", { className: styles.gameplayFloat, children: entry.text }, entry.id))), mode !== null && (_jsx("div", { className: styles.gameplayModeChip, children: modeChip(mode) })), open && (_jsxs("div", { ref: cardRef, className: styles.gameplayCard, "data-page": page, children: [page === 'root' && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.gameplayBars, children: Object.entries(stats).map(([name, stat]) => {
|
|
366
480
|
const value = view.stats[name] ?? 0;
|
|
367
481
|
return (_jsxs("div", { className: styles.gameplayBarRow, title: statLabel(name) + ' ' + String(value) + '/' + String(stat.max), children: [_jsx("span", { className: styles.gameplayBarLabel, children: statLabel(name) }), _jsx("span", { className: styles.gameplayBarTrack, children: _jsx("span", { className: styles.gameplayBarFill, style: { width: Math.round((value / stat.max) * 100) + '%' } }) })] }, name));
|
|
368
|
-
}) }), _jsxs("div", { className: styles.gameplayActions, children: [
|
|
482
|
+
}) }), _jsxs("div", { className: styles.gameplayActions, children: [menuModes.map(name => (_jsx("button", { type: "button", className: styles.action, onClick: () => setMode(mode === name ? null : name), children: modeLabel(name, mode === name) }, name))), shop !== undefined && (_jsx("button", { type: "button", className: styles.action, onClick: () => setPage('shop'), children: tr('pet.gameplay.shop') })), skins !== undefined && skins.length > 0 && (_jsx("button", { type: "button", className: styles.action, onClick: () => setPage('skins'), children: tr('pet.gameplay.skin') })), def.work !== undefined && (_jsx("button", { type: "button", className: styles.action, onClick: () => setMode(mode === 'work' ? null : 'work'), children: tr(mode === 'work' ? 'pet.gameplay.stopWork' : 'pet.gameplay.work') }))] })] })), page === 'shop' && shop !== undefined && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.gameplayShopItems, children: shop.items.map(item => (_jsxs("button", { type: "button", className: styles.gameplayShopItem, onClick: () => buy(item.id), title: item.label + ' — ' + String(item.price) + ' ' + currencyLabel(item.currency), children: [item.image !== undefined && (_jsx("img", { className: styles.gameplayShopItemImage, src: item.image, alt: "", draggable: false })), _jsx("span", { className: styles.gameplayShopItemLabel, children: item.label }), _jsxs("span", { className: styles.gameplayShopItemPrice, children: [item.price, " ", currencyLabel(item.currency)] })] }, item.id))) }), _jsx("div", { className: styles.gameplayActions, children: _jsx("button", { type: "button", className: styles.action, onClick: () => setPage('root'), children: tr('pet.gameplay.back') }) })] })), page === 'skins' && skins !== undefined && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.gameplaySkinItems, children: [_jsx("button", { type: "button", className: skinId === undefined ? styles.gameplaySkinItem + ' ' + styles.gameplaySkinItemActive : styles.gameplaySkinItem, onClick: () => selectSkin(undefined), children: tr('pet.gameplay.skinDefault') }), skins.map(skin => (_jsx("button", { type: "button", className: skinId === skin.id ? styles.gameplaySkinItem + ' ' + styles.gameplaySkinItemActive : styles.gameplaySkinItem, onClick: () => selectSkin(skin), children: skin.label }, skin.id)))] }), _jsx("div", { className: styles.gameplayActions, children: _jsx("button", { type: "button", className: styles.action, onClick: () => setPage('root'), children: tr('pet.gameplay.back') }) })] })), _jsx("button", { type: "button", className: styles.gameplayClose, "aria-label": tr('pet.gameplay.back'), onClick: () => setOpen(false), children: "\u00D7" })] }))] }));
|
|
369
483
|
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* @module @linxin666/dsh-pet/client
|
|
14
14
|
*/
|
|
15
15
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
16
|
-
import type {
|
|
16
|
+
import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
17
17
|
/** Required services (sessions powers bubble-to-session navigation). */
|
|
18
18
|
export declare const inject: string[];
|
|
19
19
|
/** Re-exported for consumers that type against the injected face. */
|
|
@@ -26,12 +26,15 @@ export type { PetDefinition } from '../registry.ts';
|
|
|
26
26
|
declare module '@deepseek-ai/cordis' {
|
|
27
27
|
interface Context {
|
|
28
28
|
/**
|
|
29
|
-
* Optional
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* Optional family binder provided by dsh-web-settings; absent when that
|
|
30
|
+
* group plugin is not installed, so callers fall back to the shared
|
|
31
|
+
* per-entry form.
|
|
32
32
|
*/
|
|
33
33
|
webUiSettings?: {
|
|
34
|
-
bind<S>(spec:
|
|
34
|
+
bind<S>(spec: {
|
|
35
|
+
namespace: string;
|
|
36
|
+
decode?: (section: unknown) => S | undefined;
|
|
37
|
+
}): ConfigForm<S>;
|
|
35
38
|
};
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGnE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGnE,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,4CAA4C,CAAA;AAqFzF,wEAAwE;AACxE,eAAO,MAAM,MAAM,UAAwF,CAAA;AAE3G,qEAAqE;AACrE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACxE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC7D,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACtF,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AACpE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf;;;;WAIG;QACH,aAAa,CAAC,EAAE;YACd,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE;gBAAE,SAAS,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC,GAAG,SAAS,CAAA;aAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;SAClG,CAAA;KACF;CACF;AA0DD,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAoU9C"}
|
|
@@ -23,6 +23,7 @@ import { frames2dRenderer } from "./renderers/frames2d.js";
|
|
|
23
23
|
import { registerPetUiTeardown, takeoverPetUiTeardown } from "./ui-teardown.js";
|
|
24
24
|
import { PetSettingsSection, PetSettingsCardController } from "./PetSettingsCard.js";
|
|
25
25
|
import { NS, en, zh, t } from "./locales.js";
|
|
26
|
+
import { mainViewSessionId } from "./main-session.js";
|
|
26
27
|
import { reportDailyHeartbeat } from "./telemetry.js";
|
|
27
28
|
/** Same-origin JSON fetch helper (GET without body, POST with JSON body). */
|
|
28
29
|
async function petFetch(path, body) {
|
|
@@ -56,10 +57,44 @@ const petApi = {
|
|
|
56
57
|
};
|
|
57
58
|
/** Poll interval for the host snapshot. */
|
|
58
59
|
const POLL_MS = 2000;
|
|
59
|
-
/** Settings namespace the pet settings
|
|
60
|
+
/** Settings namespace of the pet's settings page. It is the profile entry id the Host serves a form for. */
|
|
60
61
|
const PET_SETTINGS_NS = 'pet';
|
|
61
62
|
/** Required services (sessions powers bubble-to-session navigation). */
|
|
62
|
-
export const inject = ['slots', 'locale', 'connection', '
|
|
63
|
+
export const inject = ['slots', 'locale', 'connection', 'configForms', 'remote', 'sessions', 'uiWorkspace'];
|
|
64
|
+
/**
|
|
65
|
+
* The configuration form the settings card stages and saves through: the
|
|
66
|
+
* family binder when dsh-web-settings is mounted, otherwise the shared form of
|
|
67
|
+
* this plugin's own profile entry.
|
|
68
|
+
*
|
|
69
|
+
* The two are not interchangeable by name. A plugin's settings ARE its own
|
|
70
|
+
* config on 0.1.7, so the form belongs to the profile entry that carries the
|
|
71
|
+
* plugin — and only the family binder knows which entry that is, because the
|
|
72
|
+
* family bundle renames child rows ('pet' becomes 'web-ui-pet' there) while a
|
|
73
|
+
* standalone install keeps the package's own id.
|
|
74
|
+
* @param ctx - client root context.
|
|
75
|
+
* @returns the form for the pet's settings page.
|
|
76
|
+
*/
|
|
77
|
+
const AGGREGATE_ENTRY_ID = 'web-ui-pet';
|
|
78
|
+
const PET_ENTRY_IDS = [AGGREGATE_ENTRY_ID, 'ui-pet', PET_SETTINGS_NS];
|
|
79
|
+
function servedEntryId(forms) {
|
|
80
|
+
let served;
|
|
81
|
+
try {
|
|
82
|
+
served = forms.describe().getSnapshot().view?.namespaces.map(view => view.ns);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
served = undefined;
|
|
86
|
+
}
|
|
87
|
+
if (!served || served.length === 0)
|
|
88
|
+
return PET_SETTINGS_NS;
|
|
89
|
+
return PET_ENTRY_IDS.find(id => served.includes(id)) ?? PET_SETTINGS_NS;
|
|
90
|
+
}
|
|
91
|
+
function petSettingsForm(ctx) {
|
|
92
|
+
const binder = ctx.get('webUiSettings');
|
|
93
|
+
if (binder !== undefined && typeof binder.bind === 'function') {
|
|
94
|
+
return binder.bind({ namespace: PET_SETTINGS_NS });
|
|
95
|
+
}
|
|
96
|
+
return ctx.configForms.get(servedEntryId(ctx.configForms));
|
|
97
|
+
}
|
|
63
98
|
/**
|
|
64
99
|
* Client plugin body: register dictionaries, mount the global pet entry and
|
|
65
100
|
* poll loop while the plugin is enabled, and seat the settings card as a
|
|
@@ -94,23 +129,22 @@ export function apply(ctx) {
|
|
|
94
129
|
// M3). Registration is idempotent (id wins), so re-applies stay clean.
|
|
95
130
|
defaultPetRendererRegistry.register(live2dRenderer);
|
|
96
131
|
defaultPetRendererRegistry.register(frames2dRenderer);
|
|
97
|
-
const
|
|
98
|
-
const settingsScope = binder.bind({ namespace: PET_SETTINGS_NS });
|
|
132
|
+
const settingsForm = petSettingsForm(ctx);
|
|
99
133
|
const enabled = () => {
|
|
100
|
-
const snapshot =
|
|
134
|
+
const snapshot = settingsForm.getSnapshot();
|
|
101
135
|
return snapshot.status === 'ready'
|
|
102
136
|
? snapshot.value?.enabled ?? true
|
|
103
137
|
: snapshot.status === 'unavailable';
|
|
104
138
|
};
|
|
105
|
-
// First-level settings section: one staged form over the 'pet'
|
|
106
|
-
//
|
|
107
|
-
// the petId choices from the registry endpoint itself — the
|
|
108
|
-
// the available pets (built-in assets plus user dirs), so the
|
|
109
|
-
// ever shows installed pets. Installing new pets happens in the
|
|
110
|
-
// store.
|
|
111
|
-
const petSettings = new PetSettingsCardController(
|
|
139
|
+
// First-level settings section: one staged form over the 'pet' profile
|
|
140
|
+
// entry's configuration, registered as a top-level settings page. The
|
|
141
|
+
// controller loads the petId choices from the registry endpoint itself — the
|
|
142
|
+
// registry lists the available pets (built-in assets plus user dirs), so the
|
|
143
|
+
// section only ever shows installed pets. Installing new pets happens in the
|
|
144
|
+
// Workshop store.
|
|
145
|
+
const petSettings = new PetSettingsCardController(settingsForm);
|
|
112
146
|
// The section entry owns the controller: unregistering it (fiber disposal,
|
|
113
|
-
// hot reload) releases the
|
|
147
|
+
// hot reload) releases the form subscription through petSettings.dispose.
|
|
114
148
|
ctx.slots.inject('settings.section', () => {
|
|
115
149
|
try {
|
|
116
150
|
const unregister = ctx.slots.register({
|
|
@@ -159,19 +193,17 @@ export function apply(ctx) {
|
|
|
159
193
|
const setPets = petStore.actions.setPets;
|
|
160
194
|
const setState = petStore.actions.setState;
|
|
161
195
|
const setFeedback = petStore.actions.setFeedback;
|
|
162
|
-
// Clicking a session bubble jumps the GUI to that session; the
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
// service types, whose Context
|
|
169
|
-
// face; pin the browser runtime's
|
|
196
|
+
// Clicking a session bubble jumps the GUI to that session; the
|
|
197
|
+
// catalog's main-view ownership marker tells which session the main view
|
|
198
|
+
// holds (the multi-instance replacement for the removed list.current), so
|
|
199
|
+
// the host can lead the bubble stack with it. A bubble can outlive its
|
|
200
|
+
// disposed session by one poll tick, and navigation rejects unknown ids,
|
|
201
|
+
// so consult the live list first. The pet's type program also loads the
|
|
202
|
+
// host-side dsh-session package through the service types, whose Context
|
|
203
|
+
// merge declares a different 'sessions' face; pin the browser runtime's
|
|
204
|
+
// outward face here.
|
|
170
205
|
const sessions = ctx.sessions;
|
|
171
|
-
const currentSessionId = () =>
|
|
172
|
-
const current = sessions.list.getSnapshot().current;
|
|
173
|
-
return current === undefined ? undefined : String(current);
|
|
174
|
-
};
|
|
206
|
+
const currentSessionId = () => mainViewSessionId(sessions.list.getSnapshot().byId);
|
|
175
207
|
// The registry list is fetched lazily with retries baked into the poll
|
|
176
208
|
// cycle: until it lands, the dock entry renders nothing and every 2s
|
|
177
209
|
// tick tries again. After it lands, one list feeds both the sprite and
|
|
@@ -251,7 +283,9 @@ export function apply(ctx) {
|
|
|
251
283
|
const list = sessions.list.getSnapshot();
|
|
252
284
|
if (list.byId[sessionId] === undefined)
|
|
253
285
|
return;
|
|
254
|
-
|
|
286
|
+
// Navigation belongs to the workspace UI since the multi-instance Client
|
|
287
|
+
// Session model; the Session Controller no longer opens one.
|
|
288
|
+
ctx.uiWorkspace.openSession(sessionId);
|
|
255
289
|
};
|
|
256
290
|
const injected = () => ({
|
|
257
291
|
store: petStore,
|
|
@@ -393,7 +427,7 @@ export function apply(ctx) {
|
|
|
393
427
|
// (issue #785): disposal drops the subscription and tears the UI down
|
|
394
428
|
// (terminal), so a hot-reloaded or re-injected bundle never leaves the
|
|
395
429
|
// previous React root, container, or poll loop behind on document.body.
|
|
396
|
-
const unsubscribeSettings =
|
|
430
|
+
const unsubscribeSettings = settingsForm.subscribe(syncUi);
|
|
397
431
|
ctx.effect(() => () => {
|
|
398
432
|
unsubscribeSettings();
|
|
399
433
|
killUi();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main-view Session derivation for the multi-instance Client Session model.
|
|
3
|
+
*
|
|
4
|
+
* The Client Session Controller carries no global "current" selection: view
|
|
5
|
+
* selection belongs to the workspace UI, which owns the main-area reference and
|
|
6
|
+
* publishes it through the catalog's per-source ownership counts
|
|
7
|
+
* (`SessionSummary.retainedBy.mainView`). A plugin that needs the Session the
|
|
8
|
+
* main view shows derives it from that marker instead of the removed
|
|
9
|
+
* `SessionListState.current` field.
|
|
10
|
+
*
|
|
11
|
+
* The marker describes view ownership, not authority. It is the right input for
|
|
12
|
+
* presentation and for deciding which view a navigation targets; it is not a
|
|
13
|
+
* business fallback, because source counts never imply visibility or success.
|
|
14
|
+
* @module dsh-web/shared/main-session
|
|
15
|
+
*/
|
|
16
|
+
/** The catalog row subset this helper reads (a `SessionSummary` projection). */
|
|
17
|
+
export interface MainViewOwnedRow<Id extends string = string> {
|
|
18
|
+
/** Catalog row identity. */
|
|
19
|
+
readonly id: Id;
|
|
20
|
+
/** Per-source local ownership counts; absent rows are never owned. */
|
|
21
|
+
readonly retainedBy?: Readonly<Partial<Record<string, number>>> | undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the Session the main view currently shows.
|
|
25
|
+
*
|
|
26
|
+
* Reads the catalog's rows rather than a per-id retain-info source: ownership
|
|
27
|
+
* counts ride the list snapshot, so this neither allocates observers nor opens
|
|
28
|
+
* history, and a subscription to the list still fires when the selection moves.
|
|
29
|
+
* @param byId - the session catalog's rows (`SessionListState.byId`), when available.
|
|
30
|
+
* @returns the main-view session id, or undefined when the main view shows none.
|
|
31
|
+
*/
|
|
32
|
+
export declare function mainViewSessionId<Id extends string>(byId: Readonly<Record<Id, MainViewOwnedRow<Id> | undefined>> | undefined | null): Id | undefined;
|
|
33
|
+
//# sourceMappingURL=main-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-session.d.ts","sourceRoot":"","sources":["../../../src/client/main-session.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;GAcG;AAEH,gFAAgF;AAChF,MAAM,WAAW,gBAAgB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM;IAC1D,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAA;IACf,sEAAsE;IACtE,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;CAC5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,MAAM,EACjD,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,GAC9E,EAAE,GAAG,SAAS,CAMhB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Generated by scripts/sync-shared.mjs from shared/client/main-session.ts. Do not edit this copy; edit the shared source and run "node scripts/sync-shared.mjs".
|
|
2
|
+
/**
|
|
3
|
+
* Main-view Session derivation for the multi-instance Client Session model.
|
|
4
|
+
*
|
|
5
|
+
* The Client Session Controller carries no global "current" selection: view
|
|
6
|
+
* selection belongs to the workspace UI, which owns the main-area reference and
|
|
7
|
+
* publishes it through the catalog's per-source ownership counts
|
|
8
|
+
* (`SessionSummary.retainedBy.mainView`). A plugin that needs the Session the
|
|
9
|
+
* main view shows derives it from that marker instead of the removed
|
|
10
|
+
* `SessionListState.current` field.
|
|
11
|
+
*
|
|
12
|
+
* The marker describes view ownership, not authority. It is the right input for
|
|
13
|
+
* presentation and for deciding which view a navigation targets; it is not a
|
|
14
|
+
* business fallback, because source counts never imply visibility or success.
|
|
15
|
+
* @module dsh-web/shared/main-session
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the Session the main view currently shows.
|
|
19
|
+
*
|
|
20
|
+
* Reads the catalog's rows rather than a per-id retain-info source: ownership
|
|
21
|
+
* counts ride the list snapshot, so this neither allocates observers nor opens
|
|
22
|
+
* history, and a subscription to the list still fires when the selection moves.
|
|
23
|
+
* @param byId - the session catalog's rows (`SessionListState.byId`), when available.
|
|
24
|
+
* @returns the main-view session id, or undefined when the main view shows none.
|
|
25
|
+
*/
|
|
26
|
+
export function mainViewSessionId(byId) {
|
|
27
|
+
if (byId === undefined || byId === null)
|
|
28
|
+
return undefined;
|
|
29
|
+
for (const row of Object.values(byId)) {
|
|
30
|
+
if (row !== undefined && (row.retainedBy?.mainView ?? 0) > 0)
|
|
31
|
+
return row.id;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* each plugin's client bundle; mirrors the official ui-plugin-config
|
|
7
7
|
* card-store pattern.
|
|
8
8
|
*/
|
|
9
|
-
import type {
|
|
9
|
+
import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
10
10
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
11
11
|
/** The write one field's staged text performs when the card is saved. */
|
|
12
12
|
export type FieldWrite = {
|
|
@@ -86,7 +86,7 @@ export interface CardActions {
|
|
|
86
86
|
/** Drop every staged edit. */
|
|
87
87
|
discard: () => void;
|
|
88
88
|
}
|
|
89
|
-
/** One durable write inside the save's atomic
|
|
89
|
+
/** One durable write inside the save's atomic form mutation. */
|
|
90
90
|
export interface BatchedWrite {
|
|
91
91
|
/** Field this entry writes. */
|
|
92
92
|
field: string;
|
|
@@ -130,20 +130,20 @@ export declare class CardForm<T> {
|
|
|
130
130
|
private readonly specs;
|
|
131
131
|
private readonly staged;
|
|
132
132
|
private readonly listeners;
|
|
133
|
-
/** The
|
|
134
|
-
private readonly
|
|
133
|
+
/** The form subscription installed in the constructor; released by dispose(). */
|
|
134
|
+
private readonly disposeForm;
|
|
135
135
|
private disposed;
|
|
136
136
|
private saving;
|
|
137
137
|
private failed;
|
|
138
138
|
private failedReason;
|
|
139
|
-
/** @param scope - the bound
|
|
140
|
-
constructor(scope:
|
|
139
|
+
/** @param scope - the bound configuration form for this card's namespace. */
|
|
140
|
+
constructor(scope: ConfigForm<T>, specs: FieldSpec[]);
|
|
141
141
|
/**
|
|
142
|
-
* Release the
|
|
142
|
+
* Release the form subscription and every bound store listener. The card
|
|
143
143
|
* must call this on teardown; later calls are no-ops.
|
|
144
144
|
*/
|
|
145
145
|
dispose(): void;
|
|
146
|
-
/** Publish a projection of this form, rebuilt whenever the
|
|
146
|
+
/** Publish a projection of this form, rebuilt whenever the form or a draft changes. */
|
|
147
147
|
bind<S>(project: () => S): SnapshotStore<S>;
|
|
148
148
|
/** Read the card-level state: what the Host serves, and what a save would do. */
|
|
149
149
|
shell(): CardShell;
|
|
@@ -152,19 +152,19 @@ export declare class CardForm<T> {
|
|
|
152
152
|
/** The actions the card's slot registration injects. */
|
|
153
153
|
actions(): CardActions;
|
|
154
154
|
/**
|
|
155
|
-
* Write every staged edit in one atomic
|
|
155
|
+
* Write every staged edit in one atomic form mutation, then re-seed from
|
|
156
156
|
* what the Host accepted.
|
|
157
157
|
*
|
|
158
158
|
* The whole batch rides one mutate, so cross-field validate hooks
|
|
159
159
|
* (baseURL+model) judge it as a unit: the Host either applies every write
|
|
160
|
-
* or refuses the batch. The
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* settled snapshot back
|
|
164
|
-
* fails the whole save. A
|
|
165
|
-
*
|
|
166
|
-
* message. A save that did not land keeps its drafts, so
|
|
167
|
-
* correct them instead of retyping.
|
|
160
|
+
* or refuses the batch. The form contract answers a refusal or a skipped
|
|
161
|
+
* write with `false` (it recovers with a fresh Host view instead of
|
|
162
|
+
* throwing), so the outcome is judged twice: the answer itself, and then the
|
|
163
|
+
* settled snapshot read back one planned write at a time. One missed write
|
|
164
|
+
* fails the whole save. A transport that rejects instead (the dsh-web bridge
|
|
165
|
+
* controller on a dead connection) reports through the same failure path
|
|
166
|
+
* with its rejection message. A save that did not land keeps its drafts, so
|
|
167
|
+
* the user can correct them instead of retyping.
|
|
168
168
|
* @returns settlement after the mutation and the read-back.
|
|
169
169
|
*/
|
|
170
170
|
save(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"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"}
|