@glassly/engine 0.3.5 → 0.3.6-beta.851
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/build/engine.d.ts +11 -1
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +13 -1
- package/build/engine.js.map +1 -1
- package/build/facades/ai.d.ts +3 -3
- package/build/facades/ai.d.ts.map +1 -1
- package/build/facades/ai.js +3 -3
- package/build/facades/ai.js.map +1 -1
- package/build/facades/glasses.d.ts +5 -1
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +39 -30
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/memory.d.ts +10 -2
- package/build/facades/memory.d.ts.map +1 -1
- package/build/facades/memory.js +10 -0
- package/build/facades/memory.js.map +1 -1
- package/build/facades/miniapps.d.ts +2 -0
- package/build/facades/miniapps.d.ts.map +1 -1
- package/build/facades/miniapps.js +2 -0
- package/build/facades/miniapps.js.map +1 -1
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +3 -2
- package/build/facades/pairing.js.map +1 -1
- package/build/facades/providerKeys.d.ts +6 -2
- package/build/facades/providerKeys.d.ts.map +1 -1
- package/build/facades/providerKeys.js +6 -2
- package/build/facades/providerKeys.js.map +1 -1
- package/build/generated/releaseMetadata.js +4 -4
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/services/AiTierResolution.d.ts +3 -2
- package/build/services/AiTierResolution.d.ts.map +1 -1
- package/build/services/AiTierResolution.js +7 -2
- package/build/services/AiTierResolution.js.map +1 -1
- package/build/services/AppRegistry.d.ts +4 -1
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +16 -2
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/BlobStore.js +3 -3
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/BluetoothRestoreLaunch.d.ts +8 -0
- package/build/services/BluetoothRestoreLaunch.d.ts.map +1 -0
- package/build/services/BluetoothRestoreLaunch.js +34 -0
- package/build/services/BluetoothRestoreLaunch.js.map +1 -0
- package/build/services/CloudClientService.d.ts +4 -4
- package/build/services/ForegroundLocationPermission.d.ts +1 -1
- package/build/services/ForegroundLocationPermission.d.ts.map +1 -1
- package/build/services/ForegroundLocationPermission.js.map +1 -1
- package/build/services/GestureDotsService.d.ts.map +1 -1
- package/build/services/GestureDotsService.js +2 -1
- package/build/services/GestureDotsService.js.map +1 -1
- package/build/services/GlassesTouchInput.d.ts +6 -4
- package/build/services/GlassesTouchInput.d.ts.map +1 -1
- package/build/services/GlassesTouchInput.js +81 -41
- package/build/services/GlassesTouchInput.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +12 -4
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +21 -7
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalLlmModelManager.d.ts +3 -1
- package/build/services/LocalLlmModelManager.d.ts.map +1 -1
- package/build/services/LocalLlmModelManager.js +13 -5
- package/build/services/LocalLlmModelManager.js.map +1 -1
- package/build/services/LocalLlmPrompt.d.ts +10 -9
- package/build/services/LocalLlmPrompt.d.ts.map +1 -1
- package/build/services/LocalLlmPrompt.js +43 -32
- package/build/services/LocalLlmPrompt.js.map +1 -1
- package/build/services/LocalLlmProvider.d.ts +1 -0
- package/build/services/LocalLlmProvider.d.ts.map +1 -1
- package/build/services/LocalLlmProvider.js +62 -22
- package/build/services/LocalLlmProvider.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +28 -6
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +190 -148
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/MemoryStore.d.ts +13 -1
- package/build/services/MemoryStore.d.ts.map +1 -1
- package/build/services/MemoryStore.js +98 -1
- package/build/services/MemoryStore.js.map +1 -1
- package/build/services/MiniappExitGesture.d.ts +6 -3
- package/build/services/MiniappExitGesture.d.ts.map +1 -1
- package/build/services/MiniappExitGesture.js +4 -4
- package/build/services/MiniappExitGesture.js.map +1 -1
- package/build/services/MiniappWidgetMode.d.ts +6 -4
- package/build/services/MiniappWidgetMode.d.ts.map +1 -1
- package/build/services/MiniappWidgetMode.js +7 -6
- package/build/services/MiniappWidgetMode.js.map +1 -1
- package/build/services/ProviderKeyValidation.d.ts +2 -0
- package/build/services/ProviderKeyValidation.d.ts.map +1 -1
- package/build/services/ProviderKeyValidation.js +4 -0
- package/build/services/ProviderKeyValidation.js.map +1 -1
- package/build/services/SceneRenderer.d.ts.map +1 -1
- package/build/services/SceneRenderer.js +3 -1
- package/build/services/SceneRenderer.js.map +1 -1
- package/build/services/ScreenshotFixture.d.ts +56 -0
- package/build/services/ScreenshotFixture.d.ts.map +1 -0
- package/build/services/ScreenshotFixture.js +72 -0
- package/build/services/ScreenshotFixture.js.map +1 -0
- package/build/services/actionInvoke.d.ts +37 -0
- package/build/services/actionInvoke.d.ts.map +1 -0
- package/build/services/actionInvoke.js +89 -0
- package/build/services/actionInvoke.js.map +1 -0
- package/build/services/appleWatch/AppleWatchLink.d.ts +42 -0
- package/build/services/appleWatch/AppleWatchLink.d.ts.map +1 -0
- package/build/services/appleWatch/AppleWatchLink.js +259 -0
- package/build/services/appleWatch/AppleWatchLink.js.map +1 -0
- package/build/services/controllers.d.ts.map +1 -1
- package/build/services/controllers.js +16 -0
- package/build/services/controllers.js.map +1 -1
- package/build/services/manifestActions.d.ts +4 -2
- package/build/services/manifestActions.d.ts.map +1 -1
- package/build/services/manifestActions.js +9 -3
- package/build/services/manifestActions.js.map +1 -1
- package/build/services/memoryBackupFile.d.ts +9 -0
- package/build/services/memoryBackupFile.d.ts.map +1 -0
- package/build/services/memoryBackupFile.js +47 -0
- package/build/services/memoryBackupFile.js.map +1 -0
- package/build/services/settingsBridge.d.ts +4 -4
- package/build/services/settingsBridge.d.ts.map +1 -1
- package/build/services/settingsBridge.js +9 -4
- package/build/services/settingsBridge.js.map +1 -1
- package/build/services/widgetPlacements.d.ts +8 -7
- package/build/services/widgetPlacements.d.ts.map +1 -1
- package/build/services/widgetPlacements.js +7 -6
- package/build/services/widgetPlacements.js.map +1 -1
- package/build/stores/apps.d.ts +6 -0
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +29 -12
- package/build/stores/apps.js.map +1 -1
- package/build/stores/bluetoothSettingKeys.d.ts +2 -0
- package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
- package/build/stores/bluetoothSettingKeys.js +17 -0
- package/build/stores/bluetoothSettingKeys.js.map +1 -1
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +42 -2
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +5 -1
- package/build/types/applet.d.ts.map +1 -1
- package/build/types/applet.js.map +1 -1
- package/build/types/capabilities/rayneo-io.d.ts.map +1 -1
- package/build/types/capabilities/rayneo-io.js +2 -0
- package/build/types/capabilities/rayneo-io.js.map +1 -1
- package/build/types/enums.d.ts +2 -1
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +1 -0
- package/build/types/enums.js.map +1 -1
- package/build/utils/cloudClient/RnUdpAdapter.d.ts.map +1 -1
- package/build/utils/cloudClient/RnUdpAdapter.js +13 -2
- package/build/utils/cloudClient/RnUdpAdapter.js.map +1 -1
- package/build/utils/display/scene/index.d.ts +1 -1
- package/build/utils/display/scene/index.d.ts.map +1 -1
- package/build/utils/display/scene/index.js.map +1 -1
- package/build/utils/display/scene/process.d.ts.map +1 -1
- package/build/utils/display/scene/process.js +20 -1
- package/build/utils/display/scene/process.js.map +1 -1
- package/build/utils/display/scene/types.d.ts +1 -1
- package/build/utils/display/scene/types.d.ts.map +1 -1
- package/build/utils/display/scene/types.js.map +1 -1
- package/build/utils/miniappGlobals.d.ts +6 -0
- package/build/utils/miniappGlobals.d.ts.map +1 -1
- package/build/utils/miniappGlobals.js +28 -4
- package/build/utils/miniappGlobals.js.map +1 -1
- package/package.json +9 -9
- package/src/engine.ts +13 -1
- package/src/facades/ai.ts +3 -3
- package/src/facades/glasses.ts +65 -42
- package/src/facades/memory.ts +11 -2
- package/src/facades/miniapps.ts +3 -0
- package/src/facades/pairing.ts +4 -2
- package/src/facades/providerKeys.ts +6 -1
- package/src/generated/releaseMetadata.ts +4 -4
- package/src/services/AiTierResolution.ts +9 -3
- package/src/services/AppRegistry.ts +18 -3
- package/src/services/BlobStore.ts +3 -3
- package/src/services/BluetoothRestoreLaunch.ts +37 -0
- package/src/services/ForegroundLocationPermission.ts +1 -1
- package/src/services/GestureDotsService.ts +2 -1
- package/src/services/GlassesTouchInput.ts +86 -38
- package/src/services/LocalDisplayManager.ts +22 -8
- package/src/services/LocalLlmModelManager.ts +16 -6
- package/src/services/LocalLlmPrompt.ts +56 -37
- package/src/services/LocalLlmProvider.ts +74 -24
- package/src/services/LocalMiniappRuntime.ts +228 -147
- package/src/services/MemoryStore.ts +111 -2
- package/src/services/MiniappExitGesture.ts +8 -5
- package/src/services/MiniappWidgetMode.ts +9 -7
- package/src/services/ProviderKeyValidation.ts +5 -0
- package/src/services/SceneRenderer.ts +3 -1
- package/src/services/ScreenshotFixture.ts +113 -0
- package/src/services/actionInvoke.ts +105 -0
- package/src/services/appleWatch/AppleWatchLink.ts +297 -0
- package/src/services/controllers.ts +17 -0
- package/src/services/manifestActions.ts +16 -4
- package/src/services/memoryBackupFile.ts +50 -0
- package/src/services/settingsBridge.ts +9 -4
- package/src/services/widgetPlacements.ts +23 -9
- package/src/stores/apps.ts +35 -11
- package/src/stores/bluetoothSettingKeys.ts +20 -0
- package/src/stores/settings.ts +44 -2
- package/src/types/applet.ts +5 -1
- package/src/types/capabilities/rayneo-io.ts +2 -0
- package/src/types/enums.ts +1 -0
- package/src/utils/cloudClient/RnUdpAdapter.ts +13 -1
- package/src/utils/display/scene/index.ts +1 -0
- package/src/utils/display/scene/process.ts +17 -1
- package/src/utils/display/scene/types.ts +1 -0
- package/src/utils/miniappGlobals.ts +30 -4
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* load it migrates Assist's per-app storage namespace into the shared
|
|
17
17
|
* user-scoped keys so existing history survives the move.
|
|
18
18
|
*/
|
|
19
|
-
import type { MemoryEntry, MemoryNoteSource, MemorySession, MemorySummary } from "@glassly/miniapp";
|
|
19
|
+
import type { MemoryBackup, MemoryEntry, MemoryImportResult, MemoryNoteSource, MemorySession, MemorySummary } from "@glassly/miniapp";
|
|
20
20
|
/**
|
|
21
21
|
* Physical bounds. There is no age cap: the timeline stays until the user
|
|
22
22
|
* deletes it (clear()/removeScope). The entry cap bounds the write cost —
|
|
@@ -51,6 +51,10 @@ export interface MemoryStats {
|
|
|
51
51
|
/** Epoch ms of the oldest entry, or null when empty. */
|
|
52
52
|
oldestAt: number | null;
|
|
53
53
|
}
|
|
54
|
+
/** Thrown by importBackup for anything that isn't a backup this build can read. */
|
|
55
|
+
export declare class MemoryBackupError extends Error {
|
|
56
|
+
constructor(message: string);
|
|
57
|
+
}
|
|
54
58
|
export declare function hourStartOf(ms: number): number;
|
|
55
59
|
export declare function dayStartOf(ms: number): number;
|
|
56
60
|
export declare class MemoryStore {
|
|
@@ -132,6 +136,14 @@ export declare class MemoryStore {
|
|
|
132
136
|
summaryList(): Promise<MemorySummary[]>;
|
|
133
137
|
/** Most recent COMPLETED hour with lines but no summary, or null. */
|
|
134
138
|
pendingSummaryHour(nowMs?: number): Promise<number | null>;
|
|
139
|
+
/** The whole timeline as a backup file body (Settings > Memory, session.memory.exportFile). */
|
|
140
|
+
exportBackup(): Promise<MemoryBackup>;
|
|
141
|
+
/**
|
|
142
|
+
* Merge a backup into the timeline. Skips entries whose id is stored, notes
|
|
143
|
+
* whose text is already in the same hour, and hours that already have a
|
|
144
|
+
* summary. Throws MemoryBackupError when `data` isn't a memory backup.
|
|
145
|
+
*/
|
|
146
|
+
importBackup(data: unknown): Promise<MemoryImportResult>;
|
|
135
147
|
/** Plain-text export of a scope, for the OS share sheet. */
|
|
136
148
|
exportText(scope: "session" | "day" | "all", at?: number): Promise<string>;
|
|
137
149
|
private ensureLoaded;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryStore.d.ts","sourceRoot":"","sources":["../../src/services/MemoryStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"MemoryStore.d.ts","sourceRoot":"","sources":["../../src/services/MemoryStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,6 +56,13 @@ const QUERY_LIMIT_DEFAULT = 60;
|
|
|
56
56
|
* window. Short enough that an unexpected kill loses only the last few lines.
|
|
57
57
|
*/
|
|
58
58
|
const DEFAULT_WRITE_DEBOUNCE_MS = 3000;
|
|
59
|
+
/** Thrown by importBackup for anything that isn't a backup this build can read. */
|
|
60
|
+
export class MemoryBackupError extends Error {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.name = "MemoryBackupError";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
59
66
|
export function hourStartOf(ms) {
|
|
60
67
|
return Math.floor(ms / HOUR_MS) * HOUR_MS;
|
|
61
68
|
}
|
|
@@ -292,6 +299,62 @@ export class MemoryStore {
|
|
|
292
299
|
return null;
|
|
293
300
|
return Math.max(...hours);
|
|
294
301
|
}
|
|
302
|
+
/** The whole timeline as a backup file body (Settings > Memory, session.memory.exportFile). */
|
|
303
|
+
async exportBackup() {
|
|
304
|
+
await this.ensureLoaded();
|
|
305
|
+
return {
|
|
306
|
+
format: "glassly-memory",
|
|
307
|
+
version: 1,
|
|
308
|
+
exportedAt: Date.now(),
|
|
309
|
+
entries: [...this.entries],
|
|
310
|
+
summaries: [...this.summaries].sort((a, b) => a.hourStart - b.hourStart),
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Merge a backup into the timeline. Skips entries whose id is stored, notes
|
|
315
|
+
* whose text is already in the same hour, and hours that already have a
|
|
316
|
+
* summary. Throws MemoryBackupError when `data` isn't a memory backup.
|
|
317
|
+
*/
|
|
318
|
+
async importBackup(data) {
|
|
319
|
+
const backup = parseBackup(data);
|
|
320
|
+
await this.ensureLoaded();
|
|
321
|
+
const result = { entries: 0, summaries: 0, skipped: 0 };
|
|
322
|
+
const ids = new Set(this.entries.map((e) => e.id));
|
|
323
|
+
const noteKeys = new Set(this.entries.filter((e) => e.kind === "note").map(noteKey));
|
|
324
|
+
for (const entry of backup.entries) {
|
|
325
|
+
const key = entry.kind === "note" ? noteKey(entry) : null;
|
|
326
|
+
if (ids.has(entry.id) || (key != null && noteKeys.has(key))) {
|
|
327
|
+
result.skipped++;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
ids.add(entry.id);
|
|
331
|
+
if (key != null)
|
|
332
|
+
noteKeys.add(key);
|
|
333
|
+
this.entries.push(entry);
|
|
334
|
+
result.entries++;
|
|
335
|
+
}
|
|
336
|
+
const byHour = new Map(this.summaries.map((s) => [s.hourStart, s]));
|
|
337
|
+
for (const summary of backup.summaries) {
|
|
338
|
+
if (byHour.get(summary.hourStart)?.text.trim()) {
|
|
339
|
+
result.skipped++;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
byHour.set(summary.hourStart, summary);
|
|
343
|
+
result.summaries++;
|
|
344
|
+
}
|
|
345
|
+
if (result.entries > 0) {
|
|
346
|
+
this.entries.sort((a, b) => a.at - b.at);
|
|
347
|
+
this.prune();
|
|
348
|
+
await this.persistLog();
|
|
349
|
+
}
|
|
350
|
+
if (result.summaries > 0) {
|
|
351
|
+
this.summaries = [...byHour.values()].sort((a, b) => a.hourStart - b.hourStart).slice(-MEMORY_BOUNDS.maxSummaries);
|
|
352
|
+
await this.persistSummaries();
|
|
353
|
+
}
|
|
354
|
+
if (result.entries > 0 || result.summaries > 0)
|
|
355
|
+
this.emitChanged();
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
295
358
|
/** Plain-text export of a scope, for the OS share sheet. */
|
|
296
359
|
async exportText(scope, at) {
|
|
297
360
|
const sessions = (await this.sessionList()).filter((s) => {
|
|
@@ -494,9 +557,43 @@ function parseArray(raw) {
|
|
|
494
557
|
function normalize(text) {
|
|
495
558
|
return text
|
|
496
559
|
.toLowerCase()
|
|
497
|
-
.replace(/[
|
|
560
|
+
.replace(/[^\p{L}\p{N}]+/gu, " ")
|
|
498
561
|
.trim();
|
|
499
562
|
}
|
|
563
|
+
function noteKey(entry) {
|
|
564
|
+
return `${hourStartOf(entry.at)}:${normalize(entry.text)}`;
|
|
565
|
+
}
|
|
566
|
+
function parseBackup(data) {
|
|
567
|
+
const raw = data;
|
|
568
|
+
if (!raw || typeof raw !== "object" || raw.format !== "glassly-memory" || !Array.isArray(raw.entries)) {
|
|
569
|
+
throw new MemoryBackupError("Not a Glassly memory backup");
|
|
570
|
+
}
|
|
571
|
+
if (typeof raw.version !== "number" || raw.version > 1) {
|
|
572
|
+
throw new MemoryBackupError(`Unsupported memory backup version ${String(raw.version)}`);
|
|
573
|
+
}
|
|
574
|
+
const entries = [];
|
|
575
|
+
for (const v of raw.entries) {
|
|
576
|
+
if (!isEntry(v) || !v.id || !v.text.trim() || !Number.isFinite(v.at))
|
|
577
|
+
continue;
|
|
578
|
+
entries.push({
|
|
579
|
+
id: v.id,
|
|
580
|
+
kind: v.kind,
|
|
581
|
+
text: v.text.trim(),
|
|
582
|
+
at: v.at,
|
|
583
|
+
speakerId: typeof v.speakerId === "string" ? v.speakerId : null,
|
|
584
|
+
...(typeof v.resolvedSpeakerName === "string" && v.resolvedSpeakerName
|
|
585
|
+
? { resolvedSpeakerName: v.resolvedSpeakerName }
|
|
586
|
+
: {}),
|
|
587
|
+
language: typeof v.language === "string" ? v.language : null,
|
|
588
|
+
...(v.kind === "note" ? { source: v.source === "voice" || v.source === "auto" ? v.source : "ui" } : {}),
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
const summaries = (Array.isArray(raw.summaries) ? raw.summaries : [])
|
|
592
|
+
.filter(isSummary)
|
|
593
|
+
.filter((s) => s.text.trim() && Number.isFinite(s.hourStart))
|
|
594
|
+
.map((s) => ({ hourStart: s.hourStart, text: s.text, createdAt: s.createdAt }));
|
|
595
|
+
return { entries, summaries };
|
|
596
|
+
}
|
|
500
597
|
function isEntry(v) {
|
|
501
598
|
if (!v || typeof v !== "object")
|
|
502
599
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryStore.js","sourceRoot":"","sources":["../../src/services/MemoryStore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MemoryStore — the user's shared, phone-local memory timeline.\n *\n * One unified per-hour stream of what happened around the user — spoken\n * transcript lines AND notes (manual, voice, auto) in one timeline — plus the\n * hourly conversation summary that heads each session. Scoped to the Glassly\n * USER (not to a miniapp): every miniapp that declares the MEMORY manifest\n * permission reads and writes the same store through LocalMiniappRuntime's\n * MEMORY_* handlers, and Settings > Memory manages it via engine.memory.\n *\n * A \"session\" is one clock hour that has entries, derived from entry\n * timestamps at read time — nothing is stored per-session, so there is no\n * session id to keep in sync.\n *\n * The store began life inside the Assist miniapp (its SessionStore); on first\n * load it migrates Assist's per-app storage namespace into the shared\n * user-scoped keys so existing history survives the move.\n */\n\nimport type {MemoryEntry, MemoryNoteSource, MemorySession, MemorySummary} from \"@glassly/miniapp\"\n\nimport {searchMemoryEntries} from \"../utils/memory/search\"\n\nimport {BgTimer} from \"../utils/timers\"\n\nconst KEY_ROOT = \"memory_\"\nconst LOG_SUFFIX = \"log\"\nconst SUMMARY_SUFFIX = \"summaries\"\n\n/**\n * The pre-memory-layer Assist miniapp whose storage namespace we migrate.\n * Assist now ships as com.glassly.assistant; the timeline it reads is\n * user-scoped (KEY_ROOT below), so the rename needs no second migration and\n * this constant stays pinned to the old namespace.\n */\nconst LEGACY_ASSIST_PACKAGE = \"com.tetramo.assistant\"\nconst LEGACY_STORAGE_ROOT = \"localstorage_\"\nconst LEGACY_LOG_KEY = \"assistant:session-log\"\nconst LEGACY_SUMMARY_KEY = \"assistant:hourly-summaries\"\n// Assist's own pre-unification keys, migrated for users who never ran the\n// unified-schema Assist build.\nconst LEGACY_TRANSCRIPT_KEY = \"assistant:transcript-log\"\nconst LEGACY_NOTES_KEY = \"assistant:notes\"\n\nconst HOUR_MS = 60 * 60 * 1000\n\n/**\n * Physical bounds. There is no age cap: the timeline stays until the user\n * deletes it (clear()/removeScope). The entry cap bounds the write cost —\n * every persist re-serializes the whole timeline, so it is a perf ceiling as\n * much as a product number — and the summary cap keeps one row per hour for\n * about half a year of round-the-clock use, far longer at a normal pace.\n */\nexport const MEMORY_BOUNDS = {\n maxEntries: 24_000,\n maxSummaries: 4320,\n}\nconst QUERY_LIMIT_CAP = 200\nconst QUERY_LIMIT_DEFAULT = 60\n/**\n * How long transcript appends coalesce before hitting disk. Each write\n * re-serializes the entire timeline, so at conversational pace (a final\n * utterance every few seconds) this turns O(n) work per line into O(n) per\n * window. Short enough that an unexpected kill loses only the last few lines.\n */\nconst DEFAULT_WRITE_DEBOUNCE_MS = 3000\n\nexport interface MemoryStoreBackend {\n get(key: string): unknown | null\n set(key: string, value: unknown): void\n remove(key: string): void\n}\n\nexport interface MemoryStoreHooks {\n getUserId: () => Promise<string>\n backend: MemoryStoreBackend\n /**\n * Debounce window for transcript-line writes, in ms. Appends coalesce into\n * one serialization instead of re-stringifying the whole timeline per\n * utterance. Set to 0 to persist synchronously (tests).\n */\n writeDebounceMs?: number\n}\n\nexport interface MemoryStats {\n entryCount: number\n lineCount: number\n noteCount: number\n summaryCount: number\n /** Epoch ms of the oldest entry, or null when empty. */\n oldestAt: number | null\n}\n\nexport function hourStartOf(ms: number): number {\n return Math.floor(ms / HOUR_MS) * HOUR_MS\n}\n\nexport function dayStartOf(ms: number): number {\n const d = new Date(ms)\n d.setHours(0, 0, 0, 0)\n return d.getTime()\n}\n\nfunction makeId(): string {\n return `e-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nexport class MemoryStore {\n private entries: MemoryEntry[] = []\n private summaries: MemorySummary[] = []\n /** User the in-memory cache was loaded for; reload when identity changes. */\n private loadedUserId: string | null = null\n private loadPromise: Promise<void> | null = null\n private readonly changeListeners = new Set<() => void>()\n /** Pending debounced log write (transcript appends), if any. */\n private logFlushTimer: number | null = null\n private logDirty = false\n\n constructor(private readonly hooks: MemoryStoreHooks) {}\n\n /**\n * Write any debounced changes out now. Call before the app backgrounds or\n * terminates so a crash can't lose the coalesced tail of the timeline.\n */\n async flush(): Promise<void> {\n if (this.logFlushTimer) {\n BgTimer.clearTimeout(this.logFlushTimer)\n this.logFlushTimer = null\n }\n if (this.logDirty) await this.persistLog()\n }\n\n /** Subscribe to mutations (adds, edits, deletes, clears). */\n onChanged(listener: () => void): () => void {\n this.changeListeners.add(listener)\n return () => this.changeListeners.delete(listener)\n }\n\n // === Writes ===\n\n async appendLine(input: {\n text: string\n speakerId: string | null\n /** Resolved enrolled-speaker name (on-device speaker ID), when known. */\n resolvedSpeakerName?: string | null\n language: string | null\n at: number\n }): Promise<void> {\n if (!input.text.trim()) return\n await this.ensureLoaded()\n this.entries.push({\n id: makeId(),\n kind: \"line\",\n text: input.text.trim(),\n at: input.at,\n speakerId: input.speakerId,\n ...(input.resolvedSpeakerName ? {resolvedSpeakerName: input.resolvedSpeakerName} : {}),\n language: input.language,\n })\n this.prune()\n // Transcript lines are the hot path (one per final utterance) and each\n // persist re-serializes the whole timeline, so coalesce them. Everything\n // else — notes, edits, deletes, summaries — still writes through\n // immediately; those are user-visible and rare.\n this.schedulePersistLog()\n this.emitChanged()\n }\n\n /**\n * Add a note. `at` targets the hour it belongs to — pass a timestamp inside\n * a past hour to append to that session. Dedupes on normalized text within\n * the same hour (auto-notes re-extract); resolves null on duplicate/empty.\n */\n async addNote(text: string, source: MemoryNoteSource, at: number = Date.now()): Promise<MemoryEntry | null> {\n const body = text.trim()\n if (!body) return null\n await this.ensureLoaded()\n const hour = hourStartOf(at)\n const key = normalize(body)\n if (this.entries.some((e) => e.kind === \"note\" && hourStartOf(e.at) === hour && normalize(e.text) === key)) {\n return null\n }\n const entry: MemoryEntry = {id: makeId(), kind: \"note\", text: body, at, speakerId: null, language: null, source}\n this.entries.push(entry)\n this.entries.sort((a, b) => a.at - b.at)\n this.prune()\n await this.persistLog()\n this.emitChanged()\n return entry\n }\n\n /** Rewrite a note's text in place (Settings > Memory edit). */\n async updateNote(id: string, text: string): Promise<boolean> {\n const body = text.trim()\n if (!body) return false\n await this.ensureLoaded()\n const entry = this.entries.find((e) => e.id === id && e.kind === \"note\")\n if (!entry) return false\n entry.text = body\n await this.persistLog()\n this.emitChanged()\n return true\n }\n\n async removeEntry(id: string): Promise<boolean> {\n await this.ensureLoaded()\n const before = this.entries.length\n this.entries = this.entries.filter((e) => e.id !== id)\n if (this.entries.length === before) return false\n await this.persistLog()\n this.emitChanged()\n return true\n }\n\n /** Delete every entry (and summary) in an hour, or a whole day of hours. */\n async removeScope(scope: \"session\" | \"day\", at: number): Promise<void> {\n await this.ensureLoaded()\n const inScope =\n scope === \"day\"\n ? (ms: number) => dayStartOf(ms) === dayStartOf(at)\n : (ms: number) => hourStartOf(ms) === hourStartOf(at)\n this.entries = this.entries.filter((e) => !inScope(e.at))\n this.summaries = this.summaries.filter((s) => !inScope(s.hourStart))\n await this.persistLog()\n await this.persistSummaries()\n this.emitChanged()\n }\n\n /** Drop the entire timeline: every entry and every summary. */\n async clear(): Promise<void> {\n await this.ensureLoaded()\n this.entries = []\n this.summaries = []\n await this.persistLog()\n await this.persistSummaries()\n this.emitChanged()\n }\n\n async addSummary(summary: MemorySummary): Promise<void> {\n await this.ensureLoaded()\n const {maxSummaries} = MEMORY_BOUNDS\n this.summaries = this.summaries.filter((s) => s.hourStart !== summary.hourStart)\n this.summaries.push(summary)\n if (this.summaries.length > maxSummaries) {\n this.summaries = this.summaries.sort((a, b) => a.hourStart - b.hourStart).slice(-maxSummaries)\n }\n await this.persistSummaries()\n this.emitChanged()\n }\n\n // === Reads === (the whole stored timeline; nothing is hidden by age)\n\n /** Entries in [sinceMs, untilMs), newest last. */\n async window(sinceMs: number, untilMs: number = Date.now()): Promise<MemoryEntry[]> {\n await this.ensureLoaded()\n return this.entries.filter((e) => e.at >= sinceMs && e.at < untilMs)\n }\n\n /** All note entries, newest first (Settings > Memory list). */\n async notes(): Promise<MemoryEntry[]> {\n await this.ensureLoaded()\n return this.entries.filter((e) => e.kind === \"note\").sort((a, b) => b.at - a.at)\n }\n\n async stats(): Promise<MemoryStats> {\n await this.ensureLoaded()\n const visible = this.entries\n const noteCount = visible.filter((e) => e.kind === \"note\").length\n return {\n entryCount: visible.length,\n lineCount: visible.length - noteCount,\n noteCount,\n summaryCount: this.summaries.filter((s) => s.text.trim()).length,\n oldestAt: visible.length > 0 ? visible[0].at : null,\n }\n }\n\n /** All sessions (hours with entries), newest hour first. */\n async sessionList(): Promise<MemorySession[]> {\n await this.ensureLoaded()\n const byHour = new Map<number, MemoryEntry[]>()\n for (const e of this.entries) {\n const h = hourStartOf(e.at)\n const list = byHour.get(h) ?? []\n list.push(e)\n byHour.set(h, list)\n }\n const summaryByHour = new Map(this.summaries.map((s) => [s.hourStart, s.text]))\n return [...byHour.entries()]\n .map(([hourStart, entries]) => {\n entries.sort((a, b) => a.at - b.at)\n return {\n hourStart,\n entries,\n summary: (summaryByHour.get(hourStart) ?? \"\").trim() || null,\n lineCount: entries.filter((e) => e.kind === \"line\").length,\n noteCount: entries.filter((e) => e.kind === \"note\").length,\n }\n })\n .sort((a, b) => b.hourStart - a.hourStart)\n }\n\n /**\n * Query the FULL store by absolute-time window and keyword — the executor\n * behind LLM history-search tools. Newest last, so the limit keeps the most\n * recent matches. `contains` is an exact substring; `terms` is fuzzy any-of\n * matching (mistranscribed-name tolerant) — see utils/memory/search.ts.\n */\n async query(q: {\n sinceMs?: number\n untilMs?: number\n contains?: string\n terms?: string[]\n limit?: number\n }): Promise<MemoryEntry[]> {\n return (await this.search(q)).entries\n }\n\n /**\n * query() plus `windowCount` — how many entries the TIME window held before\n * keyword filtering, so an LLM caller can distinguish \"keyword matched\n * nothing\" from \"history doesn't reach that far back\" without a retry.\n */\n async search(q: {\n sinceMs?: number\n untilMs?: number\n contains?: string\n terms?: string[]\n limit?: number\n }): Promise<{entries: MemoryEntry[]; windowCount: number}> {\n await this.ensureLoaded()\n const limit = q.limit && q.limit > 0 ? Math.min(q.limit, QUERY_LIMIT_CAP) : QUERY_LIMIT_DEFAULT\n return searchMemoryEntries(this.entries, {\n sinceMs: q.sinceMs,\n untilMs: q.untilMs,\n contains: q.contains,\n terms: q.terms,\n limit,\n })\n }\n\n async summaryList(): Promise<MemorySummary[]> {\n await this.ensureLoaded()\n return [...this.summaries].sort((a, b) => b.hourStart - a.hourStart)\n }\n\n /** Most recent COMPLETED hour with lines but no summary, or null. */\n async pendingSummaryHour(nowMs: number = Date.now()): Promise<number | null> {\n await this.ensureLoaded()\n const currentHour = hourStartOf(nowMs)\n const summarized = new Set(this.summaries.map((s) => s.hourStart))\n const hours = new Set<number>()\n for (const e of this.entries) {\n if (e.kind !== \"line\") continue\n const h = hourStartOf(e.at)\n if (h < currentHour && !summarized.has(h)) hours.add(h)\n }\n if (hours.size === 0) return null\n return Math.max(...hours)\n }\n\n /** Plain-text export of a scope, for the OS share sheet. */\n async exportText(scope: \"session\" | \"day\" | \"all\", at?: number): Promise<string> {\n const sessions = (await this.sessionList()).filter((s) => {\n if (scope === \"all\") return true\n if (at == null) return false\n if (scope === \"day\") return dayStartOf(s.hourStart) === dayStartOf(at)\n return s.hourStart === hourStartOf(at)\n })\n if (sessions.length === 0) return \"No session history to export.\"\n\n const dayFmt = (ms: number) =>\n new Date(ms).toLocaleDateString(undefined, {weekday: \"long\", year: \"numeric\", month: \"long\", day: \"numeric\"})\n const hourFmt = (ms: number) => new Date(ms).toLocaleTimeString(undefined, {hour: \"numeric\"})\n const timeFmt = (ms: number) => new Date(ms).toLocaleTimeString(undefined, {hour: \"numeric\", minute: \"2-digit\"})\n\n const parts: string[] = []\n let lastDay: number | null = null\n for (const s of [...sessions].sort((a, b) => a.hourStart - b.hourStart)) {\n const day = dayStartOf(s.hourStart)\n if (day !== lastDay) {\n parts.push(`\\n=== ${dayFmt(day)} ===`)\n lastDay = day\n }\n parts.push(`\\n[${hourFmt(s.hourStart)}–${hourFmt(s.hourStart + HOUR_MS)}]`)\n if (s.summary) parts.push(`Summary: ${s.summary}`)\n for (const e of s.entries) {\n const who = e.kind === \"note\" ? \"NOTE\" : (e.speakerId ?? \"—\")\n parts.push(` ${timeFmt(e.at)} ${who}: ${e.text}`)\n }\n }\n return `Memory session history\\n${parts.join(\"\\n\").trim()}\\n`\n }\n\n // === Load / persist ===\n\n private async ensureLoaded(): Promise<void> {\n const userId = (await this.hooks.getUserId()).trim()\n if (!userId) throw new Error(\"Glassly user identity is unavailable\")\n if (this.loadedUserId === userId) return\n if (!this.loadPromise) {\n this.loadPromise = this.loadFor(userId).finally(() => {\n this.loadPromise = null\n })\n }\n await this.loadPromise\n }\n\n private async loadFor(userId: string): Promise<void> {\n // Don't let an identity switch discard lines still sitting in the debounce\n // window — they belong to the OUTGOING user, whose key is still loaded.\n await this.flush()\n this.entries = []\n this.summaries = []\n const rawLog = this.hooks.backend.get(this.key(userId, LOG_SUFFIX))\n if (rawLog != null) {\n this.entries = parseArray(rawLog).filter(isEntry)\n } else {\n this.migrateFromAssist(userId)\n }\n const rawSummaries = this.hooks.backend.get(this.key(userId, SUMMARY_SUFFIX))\n if (rawSummaries != null) {\n this.summaries = parseArray(rawSummaries).filter(isSummary)\n }\n this.loadedUserId = userId\n this.prune()\n }\n\n /**\n * One-time migration: fold the Assist miniapp's per-app store (the previous\n * home of this timeline) into the shared user-scoped keys. Assist's old keys\n * are left in place; its new build reads through the memory bridge instead.\n */\n private migrateFromAssist(userId: string): void {\n const legacyPrefix = `${LEGACY_STORAGE_ROOT}${userId}_${LEGACY_ASSIST_PACKAGE}_`\n try {\n const migrated: MemoryEntry[] = []\n const rawLog = this.hooks.backend.get(legacyPrefix + LEGACY_LOG_KEY)\n if (rawLog != null) {\n migrated.push(...parseArray(rawLog).filter(isEntry))\n } else {\n // Pre-unification Assist: separate transcript log + notes stores.\n for (const v of parseArray(this.hooks.backend.get(legacyPrefix + LEGACY_TRANSCRIPT_KEY))) {\n const e = v as Record<string, unknown>\n if (typeof e.text === \"string\" && typeof e.at === \"number\") {\n migrated.push({\n id: makeId(),\n kind: \"line\",\n text: e.text,\n at: e.at,\n speakerId: typeof e.speakerId === \"string\" ? e.speakerId : null,\n language: typeof e.language === \"string\" ? e.language : null,\n })\n }\n }\n for (const v of parseArray(this.hooks.backend.get(legacyPrefix + LEGACY_NOTES_KEY))) {\n const n = v as Record<string, unknown>\n if (typeof n.text === \"string\" && typeof n.createdAt === \"number\") {\n migrated.push({\n id: makeId(),\n kind: \"note\",\n text: n.text,\n at: n.createdAt,\n speakerId: null,\n language: null,\n source: n.source === \"voice\" || n.source === \"auto\" ? n.source : \"ui\",\n })\n }\n }\n }\n migrated.sort((a, b) => a.at - b.at)\n this.entries = migrated\n if (migrated.length > 0) this.hooks.backend.set(this.key(userId, LOG_SUFFIX), JSON.stringify(migrated))\n\n const rawSummaries = this.hooks.backend.get(legacyPrefix + LEGACY_SUMMARY_KEY)\n if (rawSummaries != null) {\n const summaries = parseArray(rawSummaries).filter(isSummary)\n this.summaries = summaries\n if (summaries.length > 0) this.hooks.backend.set(this.key(userId, SUMMARY_SUFFIX), JSON.stringify(summaries))\n }\n if (this.entries.length > 0 || this.summaries.length > 0) {\n console.log(\n `MemoryStore: migrated ${this.entries.length} entries + ${this.summaries.length} summaries from Assist`,\n )\n }\n } catch (err) {\n console.warn(\"MemoryStore: Assist migration failed:\", err instanceof Error ? err.message : err)\n }\n }\n\n /** Keep the newest MEMORY_BOUNDS.maxEntries; nothing goes for age — deleting is the user's call. */\n private prune(): void {\n const {maxEntries} = MEMORY_BOUNDS\n if (this.entries.length > maxEntries) this.entries = this.entries.slice(-maxEntries)\n }\n\n private key(userId: string, suffix: string): string {\n return `${KEY_ROOT}${userId}_${suffix}`\n }\n\n /**\n * Mark the log dirty and arm the debounce timer. Repeated appends inside the\n * window collapse into a single serialization; the first append after a\n * flush starts a fresh window (trailing-edge, so a steady stream of speech\n * still lands on disk every `writeDebounceMs`).\n */\n private schedulePersistLog(): void {\n const delay = this.hooks.writeDebounceMs ?? DEFAULT_WRITE_DEBOUNCE_MS\n if (delay <= 0) {\n void this.persistLog()\n return\n }\n this.logDirty = true\n if (this.logFlushTimer) return\n this.logFlushTimer = BgTimer.setTimeout(() => {\n this.logFlushTimer = null\n void this.persistLog().catch((err) =>\n console.warn(\"MemoryStore: debounced log write failed:\", err instanceof Error ? err.message : err),\n )\n }, delay)\n }\n\n private async persistLog(): Promise<void> {\n // Any write of the full array satisfies whatever the debounce was holding.\n this.logDirty = false\n if (this.logFlushTimer) {\n BgTimer.clearTimeout(this.logFlushTimer)\n this.logFlushTimer = null\n }\n if (this.loadedUserId == null) return\n this.hooks.backend.set(this.key(this.loadedUserId, LOG_SUFFIX), JSON.stringify(this.entries))\n }\n\n private async persistSummaries(): Promise<void> {\n if (this.loadedUserId == null) return\n this.hooks.backend.set(this.key(this.loadedUserId, SUMMARY_SUFFIX), JSON.stringify(this.summaries))\n }\n\n private emitChanged(): void {\n for (const listener of this.changeListeners) {\n try {\n listener()\n } catch (err) {\n console.warn(\"MemoryStore: onChanged listener threw:\", err instanceof Error ? err.message : err)\n }\n }\n }\n}\n\n/** Stored values may be a JSON string (SimpleStorage writes) or a raw array. */\nfunction parseArray(raw: unknown): unknown[] {\n try {\n if (typeof raw === \"string\") {\n const parsed = JSON.parse(raw) as unknown\n return Array.isArray(parsed) ? parsed : []\n }\n return Array.isArray(raw) ? raw : []\n } catch {\n return []\n }\n}\n\nfunction normalize(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .trim()\n}\n\nfunction isEntry(v: unknown): v is MemoryEntry {\n if (!v || typeof v !== \"object\") return false\n const e = v as Record<string, unknown>\n return (\n typeof e.id === \"string\" &&\n (e.kind === \"line\" || e.kind === \"note\") &&\n typeof e.text === \"string\" &&\n typeof e.at === \"number\"\n )\n}\n\nfunction isSummary(v: unknown): v is MemorySummary {\n if (!v || typeof v !== \"object\") return false\n const s = v as Record<string, unknown>\n return typeof s.hourStart === \"number\" && typeof s.text === \"string\" && typeof s.createdAt === \"number\"\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MemoryStore.js","sourceRoot":"","sources":["../../src/services/MemoryStore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MemoryStore — the user's shared, phone-local memory timeline.\n *\n * One unified per-hour stream of what happened around the user — spoken\n * transcript lines AND notes (manual, voice, auto) in one timeline — plus the\n * hourly conversation summary that heads each session. Scoped to the Glassly\n * USER (not to a miniapp): every miniapp that declares the MEMORY manifest\n * permission reads and writes the same store through LocalMiniappRuntime's\n * MEMORY_* handlers, and Settings > Memory manages it via engine.memory.\n *\n * A \"session\" is one clock hour that has entries, derived from entry\n * timestamps at read time — nothing is stored per-session, so there is no\n * session id to keep in sync.\n *\n * The store began life inside the Assist miniapp (its SessionStore); on first\n * load it migrates Assist's per-app storage namespace into the shared\n * user-scoped keys so existing history survives the move.\n */\n\nimport type {\n MemoryBackup,\n MemoryEntry,\n MemoryImportResult,\n MemoryNoteSource,\n MemorySession,\n MemorySummary,\n} from \"@glassly/miniapp\"\n\nimport {searchMemoryEntries} from \"../utils/memory/search\"\n\nimport {BgTimer} from \"../utils/timers\"\n\nconst KEY_ROOT = \"memory_\"\nconst LOG_SUFFIX = \"log\"\nconst SUMMARY_SUFFIX = \"summaries\"\n\n/**\n * The pre-memory-layer Assist miniapp whose storage namespace we migrate.\n * Assist now ships as com.glassly.assistant; the timeline it reads is\n * user-scoped (KEY_ROOT below), so the rename needs no second migration and\n * this constant stays pinned to the old namespace.\n */\nconst LEGACY_ASSIST_PACKAGE = \"com.tetramo.assistant\"\nconst LEGACY_STORAGE_ROOT = \"localstorage_\"\nconst LEGACY_LOG_KEY = \"assistant:session-log\"\nconst LEGACY_SUMMARY_KEY = \"assistant:hourly-summaries\"\n// Assist's own pre-unification keys, migrated for users who never ran the\n// unified-schema Assist build.\nconst LEGACY_TRANSCRIPT_KEY = \"assistant:transcript-log\"\nconst LEGACY_NOTES_KEY = \"assistant:notes\"\n\nconst HOUR_MS = 60 * 60 * 1000\n\n/**\n * Physical bounds. There is no age cap: the timeline stays until the user\n * deletes it (clear()/removeScope). The entry cap bounds the write cost —\n * every persist re-serializes the whole timeline, so it is a perf ceiling as\n * much as a product number — and the summary cap keeps one row per hour for\n * about half a year of round-the-clock use, far longer at a normal pace.\n */\nexport const MEMORY_BOUNDS = {\n maxEntries: 24_000,\n maxSummaries: 4320,\n}\nconst QUERY_LIMIT_CAP = 200\nconst QUERY_LIMIT_DEFAULT = 60\n/**\n * How long transcript appends coalesce before hitting disk. Each write\n * re-serializes the entire timeline, so at conversational pace (a final\n * utterance every few seconds) this turns O(n) work per line into O(n) per\n * window. Short enough that an unexpected kill loses only the last few lines.\n */\nconst DEFAULT_WRITE_DEBOUNCE_MS = 3000\n\nexport interface MemoryStoreBackend {\n get(key: string): unknown | null\n set(key: string, value: unknown): void\n remove(key: string): void\n}\n\nexport interface MemoryStoreHooks {\n getUserId: () => Promise<string>\n backend: MemoryStoreBackend\n /**\n * Debounce window for transcript-line writes, in ms. Appends coalesce into\n * one serialization instead of re-stringifying the whole timeline per\n * utterance. Set to 0 to persist synchronously (tests).\n */\n writeDebounceMs?: number\n}\n\nexport interface MemoryStats {\n entryCount: number\n lineCount: number\n noteCount: number\n summaryCount: number\n /** Epoch ms of the oldest entry, or null when empty. */\n oldestAt: number | null\n}\n\n/** Thrown by importBackup for anything that isn't a backup this build can read. */\nexport class MemoryBackupError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"MemoryBackupError\"\n }\n}\n\nexport function hourStartOf(ms: number): number {\n return Math.floor(ms / HOUR_MS) * HOUR_MS\n}\n\nexport function dayStartOf(ms: number): number {\n const d = new Date(ms)\n d.setHours(0, 0, 0, 0)\n return d.getTime()\n}\n\nfunction makeId(): string {\n return `e-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nexport class MemoryStore {\n private entries: MemoryEntry[] = []\n private summaries: MemorySummary[] = []\n /** User the in-memory cache was loaded for; reload when identity changes. */\n private loadedUserId: string | null = null\n private loadPromise: Promise<void> | null = null\n private readonly changeListeners = new Set<() => void>()\n /** Pending debounced log write (transcript appends), if any. */\n private logFlushTimer: number | null = null\n private logDirty = false\n\n constructor(private readonly hooks: MemoryStoreHooks) {}\n\n /**\n * Write any debounced changes out now. Call before the app backgrounds or\n * terminates so a crash can't lose the coalesced tail of the timeline.\n */\n async flush(): Promise<void> {\n if (this.logFlushTimer) {\n BgTimer.clearTimeout(this.logFlushTimer)\n this.logFlushTimer = null\n }\n if (this.logDirty) await this.persistLog()\n }\n\n /** Subscribe to mutations (adds, edits, deletes, clears). */\n onChanged(listener: () => void): () => void {\n this.changeListeners.add(listener)\n return () => this.changeListeners.delete(listener)\n }\n\n // === Writes ===\n\n async appendLine(input: {\n text: string\n speakerId: string | null\n /** Resolved enrolled-speaker name (on-device speaker ID), when known. */\n resolvedSpeakerName?: string | null\n language: string | null\n at: number\n }): Promise<void> {\n if (!input.text.trim()) return\n await this.ensureLoaded()\n this.entries.push({\n id: makeId(),\n kind: \"line\",\n text: input.text.trim(),\n at: input.at,\n speakerId: input.speakerId,\n ...(input.resolvedSpeakerName ? {resolvedSpeakerName: input.resolvedSpeakerName} : {}),\n language: input.language,\n })\n this.prune()\n // Transcript lines are the hot path (one per final utterance) and each\n // persist re-serializes the whole timeline, so coalesce them. Everything\n // else — notes, edits, deletes, summaries — still writes through\n // immediately; those are user-visible and rare.\n this.schedulePersistLog()\n this.emitChanged()\n }\n\n /**\n * Add a note. `at` targets the hour it belongs to — pass a timestamp inside\n * a past hour to append to that session. Dedupes on normalized text within\n * the same hour (auto-notes re-extract); resolves null on duplicate/empty.\n */\n async addNote(text: string, source: MemoryNoteSource, at: number = Date.now()): Promise<MemoryEntry | null> {\n const body = text.trim()\n if (!body) return null\n await this.ensureLoaded()\n const hour = hourStartOf(at)\n const key = normalize(body)\n if (this.entries.some((e) => e.kind === \"note\" && hourStartOf(e.at) === hour && normalize(e.text) === key)) {\n return null\n }\n const entry: MemoryEntry = {id: makeId(), kind: \"note\", text: body, at, speakerId: null, language: null, source}\n this.entries.push(entry)\n this.entries.sort((a, b) => a.at - b.at)\n this.prune()\n await this.persistLog()\n this.emitChanged()\n return entry\n }\n\n /** Rewrite a note's text in place (Settings > Memory edit). */\n async updateNote(id: string, text: string): Promise<boolean> {\n const body = text.trim()\n if (!body) return false\n await this.ensureLoaded()\n const entry = this.entries.find((e) => e.id === id && e.kind === \"note\")\n if (!entry) return false\n entry.text = body\n await this.persistLog()\n this.emitChanged()\n return true\n }\n\n async removeEntry(id: string): Promise<boolean> {\n await this.ensureLoaded()\n const before = this.entries.length\n this.entries = this.entries.filter((e) => e.id !== id)\n if (this.entries.length === before) return false\n await this.persistLog()\n this.emitChanged()\n return true\n }\n\n /** Delete every entry (and summary) in an hour, or a whole day of hours. */\n async removeScope(scope: \"session\" | \"day\", at: number): Promise<void> {\n await this.ensureLoaded()\n const inScope =\n scope === \"day\"\n ? (ms: number) => dayStartOf(ms) === dayStartOf(at)\n : (ms: number) => hourStartOf(ms) === hourStartOf(at)\n this.entries = this.entries.filter((e) => !inScope(e.at))\n this.summaries = this.summaries.filter((s) => !inScope(s.hourStart))\n await this.persistLog()\n await this.persistSummaries()\n this.emitChanged()\n }\n\n /** Drop the entire timeline: every entry and every summary. */\n async clear(): Promise<void> {\n await this.ensureLoaded()\n this.entries = []\n this.summaries = []\n await this.persistLog()\n await this.persistSummaries()\n this.emitChanged()\n }\n\n async addSummary(summary: MemorySummary): Promise<void> {\n await this.ensureLoaded()\n const {maxSummaries} = MEMORY_BOUNDS\n this.summaries = this.summaries.filter((s) => s.hourStart !== summary.hourStart)\n this.summaries.push(summary)\n if (this.summaries.length > maxSummaries) {\n this.summaries = this.summaries.sort((a, b) => a.hourStart - b.hourStart).slice(-maxSummaries)\n }\n await this.persistSummaries()\n this.emitChanged()\n }\n\n // === Reads === (the whole stored timeline; nothing is hidden by age)\n\n /** Entries in [sinceMs, untilMs), newest last. */\n async window(sinceMs: number, untilMs: number = Date.now()): Promise<MemoryEntry[]> {\n await this.ensureLoaded()\n return this.entries.filter((e) => e.at >= sinceMs && e.at < untilMs)\n }\n\n /** All note entries, newest first (Settings > Memory list). */\n async notes(): Promise<MemoryEntry[]> {\n await this.ensureLoaded()\n return this.entries.filter((e) => e.kind === \"note\").sort((a, b) => b.at - a.at)\n }\n\n async stats(): Promise<MemoryStats> {\n await this.ensureLoaded()\n const visible = this.entries\n const noteCount = visible.filter((e) => e.kind === \"note\").length\n return {\n entryCount: visible.length,\n lineCount: visible.length - noteCount,\n noteCount,\n summaryCount: this.summaries.filter((s) => s.text.trim()).length,\n oldestAt: visible.length > 0 ? visible[0].at : null,\n }\n }\n\n /** All sessions (hours with entries), newest hour first. */\n async sessionList(): Promise<MemorySession[]> {\n await this.ensureLoaded()\n const byHour = new Map<number, MemoryEntry[]>()\n for (const e of this.entries) {\n const h = hourStartOf(e.at)\n const list = byHour.get(h) ?? []\n list.push(e)\n byHour.set(h, list)\n }\n const summaryByHour = new Map(this.summaries.map((s) => [s.hourStart, s.text]))\n return [...byHour.entries()]\n .map(([hourStart, entries]) => {\n entries.sort((a, b) => a.at - b.at)\n return {\n hourStart,\n entries,\n summary: (summaryByHour.get(hourStart) ?? \"\").trim() || null,\n lineCount: entries.filter((e) => e.kind === \"line\").length,\n noteCount: entries.filter((e) => e.kind === \"note\").length,\n }\n })\n .sort((a, b) => b.hourStart - a.hourStart)\n }\n\n /**\n * Query the FULL store by absolute-time window and keyword — the executor\n * behind LLM history-search tools. Newest last, so the limit keeps the most\n * recent matches. `contains` is an exact substring; `terms` is fuzzy any-of\n * matching (mistranscribed-name tolerant) — see utils/memory/search.ts.\n */\n async query(q: {\n sinceMs?: number\n untilMs?: number\n contains?: string\n terms?: string[]\n limit?: number\n }): Promise<MemoryEntry[]> {\n return (await this.search(q)).entries\n }\n\n /**\n * query() plus `windowCount` — how many entries the TIME window held before\n * keyword filtering, so an LLM caller can distinguish \"keyword matched\n * nothing\" from \"history doesn't reach that far back\" without a retry.\n */\n async search(q: {\n sinceMs?: number\n untilMs?: number\n contains?: string\n terms?: string[]\n limit?: number\n }): Promise<{entries: MemoryEntry[]; windowCount: number}> {\n await this.ensureLoaded()\n const limit = q.limit && q.limit > 0 ? Math.min(q.limit, QUERY_LIMIT_CAP) : QUERY_LIMIT_DEFAULT\n return searchMemoryEntries(this.entries, {\n sinceMs: q.sinceMs,\n untilMs: q.untilMs,\n contains: q.contains,\n terms: q.terms,\n limit,\n })\n }\n\n async summaryList(): Promise<MemorySummary[]> {\n await this.ensureLoaded()\n return [...this.summaries].sort((a, b) => b.hourStart - a.hourStart)\n }\n\n /** Most recent COMPLETED hour with lines but no summary, or null. */\n async pendingSummaryHour(nowMs: number = Date.now()): Promise<number | null> {\n await this.ensureLoaded()\n const currentHour = hourStartOf(nowMs)\n const summarized = new Set(this.summaries.map((s) => s.hourStart))\n const hours = new Set<number>()\n for (const e of this.entries) {\n if (e.kind !== \"line\") continue\n const h = hourStartOf(e.at)\n if (h < currentHour && !summarized.has(h)) hours.add(h)\n }\n if (hours.size === 0) return null\n return Math.max(...hours)\n }\n\n /** The whole timeline as a backup file body (Settings > Memory, session.memory.exportFile). */\n async exportBackup(): Promise<MemoryBackup> {\n await this.ensureLoaded()\n return {\n format: \"glassly-memory\",\n version: 1,\n exportedAt: Date.now(),\n entries: [...this.entries],\n summaries: [...this.summaries].sort((a, b) => a.hourStart - b.hourStart),\n }\n }\n\n /**\n * Merge a backup into the timeline. Skips entries whose id is stored, notes\n * whose text is already in the same hour, and hours that already have a\n * summary. Throws MemoryBackupError when `data` isn't a memory backup.\n */\n async importBackup(data: unknown): Promise<MemoryImportResult> {\n const backup = parseBackup(data)\n await this.ensureLoaded()\n const result: MemoryImportResult = {entries: 0, summaries: 0, skipped: 0}\n\n const ids = new Set(this.entries.map((e) => e.id))\n const noteKeys = new Set(this.entries.filter((e) => e.kind === \"note\").map(noteKey))\n for (const entry of backup.entries) {\n const key = entry.kind === \"note\" ? noteKey(entry) : null\n if (ids.has(entry.id) || (key != null && noteKeys.has(key))) {\n result.skipped++\n continue\n }\n ids.add(entry.id)\n if (key != null) noteKeys.add(key)\n this.entries.push(entry)\n result.entries++\n }\n\n const byHour = new Map(this.summaries.map((s) => [s.hourStart, s]))\n for (const summary of backup.summaries) {\n if (byHour.get(summary.hourStart)?.text.trim()) {\n result.skipped++\n continue\n }\n byHour.set(summary.hourStart, summary)\n result.summaries++\n }\n\n if (result.entries > 0) {\n this.entries.sort((a, b) => a.at - b.at)\n this.prune()\n await this.persistLog()\n }\n if (result.summaries > 0) {\n this.summaries = [...byHour.values()].sort((a, b) => a.hourStart - b.hourStart).slice(-MEMORY_BOUNDS.maxSummaries)\n await this.persistSummaries()\n }\n if (result.entries > 0 || result.summaries > 0) this.emitChanged()\n return result\n }\n\n /** Plain-text export of a scope, for the OS share sheet. */\n async exportText(scope: \"session\" | \"day\" | \"all\", at?: number): Promise<string> {\n const sessions = (await this.sessionList()).filter((s) => {\n if (scope === \"all\") return true\n if (at == null) return false\n if (scope === \"day\") return dayStartOf(s.hourStart) === dayStartOf(at)\n return s.hourStart === hourStartOf(at)\n })\n if (sessions.length === 0) return \"No session history to export.\"\n\n const dayFmt = (ms: number) =>\n new Date(ms).toLocaleDateString(undefined, {weekday: \"long\", year: \"numeric\", month: \"long\", day: \"numeric\"})\n const hourFmt = (ms: number) => new Date(ms).toLocaleTimeString(undefined, {hour: \"numeric\"})\n const timeFmt = (ms: number) => new Date(ms).toLocaleTimeString(undefined, {hour: \"numeric\", minute: \"2-digit\"})\n\n const parts: string[] = []\n let lastDay: number | null = null\n for (const s of [...sessions].sort((a, b) => a.hourStart - b.hourStart)) {\n const day = dayStartOf(s.hourStart)\n if (day !== lastDay) {\n parts.push(`\\n=== ${dayFmt(day)} ===`)\n lastDay = day\n }\n parts.push(`\\n[${hourFmt(s.hourStart)}–${hourFmt(s.hourStart + HOUR_MS)}]`)\n if (s.summary) parts.push(`Summary: ${s.summary}`)\n for (const e of s.entries) {\n const who = e.kind === \"note\" ? \"NOTE\" : (e.speakerId ?? \"—\")\n parts.push(` ${timeFmt(e.at)} ${who}: ${e.text}`)\n }\n }\n return `Memory session history\\n${parts.join(\"\\n\").trim()}\\n`\n }\n\n // === Load / persist ===\n\n private async ensureLoaded(): Promise<void> {\n const userId = (await this.hooks.getUserId()).trim()\n if (!userId) throw new Error(\"Glassly user identity is unavailable\")\n if (this.loadedUserId === userId) return\n if (!this.loadPromise) {\n this.loadPromise = this.loadFor(userId).finally(() => {\n this.loadPromise = null\n })\n }\n await this.loadPromise\n }\n\n private async loadFor(userId: string): Promise<void> {\n // Don't let an identity switch discard lines still sitting in the debounce\n // window — they belong to the OUTGOING user, whose key is still loaded.\n await this.flush()\n this.entries = []\n this.summaries = []\n const rawLog = this.hooks.backend.get(this.key(userId, LOG_SUFFIX))\n if (rawLog != null) {\n this.entries = parseArray(rawLog).filter(isEntry)\n } else {\n this.migrateFromAssist(userId)\n }\n const rawSummaries = this.hooks.backend.get(this.key(userId, SUMMARY_SUFFIX))\n if (rawSummaries != null) {\n this.summaries = parseArray(rawSummaries).filter(isSummary)\n }\n this.loadedUserId = userId\n this.prune()\n }\n\n /**\n * One-time migration: fold the Assist miniapp's per-app store (the previous\n * home of this timeline) into the shared user-scoped keys. Assist's old keys\n * are left in place; its new build reads through the memory bridge instead.\n */\n private migrateFromAssist(userId: string): void {\n const legacyPrefix = `${LEGACY_STORAGE_ROOT}${userId}_${LEGACY_ASSIST_PACKAGE}_`\n try {\n const migrated: MemoryEntry[] = []\n const rawLog = this.hooks.backend.get(legacyPrefix + LEGACY_LOG_KEY)\n if (rawLog != null) {\n migrated.push(...parseArray(rawLog).filter(isEntry))\n } else {\n // Pre-unification Assist: separate transcript log + notes stores.\n for (const v of parseArray(this.hooks.backend.get(legacyPrefix + LEGACY_TRANSCRIPT_KEY))) {\n const e = v as Record<string, unknown>\n if (typeof e.text === \"string\" && typeof e.at === \"number\") {\n migrated.push({\n id: makeId(),\n kind: \"line\",\n text: e.text,\n at: e.at,\n speakerId: typeof e.speakerId === \"string\" ? e.speakerId : null,\n language: typeof e.language === \"string\" ? e.language : null,\n })\n }\n }\n for (const v of parseArray(this.hooks.backend.get(legacyPrefix + LEGACY_NOTES_KEY))) {\n const n = v as Record<string, unknown>\n if (typeof n.text === \"string\" && typeof n.createdAt === \"number\") {\n migrated.push({\n id: makeId(),\n kind: \"note\",\n text: n.text,\n at: n.createdAt,\n speakerId: null,\n language: null,\n source: n.source === \"voice\" || n.source === \"auto\" ? n.source : \"ui\",\n })\n }\n }\n }\n migrated.sort((a, b) => a.at - b.at)\n this.entries = migrated\n if (migrated.length > 0) this.hooks.backend.set(this.key(userId, LOG_SUFFIX), JSON.stringify(migrated))\n\n const rawSummaries = this.hooks.backend.get(legacyPrefix + LEGACY_SUMMARY_KEY)\n if (rawSummaries != null) {\n const summaries = parseArray(rawSummaries).filter(isSummary)\n this.summaries = summaries\n if (summaries.length > 0) this.hooks.backend.set(this.key(userId, SUMMARY_SUFFIX), JSON.stringify(summaries))\n }\n if (this.entries.length > 0 || this.summaries.length > 0) {\n console.log(\n `MemoryStore: migrated ${this.entries.length} entries + ${this.summaries.length} summaries from Assist`,\n )\n }\n } catch (err) {\n console.warn(\"MemoryStore: Assist migration failed:\", err instanceof Error ? err.message : err)\n }\n }\n\n /** Keep the newest MEMORY_BOUNDS.maxEntries; nothing goes for age — deleting is the user's call. */\n private prune(): void {\n const {maxEntries} = MEMORY_BOUNDS\n if (this.entries.length > maxEntries) this.entries = this.entries.slice(-maxEntries)\n }\n\n private key(userId: string, suffix: string): string {\n return `${KEY_ROOT}${userId}_${suffix}`\n }\n\n /**\n * Mark the log dirty and arm the debounce timer. Repeated appends inside the\n * window collapse into a single serialization; the first append after a\n * flush starts a fresh window (trailing-edge, so a steady stream of speech\n * still lands on disk every `writeDebounceMs`).\n */\n private schedulePersistLog(): void {\n const delay = this.hooks.writeDebounceMs ?? DEFAULT_WRITE_DEBOUNCE_MS\n if (delay <= 0) {\n void this.persistLog()\n return\n }\n this.logDirty = true\n if (this.logFlushTimer) return\n this.logFlushTimer = BgTimer.setTimeout(() => {\n this.logFlushTimer = null\n void this.persistLog().catch((err) =>\n console.warn(\"MemoryStore: debounced log write failed:\", err instanceof Error ? err.message : err),\n )\n }, delay)\n }\n\n private async persistLog(): Promise<void> {\n // Any write of the full array satisfies whatever the debounce was holding.\n this.logDirty = false\n if (this.logFlushTimer) {\n BgTimer.clearTimeout(this.logFlushTimer)\n this.logFlushTimer = null\n }\n if (this.loadedUserId == null) return\n this.hooks.backend.set(this.key(this.loadedUserId, LOG_SUFFIX), JSON.stringify(this.entries))\n }\n\n private async persistSummaries(): Promise<void> {\n if (this.loadedUserId == null) return\n this.hooks.backend.set(this.key(this.loadedUserId, SUMMARY_SUFFIX), JSON.stringify(this.summaries))\n }\n\n private emitChanged(): void {\n for (const listener of this.changeListeners) {\n try {\n listener()\n } catch (err) {\n console.warn(\"MemoryStore: onChanged listener threw:\", err instanceof Error ? err.message : err)\n }\n }\n }\n}\n\n/** Stored values may be a JSON string (SimpleStorage writes) or a raw array. */\nfunction parseArray(raw: unknown): unknown[] {\n try {\n if (typeof raw === \"string\") {\n const parsed = JSON.parse(raw) as unknown\n return Array.isArray(parsed) ? parsed : []\n }\n return Array.isArray(raw) ? raw : []\n } catch {\n return []\n }\n}\n\nfunction normalize(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, \" \")\n .trim()\n}\n\nfunction noteKey(entry: MemoryEntry): string {\n return `${hourStartOf(entry.at)}:${normalize(entry.text)}`\n}\n\nfunction parseBackup(data: unknown): {entries: MemoryEntry[]; summaries: MemorySummary[]} {\n const raw = data as Record<string, unknown> | null\n if (!raw || typeof raw !== \"object\" || raw.format !== \"glassly-memory\" || !Array.isArray(raw.entries)) {\n throw new MemoryBackupError(\"Not a Glassly memory backup\")\n }\n if (typeof raw.version !== \"number\" || raw.version > 1) {\n throw new MemoryBackupError(`Unsupported memory backup version ${String(raw.version)}`)\n }\n const entries: MemoryEntry[] = []\n for (const v of raw.entries) {\n if (!isEntry(v) || !v.id || !v.text.trim() || !Number.isFinite(v.at)) continue\n entries.push({\n id: v.id,\n kind: v.kind,\n text: v.text.trim(),\n at: v.at,\n speakerId: typeof v.speakerId === \"string\" ? v.speakerId : null,\n ...(typeof v.resolvedSpeakerName === \"string\" && v.resolvedSpeakerName\n ? {resolvedSpeakerName: v.resolvedSpeakerName}\n : {}),\n language: typeof v.language === \"string\" ? v.language : null,\n ...(v.kind === \"note\" ? {source: v.source === \"voice\" || v.source === \"auto\" ? v.source : \"ui\"} : {}),\n })\n }\n const summaries = (Array.isArray(raw.summaries) ? raw.summaries : [])\n .filter(isSummary)\n .filter((s) => s.text.trim() && Number.isFinite(s.hourStart))\n .map((s) => ({hourStart: s.hourStart, text: s.text, createdAt: s.createdAt}))\n return {entries, summaries}\n}\n\nfunction isEntry(v: unknown): v is MemoryEntry {\n if (!v || typeof v !== \"object\") return false\n const e = v as Record<string, unknown>\n return (\n typeof e.id === \"string\" &&\n (e.kind === \"line\" || e.kind === \"note\") &&\n typeof e.text === \"string\" &&\n typeof e.at === \"number\"\n )\n}\n\nfunction isSummary(v: unknown): v is MemorySummary {\n if (!v || typeof v !== \"object\") return false\n const s = v as Record<string, unknown>\n return typeof s.hourStart === \"number\" && typeof s.text === \"string\" && typeof s.createdAt === \"number\"\n}\n"]}
|
|
@@ -3,6 +3,8 @@ interface ExitGestureApp {
|
|
|
3
3
|
packageName: string;
|
|
4
4
|
name: string;
|
|
5
5
|
running: boolean;
|
|
6
|
+
/** Running only for a placed widget: the wearer is not in it, so there is nothing to leave. */
|
|
7
|
+
widgetOnly?: boolean;
|
|
6
8
|
}
|
|
7
9
|
interface ExitGestureState {
|
|
8
10
|
apps: ExitGestureApp[];
|
|
@@ -12,7 +14,8 @@ interface ExitGestureState {
|
|
|
12
14
|
}
|
|
13
15
|
export interface ExitGestureDependencies {
|
|
14
16
|
getState: () => ExitGestureState;
|
|
15
|
-
|
|
17
|
+
/** The miniapp a double tap leaves right now, or null when the tap is the system's. */
|
|
18
|
+
getTargetPackageName: () => string | null;
|
|
16
19
|
beginExitNotice: (packageName: string, text: string) => boolean;
|
|
17
20
|
finishExitNotice: (packageName: string) => void;
|
|
18
21
|
cancelExitNotice: (packageName: string) => void;
|
|
@@ -24,8 +27,8 @@ export declare class MiniappExitGesture {
|
|
|
24
27
|
private readonly deps;
|
|
25
28
|
private pending;
|
|
26
29
|
constructor(deps: ExitGestureDependencies);
|
|
27
|
-
/** Returns true when the system gesture was consumed by a
|
|
28
|
-
|
|
30
|
+
/** Returns true when the system gesture was consumed by a miniapp exit. */
|
|
31
|
+
tryExitMiniapp(): boolean;
|
|
29
32
|
/** Cancel an in-flight handoff when the device-event router shuts down. */
|
|
30
33
|
reset(): void;
|
|
31
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiniappExitGesture.d.ts","sourceRoot":"","sources":["../../src/services/MiniappExitGesture.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAE1C,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"MiniappExitGesture.d.ts","sourceRoot":"","sources":["../../src/services/MiniappExitGesture.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAE1C,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,+FAA+F;IAC/F,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,cAAc,EAAE,CAAA;IACtB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7C;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,gBAAgB,CAAA;IAChC,uFAAuF;IACvF,oBAAoB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;IACzC,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;IAC/D,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC3D,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC;AAED,qEAAqE;AACrE,qBAAa,kBAAkB;IAGV,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFxC,OAAO,CAAC,OAAO,CAAsD;gBAEjC,IAAI,EAAE,uBAAuB;IAEjE,2EAA2E;IACpE,cAAc,IAAI,OAAO;IAmChC,2EAA2E;IACpE,KAAK,IAAI,IAAI;CAOrB"}
|
|
@@ -6,16 +6,16 @@ export class MiniappExitGesture {
|
|
|
6
6
|
constructor(deps) {
|
|
7
7
|
this.deps = deps;
|
|
8
8
|
}
|
|
9
|
-
/** Returns true when the system gesture was consumed by a
|
|
10
|
-
|
|
9
|
+
/** Returns true when the system gesture was consumed by a miniapp exit. */
|
|
10
|
+
tryExitMiniapp() {
|
|
11
11
|
// Swallow repeat taps while the notice is already counting down.
|
|
12
12
|
if (this.pending)
|
|
13
13
|
return true;
|
|
14
|
-
const packageName = this.deps.
|
|
14
|
+
const packageName = this.deps.getTargetPackageName();
|
|
15
15
|
if (!packageName)
|
|
16
16
|
return false;
|
|
17
17
|
const app = this.deps.getState().apps.find((candidate) => candidate.packageName === packageName);
|
|
18
|
-
if (!app?.running)
|
|
18
|
+
if (!app?.running || app.widgetOnly)
|
|
19
19
|
return false;
|
|
20
20
|
const name = app.name.trim() || packageName;
|
|
21
21
|
if (!this.deps.beginExitNotice(packageName, `Exiting ${name}…`))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiniappExitGesture.js","sourceRoot":"","sources":["../../src/services/MiniappExitGesture.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"MiniappExitGesture.js","sourceRoot":"","sources":["../../src/services/MiniappExitGesture.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAA;AA4B1C,qEAAqE;AACrE,MAAM,OAAO,kBAAkB;IAGO;IAF5B,OAAO,GAAkD,IAAI,CAAA;IAErE,YAAoC,IAA6B;QAA7B,SAAI,GAAJ,IAAI,CAAyB;IAAG,CAAC;IAErE,2EAA2E;IACpE,cAAc;QACnB,iEAAiE;QACjE,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QAE7B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAA;QACpD,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAA;QAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,KAAK,WAAW,CAAC,CAAA;QAChG,IAAI,CAAC,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,UAAU;YAAE,OAAO,KAAK,CAAA;QAEjD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,WAAW,CAAA;QAC3C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,WAAW,IAAI,GAAG,CAAC;YAAE,OAAO,KAAK,CAAA;QAE7E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE;YACxC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAA;YAClC,IAAI,KAAK,CAAC,mBAAmB,KAAK,WAAW;gBAAE,KAAK,CAAC,eAAe,EAAE,CAAA;YAEtE,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,KAAK,WAAW,IAAI,SAAS,CAAC,OAAO,CAAC,CAAA;YAC/G,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;YACvE,KAAK,IAAI;iBACN,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,WAAW,GAAG,EAAE,KAAK,CAAC,CAAA;YAC5E,CAAC,CAAC;iBACD,OAAO,CAAC,GAAG,EAAE;gBACZ,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,KAAK,WAAW;oBAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;gBAClE,mEAAmE;gBACnE,iDAAiD;gBACjD,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAA;YACzC,CAAC,CAAC,CAAA;QACN,CAAC,EAAE,sBAAsB,CAAC,CAAA;QAE1B,IAAI,CAAC,OAAO,GAAG,EAAC,WAAW,EAAE,OAAO,EAAC,CAAA;QACrC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,2EAA2E;IACpE,KAAK;QACV,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QACzB,MAAM,EAAC,WAAW,EAAE,OAAO,EAAC,GAAG,IAAI,CAAC,OAAO,CAAA;QAC3C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA;QAC/B,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAA;IACzC,CAAC;CACF","sourcesContent":["export const MINIAPP_EXIT_NOTICE_MS = 1500\n\ninterface ExitGestureApp {\n packageName: string\n name: string\n running: boolean\n /** Running only for a placed widget: the wearer is not in it, so there is nothing to leave. */\n widgetOnly?: boolean\n}\n\ninterface ExitGestureState {\n apps: ExitGestureApp[]\n foregroundedPackage: string | null\n clearForeground: () => void\n stop: (packageName: string) => Promise<void>\n}\n\nexport interface ExitGestureDependencies {\n getState: () => ExitGestureState\n /** The miniapp a double tap leaves right now, or null when the tap is the system's. */\n getTargetPackageName: () => string | null\n beginExitNotice: (packageName: string, text: string) => boolean\n finishExitNotice: (packageName: string) => void\n cancelExitNotice: (packageName: string) => void\n setTimeout: (callback: () => void, delay: number) => number\n clearTimeout: (timerId: number) => void\n}\n\n/** Owns the short double-tap → exit-notice → normal-stop handoff. */\nexport class MiniappExitGesture {\n private pending: {packageName: string; timerId: number} | null = null\n\n public constructor(private readonly deps: ExitGestureDependencies) {}\n\n /** Returns true when the system gesture was consumed by a miniapp exit. */\n public tryExitMiniapp(): boolean {\n // Swallow repeat taps while the notice is already counting down.\n if (this.pending) return true\n\n const packageName = this.deps.getTargetPackageName()\n if (!packageName) return false\n\n const app = this.deps.getState().apps.find((candidate) => candidate.packageName === packageName)\n if (!app?.running || app.widgetOnly) return false\n\n const name = app.name.trim() || packageName\n if (!this.deps.beginExitNotice(packageName, `Exiting ${name}…`)) return false\n\n const timerId = this.deps.setTimeout(() => {\n const state = this.deps.getState()\n if (state.foregroundedPackage === packageName) state.clearForeground()\n\n const stillRunning = state.apps.some((candidate) => candidate.packageName === packageName && candidate.running)\n const stop = stillRunning ? state.stop(packageName) : Promise.resolve()\n void stop\n .catch((error) => {\n console.error(`MiniappExitGesture: failed to stop ${packageName}:`, error)\n })\n .finally(() => {\n if (this.pending?.packageName === packageName) this.pending = null\n // LocalMiniappRuntime.onUnmount normally finishes the notice. This\n // fallback also handles a failed/no-op teardown.\n this.deps.finishExitNotice(packageName)\n })\n }, MINIAPP_EXIT_NOTICE_MS)\n\n this.pending = {packageName, timerId}\n return true\n }\n\n /** Cancel an in-flight handoff when the device-event router shuts down. */\n public reset(): void {\n if (!this.pending) return\n const {packageName, timerId} = this.pending\n this.pending = null\n this.deps.clearTimeout(timerId)\n this.deps.cancelExitNotice(packageName)\n }\n}\n"]}
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* Widget mode: a miniapp whose background context runs only because a host
|
|
3
3
|
* (the dashboard) placed one of its widgets. It is running, but it has no
|
|
4
4
|
* card in the app switcher, draws nothing of its own on the glasses and
|
|
5
|
-
* hears no touch input; the Widgets pill lists it.
|
|
6
|
-
*
|
|
7
|
-
* tray demotes it back here instead of
|
|
5
|
+
* hears no touch input; the Widgets pill lists it. Foregrounding the app on
|
|
6
|
+
* the phone promotes it to a normal run (the store's start/setForeground);
|
|
7
|
+
* closing a placed app from the tray demotes it back here instead of
|
|
8
|
+
* stopping it.
|
|
8
9
|
*
|
|
9
10
|
* The runtime is the writer (placements come and go through it); the apps
|
|
10
11
|
* store projects `widgetOnly` from here beside `running`.
|
|
11
12
|
*/
|
|
12
|
-
|
|
13
|
+
/** Called with the app whose mode changed and whether it is now widget-only. */
|
|
14
|
+
type Listener = (packageName: string, widgetOnly: boolean) => void;
|
|
13
15
|
export declare const miniappWidgetMode: {
|
|
14
16
|
/** Mark (or clear) widget mode. Clearing promotes: the app keeps running as a normal app. */
|
|
15
17
|
setWidgetOnly(packageName: string, on: boolean): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiniappWidgetMode.d.ts","sourceRoot":"","sources":["../../src/services/MiniappWidgetMode.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MiniappWidgetMode.d.ts","sourceRoot":"","sources":["../../src/services/MiniappWidgetMode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gFAAgF;AAChF,KAAK,QAAQ,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAA;AAiBlE,eAAO,MAAM,iBAAiB;IAC5B,6FAA6F;+BAClE,MAAM,MAAM,OAAO,GAAG,IAAI;8BAM3B,MAAM,GAAG,OAAO;IAI1C,oEAAoE;2BAC7C,MAAM,MAAM,OAAO,GAAG,IAAI;0BAK3B,MAAM,GAAG,OAAO;cAI5B,MAAM,EAAE;kBAIJ,QAAQ,GAAG,MAAM,IAAI;CAMpC,CAAA"}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Widget mode: a miniapp whose background context runs only because a host
|
|
3
3
|
* (the dashboard) placed one of its widgets. It is running, but it has no
|
|
4
4
|
* card in the app switcher, draws nothing of its own on the glasses and
|
|
5
|
-
* hears no touch input; the Widgets pill lists it.
|
|
6
|
-
*
|
|
7
|
-
* tray demotes it back here instead of
|
|
5
|
+
* hears no touch input; the Widgets pill lists it. Foregrounding the app on
|
|
6
|
+
* the phone promotes it to a normal run (the store's start/setForeground);
|
|
7
|
+
* closing a placed app from the tray demotes it back here instead of
|
|
8
|
+
* stopping it.
|
|
8
9
|
*
|
|
9
10
|
* The runtime is the writer (placements come and go through it); the apps
|
|
10
11
|
* store projects `widgetOnly` from here beside `running`.
|
|
@@ -13,10 +14,10 @@ const widgetOnly = new Set();
|
|
|
13
14
|
/** Providers with at least one widget placed by some host. */
|
|
14
15
|
const placed = new Set();
|
|
15
16
|
const listeners = new Set();
|
|
16
|
-
function notify() {
|
|
17
|
+
function notify(packageName, on) {
|
|
17
18
|
for (const fn of listeners) {
|
|
18
19
|
try {
|
|
19
|
-
fn();
|
|
20
|
+
fn(packageName, on);
|
|
20
21
|
}
|
|
21
22
|
catch (e) {
|
|
22
23
|
console.warn("MiniappWidgetMode: listener threw", e);
|
|
@@ -30,7 +31,7 @@ export const miniappWidgetMode = {
|
|
|
30
31
|
if (on)
|
|
31
32
|
widgetOnly.add(packageName);
|
|
32
33
|
if (changed)
|
|
33
|
-
notify();
|
|
34
|
+
notify(packageName, on);
|
|
34
35
|
},
|
|
35
36
|
isWidgetOnly(packageName) {
|
|
36
37
|
return widgetOnly.has(packageName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiniappWidgetMode.js","sourceRoot":"","sources":["../../src/services/MiniappWidgetMode.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MiniappWidgetMode.js","sourceRoot":"","sources":["../../src/services/MiniappWidgetMode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;AACpC,8DAA8D;AAC9D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAA;AAChC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAY,CAAA;AAErC,SAAS,MAAM,CAAC,WAAmB,EAAE,EAAW;IAC9C,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;QACrB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,mCAAmC,EAAE,CAAC,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,6FAA6F;IAC7F,aAAa,CAAC,WAAmB,EAAE,EAAW;QAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QAClF,IAAI,EAAE;YAAE,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QACnC,IAAI,OAAO;YAAE,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IACtC,CAAC;IAED,YAAY,CAAC,WAAmB;QAC9B,OAAO,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACpC,CAAC;IAED,oEAAoE;IACpE,SAAS,CAAC,WAAmB,EAAE,EAAW;QACxC,IAAI,EAAE;YAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;;YAC1B,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACjC,CAAC;IAED,QAAQ,CAAC,WAAmB;QAC1B,OAAO,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAChC,CAAC;IAED,MAAM;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAC/B,CAAC;IAED,SAAS,CAAC,EAAY;QACpB,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACjB,OAAO,GAAG,EAAE;YACV,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACtB,CAAC,CAAA;IACH,CAAC;CACF,CAAA","sourcesContent":["/**\n * Widget mode: a miniapp whose background context runs only because a host\n * (the dashboard) placed one of its widgets. It is running, but it has no\n * card in the app switcher, draws nothing of its own on the glasses and\n * hears no touch input; the Widgets pill lists it. Foregrounding the app on\n * the phone promotes it to a normal run (the store's start/setForeground);\n * closing a placed app from the tray demotes it back here instead of\n * stopping it.\n *\n * The runtime is the writer (placements come and go through it); the apps\n * store projects `widgetOnly` from here beside `running`.\n */\n\n/** Called with the app whose mode changed and whether it is now widget-only. */\ntype Listener = (packageName: string, widgetOnly: boolean) => void\n\nconst widgetOnly = new Set<string>()\n/** Providers with at least one widget placed by some host. */\nconst placed = new Set<string>()\nconst listeners = new Set<Listener>()\n\nfunction notify(packageName: string, on: boolean): void {\n for (const fn of listeners) {\n try {\n fn(packageName, on)\n } catch (e) {\n console.warn(\"MiniappWidgetMode: listener threw\", e)\n }\n }\n}\n\nexport const miniappWidgetMode = {\n /** Mark (or clear) widget mode. Clearing promotes: the app keeps running as a normal app. */\n setWidgetOnly(packageName: string, on: boolean): void {\n const changed = on ? !widgetOnly.has(packageName) : widgetOnly.delete(packageName)\n if (on) widgetOnly.add(packageName)\n if (changed) notify(packageName, on)\n },\n\n isWidgetOnly(packageName: string): boolean {\n return widgetOnly.has(packageName)\n },\n\n /** Record whether any host has a widget of this provider placed. */\n setPlaced(packageName: string, on: boolean): void {\n if (on) placed.add(packageName)\n else placed.delete(packageName)\n },\n\n isPlaced(packageName: string): boolean {\n return placed.has(packageName)\n },\n\n getAll(): string[] {\n return Array.from(widgetOnly)\n },\n\n subscribe(fn: Listener): () => void {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n },\n}\n"]}
|
|
@@ -22,6 +22,8 @@ export declare function validateAnthropicApiKey(apiKey: string): Promise<KeyVali
|
|
|
22
22
|
export declare function validateGeminiApiKey(apiKey: string): Promise<KeyValidationResult>;
|
|
23
23
|
/** GET /v1/models with the candidate key; OpenAI answers 401 for bad keys. */
|
|
24
24
|
export declare function validateOpenAiApiKey(apiKey: string): Promise<KeyValidationResult>;
|
|
25
|
+
/** GET /models with the candidate key; DeepSeek answers 401 for bad keys. */
|
|
26
|
+
export declare function validateDeepSeekApiKey(apiKey: string): Promise<KeyValidationResult>;
|
|
25
27
|
/** GET /v1/user with the candidate key; ElevenLabs answers 401 for bad keys. */
|
|
26
28
|
export declare function validateElevenLabsApiKey(apiKey: string): Promise<KeyValidationResult>;
|
|
27
29
|
//# sourceMappingURL=ProviderKeyValidation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderKeyValidation.d.ts","sourceRoot":"","sources":["../../src/services/ProviderKeyValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,mBAAmB,GAAG;IAAC,EAAE,EAAE,IAAI,CAAA;CAAC,GAAG;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAA;CAAC,CAAA;AAiB7F,iFAAiF;AACjF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMpF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMjF;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAEjF;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAErF"}
|
|
1
|
+
{"version":3,"file":"ProviderKeyValidation.d.ts","sourceRoot":"","sources":["../../src/services/ProviderKeyValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,mBAAmB,GAAG;IAAC,EAAE,EAAE,IAAI,CAAA;CAAC,GAAG;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAA;CAAC,CAAA;AAiB7F,iFAAiF;AACjF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMpF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMjF;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAEjF;AAED,6EAA6E;AAC7E,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAEnF;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAErF"}
|
|
@@ -35,6 +35,10 @@ export function validateGeminiApiKey(apiKey) {
|
|
|
35
35
|
export function validateOpenAiApiKey(apiKey) {
|
|
36
36
|
return probe("https://api.openai.com/v1/models", { Authorization: `Bearer ${apiKey.trim()}` }, [401, 403]);
|
|
37
37
|
}
|
|
38
|
+
/** GET /models with the candidate key; DeepSeek answers 401 for bad keys. */
|
|
39
|
+
export function validateDeepSeekApiKey(apiKey) {
|
|
40
|
+
return probe("https://api.deepseek.com/models", { Authorization: `Bearer ${apiKey.trim()}` }, [401, 403]);
|
|
41
|
+
}
|
|
38
42
|
/** GET /v1/user with the candidate key; ElevenLabs answers 401 for bad keys. */
|
|
39
43
|
export function validateElevenLabsApiKey(apiKey) {
|
|
40
44
|
return probe("https://api.elevenlabs.io/v1/user", { "xi-api-key": apiKey.trim() }, [401, 403]);
|