@linxin666/dsh-pet 0.3.5 → 0.3.9
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 -0
- package/README.zh.md +4 -0
- package/contracts/voice-pack-v1.schema.json +30 -0
- package/cordis.patch.yml +1 -1
- package/lib/client.js +330 -103
- package/lib/client.js.map +1 -1
- package/lib/index.js +145 -28
- package/lib/invariant.js +1 -1
- package/lib/live2d-vendor.js +106 -95
- package/lib/live2d-vendor.js.map +1 -1
- package/lib/{state-DrMX22GL.js → state-NvDEoCln.js} +5 -2
- package/lib/types/access.d.ts +5 -4
- package/lib/types/access.d.ts.map +1 -1
- package/lib/types/access.js +2 -12
- package/lib/types/affinity.d.ts +2 -0
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +12 -0
- package/lib/types/announce.d.ts +53 -0
- package/lib/types/announce.d.ts.map +1 -0
- package/lib/types/announce.js +80 -0
- package/lib/types/client/PetDockEntry.d.ts +14 -5
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +6 -5
- package/lib/types/client/PetSettingsCard.d.ts +2 -1
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSprite.d.ts +8 -0
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +36 -5
- 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 +11 -5
- package/lib/types/client/locales.d.ts +20 -2
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +20 -2
- package/lib/types/client/pet-store.d.ts +1 -1
- package/lib/types/client/pet-store.d.ts.map +1 -1
- package/lib/types/client/pet-store.js +1 -1
- package/lib/types/client/renderers/frames2d.d.ts +12 -0
- package/lib/types/client/renderers/frames2d.d.ts.map +1 -1
- package/lib/types/client/renderers/frames2d.js +143 -18
- package/lib/types/client/settings-form.d.ts +35 -43
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +60 -53
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +10 -9
- package/lib/types/ledger.d.ts +4 -2
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +4 -4
- package/lib/types/pair-access.d.ts +35 -0
- package/lib/types/pair-access.d.ts.map +1 -0
- package/lib/types/pair-access.js +19 -0
- package/lib/types/remarks.d.ts +1 -1
- package/lib/types/remarks.d.ts.map +1 -1
- package/lib/types/remarks.js +11 -2
- package/lib/types/service.d.ts +18 -0
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +26 -1
- package/lib/types/voice-pack.d.ts +5 -0
- package/lib/types/voice-pack.d.ts.map +1 -1
- package/lib/types/voice-pack.js +36 -2
- package/package.json +17 -13
- package/src/access.ts +7 -27
- package/src/affinity.ts +13 -0
- package/src/announce.ts +103 -0
- package/src/client/PetDockEntry.test.tsx +1 -1
- package/src/client/PetDockEntry.tsx +15 -4
- package/src/client/PetSettingsCard.tsx +2 -1
- package/src/client/PetSprite.test.tsx +36 -0
- package/src/client/PetSprite.tsx +75 -4
- package/src/client/gameplay-hud.test.tsx +1 -1
- package/src/client/index.test.tsx +2 -2
- package/src/client/index.ts +17 -6
- package/src/client/locales.ts +20 -2
- package/src/client/pet-store.ts +2 -2
- package/src/client/pet.module.css +104 -0
- package/src/client/renderers/frames2d.test.ts +101 -0
- package/src/client/renderers/frames2d.ts +138 -18
- package/src/client/settings-form.ts +78 -92
- package/src/dsh-home.ts +1 -1
- package/src/index.ts +17 -15
- package/src/ledger.ts +6 -4
- package/src/pair-access.ts +49 -0
- package/src/remarks.test.ts +10 -0
- package/src/remarks.ts +9 -2
- package/src/service.ts +32 -2
- package/src/voice-pack.test.ts +39 -0
- package/src/voice-pack.ts +37 -2
|
@@ -13,6 +13,15 @@ export const zh = {
|
|
|
13
13
|
'pet.namePlaceholder': '输入新名字',
|
|
14
14
|
'pet.summon': '召唤{name}',
|
|
15
15
|
'pet.rank': '亲密度 {rank}',
|
|
16
|
+
'pet.rank.name.幼鲸': '幼鲸',
|
|
17
|
+
'pet.rank.name.伙伴': '伙伴',
|
|
18
|
+
'pet.rank.name.挚友': '挚友',
|
|
19
|
+
'pet.rank.name.深海羁绊': '深海羁绊',
|
|
20
|
+
'pet.rank.name.心有灵犀': '心有灵犀',
|
|
21
|
+
'pet.rank.name.传说羁绊': '传说羁绊',
|
|
22
|
+
'pet.rank.name.神话羁绊': '神话羁绊',
|
|
23
|
+
'pet.rank.name.永恒之契': '永恒之契',
|
|
24
|
+
'pet.rank.name.鲸生共渡': '鲸生共渡',
|
|
16
25
|
'pet.points': '{points} 点',
|
|
17
26
|
'pet.treats': '小鱼干 ×{n}',
|
|
18
27
|
'pet.state.loading': '宠物正在赶来…',
|
|
@@ -65,7 +74,7 @@ export const zh = {
|
|
|
65
74
|
'settings.off': '关',
|
|
66
75
|
'settings.overridden': '已覆盖',
|
|
67
76
|
'settings.reset': '恢复默认',
|
|
68
|
-
'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑
|
|
77
|
+
'settings.notExposed': '当前 DSH 版本未向设置页暴露本插件的配置命名空间,表单不可用。可编辑 $DSH_HOME/settings.yaml 直接配置,或确认提供该命名空间的插件已挂载其设置域并重启。',
|
|
69
78
|
'settings.readOnly': '当前部署的设置只读。',
|
|
70
79
|
'settings.expand': '展开设置',
|
|
71
80
|
'settings.collapse': '收起设置',
|
|
@@ -85,6 +94,15 @@ export const en = {
|
|
|
85
94
|
'pet.namePlaceholder': 'Enter a new name',
|
|
86
95
|
'pet.summon': 'Summon {name}',
|
|
87
96
|
'pet.rank': 'Affinity {rank}',
|
|
97
|
+
'pet.rank.name.幼鲸': 'Baby Whale',
|
|
98
|
+
'pet.rank.name.伙伴': 'Companion',
|
|
99
|
+
'pet.rank.name.挚友': 'Close Friend',
|
|
100
|
+
'pet.rank.name.深海羁绊': 'Deep Sea Bond',
|
|
101
|
+
'pet.rank.name.心有灵犀': 'Kindred Spirit',
|
|
102
|
+
'pet.rank.name.传说羁绊': 'Legendary Bond',
|
|
103
|
+
'pet.rank.name.神话羁绊': 'Mythic Bond',
|
|
104
|
+
'pet.rank.name.永恒之契': 'Eternal Covenant',
|
|
105
|
+
'pet.rank.name.鲸生共渡': 'Lifelong Companion',
|
|
88
106
|
'pet.points': '{points} pts',
|
|
89
107
|
'pet.treats': 'Treats ×{n}',
|
|
90
108
|
'pet.state.loading': 'The pet is on its way…',
|
|
@@ -137,7 +155,7 @@ export const en = {
|
|
|
137
155
|
'settings.off': 'Off',
|
|
138
156
|
'settings.overridden': 'Overridden',
|
|
139
157
|
'settings.reset': 'Reset to default',
|
|
140
|
-
'settings.notExposed': 'This DSH version does not expose this plugin\'s settings namespace to the configuration page, so the form is unavailable. Edit
|
|
158
|
+
'settings.notExposed': 'This DSH version does not expose this plugin\'s settings namespace to the configuration page, so the form is unavailable. Edit $DSH_HOME/settings.yaml directly, or confirm that the plugin owning the namespace is mounted with its settings domain and restart.',
|
|
141
159
|
'settings.readOnly': 'This deployment stores settings read-only.',
|
|
142
160
|
'settings.expand': 'Show settings',
|
|
143
161
|
'settings.collapse': 'Hide settings',
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* only ever read snapshots.
|
|
6
6
|
* @module @linxin666/dsh-pet/client/pet-store
|
|
7
7
|
*/
|
|
8
|
-
import type { EngineStoreHandle, EngineStoreInstance } from '@deepseek-ai/dsh-client-
|
|
8
|
+
import type { EngineStoreHandle, EngineStoreInstance } from '@deepseek-ai/dsh-client-store';
|
|
9
9
|
import type { PetGameplayStateView, PetStateView } from '../service.ts';
|
|
10
10
|
import type { PetInteraction } from '../affinity.ts';
|
|
11
11
|
import type { PetDefinition } from '../registry.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pet-store.d.ts","sourceRoot":"","sources":["../../../src/client/pet-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"pet-store.d.ts","sourceRoot":"","sources":["../../../src/client/pet-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,IAAI,EAAE,cAAc,GAAG,MAAM,CAAA;IAC7B,sDAAsD;IACtD,EAAE,EAAE,MAAM,CAAA;CACX;AAED,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,aAAa,EAAE,CAAA;IACrB,uBAAuB;IACvB,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;IACpC,iEAAiE;IACjE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;CAC7B;AAED,uBAAuB;AACvB,MAAM,MAAM,YAAY,GAAG;IACzB,+CAA+C;IAC/C,WAAW,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAA;IAChE,iCAAiC;IACjC,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,IAAI,CAAA;IAC3D,gCAAgC;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACvF,8BAA8B;IAC9B,WAAW,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IACtE;;;;OAIG;IACH,eAAe,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAA;CACzE,CAAA;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,IAAI,iBAAiB,CAAC,UAAU,EAAE,YAAY,CAAC,CA8B5E;AAED,YAAY,EAAE,cAAc,EAAE,CAAA;AAE9B;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* only ever read snapshots.
|
|
6
6
|
* @module @linxin666/dsh-pet/client/pet-store
|
|
7
7
|
*/
|
|
8
|
-
import { defineStore } from '@deepseek-ai/dsh-client-
|
|
8
|
+
import { defineStore } from '@deepseek-ai/dsh-client-store';
|
|
9
9
|
/** Create the pet store handle (apply world only; never module-level). */
|
|
10
10
|
export function createPetStore() {
|
|
11
11
|
return defineStore({
|
|
@@ -8,6 +8,18 @@
|
|
|
8
8
|
* phase-mapped track. Rendering never throws: a broken track list degrades
|
|
9
9
|
* to the first decodable frame, and the 1.2 s stall watchdog re-kicks the
|
|
10
10
|
* playback chain after timer throttling.
|
|
11
|
+
*
|
|
12
|
+
* Frame presentation has two modes picked once at mount by capability
|
|
13
|
+
* probing:
|
|
14
|
+
* - Canvas bitmap buffer (default where createImageBitmap/fetch/2D context
|
|
15
|
+
* exist): every frame is decoded exactly once into an ImageBitmap during
|
|
16
|
+
* the warm pass and drawn onto one <canvas> - steady-state playback issues
|
|
17
|
+
* zero DOM mutations and zero re-decodes (measured hotspot: swapping
|
|
18
|
+
* <img>.src per frame drove image decode + invalidation every tick).
|
|
19
|
+
* - Classic <img> fallback (jsdom/tests or missing APIs): identical to the
|
|
20
|
+
* historical behavior - cache-warm Image elements plus guarded src swaps,
|
|
21
|
+
* so environments without modern decoding keep working unchanged.
|
|
22
|
+
*
|
|
11
23
|
* @module @linxin666/dsh-pet/client/renderers/frames2d
|
|
12
24
|
*/
|
|
13
25
|
import { type PetRenderer, type PetRendererHandle } from '../../contracts/renderer.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frames2d.d.ts","sourceRoot":"","sources":["../../../../src/client/renderers/frames2d.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"frames2d.d.ts","sourceRoot":"","sources":["../../../../src/client/renderers/frames2d.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAA4B,KAAK,WAAW,EAA2B,KAAK,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AACzI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,oEAAoE;AACpE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,8DAA8D;AAC9D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAClE;AAED,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;IACzC,2DAA2D;IAC3D,YAAY,IAAI,MAAM,CAAA;CACvB;AA0CD,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,iBAAiB,CAsP3D,CAAA"}
|
|
@@ -8,6 +8,18 @@
|
|
|
8
8
|
* phase-mapped track. Rendering never throws: a broken track list degrades
|
|
9
9
|
* to the first decodable frame, and the 1.2 s stall watchdog re-kicks the
|
|
10
10
|
* playback chain after timer throttling.
|
|
11
|
+
*
|
|
12
|
+
* Frame presentation has two modes picked once at mount by capability
|
|
13
|
+
* probing:
|
|
14
|
+
* - Canvas bitmap buffer (default where createImageBitmap/fetch/2D context
|
|
15
|
+
* exist): every frame is decoded exactly once into an ImageBitmap during
|
|
16
|
+
* the warm pass and drawn onto one <canvas> - steady-state playback issues
|
|
17
|
+
* zero DOM mutations and zero re-decodes (measured hotspot: swapping
|
|
18
|
+
* <img>.src per frame drove image decode + invalidation every tick).
|
|
19
|
+
* - Classic <img> fallback (jsdom/tests or missing APIs): identical to the
|
|
20
|
+
* historical behavior - cache-warm Image elements plus guarded src swaps,
|
|
21
|
+
* so environments without modern decoding keep working unchanged.
|
|
22
|
+
*
|
|
11
23
|
* @module @linxin666/dsh-pet/client/renderers/frames2d
|
|
12
24
|
*/
|
|
13
25
|
import { PET_RENDERER_API_VERSION } from "../../contracts/renderer.js";
|
|
@@ -50,23 +62,83 @@ export const frames2dRenderer = {
|
|
|
50
62
|
const reducedMotion = typeof window !== 'undefined'
|
|
51
63
|
&& typeof window.matchMedia === 'function'
|
|
52
64
|
&& window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
img
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const pre = new Image();
|
|
67
|
-
pre.src = url;
|
|
65
|
+
// Capability probe: the canvas path needs decode-to-bitmap, same-origin
|
|
66
|
+
// fetch, and a real 2D context (jsdom returns null and falls back below).
|
|
67
|
+
let canvas = null;
|
|
68
|
+
let context2d = null;
|
|
69
|
+
let img = null;
|
|
70
|
+
try {
|
|
71
|
+
if (typeof createImageBitmap === 'function' && typeof fetch === 'function') {
|
|
72
|
+
const probe = document.createElement('canvas');
|
|
73
|
+
const c2d = probe.getContext('2d');
|
|
74
|
+
if (c2d !== null) {
|
|
75
|
+
canvas = probe;
|
|
76
|
+
context2d = c2d;
|
|
77
|
+
}
|
|
68
78
|
}
|
|
69
79
|
}
|
|
80
|
+
catch {
|
|
81
|
+
canvas = null;
|
|
82
|
+
context2d = null;
|
|
83
|
+
}
|
|
84
|
+
if (canvas !== null && context2d !== null) {
|
|
85
|
+
canvas.dataset.dshPetFrames2d = ctx.petId;
|
|
86
|
+
canvas.draggable = false;
|
|
87
|
+
canvas.style.width = '100%';
|
|
88
|
+
canvas.style.height = '100%';
|
|
89
|
+
canvas.style.objectFit = 'contain';
|
|
90
|
+
canvas.style.pointerEvents = 'none';
|
|
91
|
+
ctx.container.appendChild(canvas);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
img = document.createElement('img');
|
|
95
|
+
img.dataset.dshPetFrames2d = ctx.petId;
|
|
96
|
+
img.alt = '';
|
|
97
|
+
img.draggable = false;
|
|
98
|
+
img.style.width = '100%';
|
|
99
|
+
img.style.height = '100%';
|
|
100
|
+
img.style.objectFit = 'contain';
|
|
101
|
+
img.style.pointerEvents = 'none';
|
|
102
|
+
ctx.container.appendChild(img);
|
|
103
|
+
}
|
|
104
|
+
// Decode cache: one concurrent decode per URL, memoized forever (frames
|
|
105
|
+
// are tiny same-origin webp files; failures resolve undefined and keep
|
|
106
|
+
// the last painted frame instead of breaking playback).
|
|
107
|
+
const decoding = new Map();
|
|
108
|
+
const decodedAll = [];
|
|
109
|
+
const loadFrame = (url) => {
|
|
110
|
+
const cached = decoding.get(url);
|
|
111
|
+
if (cached !== undefined)
|
|
112
|
+
return cached;
|
|
113
|
+
const job = (async () => {
|
|
114
|
+
try {
|
|
115
|
+
const response = await fetch(url);
|
|
116
|
+
if (!response.ok)
|
|
117
|
+
throw new Error('http ' + response.status);
|
|
118
|
+
const bitmap = await createImageBitmap(await response.blob());
|
|
119
|
+
return { source: bitmap, width: bitmap.width, height: bitmap.height };
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Fail-open: classic Image decode keeps non-modern runtimes alive.
|
|
123
|
+
return await new Promise((resolve) => {
|
|
124
|
+
try {
|
|
125
|
+
const pre = new Image();
|
|
126
|
+
pre.onload = () => {
|
|
127
|
+
resolve(pre.naturalWidth > 0 ? { source: pre, width: pre.naturalWidth, height: pre.naturalHeight } : undefined);
|
|
128
|
+
};
|
|
129
|
+
pre.onerror = () => resolve(undefined);
|
|
130
|
+
pre.src = url;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
resolve(undefined);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
})();
|
|
138
|
+
decoding.set(url, job);
|
|
139
|
+
decodedAll.push(job.then(() => undefined, () => undefined));
|
|
140
|
+
return job;
|
|
141
|
+
};
|
|
70
142
|
let disposed = false;
|
|
71
143
|
let timer;
|
|
72
144
|
let watchdog;
|
|
@@ -74,15 +146,45 @@ export const frames2dRenderer = {
|
|
|
74
146
|
let frameIndex = 0;
|
|
75
147
|
let lastAdvance = Date.now();
|
|
76
148
|
let override;
|
|
149
|
+
let drawToken = 0;
|
|
150
|
+
let lastDrawnUrl;
|
|
77
151
|
const trackForPhase = (phase) => {
|
|
78
152
|
const mapped = config.phases[phase];
|
|
79
153
|
return mapped !== undefined && config.tracks[mapped] !== undefined ? mapped : config.phases.idle;
|
|
80
154
|
};
|
|
155
|
+
/** Canvas path: paints the newest requested frame; stale draws drop out. */
|
|
156
|
+
const paintCanvas = (url) => {
|
|
157
|
+
if (context2d === null || canvas === null)
|
|
158
|
+
return;
|
|
159
|
+
const myToken = ++drawToken;
|
|
160
|
+
void loadFrame(url).then((frame) => {
|
|
161
|
+
if (disposed || frame === undefined || myToken !== drawToken)
|
|
162
|
+
return;
|
|
163
|
+
if (lastDrawnUrl === url)
|
|
164
|
+
return;
|
|
165
|
+
lastDrawnUrl = url;
|
|
166
|
+
// Resizing clears the canvas, so size only when it actually differs.
|
|
167
|
+
if (canvas.width !== frame.width || canvas.height !== frame.height) {
|
|
168
|
+
canvas.width = frame.width;
|
|
169
|
+
canvas.height = frame.height;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
context2d.clearRect(0, 0, canvas.width, canvas.height);
|
|
173
|
+
}
|
|
174
|
+
context2d.drawImage(frame.source, 0, 0);
|
|
175
|
+
}).catch(() => { });
|
|
176
|
+
};
|
|
81
177
|
const show = (trackId, index) => {
|
|
82
178
|
const def = config.tracks[trackId];
|
|
83
179
|
const url = def?.frames[index];
|
|
84
|
-
if (url
|
|
85
|
-
|
|
180
|
+
if (url === undefined)
|
|
181
|
+
return;
|
|
182
|
+
if (img !== null) {
|
|
183
|
+
if (img.getAttribute('src') !== url)
|
|
184
|
+
img.src = url;
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
paintCanvas(url);
|
|
86
188
|
};
|
|
87
189
|
const schedule = (ms) => {
|
|
88
190
|
if (disposed)
|
|
@@ -155,6 +257,13 @@ export const frames2dRenderer = {
|
|
|
155
257
|
tick();
|
|
156
258
|
}, WATCHDOG_MS);
|
|
157
259
|
}
|
|
260
|
+
// Warm pass: decode every frame up front (tiny same-origin webp files)
|
|
261
|
+
// so loops and phase switches never wait on a first decode - same intent
|
|
262
|
+
// as the historical Image-cache warm loop, now feeding the decode cache.
|
|
263
|
+
for (const warmTrack of Object.values(config.tracks)) {
|
|
264
|
+
for (const warmUrl of warmTrack.frames)
|
|
265
|
+
void loadFrame(warmUrl);
|
|
266
|
+
}
|
|
158
267
|
play(track);
|
|
159
268
|
let disposedOnce = false;
|
|
160
269
|
const dispose = () => {
|
|
@@ -167,7 +276,23 @@ export const frames2dRenderer = {
|
|
|
167
276
|
clearTimeout(timer);
|
|
168
277
|
if (watchdog !== undefined)
|
|
169
278
|
clearInterval(watchdog);
|
|
170
|
-
|
|
279
|
+
// Release decoded bitmaps after pending decodes settle; close() is
|
|
280
|
+
// browser-only, so guard it for exotic hosts.
|
|
281
|
+
void Promise.allSettled(decodedAll).then(() => {
|
|
282
|
+
for (const job of decoding.values()) {
|
|
283
|
+
void job.then((frame) => {
|
|
284
|
+
try {
|
|
285
|
+
const maybeClose = frame?.source?.close;
|
|
286
|
+
if (typeof maybeClose === 'function' && frame !== undefined)
|
|
287
|
+
maybeClose.call(frame.source);
|
|
288
|
+
}
|
|
289
|
+
catch { /* already released */ }
|
|
290
|
+
}).catch(() => { });
|
|
291
|
+
}
|
|
292
|
+
decoding.clear();
|
|
293
|
+
});
|
|
294
|
+
canvas?.remove();
|
|
295
|
+
img?.remove();
|
|
171
296
|
};
|
|
172
297
|
ctx.onCleanup(dispose);
|
|
173
298
|
return {
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* each plugin's client bundle; mirrors the official ui-plugin-config
|
|
7
7
|
* card-store pattern.
|
|
8
8
|
*/
|
|
9
|
-
import type { SettingsScope
|
|
9
|
+
import type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
10
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
10
11
|
/** The write one field's staged text performs when the card is saved. */
|
|
11
12
|
export type FieldWrite = {
|
|
12
13
|
kind: 'set';
|
|
@@ -21,9 +22,11 @@ export interface FieldSpec {
|
|
|
21
22
|
/**
|
|
22
23
|
* Whether the Host treats this field as a secret and redacts its value from
|
|
23
24
|
* the read-back (role('secret') in the section schema). Redacted secrets are
|
|
24
|
-
* never compared against the draft on save
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* never compared against the draft on save: the Host strips them from every
|
|
26
|
+
* wire view layer, so the settled snapshot carries nothing to read back. A
|
|
27
|
+
* staged secret set is judged by the mutation settling; the rest of its
|
|
28
|
+
* batch, when one exists, is still judged by read-back, and the atomic
|
|
29
|
+
* mutation lands every write or none.
|
|
27
30
|
*/
|
|
28
31
|
secret?: boolean;
|
|
29
32
|
/** Render a stored value as draft text; the empty string when the section carries none. */
|
|
@@ -49,8 +52,8 @@ export interface CardShell {
|
|
|
49
52
|
available: boolean;
|
|
50
53
|
/**
|
|
51
54
|
* Whether the namespace is actually served to this client. False when the
|
|
52
|
-
* Host deployment does not expose it (e.g. the
|
|
53
|
-
*
|
|
55
|
+
* Host deployment does not expose it (e.g. the owning plugin's settings
|
|
56
|
+
* domain is not mounted): the card renders an explanation
|
|
54
57
|
* instead of its form, so a missing namespace never looks like a missing
|
|
55
58
|
* plugin.
|
|
56
59
|
*/
|
|
@@ -83,7 +86,7 @@ export interface CardActions {
|
|
|
83
86
|
/** Drop every staged edit. */
|
|
84
87
|
discard: () => void;
|
|
85
88
|
}
|
|
86
|
-
/** One durable write
|
|
89
|
+
/** One durable write inside the save's atomic scope mutation. */
|
|
87
90
|
export interface BatchedWrite {
|
|
88
91
|
/** Field this entry writes. */
|
|
89
92
|
field: string;
|
|
@@ -92,28 +95,6 @@ export interface BatchedWrite {
|
|
|
92
95
|
/** Value for op set (absent for unset). */
|
|
93
96
|
value?: unknown;
|
|
94
97
|
}
|
|
95
|
-
/** Per-field outcome of one batched scope write. */
|
|
96
|
-
export interface BatchedFieldResult {
|
|
97
|
-
/** Field this entry writes. */
|
|
98
|
-
field: string;
|
|
99
|
-
/** Whether the Host accepted this field's write (per the read-back view). */
|
|
100
|
-
landed: boolean;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Result of a batched scope write. The bridge scope posts every planned write
|
|
104
|
-
* in one /mutate so the Host validate hook judges baseURL+model together; a
|
|
105
|
-
* batched refusal fails the whole save rather than per-field.
|
|
106
|
-
*/
|
|
107
|
-
export interface BatchResult {
|
|
108
|
-
/** Whether the whole mutate was accepted. */
|
|
109
|
-
ok: boolean;
|
|
110
|
-
/** Per-field success, in the request order (always present when ok). */
|
|
111
|
-
fields: BatchedFieldResult[];
|
|
112
|
-
/** Host rejection code (mutate refused). */
|
|
113
|
-
code?: string;
|
|
114
|
-
/** Host rejection message (mutate refused). */
|
|
115
|
-
message?: string;
|
|
116
|
-
}
|
|
117
98
|
/** Constraints a numeric field's accepted drafts must satisfy, mirroring the host schema. */
|
|
118
99
|
export interface NumberConstraints {
|
|
119
100
|
/** The accepted value must be a whole number. */
|
|
@@ -128,8 +109,8 @@ export declare function textField(field: string): FieldSpec;
|
|
|
128
109
|
/**
|
|
129
110
|
* A free-text field the Host treats as a secret and redacts from the read-back
|
|
130
111
|
* (role('secret') in the section schema). The card still edits it like text,
|
|
131
|
-
* but a save never compares the redacted value back
|
|
132
|
-
*
|
|
112
|
+
* but a save never compares the redacted value back: the staged set is judged
|
|
113
|
+
* by the mutation settling (see {@link FieldSpec.secret}).
|
|
133
114
|
*/
|
|
134
115
|
export declare function secretField(field: string): FieldSpec;
|
|
135
116
|
/** A boolean field, edited through true/false draft text. */
|
|
@@ -171,19 +152,22 @@ export declare class CardForm<T> {
|
|
|
171
152
|
/** The actions the card's slot registration injects. */
|
|
172
153
|
actions(): CardActions;
|
|
173
154
|
/**
|
|
174
|
-
* Write every staged edit, then re-seed from
|
|
155
|
+
* Write every staged edit in one atomic scope mutation, then re-seed from
|
|
156
|
+
* what the Host accepted.
|
|
175
157
|
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
158
|
+
* The whole batch rides one mutate, so cross-field validate hooks
|
|
159
|
+
* (baseURL+model) judge it as a unit: the Host either applies every write
|
|
160
|
+
* or refuses the batch. The 0.1.2 scope contract never rejects a refused
|
|
161
|
+
* mutation — the scope recovers with a fresh Host view and resolves — so
|
|
162
|
+
* resolution alone proves nothing: the outcome is judged by reading the
|
|
163
|
+
* settled snapshot back, one planned write at a time, and one missed write
|
|
164
|
+
* fails the whole save. A scope that still rejects on refusal (the dsh-web
|
|
165
|
+
* bridge scope) reports through the same failure path with its rejection
|
|
166
|
+
* message. A save that did not land keeps its drafts, so the user can
|
|
167
|
+
* correct them instead of retyping.
|
|
168
|
+
* @returns settlement after the mutation and the read-back.
|
|
183
169
|
*/
|
|
184
170
|
save(): Promise<void>;
|
|
185
|
-
/** The scope's batch surface when it supports one; undefined conservatively otherwise. */
|
|
186
|
-
private batchedScope;
|
|
187
171
|
/**
|
|
188
172
|
* Every staged edit a save would write. An entry whose draft is not a value
|
|
189
173
|
* its field accepts carries no write: the form is still dirty, and the save
|
|
@@ -192,8 +176,16 @@ export declare class CardForm<T> {
|
|
|
192
176
|
* @returns the planned writes, in the order the fields were staged.
|
|
193
177
|
*/
|
|
194
178
|
private plan;
|
|
195
|
-
|
|
196
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Read-back judgment for a planned set: the user layer must hold the
|
|
181
|
+
* intended value once the mutation has settled.
|
|
182
|
+
*/
|
|
183
|
+
private landedSet;
|
|
184
|
+
/**
|
|
185
|
+
* Read-back judgment for a planned unset: the field must be gone from the
|
|
186
|
+
* user layer once the mutation has settled.
|
|
187
|
+
*/
|
|
188
|
+
private landedUnset;
|
|
197
189
|
private stage;
|
|
198
190
|
private specOf;
|
|
199
191
|
private snapshotOf;
|
|
@@ -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,aAAa,EAAyB,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"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"}
|