@jxgame2020/dsh-token-quota 0.1.41 → 0.1.42
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/lib/client.js +162 -137
- package/lib/index.js +1 -1
- package/lib/types/client/index.js +38 -7
- package/lib/types/client/mic.d.ts +11 -7
- package/lib/types/client/mic.js +11 -12
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -132,7 +132,7 @@ window.__ModuleLoader__.load({
|
|
|
132
132
|
d.transcribe = settings;
|
|
133
133
|
},
|
|
134
134
|
setUpgrade: (d, upgrade) => {
|
|
135
|
-
const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.
|
|
135
|
+
const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.42" ? upgrade : null;
|
|
136
136
|
if (d.upgrade === null || d.upgrade.latestVersion !== normalized?.latestVersion) d.upgradeDismissed = false;
|
|
137
137
|
d.upgrade = normalized;
|
|
138
138
|
},
|
|
@@ -262,142 +262,142 @@ window.__ModuleLoader__.load({
|
|
|
262
262
|
document.head.appendChild(tag);
|
|
263
263
|
}
|
|
264
264
|
var TokenQuotaPanel_module_css_default = {
|
|
265
|
-
"
|
|
266
|
-
"
|
|
267
|
-
"
|
|
268
|
-
"
|
|
269
|
-
"
|
|
270
|
-
"
|
|
271
|
-
"
|
|
265
|
+
"noteNewPlus": "NPLLIq_noteNewPlus",
|
|
266
|
+
"resetSelect": "NPLLIq_resetSelect",
|
|
267
|
+
"balanceValueError": "NPLLIq_balanceValueError",
|
|
268
|
+
"noteWin": "NPLLIq_noteWin",
|
|
269
|
+
"selectBtn": "NPLLIq_selectBtn",
|
|
270
|
+
"dialog": "NPLLIq_dialog",
|
|
271
|
+
"dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
|
|
272
|
+
"balanceBarBadge": "NPLLIq_balanceBarBadge",
|
|
273
|
+
"noteWinResize": "NPLLIq_noteWinResize",
|
|
274
|
+
"upgradeClose": "NPLLIq_upgradeClose",
|
|
275
|
+
"balanceWin": "NPLLIq_balanceWin",
|
|
272
276
|
"logPagerControls": "NPLLIq_logPagerControls",
|
|
273
|
-
"
|
|
274
|
-
"
|
|
275
|
-
"
|
|
276
|
-
"
|
|
277
|
-
"
|
|
277
|
+
"upgradeBannerText": "NPLLIq_upgradeBannerText",
|
|
278
|
+
"checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
|
|
279
|
+
"logTable": "NPLLIq_logTable",
|
|
280
|
+
"logClearDate": "NPLLIq_logClearDate",
|
|
281
|
+
"headerText": "NPLLIq_headerText",
|
|
282
|
+
"currentBadge": "NPLLIq_currentBadge",
|
|
283
|
+
"balanceStateHint": "NPLLIq_balanceStateHint",
|
|
284
|
+
"rowDropTarget": "NPLLIq_rowDropTarget",
|
|
285
|
+
"noteWinTitle": "NPLLIq_noteWinTitle",
|
|
286
|
+
"switch": "NPLLIq_switch",
|
|
287
|
+
"noteWinText": "NPLLIq_noteWinText",
|
|
288
|
+
"rowHeader": "NPLLIq_rowHeader",
|
|
289
|
+
"balanceSortBtn": "NPLLIq_balanceSortBtn",
|
|
290
|
+
"versionNew": "NPLLIq_versionNew",
|
|
291
|
+
"header": "NPLLIq_header",
|
|
292
|
+
"settingsDialog": "NPLLIq_settingsDialog",
|
|
293
|
+
"upgradeCommandRow": "NPLLIq_upgradeCommandRow",
|
|
278
294
|
"noteChip": "NPLLIq_noteChip",
|
|
279
|
-
"dialogClose": "NPLLIq_dialogClose",
|
|
280
|
-
"radioRow": "NPLLIq_radioRow",
|
|
281
|
-
"noteMenuBackdrop": "NPLLIq_noteMenuBackdrop",
|
|
282
|
-
"rowMeta": "NPLLIq_rowMeta",
|
|
283
|
-
"balanceRowValue": "NPLLIq_balanceRowValue",
|
|
284
|
-
"collapse": "NPLLIq_collapse",
|
|
285
|
-
"tab": "NPLLIq_tab",
|
|
286
295
|
"balanceRowRefresh": "NPLLIq_balanceRowRefresh",
|
|
287
|
-
"
|
|
288
|
-
"
|
|
289
|
-
"
|
|
290
|
-
"
|
|
291
|
-
"
|
|
296
|
+
"noticeError": "NPLLIq_noticeError",
|
|
297
|
+
"copyBtnDone": "NPLLIq_copyBtnDone",
|
|
298
|
+
"logDialog": "NPLLIq_logDialog",
|
|
299
|
+
"logPagerBtn": "NPLLIq_logPagerBtn",
|
|
300
|
+
"resetRow": "NPLLIq_resetRow",
|
|
301
|
+
"checkUpdatesRow": "NPLLIq_checkUpdatesRow",
|
|
302
|
+
"logPager": "NPLLIq_logPager",
|
|
303
|
+
"rowName": "NPLLIq_rowName",
|
|
304
|
+
"upgradeCommand": "NPLLIq_upgradeCommand",
|
|
305
|
+
"noteMenuItem": "NPLLIq_noteMenuItem",
|
|
306
|
+
"collapse": "NPLLIq_collapse",
|
|
307
|
+
"fillWarn": "NPLLIq_fillWarn",
|
|
308
|
+
"headerActions": "NPLLIq_headerActions",
|
|
309
|
+
"balanceBar": "NPLLIq_balanceBar",
|
|
310
|
+
"noteWinCollapsed": "NPLLIq_noteWinCollapsed",
|
|
292
311
|
"noteWinBtn": "NPLLIq_noteWinBtn",
|
|
312
|
+
"checkErrorHint": "NPLLIq_checkErrorHint",
|
|
313
|
+
"input": "NPLLIq_input",
|
|
314
|
+
"notice": "NPLLIq_notice",
|
|
315
|
+
"balanceValueLow": "NPLLIq_balanceValueLow",
|
|
316
|
+
"title": "NPLLIq_title",
|
|
317
|
+
"balanceRefreshAll": "NPLLIq_balanceRefreshAll",
|
|
318
|
+
"dialogHint": "NPLLIq_dialogHint",
|
|
319
|
+
"upgradeHint": "NPLLIq_upgradeHint",
|
|
320
|
+
"panel": "NPLLIq_panel",
|
|
321
|
+
"dialogClose": "NPLLIq_dialogClose",
|
|
322
|
+
"upgradeBanner": "NPLLIq_upgradeBanner",
|
|
323
|
+
"upgradeCommands": "NPLLIq_upgradeCommands",
|
|
324
|
+
"balanceRowName": "NPLLIq_balanceRowName",
|
|
325
|
+
"version": "NPLLIq_version",
|
|
326
|
+
"dialogTab": "NPLLIq_dialogTab",
|
|
327
|
+
"panelDim": "NPLLIq_panelDim",
|
|
328
|
+
"rowDragging": "NPLLIq_rowDragging",
|
|
329
|
+
"balanceBarDim": "NPLLIq_balanceBarDim",
|
|
293
330
|
"subtitle": "NPLLIq_subtitle",
|
|
294
|
-
"rowHeader": "NPLLIq_rowHeader",
|
|
295
|
-
"monitorName": "NPLLIq_monitorName",
|
|
296
|
-
"logClearDate": "NPLLIq_logClearDate",
|
|
297
|
-
"balanceStateError": "NPLLIq_balanceStateError",
|
|
298
331
|
"row": "NPLLIq_row",
|
|
299
|
-
"
|
|
300
|
-
"
|
|
301
|
-
"headerText": "NPLLIq_headerText",
|
|
302
|
-
"settingsDialog": "NPLLIq_settingsDialog",
|
|
303
|
-
"panelDimStrong": "NPLLIq_panelDimStrong",
|
|
304
|
-
"balanceValueOk": "NPLLIq_balanceValueOk",
|
|
332
|
+
"logUsedCol": "NPLLIq_logUsedCol",
|
|
333
|
+
"body": "NPLLIq_body",
|
|
305
334
|
"noteChipOpen": "NPLLIq_noteChipOpen",
|
|
306
|
-
"
|
|
307
|
-
"
|
|
308
|
-
"
|
|
335
|
+
"balanceBarError": "NPLLIq_balanceBarError",
|
|
336
|
+
"noteWinTitleText": "NPLLIq_noteWinTitleText",
|
|
337
|
+
"save": "NPLLIq_save",
|
|
309
338
|
"logPagerInfo": "NPLLIq_logPagerInfo",
|
|
310
339
|
"balanceWinBody": "NPLLIq_balanceWinBody",
|
|
311
|
-
"
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
"
|
|
315
|
-
"
|
|
316
|
-
"
|
|
317
|
-
"logToolbar": "NPLLIq_logToolbar",
|
|
318
|
-
"balanceValueError": "NPLLIq_balanceValueError",
|
|
319
|
-
"upgradeCommand": "NPLLIq_upgradeCommand",
|
|
320
|
-
"input": "NPLLIq_input",
|
|
340
|
+
"bar": "NPLLIq_bar",
|
|
341
|
+
"balanceWinHeader": "NPLLIq_balanceWinHeader",
|
|
342
|
+
"noteMenuBackdrop": "NPLLIq_noteMenuBackdrop",
|
|
343
|
+
"dialogSection": "NPLLIq_dialogSection",
|
|
344
|
+
"balanceToggleOpen": "NPLLIq_balanceToggleOpen",
|
|
345
|
+
"tabIcon": "NPLLIq_tabIcon",
|
|
321
346
|
"monitorList": "NPLLIq_monitorList",
|
|
322
|
-
"
|
|
323
|
-
"
|
|
324
|
-
"
|
|
347
|
+
"notesBar": "NPLLIq_notesBar",
|
|
348
|
+
"logSearch": "NPLLIq_logSearch",
|
|
349
|
+
"rowDrag": "NPLLIq_rowDrag",
|
|
350
|
+
"balanceStateError": "NPLLIq_balanceStateError",
|
|
351
|
+
"noteMenu": "NPLLIq_noteMenu",
|
|
352
|
+
"tabLabel": "NPLLIq_tabLabel",
|
|
353
|
+
"settingsBtn": "NPLLIq_settingsBtn",
|
|
325
354
|
"balanceRow": "NPLLIq_balanceRow",
|
|
326
|
-
"
|
|
355
|
+
"panelDimStrong": "NPLLIq_panelDimStrong",
|
|
327
356
|
"fillIdle": "NPLLIq_fillIdle",
|
|
328
|
-
"balanceRowName": "NPLLIq_balanceRowName",
|
|
329
|
-
"noteMenu": "NPLLIq_noteMenu",
|
|
330
|
-
"fillWarn": "NPLLIq_fillWarn",
|
|
331
357
|
"noteWinGripBar": "NPLLIq_noteWinGripBar",
|
|
332
|
-
"
|
|
333
|
-
"
|
|
334
|
-
"
|
|
335
|
-
"
|
|
336
|
-
"
|
|
337
|
-
"controls": "NPLLIq_controls",
|
|
338
|
-
"balanceSortBtn": "NPLLIq_balanceSortBtn",
|
|
339
|
-
"currentBadge": "NPLLIq_currentBadge",
|
|
340
|
-
"checkUpdatesRow": "NPLLIq_checkUpdatesRow",
|
|
341
|
-
"dialogHeader": "NPLLIq_dialogHeader",
|
|
342
|
-
"upgradeCommandRow": "NPLLIq_upgradeCommandRow",
|
|
343
|
-
"upgradeHint": "NPLLIq_upgradeHint",
|
|
344
|
-
"noteWin": "NPLLIq_noteWin",
|
|
345
|
-
"dialogTab": "NPLLIq_dialogTab",
|
|
358
|
+
"gearBtn": "NPLLIq_gearBtn",
|
|
359
|
+
"dialogActions": "NPLLIq_dialogActions",
|
|
360
|
+
"logPagerPages": "NPLLIq_logPagerPages",
|
|
361
|
+
"rowMeta": "NPLLIq_rowMeta",
|
|
362
|
+
"upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
|
|
346
363
|
"dialogTitle": "NPLLIq_dialogTitle",
|
|
347
|
-
"
|
|
348
|
-
"
|
|
349
|
-
"
|
|
350
|
-
"
|
|
351
|
-
"
|
|
352
|
-
"logSearch": "NPLLIq_logSearch",
|
|
353
|
-
"noticeError": "NPLLIq_noticeError",
|
|
354
|
-
"monitorRow": "NPLLIq_monitorRow",
|
|
355
|
-
"resetSelect": "NPLLIq_resetSelect",
|
|
356
|
-
"logModelCol": "NPLLIq_logModelCol",
|
|
357
|
-
"bar": "NPLLIq_bar",
|
|
358
|
-
"logClearBtn": "NPLLIq_logClearBtn",
|
|
364
|
+
"balanceWinTitle": "NPLLIq_balanceWinTitle",
|
|
365
|
+
"logHeader": "NPLLIq_logHeader",
|
|
366
|
+
"dialogTabs": "NPLLIq_dialogTabs",
|
|
367
|
+
"dialogOverlay": "NPLLIq_dialogOverlay",
|
|
368
|
+
"checkBtn": "NPLLIq_checkBtn",
|
|
359
369
|
"settingsBtnActive": "NPLLIq_settingsBtnActive",
|
|
360
|
-
"
|
|
361
|
-
"
|
|
362
|
-
"
|
|
363
|
-
"
|
|
364
|
-
"
|
|
365
|
-
"
|
|
366
|
-
"
|
|
367
|
-
"panelDim": "NPLLIq_panelDim",
|
|
368
|
-
"balanceWin": "NPLLIq_balanceWin",
|
|
370
|
+
"balanceValueOk": "NPLLIq_balanceValueOk",
|
|
371
|
+
"dialogBody": "NPLLIq_dialogBody",
|
|
372
|
+
"logScroll": "NPLLIq_logScroll",
|
|
373
|
+
"balanceBarRefresh": "NPLLIq_balanceBarRefresh",
|
|
374
|
+
"fillOver": "NPLLIq_fillOver",
|
|
375
|
+
"monitorRow": "NPLLIq_monitorRow",
|
|
376
|
+
"logDayCol": "NPLLIq_logDayCol",
|
|
369
377
|
"balanceBarText": "NPLLIq_balanceBarText",
|
|
370
|
-
"upgradeBannerText": "NPLLIq_upgradeBannerText",
|
|
371
378
|
"fullNotice": "NPLLIq_fullNotice",
|
|
372
|
-
"
|
|
373
|
-
"
|
|
374
|
-
"
|
|
375
|
-
"
|
|
376
|
-
"
|
|
377
|
-
"
|
|
378
|
-
"balanceValueLow": "NPLLIq_balanceValueLow",
|
|
379
|
-
"switch": "NPLLIq_switch",
|
|
379
|
+
"dialogTabActive": "NPLLIq_dialogTabActive",
|
|
380
|
+
"balanceToggle": "NPLLIq_balanceToggle",
|
|
381
|
+
"logClearBtn": "NPLLIq_logClearBtn",
|
|
382
|
+
"dialogBtn": "NPLLIq_dialogBtn",
|
|
383
|
+
"monitorName": "NPLLIq_monitorName",
|
|
384
|
+
"monitorHint": "NPLLIq_monitorHint",
|
|
380
385
|
"noteNew": "NPLLIq_noteNew",
|
|
381
|
-
"
|
|
382
|
-
"
|
|
383
|
-
"
|
|
384
|
-
"
|
|
385
|
-
"
|
|
386
|
-
"
|
|
387
|
-
"logDialog": "NPLLIq_logDialog",
|
|
388
|
-
"dialogHint": "NPLLIq_dialogHint",
|
|
389
|
-
"logPagerPages": "NPLLIq_logPagerPages",
|
|
390
|
-
"notice": "NPLLIq_notice",
|
|
391
|
-
"dialogSection": "NPLLIq_dialogSection",
|
|
392
|
-
"copyBtn": "NPLLIq_copyBtn",
|
|
393
|
-
"checkBtn": "NPLLIq_checkBtn",
|
|
394
|
-
"noteWinTitle": "NPLLIq_noteWinTitle",
|
|
395
|
-
"notesBar": "NPLLIq_notesBar",
|
|
386
|
+
"dialogHeader": "NPLLIq_dialogHeader",
|
|
387
|
+
"balanceBarLow": "NPLLIq_balanceBarLow",
|
|
388
|
+
"noteWinBar": "NPLLIq_noteWinBar",
|
|
389
|
+
"logModelCol": "NPLLIq_logModelCol",
|
|
390
|
+
"logClearDialog": "NPLLIq_logClearDialog",
|
|
391
|
+
"dialogLabel": "NPLLIq_dialogLabel",
|
|
396
392
|
"balanceLastLine": "NPLLIq_balanceLastLine",
|
|
397
|
-
"
|
|
398
|
-
"
|
|
399
|
-
"
|
|
400
|
-
"
|
|
393
|
+
"copyBtn": "NPLLIq_copyBtn",
|
|
394
|
+
"controls": "NPLLIq_controls",
|
|
395
|
+
"radioRow": "NPLLIq_radioRow",
|
|
396
|
+
"tab": "NPLLIq_tab",
|
|
397
|
+
"balanceRowHeader": "NPLLIq_balanceRowHeader",
|
|
398
|
+
"balanceRowValue": "NPLLIq_balanceRowValue",
|
|
399
|
+
"logToolbar": "NPLLIq_logToolbar",
|
|
400
|
+
"logPageSizeSelect": "NPLLIq_logPageSizeSelect"
|
|
401
401
|
};
|
|
402
402
|
//#endregion
|
|
403
403
|
//#region lib/types/client/TokenQuotaPanel.js
|
|
@@ -1068,13 +1068,13 @@ window.__ModuleLoader__.load({
|
|
|
1068
1068
|
title: t("upgradeAvailableHint"),
|
|
1069
1069
|
children: [
|
|
1070
1070
|
"v",
|
|
1071
|
-
"0.1.
|
|
1071
|
+
"0.1.42",
|
|
1072
1072
|
" → v",
|
|
1073
1073
|
upgrade.latestVersion
|
|
1074
1074
|
]
|
|
1075
1075
|
}) : (0, react_jsx_runtime.jsxs)("span", {
|
|
1076
1076
|
className: TokenQuotaPanel_module_css_default.version,
|
|
1077
|
-
children: ["v", "0.1.
|
|
1077
|
+
children: ["v", "0.1.42"]
|
|
1078
1078
|
})]
|
|
1079
1079
|
})
|
|
1080
1080
|
}),
|
|
@@ -2891,11 +2891,11 @@ window.__ModuleLoader__.load({
|
|
|
2891
2891
|
}
|
|
2892
2892
|
var mic_module_css_default = {
|
|
2893
2893
|
"micRec": "KCoVpa_micRec",
|
|
2894
|
-
"micErr": "KCoVpa_micErr",
|
|
2895
|
-
"micErrTip": "KCoVpa_micErrTip",
|
|
2896
|
-
"micBusy": "KCoVpa_micBusy",
|
|
2897
2894
|
"micWrap": "KCoVpa_micWrap",
|
|
2898
2895
|
"micBtn": "KCoVpa_micBtn",
|
|
2896
|
+
"micBusy": "KCoVpa_micBusy",
|
|
2897
|
+
"micErr": "KCoVpa_micErr",
|
|
2898
|
+
"micErrTip": "KCoVpa_micErrTip",
|
|
2899
2899
|
"micPulse": "KCoVpa_micPulse"
|
|
2900
2900
|
};
|
|
2901
2901
|
//#endregion
|
|
@@ -2907,11 +2907,17 @@ window.__ModuleLoader__.load({
|
|
|
2907
2907
|
* Host, which forwards it to the configured OpenAI-compatible transcription
|
|
2908
2908
|
* endpoint. The returned text is appended to the composer. The button only
|
|
2909
2909
|
* renders while transcription is enabled in the token-quota settings.
|
|
2910
|
+
*
|
|
2911
|
+
* This entry is mounted in a session-scoped slot, so it cannot share the
|
|
2912
|
+
* panel's root-scoped store handle (which would fork a per-session instance
|
|
2913
|
+
* with stale state). Instead it subscribes to a tiny transcribe-only
|
|
2914
|
+
* observable passed through injection and reads the locale-bound `t` from
|
|
2915
|
+
* injection as well.
|
|
2910
2916
|
*/
|
|
2911
2917
|
/**
|
|
2912
2918
|
* Append recognised text to the contentEditable composer. Focuses the editor,
|
|
2913
2919
|
* moves the caret to the end, and uses `insertText` so the host editor's own
|
|
2914
|
-
* input handling (undo,
|
|
2920
|
+
* input handling (undo, lexical binding) sees it as a typed insertion.
|
|
2915
2921
|
*/
|
|
2916
2922
|
function appendToComposer(text) {
|
|
2917
2923
|
const editor = document.querySelector("[data-composer-input]");
|
|
@@ -2938,8 +2944,8 @@ window.__ModuleLoader__.load({
|
|
|
2938
2944
|
* Mic button rendered inside the composer card. Manages its own MediaRecorder
|
|
2939
2945
|
* lifecycle; only the button is shown — no floating panel UI.
|
|
2940
2946
|
*/
|
|
2941
|
-
function TokenQuotaMic({ t,
|
|
2942
|
-
const
|
|
2947
|
+
function TokenQuotaMic({ t, transcribe, subscribeTranscribe, getTranscribe }) {
|
|
2948
|
+
const settings = (0, react.useSyncExternalStore)(subscribeTranscribe, getTranscribe, getTranscribe);
|
|
2943
2949
|
const [recording, setRecording] = (0, react.useState)(false);
|
|
2944
2950
|
const [transcribing, setTranscribing] = (0, react.useState)(false);
|
|
2945
2951
|
const [error, setError] = (0, react.useState)(null);
|
|
@@ -3016,7 +3022,7 @@ window.__ModuleLoader__.load({
|
|
|
3016
3022
|
if (recording) stopAndTranscribe();
|
|
3017
3023
|
else startRecording();
|
|
3018
3024
|
};
|
|
3019
|
-
if (!enabled) return null;
|
|
3025
|
+
if (!settings.enabled) return null;
|
|
3020
3026
|
const state = transcribing ? "busy" : recording ? "rec" : "idle";
|
|
3021
3027
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
3022
3028
|
className: mic_module_css_default.micWrap,
|
|
@@ -3544,7 +3550,10 @@ window.__ModuleLoader__.load({
|
|
|
3544
3550
|
bound?.setMusicVolume(musicSettings.volume);
|
|
3545
3551
|
bound?.setMusicStyle(musicSettings.style);
|
|
3546
3552
|
bound?.setMusicOnlyCurrentSession(musicSettings.onlyCurrentSession);
|
|
3547
|
-
|
|
3553
|
+
const transcribeRaw = doc?.transcribe;
|
|
3554
|
+
const resolvedTranscribe = transcribeDefaults(transcribeRaw);
|
|
3555
|
+
applyTranscribe(resolvedTranscribe);
|
|
3556
|
+
bound?.setTranscribeSettings(resolvedTranscribe);
|
|
3548
3557
|
fetch("/token-quota", { headers: { accept: "application/json" } }).then((response) => {
|
|
3549
3558
|
if (!response.ok) {
|
|
3550
3559
|
bound?.setError(`quota route: ${String(response.status)}`);
|
|
@@ -3634,7 +3643,25 @@ window.__ModuleLoader__.load({
|
|
|
3634
3643
|
});
|
|
3635
3644
|
};
|
|
3636
3645
|
/** Persist the voice transcription settings and mirror them into the store. */
|
|
3646
|
+
let currentTranscribe = TOKEN_QUOTA_DEFAULT_TRANSCRIBE;
|
|
3647
|
+
const transcribeSubscribers = /* @__PURE__ */ new Set();
|
|
3648
|
+
const emitTranscribe = () => {
|
|
3649
|
+
for (const fn of transcribeSubscribers) fn();
|
|
3650
|
+
};
|
|
3651
|
+
const subscribeTranscribe = (cb) => {
|
|
3652
|
+
transcribeSubscribers.add(cb);
|
|
3653
|
+
return () => {
|
|
3654
|
+
transcribeSubscribers.delete(cb);
|
|
3655
|
+
};
|
|
3656
|
+
};
|
|
3657
|
+
const getTranscribe = () => currentTranscribe;
|
|
3658
|
+
const applyTranscribe = (settings) => {
|
|
3659
|
+
if (settings.enabled === currentTranscribe.enabled && settings.baseURL === currentTranscribe.baseURL && settings.apiKeyEnv === currentTranscribe.apiKeyEnv && settings.model === currentTranscribe.model) return;
|
|
3660
|
+
currentTranscribe = settings;
|
|
3661
|
+
emitTranscribe();
|
|
3662
|
+
};
|
|
3637
3663
|
const setTranscribeSettings = (settings) => {
|
|
3664
|
+
applyTranscribe(settings);
|
|
3638
3665
|
bound?.setTranscribeSettings(settings);
|
|
3639
3666
|
scope.set("transcribe", settings);
|
|
3640
3667
|
};
|
|
@@ -3809,15 +3836,13 @@ window.__ModuleLoader__.load({
|
|
|
3809
3836
|
id: "token-quota-mic",
|
|
3810
3837
|
order: 100,
|
|
3811
3838
|
label: () => t("transcribeTitle"),
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
};
|
|
3820
|
-
}
|
|
3839
|
+
inject: (_sessionId) => ({
|
|
3840
|
+
transcribe,
|
|
3841
|
+
setTranscribeSettings,
|
|
3842
|
+
subscribeTranscribe,
|
|
3843
|
+
getTranscribe,
|
|
3844
|
+
t
|
|
3845
|
+
})
|
|
3821
3846
|
}, TokenQuotaMic));
|
|
3822
3847
|
}
|
|
3823
3848
|
//#endregion
|
package/lib/index.js
CHANGED
|
@@ -651,7 +651,7 @@ var TokenQuotaService = class TokenQuotaService extends Service {
|
|
|
651
651
|
return this.upgradeCheck;
|
|
652
652
|
}
|
|
653
653
|
async doRefreshUpgrade() {
|
|
654
|
-
const current = "0.1.
|
|
654
|
+
const current = "0.1.42";
|
|
655
655
|
let latest;
|
|
656
656
|
try {
|
|
657
657
|
const response = await fetch(REGISTRY_LATEST_URL, {
|
|
@@ -299,7 +299,10 @@ export function apply(ctx) {
|
|
|
299
299
|
bound?.setMusicVolume(musicSettings.volume);
|
|
300
300
|
bound?.setMusicStyle(musicSettings.style);
|
|
301
301
|
bound?.setMusicOnlyCurrentSession(musicSettings.onlyCurrentSession);
|
|
302
|
-
|
|
302
|
+
const transcribeRaw = doc?.transcribe;
|
|
303
|
+
const resolvedTranscribe = transcribeDefaults(transcribeRaw);
|
|
304
|
+
applyTranscribe(resolvedTranscribe);
|
|
305
|
+
bound?.setTranscribeSettings(resolvedTranscribe);
|
|
303
306
|
void fetch('/token-quota', { headers: { accept: 'application/json' } }).then((response) => {
|
|
304
307
|
if (!response.ok) {
|
|
305
308
|
bound?.setError(`quota route: ${String(response.status)}`);
|
|
@@ -388,7 +391,30 @@ export function apply(ctx) {
|
|
|
388
391
|
void scope.set('balance', { enabled, pollMinutes });
|
|
389
392
|
};
|
|
390
393
|
/** Persist the voice transcription settings and mirror them into the store. */
|
|
394
|
+
// --- Transcription settings source (independent of the panel store, so the
|
|
395
|
+
// mic entry — mounted in the session-scoped conversation.input.overlay
|
|
396
|
+
// slot — can subscribe without sharing the panel's root-scoped store
|
|
397
|
+
// instance (which would fork state across scopes). ---
|
|
398
|
+
let currentTranscribe = TOKEN_QUOTA_DEFAULT_TRANSCRIBE;
|
|
399
|
+
const transcribeSubscribers = new Set();
|
|
400
|
+
const emitTranscribe = () => { for (const fn of transcribeSubscribers)
|
|
401
|
+
fn(); };
|
|
402
|
+
const subscribeTranscribe = (cb) => {
|
|
403
|
+
transcribeSubscribers.add(cb);
|
|
404
|
+
return () => { transcribeSubscribers.delete(cb); };
|
|
405
|
+
};
|
|
406
|
+
const getTranscribe = () => currentTranscribe;
|
|
407
|
+
const applyTranscribe = (settings) => {
|
|
408
|
+
if (settings.enabled === currentTranscribe.enabled
|
|
409
|
+
&& settings.baseURL === currentTranscribe.baseURL
|
|
410
|
+
&& settings.apiKeyEnv === currentTranscribe.apiKeyEnv
|
|
411
|
+
&& settings.model === currentTranscribe.model)
|
|
412
|
+
return;
|
|
413
|
+
currentTranscribe = settings;
|
|
414
|
+
emitTranscribe();
|
|
415
|
+
};
|
|
391
416
|
const setTranscribeSettings = (settings) => {
|
|
417
|
+
applyTranscribe(settings);
|
|
392
418
|
bound?.setTranscribeSettings(settings);
|
|
393
419
|
void scope.set('transcribe', settings);
|
|
394
420
|
};
|
|
@@ -562,17 +588,22 @@ export function apply(ctx) {
|
|
|
562
588
|
// transcription is enabled in settings; a press starts recording, a second
|
|
563
589
|
// press stops and sends the audio to the Host for transcription, then the
|
|
564
590
|
// recognised text is appended to the composer.
|
|
591
|
+
// NOTE: This entry is scoped to a session (not root), so it cannot share the
|
|
592
|
+
// panel's root-scoped store handle without forking a separate per-session
|
|
593
|
+
// instance. Instead it subscribes to a tiny transcribe-only observable and
|
|
594
|
+
// receives the locale-bound `t` function through injection.
|
|
565
595
|
ctx.slots.inject('conversation.input.overlay', () => ctx.slots.register({
|
|
566
596
|
name: 'conversation.input.overlay',
|
|
567
597
|
id: 'token-quota-mic',
|
|
568
598
|
order: 100,
|
|
569
599
|
label: () => t('transcribeTitle'),
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
600
|
+
inject: (_sessionId) => ({
|
|
601
|
+
transcribe,
|
|
602
|
+
setTranscribeSettings,
|
|
603
|
+
subscribeTranscribe,
|
|
604
|
+
getTranscribe,
|
|
605
|
+
t: t,
|
|
606
|
+
}),
|
|
576
607
|
}, TokenQuotaMic));
|
|
577
608
|
}
|
|
578
609
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { TOKEN_QUOTA_NAMESPACE } from '@jxgame2020/dsh-token-quota/types';
|
|
1
|
+
import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
2
|
import type { TokenQuotaTranscribeSettings } from '@jxgame2020/dsh-token-quota/types';
|
|
4
|
-
|
|
5
|
-
/** Injected business face: transcription send + settings persistence. */
|
|
3
|
+
/** Injected business face: transcription send + settings subscription. */
|
|
6
4
|
export interface TokenQuotaMicInjected {
|
|
7
5
|
/** Send a recorded audio blob to the Host for transcription. */
|
|
8
6
|
transcribe: (blob: Blob) => Promise<string>;
|
|
9
7
|
/** Persist the transcription settings (the panel owns the settings UI). */
|
|
10
8
|
setTranscribeSettings: (settings: TokenQuotaTranscribeSettings) => void;
|
|
9
|
+
/** Subscribe to transcribe settings changes (returns an unsubscribe). */
|
|
10
|
+
subscribeTranscribe: (cb: () => void) => () => void;
|
|
11
|
+
/** Read the current transcribe settings snapshot. */
|
|
12
|
+
getTranscribe: () => TokenQuotaTranscribeSettings;
|
|
13
|
+
/** Locale-bound translate function. */
|
|
14
|
+
t: (key: string) => string;
|
|
11
15
|
}
|
|
12
|
-
/** Full mic component props: runtime +
|
|
13
|
-
export type TokenQuotaMicComponentProps = PropsRuntime<'conversation.input.overlay'> &
|
|
16
|
+
/** Full mic component props: runtime + injected face (no store/locale shares). */
|
|
17
|
+
export type TokenQuotaMicComponentProps = PropsRuntime<'conversation.input.overlay'> & TokenQuotaMicInjected;
|
|
14
18
|
/**
|
|
15
19
|
* Mic button rendered inside the composer card. Manages its own MediaRecorder
|
|
16
20
|
* lifecycle; only the button is shown — no floating panel UI.
|
|
17
21
|
*/
|
|
18
|
-
export declare function TokenQuotaMic({ t,
|
|
22
|
+
export declare function TokenQuotaMic({ t, transcribe, subscribeTranscribe, getTranscribe, }: TokenQuotaMicComponentProps): JSX.Element | null;
|
|
19
23
|
//# sourceMappingURL=mic.d.ts.map
|
package/lib/types/client/mic.js
CHANGED
|
@@ -6,23 +6,27 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
* Host, which forwards it to the configured OpenAI-compatible transcription
|
|
7
7
|
* endpoint. The returned text is appended to the composer. The button only
|
|
8
8
|
* renders while transcription is enabled in the token-quota settings.
|
|
9
|
+
*
|
|
10
|
+
* This entry is mounted in a session-scoped slot, so it cannot share the
|
|
11
|
+
* panel's root-scoped store handle (which would fork a per-session instance
|
|
12
|
+
* with stale state). Instead it subscribes to a tiny transcribe-only
|
|
13
|
+
* observable passed through injection and reads the locale-bound `t` from
|
|
14
|
+
* injection as well.
|
|
9
15
|
*/
|
|
10
|
-
import { useEffect, useRef, useState } from 'react';
|
|
16
|
+
import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
11
17
|
import css from './mic.module.css';
|
|
12
18
|
/**
|
|
13
19
|
* Append recognised text to the contentEditable composer. Focuses the editor,
|
|
14
20
|
* moves the caret to the end, and uses `insertText` so the host editor's own
|
|
15
|
-
* input handling (undo,
|
|
21
|
+
* input handling (undo, lexical binding) sees it as a typed insertion.
|
|
16
22
|
*/
|
|
17
23
|
function appendToComposer(text) {
|
|
18
24
|
const editor = document.querySelector('[data-composer-input]');
|
|
19
25
|
if (editor === null) {
|
|
20
|
-
// No composer on this page — copy to the clipboard as a fallback.
|
|
21
26
|
void navigator.clipboard?.writeText(text).catch(() => { });
|
|
22
27
|
return;
|
|
23
28
|
}
|
|
24
29
|
editor.focus();
|
|
25
|
-
// Move the caret to the end of the editor's text content.
|
|
26
30
|
const selection = window.getSelection();
|
|
27
31
|
if (selection !== null) {
|
|
28
32
|
const range = document.createRange();
|
|
@@ -31,9 +35,6 @@ function appendToComposer(text) {
|
|
|
31
35
|
selection.removeAllRanges();
|
|
32
36
|
selection.addRange(range);
|
|
33
37
|
}
|
|
34
|
-
// execCommand is deprecated but remains the only cross-browser way to trigger
|
|
35
|
-
// a contentEditable editor's own "typed text" handling (undo stack, lexical
|
|
36
|
-
// binding). The host composer listens to it.
|
|
37
38
|
let inserted = false;
|
|
38
39
|
try {
|
|
39
40
|
inserted = document.execCommand('insertText', false, text);
|
|
@@ -49,8 +50,8 @@ function appendToComposer(text) {
|
|
|
49
50
|
* Mic button rendered inside the composer card. Manages its own MediaRecorder
|
|
50
51
|
* lifecycle; only the button is shown — no floating panel UI.
|
|
51
52
|
*/
|
|
52
|
-
export function TokenQuotaMic({ t,
|
|
53
|
-
const
|
|
53
|
+
export function TokenQuotaMic({ t, transcribe, subscribeTranscribe, getTranscribe, }) {
|
|
54
|
+
const settings = useSyncExternalStore(subscribeTranscribe, getTranscribe, getTranscribe);
|
|
54
55
|
const [recording, setRecording] = useState(false);
|
|
55
56
|
const [transcribing, setTranscribing] = useState(false);
|
|
56
57
|
const [error, setError] = useState(null);
|
|
@@ -58,8 +59,6 @@ export function TokenQuotaMic({ t, useStore, transcribe, }) {
|
|
|
58
59
|
const chunksRef = useRef([]);
|
|
59
60
|
const streamRef = useRef(null);
|
|
60
61
|
const errorTimerRef = useRef(undefined);
|
|
61
|
-
// Clean up the recorder / stream on unmount so a navigation while recording
|
|
62
|
-
// stops the mic tracks rather than leaving them open.
|
|
63
62
|
useEffect(() => {
|
|
64
63
|
return () => {
|
|
65
64
|
if (errorTimerRef.current !== undefined)
|
|
@@ -150,7 +149,7 @@ export function TokenQuotaMic({ t, useStore, transcribe, }) {
|
|
|
150
149
|
void startRecording();
|
|
151
150
|
}
|
|
152
151
|
};
|
|
153
|
-
if (!enabled)
|
|
152
|
+
if (!settings.enabled)
|
|
154
153
|
return null;
|
|
155
154
|
const state = transcribing ? 'busy' : recording ? 'rec' : 'idle';
|
|
156
155
|
return (_jsxs("div", { className: css.micWrap, title: error ?? t('transcribeHint'), children: [_jsx("button", { type: "button", className: `${css.micBtn}${state === 'rec' ? ` ${css.micRec}` : ''}${state === 'busy' ? ` ${css.micBusy}` : ''}${error !== null ? ` ${css.micErr}` : ''}`, disabled: transcribing, onClick: (event) => { event.stopPropagation(); onToggle(); }, onPointerDown: (event) => { event.stopPropagation(); }, "aria-pressed": recording, "aria-label": error ?? t('transcribeTitle'), children: transcribing ? '…' : '🎤' }), error !== null && _jsx("span", { className: css.micErrTip, children: error })] }));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxgame2020/dsh-token-quota",
|
|
3
3
|
"description": "Daily per-model token quota accounting, enforcement, and a floating quota panel for the DeepSeek Harness — a fully self-contained plugin (no core-Harness wiring, no generated RPC contract)",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.42",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|