@senguoyun/dsh-arkme 0.1.85 → 0.1.87
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/docs/recognized-speaker-directory-backend-handoff-2026-09-28.md +2 -0
- package/docs/recognized-speaker-entry-and-visits.md +2 -0
- package/docs/recognized-speaker-sorting.md +2 -0
- package/docs/self-role-avatar-cache.md +59 -0
- package/docs/speaker-directory-integration-2026-09-30.md +53 -0
- package/lib/client.js +1336 -1168
- package/lib/client.js.map +1 -1
- package/lib/harness-model-client.js +14 -0
- package/lib/harness-native-selection-client.js +14 -0
- package/lib/harness-sidebar-client.js +14 -0
- package/lib/index.js +28 -9
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-adGFmkIa.js → persistent-runtime-0qn1BZ6S.js} +733 -136
- package/lib/sdk.js +14 -0
- package/lib/types/arkme-service.d.ts +7 -0
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/client/ArkmeAvatar.d.ts +2 -1
- package/lib/types/client/ArkmeAvatar.d.ts.map +1 -1
- package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts +3 -30
- package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSelfRolePicker.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +1 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/avatar-image-runtime.d.ts.map +1 -1
- package/lib/types/client/avatar-image-store.d.ts +10 -0
- package/lib/types/client/avatar-image-store.d.ts.map +1 -1
- package/lib/types/client/avatar-persistent-cache.d.ts +16 -0
- package/lib/types/client/avatar-persistent-cache.d.ts.map +1 -0
- package/lib/types/client/locales/actions-en.d.ts.map +1 -1
- package/lib/types/client/reaction-notifications.d.ts.map +1 -1
- package/lib/types/client/reaction-preview-store.d.ts +4 -1
- package/lib/types/client/reaction-preview-store.d.ts.map +1 -1
- package/lib/types/client/reaction-transport.d.ts +4 -0
- package/lib/types/client/reaction-transport.d.ts.map +1 -0
- package/lib/types/client/realtime-client-events.d.ts.map +1 -1
- package/lib/types/client/recognized-speaker-directory.d.ts +51 -22
- package/lib/types/client/recognized-speaker-directory.d.ts.map +1 -1
- package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts +2 -4
- package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts.map +1 -1
- package/lib/types/client/recordings/recording-speaker-options-store.d.ts.map +1 -1
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/local-database.d.ts +1 -0
- package/lib/types/local-database.d.ts.map +1 -1
- package/lib/types/reaction-contract.d.ts +4 -0
- package/lib/types/reaction-contract.d.ts.map +1 -1
- package/lib/types/reaction-diagnostics.d.ts +4 -0
- package/lib/types/reaction-diagnostics.d.ts.map +1 -0
- package/lib/types/reaction-host-diagnostics.d.ts +6 -0
- package/lib/types/reaction-host-diagnostics.d.ts.map +1 -0
- package/lib/types/recording-presence.d.ts +1 -1
- package/lib/types/request-coordinator.d.ts +2 -0
- package/lib/types/request-coordinator.d.ts.map +1 -1
- package/lib/types/sdk/index.d.ts +2 -0
- package/lib/types/sdk/index.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +1 -0
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/media-service.d.ts +14 -0
- package/lib/types/services/media-service.d.ts.map +1 -1
- package/lib/types/services/profile-service.d.ts.map +1 -1
- package/lib/types/services/reaction-service.d.ts.map +1 -1
- package/lib/types/services/recording-service.d.ts +4 -0
- package/lib/types/services/recording-service.d.ts.map +1 -1
- package/lib/types/services/service.d.ts +1 -0
- package/lib/types/services/service.d.ts.map +1 -1
- package/lib/types/services/speaker-directory-service.d.ts +19 -0
- package/lib/types/services/speaker-directory-service.d.ts.map +1 -0
- package/lib/types/services/unmarked-speaker-service.d.ts +2 -0
- package/lib/types/services/unmarked-speaker-service.d.ts.map +1 -1
- package/lib/types/speaker-directory-contract.d.ts +71 -0
- package/lib/types/speaker-directory-contract.d.ts.map +1 -0
- package/lib/types/tools/business/media/read-image.d.ts.map +1 -1
- package/lib/types/tools/ports/media.d.ts +1 -0
- package/lib/types/tools/ports/media.d.ts.map +1 -1
- package/lib/types/types.d.ts +2 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
package/lib/client.js
CHANGED
|
@@ -800,6 +800,20 @@ window.__ModuleLoader__.load({
|
|
|
800
800
|
if (imageRef.trim() === "") throw new TypeError("Arkme image reference must not be empty");
|
|
801
801
|
return await this.call("image.read", { imageRef }, signal);
|
|
802
802
|
}
|
|
803
|
+
/** Probe immutable image bytes without starting an upstream request. */
|
|
804
|
+
async readCachedImage(imageRef, signal) {
|
|
805
|
+
if (imageRef.trim() === "") throw new TypeError("Arkme image reference must not be empty");
|
|
806
|
+
if ((await this.capabilities(signal)).features.imageCacheRead !== true) throw new Error("当前 Arkme Provider 不支持本地头像探测,请升级");
|
|
807
|
+
try {
|
|
808
|
+
return await this.call("image.read", {
|
|
809
|
+
imageRef,
|
|
810
|
+
cacheOnly: true
|
|
811
|
+
}, signal);
|
|
812
|
+
} catch (error) {
|
|
813
|
+
if (error instanceof ArkmeClientError && error.body.code === "image-cache-miss") return void 0;
|
|
814
|
+
throw error;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
803
817
|
/** Convert a Provider image payload into a browser-renderable data URL. */
|
|
804
818
|
imageDataUrl(image) {
|
|
805
819
|
return `data:${image.mediaType};base64,${image.dataBase64}`;
|
|
@@ -35173,6 +35187,23 @@ Bot 列表加载失败,点击重试|Could not load Bots. Click to retry
|
|
|
35173
35187
|
//#endregion
|
|
35174
35188
|
//#region src/client/locales/actions-en.ts
|
|
35175
35189
|
const actionEnglish = {
|
|
35190
|
+
"加载更多说话人": "Load more speakers",
|
|
35191
|
+
"该分类暂无说话人": "No speakers in this category",
|
|
35192
|
+
"没有匹配的说话人": "No matching speakers",
|
|
35193
|
+
"目录有更新,刷新后查看最新人物。": "The directory has updates. Refresh to see the latest people.",
|
|
35194
|
+
"搜索内容过长,请缩短至 256 字节以内。": "Search text is too long. Keep it within 256 bytes.",
|
|
35195
|
+
"搜索名称或编号": "Search by name or number",
|
|
35196
|
+
"查看状态暂未同步,联网后自动重试。": "View status has not synced. It will retry when online.",
|
|
35197
|
+
"正在加载人物详情…": "Loading person details…",
|
|
35198
|
+
"部分录音仍在整理,人物可能继续更新。": "Some recordings are still being processed. People may continue to update.",
|
|
35199
|
+
"正在更新,当前显示已整理的目录。": "Updating. Showing the available directory.",
|
|
35200
|
+
"更新暂未完成,当前显示上次整理的目录。": "The update has not completed. Showing the previous directory.",
|
|
35201
|
+
"正在整理说话人目录…": "Preparing the speaker directory…",
|
|
35202
|
+
"说话人目录暂不可用,请稍后刷新。": "The speaker directory is unavailable. Please refresh later.",
|
|
35203
|
+
"说话人目录暂不可用,请稍后再试。": "The speaker directory is unavailable. Please try again later.",
|
|
35204
|
+
"声纹状态暂不可用": "Voiceprint status unavailable",
|
|
35205
|
+
"暂时无法更新": "Unable to update",
|
|
35206
|
+
"目录暂不可用": "Directory unavailable",
|
|
35176
35207
|
"发现未发布的草稿": "Unpublished draft found",
|
|
35177
35208
|
"草稿预览": "Draft preview",
|
|
35178
35209
|
"预览草稿": "Preview draft",
|
|
@@ -54565,84 +54596,15 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54565
54596
|
});
|
|
54566
54597
|
}
|
|
54567
54598
|
//#endregion
|
|
54568
|
-
//#region src/avatar-diagnostics.ts
|
|
54569
|
-
function record(value) {
|
|
54570
|
-
return value !== null && typeof value === "object" ? value : {};
|
|
54571
|
-
}
|
|
54572
|
-
function positiveId(value) {
|
|
54573
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
54574
|
-
}
|
|
54575
|
-
/** Decoded IDs are diagnostic hints only, never authentication or authorization inputs. */
|
|
54576
|
-
function avatarReferenceDiagnostic(imageRef) {
|
|
54577
|
-
const ref = imageRef.trim();
|
|
54578
|
-
if (!ref.startsWith("arkme-profile-image-v1.")) return { referenceKind: ref.startsWith("arkme-media-v1.") ? "media" : "other" };
|
|
54579
|
-
const context = { referenceKind: "profile" };
|
|
54580
|
-
try {
|
|
54581
|
-
const parts = ref.split(".");
|
|
54582
|
-
const encoded = parts[1] ?? "";
|
|
54583
|
-
if (parts.length !== 3 || encoded.length > 1024 || !/^[A-Za-z0-9_-]+$/.test(encoded)) return context;
|
|
54584
|
-
const base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
54585
|
-
const payload = record(JSON.parse(globalThis.atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "="))));
|
|
54586
|
-
if (payload.version !== 1) return context;
|
|
54587
|
-
const viewer = positiveId(payload.viewerUserId);
|
|
54588
|
-
const target = positiveId(payload.targetUserId);
|
|
54589
|
-
if (viewer !== void 0) context.referenceViewerUserId = viewer;
|
|
54590
|
-
if (target !== void 0) context.referenceTargetUserId = target;
|
|
54591
|
-
} catch {}
|
|
54592
|
-
return context;
|
|
54593
|
-
}
|
|
54594
|
-
function avatarScopeDiagnostic(scopeKey) {
|
|
54595
|
-
const match = /^(prod|test):([1-9][0-9]*)$/.exec(scopeKey ?? "");
|
|
54596
|
-
const viewerUserId = positiveId(Number(match?.[2]));
|
|
54597
|
-
return match === null || viewerUserId === void 0 ? {} : {
|
|
54598
|
-
environment: match[1],
|
|
54599
|
-
viewerUserId
|
|
54600
|
-
};
|
|
54601
|
-
}
|
|
54602
|
-
function safeErrorCode(value) {
|
|
54603
|
-
return typeof value === "string" && /^(?:(?:arkme|image|auth-http|local|profile)-[A-Za-z0-9_-]{1,80}|UND_ERR_[A-Z_]{1,64}|E[A-Z_]{1,64})$/.test(value) ? value : void 0;
|
|
54604
|
-
}
|
|
54605
|
-
function httpStatus(value) {
|
|
54606
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599 ? value : void 0;
|
|
54607
|
-
}
|
|
54608
|
-
function imageDownloadStatus(error) {
|
|
54609
|
-
if (error.name !== "ArkmePluginError" || error.code !== "image-download-failed" || typeof error.message !== "string") return void 0;
|
|
54610
|
-
const match = /^Arkme 图片读取返回 HTTP ([1-5][0-9]{2})$/.exec(error.message);
|
|
54611
|
-
return match === null ? void 0 : httpStatus(Number(match[1]));
|
|
54612
|
-
}
|
|
54613
|
-
function logArkmeAvatarDiagnostic(event, context, error) {
|
|
54614
|
-
try {
|
|
54615
|
-
const source = record(error);
|
|
54616
|
-
const body = record(source.body);
|
|
54617
|
-
const detail = source.name === "ArkmeClientError" ? body : source;
|
|
54618
|
-
const errorName = [
|
|
54619
|
-
"Error",
|
|
54620
|
-
"TypeError",
|
|
54621
|
-
"AbortError",
|
|
54622
|
-
"TimeoutError",
|
|
54623
|
-
"ArkmePluginError",
|
|
54624
|
-
"ArkmeClientError"
|
|
54625
|
-
].includes(String(source.name)) ? String(source.name) : "unknown";
|
|
54626
|
-
console.warn(`[ArkmeAvatarDiag] ${JSON.stringify({
|
|
54627
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54628
|
-
event,
|
|
54629
|
-
...context,
|
|
54630
|
-
...error === void 0 ? {} : { error: {
|
|
54631
|
-
name: errorName,
|
|
54632
|
-
code: safeErrorCode(detail.code),
|
|
54633
|
-
retryable: typeof detail.retryable === "boolean" ? detail.retryable : void 0,
|
|
54634
|
-
httpStatus: httpStatus(source.httpStatus),
|
|
54635
|
-
upstreamStatus: httpStatus(source.upstreamStatus) ?? imageDownloadStatus(source),
|
|
54636
|
-
causeCode: safeErrorCode(record(source.cause).code)
|
|
54637
|
-
} }
|
|
54638
|
-
})}`);
|
|
54639
|
-
} catch {}
|
|
54640
|
-
}
|
|
54641
|
-
//#endregion
|
|
54642
54599
|
//#region src/client/avatar-image-store.ts
|
|
54600
|
+
/** These references identify immutable bytes, unlike mutable profile references. */
|
|
54601
|
+
function isImmutableAvatarRef(ref) {
|
|
54602
|
+
return /^file_asset:\/\/[A-Za-z0-9_-]{8,128}$/.test(ref) || /^arkme-self-role-image-v1\.[A-Za-z0-9_-]+$/.test(ref);
|
|
54603
|
+
}
|
|
54643
54604
|
const DEFAULT_TTL_MILLIS = 600 * 1e3;
|
|
54644
54605
|
const DEFAULT_JITTER_MILLIS$1 = 120 * 1e3;
|
|
54645
|
-
const DEFAULT_CONCURRENCY =
|
|
54606
|
+
const DEFAULT_CONCURRENCY = 3;
|
|
54607
|
+
const IMMUTABLE_CONCURRENCY = 2;
|
|
54646
54608
|
const MAX_RETAINED_AVATARS = 256;
|
|
54647
54609
|
const MAX_QUEUED_AVATARS = 512;
|
|
54648
54610
|
const AVATAR_IMAGE_SCOPE_CHANGED = "Avatar image scope changed";
|
|
@@ -54656,6 +54618,8 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54656
54618
|
jitterMillis;
|
|
54657
54619
|
concurrency;
|
|
54658
54620
|
activeDownloads = 0;
|
|
54621
|
+
activeImmutableReads = 0;
|
|
54622
|
+
activeCacheProbes = 0;
|
|
54659
54623
|
generation = 0;
|
|
54660
54624
|
scopeKey;
|
|
54661
54625
|
constructor(options) {
|
|
@@ -54709,10 +54673,26 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54709
54673
|
expiresAtMillis: 0,
|
|
54710
54674
|
pending: void 0
|
|
54711
54675
|
};
|
|
54712
|
-
const
|
|
54676
|
+
const readRemote = () => this.schedule(isImmutableAvatarRef(imageRef) ? "immutable" : "remote", async () => {
|
|
54713
54677
|
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54714
54678
|
return await this.options.reader(imageRef);
|
|
54715
|
-
})
|
|
54679
|
+
});
|
|
54680
|
+
const persistent = scopeKey !== void 0 && isImmutableAvatarRef(imageRef) ? this.options.persistentCache : void 0;
|
|
54681
|
+
const probe = isImmutableAvatarRef(imageRef) ? this.options.cachedReader : void 0;
|
|
54682
|
+
const pending = (persistent === void 0 && probe === void 0 ? readRemote() : (async () => {
|
|
54683
|
+
const cached = await persistent?.read(scopeKey, imageRef).catch(() => void 0);
|
|
54684
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54685
|
+
if (cached !== void 0) return cached;
|
|
54686
|
+
const local = probe === void 0 ? void 0 : await this.schedule("probe", async () => {
|
|
54687
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54688
|
+
return await probe(imageRef);
|
|
54689
|
+
});
|
|
54690
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54691
|
+
const payload = local ?? await readRemote();
|
|
54692
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54693
|
+
persistent?.write(scopeKey, imageRef, payload).catch(() => void 0);
|
|
54694
|
+
return payload;
|
|
54695
|
+
})()).then((payload) => {
|
|
54716
54696
|
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54717
54697
|
const value = `data:${payload.mediaType};base64,${payload.dataBase64}`;
|
|
54718
54698
|
const previousValue = entry.value;
|
|
@@ -54751,27 +54731,35 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54751
54731
|
if (entry.pending === void 0 && !this.listeners.has(ref)) this.entries.delete(ref);
|
|
54752
54732
|
}
|
|
54753
54733
|
}
|
|
54754
|
-
schedule(load) {
|
|
54734
|
+
schedule(lane, load) {
|
|
54755
54735
|
return new Promise((resolve, reject) => {
|
|
54756
54736
|
if (this.queue.length >= MAX_QUEUED_AVATARS) {
|
|
54757
54737
|
reject(/* @__PURE__ */ new Error("Avatar loading queue is full"));
|
|
54758
54738
|
return;
|
|
54759
54739
|
}
|
|
54760
|
-
this.queue.push(
|
|
54761
|
-
|
|
54762
|
-
|
|
54763
|
-
|
|
54764
|
-
|
|
54740
|
+
this.queue.push({
|
|
54741
|
+
lane,
|
|
54742
|
+
start: () => {
|
|
54743
|
+
load().then(resolve, reject).finally(() => {
|
|
54744
|
+
if (lane === "probe") this.activeCacheProbes -= 1;
|
|
54745
|
+
else if (lane === "immutable") this.activeImmutableReads -= 1;
|
|
54746
|
+
else this.activeDownloads -= 1;
|
|
54747
|
+
this.drainQueue();
|
|
54748
|
+
});
|
|
54749
|
+
}
|
|
54765
54750
|
});
|
|
54766
54751
|
this.drainQueue();
|
|
54767
54752
|
});
|
|
54768
54753
|
}
|
|
54769
54754
|
drainQueue() {
|
|
54770
|
-
|
|
54771
|
-
const
|
|
54772
|
-
if (
|
|
54773
|
-
this.
|
|
54774
|
-
|
|
54755
|
+
for (;;) {
|
|
54756
|
+
const index = this.queue.findIndex((job) => job.lane === "probe" ? this.activeCacheProbes < 1 : job.lane === "immutable" ? this.activeImmutableReads < IMMUTABLE_CONCURRENCY : this.activeDownloads < this.concurrency);
|
|
54757
|
+
if (index === -1) return;
|
|
54758
|
+
const job = this.queue.splice(index, 1)[0];
|
|
54759
|
+
if (job.lane === "probe") this.activeCacheProbes += 1;
|
|
54760
|
+
else if (job.lane === "immutable") this.activeImmutableReads += 1;
|
|
54761
|
+
else this.activeDownloads += 1;
|
|
54762
|
+
job.start();
|
|
54775
54763
|
}
|
|
54776
54764
|
}
|
|
54777
54765
|
notify(imageRef, value) {
|
|
@@ -54779,8 +54767,185 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54779
54767
|
}
|
|
54780
54768
|
};
|
|
54781
54769
|
//#endregion
|
|
54770
|
+
//#region src/client/avatar-persistent-cache.ts
|
|
54771
|
+
const CACHE_NAME = "arkme-immutable-avatars-v1";
|
|
54772
|
+
const MAX_ENTRIES$1 = 64;
|
|
54773
|
+
const MAX_BYTES$1 = 64 * 1024 * 1024;
|
|
54774
|
+
const MAX_BASE64_LENGTH = Math.ceil(8 * 1024 * 1024 / 3) * 4;
|
|
54775
|
+
function validPayload(value) {
|
|
54776
|
+
if (typeof value !== "object" || value === null) return false;
|
|
54777
|
+
const payload = value;
|
|
54778
|
+
return typeof payload.mediaType === "string" && /^image\/(png|jpeg|webp|gif|avif)$/.test(payload.mediaType) && typeof payload.dataBase64 === "string" && payload.dataBase64.length > 0 && payload.dataBase64.length <= MAX_BASE64_LENGTH && payload.dataBase64.length % 4 === 0 && !/[^A-Za-z0-9+/]/.test(payload.dataBase64.replace(/={1,2}$/, ""));
|
|
54779
|
+
}
|
|
54780
|
+
/** Validate browser-persisted bytes too: base64 syntax is not image validity. */
|
|
54781
|
+
async function decodableAvatar(payload) {
|
|
54782
|
+
try {
|
|
54783
|
+
const bytes = Uint8Array.from(atob(payload.dataBase64), (character) => character.charCodeAt(0));
|
|
54784
|
+
const blob = new Blob([bytes], { type: payload.mediaType });
|
|
54785
|
+
if (typeof createImageBitmap === "function") {
|
|
54786
|
+
(await createImageBitmap(blob)).close();
|
|
54787
|
+
return true;
|
|
54788
|
+
}
|
|
54789
|
+
if (typeof Image === "undefined") return false;
|
|
54790
|
+
const url = URL.createObjectURL(blob);
|
|
54791
|
+
try {
|
|
54792
|
+
return await new Promise((resolve) => {
|
|
54793
|
+
const image = new Image();
|
|
54794
|
+
image.onload = () => resolve(image.naturalWidth > 0 && image.naturalHeight > 0);
|
|
54795
|
+
image.onerror = () => resolve(false);
|
|
54796
|
+
image.src = url;
|
|
54797
|
+
});
|
|
54798
|
+
} finally {
|
|
54799
|
+
URL.revokeObjectURL(url);
|
|
54800
|
+
}
|
|
54801
|
+
} catch {
|
|
54802
|
+
return false;
|
|
54803
|
+
}
|
|
54804
|
+
}
|
|
54805
|
+
/** Browser bytes survive reloads. Host remains the authenticated source on misses.
|
|
54806
|
+
* No TTL for immutable refs; quota eviction and clearing site data are cache misses.
|
|
54807
|
+
* Synthetic keys are never fetched and include the environment/account scope.
|
|
54808
|
+
*/
|
|
54809
|
+
var BrowserAvatarPersistentCache = class {
|
|
54810
|
+
decode;
|
|
54811
|
+
constructor(decode = decodableAvatar) {
|
|
54812
|
+
this.decode = decode;
|
|
54813
|
+
}
|
|
54814
|
+
writes = Promise.resolve();
|
|
54815
|
+
key(scope, ref) {
|
|
54816
|
+
try {
|
|
54817
|
+
if (!scope.trim() || !isImmutableAvatarRef(ref) || typeof globalThis.caches === "undefined" || typeof globalThis.location === "undefined") return void 0;
|
|
54818
|
+
return new URL(`/arkme-self/avatar-cache/v1/${encodeURIComponent(scope)}/${encodeURIComponent(ref)}`, globalThis.location.origin).href;
|
|
54819
|
+
} catch {
|
|
54820
|
+
return;
|
|
54821
|
+
}
|
|
54822
|
+
}
|
|
54823
|
+
async read(scope, ref) {
|
|
54824
|
+
const key = this.key(scope, ref);
|
|
54825
|
+
if (key === void 0) return void 0;
|
|
54826
|
+
try {
|
|
54827
|
+
const cache = await caches.open(CACHE_NAME);
|
|
54828
|
+
const response = await cache.match(key);
|
|
54829
|
+
if (response === void 0) return void 0;
|
|
54830
|
+
const payload = await response.json().catch(() => void 0);
|
|
54831
|
+
if (validPayload(payload) && await this.decode(payload)) return payload;
|
|
54832
|
+
await cache.delete(key);
|
|
54833
|
+
} catch {}
|
|
54834
|
+
}
|
|
54835
|
+
write(scope, ref, payload) {
|
|
54836
|
+
const key = this.key(scope, ref);
|
|
54837
|
+
if (key === void 0 || !validPayload(payload)) return Promise.resolve();
|
|
54838
|
+
const operation = this.writes.then(async () => {
|
|
54839
|
+
if (!await this.decode(payload)) return;
|
|
54840
|
+
const cache = await caches.open(CACHE_NAME);
|
|
54841
|
+
const body = JSON.stringify(payload);
|
|
54842
|
+
const keys = (await cache.keys()).filter((request) => request.url !== key);
|
|
54843
|
+
const sizes = await Promise.all(keys.map(async (request) => Number((await cache.match(request))?.headers.get("Content-Length")) || 0));
|
|
54844
|
+
let bytes = sizes.reduce((sum, size) => sum + size, 0) + body.length;
|
|
54845
|
+
let count = keys.length + 1;
|
|
54846
|
+
for (let index = 0; index < keys.length && (count > MAX_ENTRIES$1 || bytes > MAX_BYTES$1); index++) {
|
|
54847
|
+
await cache.delete(keys[index]);
|
|
54848
|
+
bytes -= sizes[index];
|
|
54849
|
+
count -= 1;
|
|
54850
|
+
}
|
|
54851
|
+
await cache.put(key, new Response(body, { headers: {
|
|
54852
|
+
"Content-Type": "application/json",
|
|
54853
|
+
"Content-Length": String(body.length)
|
|
54854
|
+
} }));
|
|
54855
|
+
});
|
|
54856
|
+
this.writes = operation.catch(() => void 0);
|
|
54857
|
+
return this.writes;
|
|
54858
|
+
}
|
|
54859
|
+
};
|
|
54860
|
+
//#endregion
|
|
54861
|
+
//#region src/avatar-diagnostics.ts
|
|
54862
|
+
function record(value) {
|
|
54863
|
+
return value !== null && typeof value === "object" ? value : {};
|
|
54864
|
+
}
|
|
54865
|
+
function positiveId(value) {
|
|
54866
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
54867
|
+
}
|
|
54868
|
+
/** Decoded IDs are diagnostic hints only, never authentication or authorization inputs. */
|
|
54869
|
+
function avatarReferenceDiagnostic(imageRef) {
|
|
54870
|
+
const ref = imageRef.trim();
|
|
54871
|
+
if (!ref.startsWith("arkme-profile-image-v1.")) return { referenceKind: ref.startsWith("arkme-media-v1.") ? "media" : "other" };
|
|
54872
|
+
const context = { referenceKind: "profile" };
|
|
54873
|
+
try {
|
|
54874
|
+
const parts = ref.split(".");
|
|
54875
|
+
const encoded = parts[1] ?? "";
|
|
54876
|
+
if (parts.length !== 3 || encoded.length > 1024 || !/^[A-Za-z0-9_-]+$/.test(encoded)) return context;
|
|
54877
|
+
const base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
54878
|
+
const payload = record(JSON.parse(globalThis.atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "="))));
|
|
54879
|
+
if (payload.version !== 1) return context;
|
|
54880
|
+
const viewer = positiveId(payload.viewerUserId);
|
|
54881
|
+
const target = positiveId(payload.targetUserId);
|
|
54882
|
+
if (viewer !== void 0) context.referenceViewerUserId = viewer;
|
|
54883
|
+
if (target !== void 0) context.referenceTargetUserId = target;
|
|
54884
|
+
} catch {}
|
|
54885
|
+
return context;
|
|
54886
|
+
}
|
|
54887
|
+
function avatarScopeDiagnostic(scopeKey) {
|
|
54888
|
+
const match = /^(prod|test):([1-9][0-9]*)$/.exec(scopeKey ?? "");
|
|
54889
|
+
const viewerUserId = positiveId(Number(match?.[2]));
|
|
54890
|
+
return match === null || viewerUserId === void 0 ? {} : {
|
|
54891
|
+
environment: match[1],
|
|
54892
|
+
viewerUserId
|
|
54893
|
+
};
|
|
54894
|
+
}
|
|
54895
|
+
function safeErrorCode(value) {
|
|
54896
|
+
return typeof value === "string" && /^(?:(?:arkme|image|auth-http|local|profile)-[A-Za-z0-9_-]{1,80}|UND_ERR_[A-Z_]{1,64}|E[A-Z_]{1,64})$/.test(value) ? value : void 0;
|
|
54897
|
+
}
|
|
54898
|
+
function httpStatus(value) {
|
|
54899
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599 ? value : void 0;
|
|
54900
|
+
}
|
|
54901
|
+
function imageDownloadStatus(error) {
|
|
54902
|
+
if (error.name !== "ArkmePluginError" || error.code !== "image-download-failed" || typeof error.message !== "string") return void 0;
|
|
54903
|
+
const match = /^Arkme 图片读取返回 HTTP ([1-5][0-9]{2})$/.exec(error.message);
|
|
54904
|
+
return match === null ? void 0 : httpStatus(Number(match[1]));
|
|
54905
|
+
}
|
|
54906
|
+
function logArkmeAvatarDiagnostic(event, context, error) {
|
|
54907
|
+
try {
|
|
54908
|
+
const source = record(error);
|
|
54909
|
+
const body = record(source.body);
|
|
54910
|
+
const detail = source.name === "ArkmeClientError" ? body : source;
|
|
54911
|
+
const errorName = [
|
|
54912
|
+
"Error",
|
|
54913
|
+
"TypeError",
|
|
54914
|
+
"AbortError",
|
|
54915
|
+
"TimeoutError",
|
|
54916
|
+
"ArkmePluginError",
|
|
54917
|
+
"ArkmeClientError"
|
|
54918
|
+
].includes(String(source.name)) ? String(source.name) : "unknown";
|
|
54919
|
+
console.warn(`[ArkmeAvatarDiag] ${JSON.stringify({
|
|
54920
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54921
|
+
event,
|
|
54922
|
+
...context,
|
|
54923
|
+
...error === void 0 ? {} : { error: {
|
|
54924
|
+
name: errorName,
|
|
54925
|
+
code: safeErrorCode(detail.code),
|
|
54926
|
+
retryable: typeof detail.retryable === "boolean" ? detail.retryable : void 0,
|
|
54927
|
+
httpStatus: httpStatus(source.httpStatus),
|
|
54928
|
+
upstreamStatus: httpStatus(source.upstreamStatus) ?? imageDownloadStatus(source),
|
|
54929
|
+
causeCode: safeErrorCode(record(source.cause).code)
|
|
54930
|
+
} }
|
|
54931
|
+
})}`);
|
|
54932
|
+
} catch {}
|
|
54933
|
+
}
|
|
54934
|
+
//#endregion
|
|
54782
54935
|
//#region src/client/avatar-image-runtime.ts
|
|
54783
54936
|
const arkmeAvatarImages = new InMemoryArkmeAvatarImageStore({
|
|
54937
|
+
persistentCache: new BrowserAvatarPersistentCache(),
|
|
54938
|
+
cachedReader: async (imageRef) => {
|
|
54939
|
+
try {
|
|
54940
|
+
return await callArkme("image.read", {
|
|
54941
|
+
imageRef,
|
|
54942
|
+
cacheOnly: true
|
|
54943
|
+
});
|
|
54944
|
+
} catch (error) {
|
|
54945
|
+
if (error instanceof ArkmeClientError && error.body.code === "image-cache-miss") return void 0;
|
|
54946
|
+
throw error;
|
|
54947
|
+
}
|
|
54948
|
+
},
|
|
54784
54949
|
reader: async (imageRef) => await callArkme("image.read", { imageRef }),
|
|
54785
54950
|
onLoadFailure: ({ imageRef, scopeKey, error, ...context }) => {
|
|
54786
54951
|
logArkmeAvatarDiagnostic("image_load_failed", {
|
|
@@ -55011,7 +55176,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55011
55176
|
children: fallback.label || "--"
|
|
55012
55177
|
});
|
|
55013
55178
|
}
|
|
55014
|
-
function ArkmeUserAvatar({ avatarRef, lazy = false, fallback, size = 44, label = "用户头像", senderKind }) {
|
|
55179
|
+
function ArkmeUserAvatar({ avatarRef, lazy = false, fallback, fallbackContent, size = 44, label = "用户头像", senderKind }) {
|
|
55015
55180
|
const normalizedRef = avatarRef?.trim() ?? "";
|
|
55016
55181
|
const container = (0, react$1.useRef)(null);
|
|
55017
55182
|
const imageUrl = useArkmeAvatarImage(normalizedRef, lazy ? container : void 0);
|
|
@@ -55029,7 +55194,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55029
55194
|
}) : fallback?.kind === "phone_default" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PhoneDefaultAvatar, {
|
|
55030
55195
|
fallback,
|
|
55031
55196
|
size
|
|
55032
|
-
}) : senderKind === "bot" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeBotAvatarFallback, { size }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultUserAvatar, { size })
|
|
55197
|
+
}) : fallbackContent ?? (senderKind === "bot" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeBotAvatarFallback, { size }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultUserAvatar, { size }))
|
|
55033
55198
|
});
|
|
55034
55199
|
}
|
|
55035
55200
|
function GroupAvatarMember({ slot, size }) {
|
|
@@ -55526,6 +55691,54 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55526
55691
|
return stop;
|
|
55527
55692
|
}
|
|
55528
55693
|
//#endregion
|
|
55694
|
+
//#region src/reaction-diagnostics.ts
|
|
55695
|
+
/** Timing metadata only: no credentials, message refs, names or message bodies. */
|
|
55696
|
+
function reactionTraceId(value) {
|
|
55697
|
+
return value && /^[a-f0-9-]{36}$/.test(value) ? value : globalThis.crypto.randomUUID();
|
|
55698
|
+
}
|
|
55699
|
+
function logReactionTiming(traceId, stage, started, detail = {}) {
|
|
55700
|
+
console.info(`[ArkmeReactionTiming] ${JSON.stringify({
|
|
55701
|
+
traceId,
|
|
55702
|
+
stage,
|
|
55703
|
+
at: Date.now(),
|
|
55704
|
+
durationMs: Math.round((performance.now() - started) * 100) / 100,
|
|
55705
|
+
...detail
|
|
55706
|
+
})}`);
|
|
55707
|
+
}
|
|
55708
|
+
//#endregion
|
|
55709
|
+
//#region src/client/reaction-transport.ts
|
|
55710
|
+
const timings = /* @__PURE__ */ new WeakMap();
|
|
55711
|
+
function traceReactionApplied(value, stage) {
|
|
55712
|
+
const timing = timings.get(value);
|
|
55713
|
+
if (timing) logReactionTiming(timing.traceId, stage, timing.started);
|
|
55714
|
+
}
|
|
55715
|
+
async function callReaction(input, signal) {
|
|
55716
|
+
let diagnostics = false;
|
|
55717
|
+
try {
|
|
55718
|
+
diagnostics = globalThis.sessionStorage?.getItem("arkme.reaction.diagnostics") === "1";
|
|
55719
|
+
} catch {}
|
|
55720
|
+
if (!diagnostics) return await callArkme("reactions", input, signal);
|
|
55721
|
+
const traceId = reactionTraceId(input.traceId), started = performance.now();
|
|
55722
|
+
let ok = false;
|
|
55723
|
+
try {
|
|
55724
|
+
const value = await callArkme("reactions", {
|
|
55725
|
+
...input,
|
|
55726
|
+
traceId
|
|
55727
|
+
}, signal);
|
|
55728
|
+
ok = true;
|
|
55729
|
+
if (diagnostics && value && typeof value === "object") timings.set(value, {
|
|
55730
|
+
traceId,
|
|
55731
|
+
started
|
|
55732
|
+
});
|
|
55733
|
+
return value;
|
|
55734
|
+
} finally {
|
|
55735
|
+
if (diagnostics) logReactionTiming(traceId, "browser-request", started, {
|
|
55736
|
+
action: input.action,
|
|
55737
|
+
ok
|
|
55738
|
+
});
|
|
55739
|
+
}
|
|
55740
|
+
}
|
|
55741
|
+
//#endregion
|
|
55529
55742
|
//#region src/client/reaction-label-content.ts
|
|
55530
55743
|
const reactionHandIds = [
|
|
55531
55744
|
"ok_hand",
|
|
@@ -55778,10 +55991,12 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55778
55991
|
targets = /* @__PURE__ */ new Map();
|
|
55779
55992
|
states = /* @__PURE__ */ new Map();
|
|
55780
55993
|
inactive = /* @__PURE__ */ new Set();
|
|
55994
|
+
actorRefreshAt = /* @__PURE__ */ new Map();
|
|
55781
55995
|
knownTargets = /* @__PURE__ */ new Map();
|
|
55782
55996
|
failures = /* @__PURE__ */ new Map();
|
|
55783
55997
|
listeners = /* @__PURE__ */ new Set();
|
|
55784
55998
|
revision = 0;
|
|
55999
|
+
reading;
|
|
55785
56000
|
refreshing;
|
|
55786
56001
|
timer;
|
|
55787
56002
|
timerDue = 0;
|
|
@@ -55789,7 +56004,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55789
56004
|
retryMillis = 2e3;
|
|
55790
56005
|
pending;
|
|
55791
56006
|
writing = false;
|
|
55792
|
-
constructor(transport =
|
|
56007
|
+
constructor(transport = callReaction) {
|
|
55793
56008
|
this.transport = transport;
|
|
55794
56009
|
}
|
|
55795
56010
|
subscribe = (listener) => {
|
|
@@ -55811,6 +56026,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55811
56026
|
this.targets.clear();
|
|
55812
56027
|
this.states.clear();
|
|
55813
56028
|
this.inactive.clear();
|
|
56029
|
+
this.actorRefreshAt.clear();
|
|
55814
56030
|
this.knownTargets.clear();
|
|
55815
56031
|
this.failures.clear();
|
|
55816
56032
|
this.pending = void 0;
|
|
@@ -55823,6 +56039,11 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55823
56039
|
}
|
|
55824
56040
|
watch(scope, target) {
|
|
55825
56041
|
if (scope !== this.scope) return () => {};
|
|
56042
|
+
const resolver = target.resolveActor ?? this.knownTargets.get(target.id)?.resolveActor;
|
|
56043
|
+
if (resolver) target = {
|
|
56044
|
+
...target,
|
|
56045
|
+
resolveActor: resolver
|
|
56046
|
+
};
|
|
55826
56047
|
const existing = this.targets.get(target.id);
|
|
55827
56048
|
if (!existing && this.targets.size >= 200) {
|
|
55828
56049
|
this.failures.set(target.id, "请打开消息后刷新表态");
|
|
@@ -55851,6 +56072,8 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55851
56072
|
this.failures.delete(target.id);
|
|
55852
56073
|
this.retainInactive(target.id);
|
|
55853
56074
|
}
|
|
56075
|
+
const reading = this.reading;
|
|
56076
|
+
if (reading && ![...reading.entries].some(([id, entry]) => this.targets.get(id) === entry)) reading.controller.abort();
|
|
55854
56077
|
if (!this.targets.size) this.stop();
|
|
55855
56078
|
};
|
|
55856
56079
|
}
|
|
@@ -55862,6 +56085,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55862
56085
|
const oldest = this.inactive.values().next().value;
|
|
55863
56086
|
this.inactive.delete(oldest);
|
|
55864
56087
|
this.states.delete(oldest);
|
|
56088
|
+
this.actorRefreshAt.delete(oldest);
|
|
55865
56089
|
this.knownTargets.delete(oldest);
|
|
55866
56090
|
this.failures.delete(oldest);
|
|
55867
56091
|
}
|
|
@@ -55884,9 +56108,20 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55884
56108
|
await this.refresh();
|
|
55885
56109
|
if (active && !signal.aborted && scope === this.scope && (alreadyReading || missing.some((target) => !this.states.has(target.id) && !this.failures.has(target.id)))) await this.refresh();
|
|
55886
56110
|
};
|
|
56111
|
+
let unsubscribe = () => {};
|
|
56112
|
+
const factsReady = new Promise((resolve) => {
|
|
56113
|
+
unsubscribe = this.subscribe(() => {
|
|
56114
|
+
if (missing.every((target) => this.states.has(target.id) || this.failures.has(target.id))) resolve();
|
|
56115
|
+
});
|
|
56116
|
+
});
|
|
55887
56117
|
try {
|
|
55888
|
-
await Promise.race([
|
|
56118
|
+
await Promise.race([
|
|
56119
|
+
load(),
|
|
56120
|
+
deadline,
|
|
56121
|
+
factsReady
|
|
56122
|
+
]);
|
|
55889
56123
|
} finally {
|
|
56124
|
+
unsubscribe();
|
|
55890
56125
|
active = false;
|
|
55891
56126
|
clearTimeout(timer);
|
|
55892
56127
|
signal.removeEventListener("abort", finish);
|
|
@@ -55947,11 +56182,17 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55947
56182
|
}
|
|
55948
56183
|
async refresh() {
|
|
55949
56184
|
if (this.refreshing) return this.refreshing;
|
|
55950
|
-
const scope = this.scope
|
|
56185
|
+
const scope = this.scope;
|
|
55951
56186
|
if (!scope) return;
|
|
56187
|
+
const controller = new AbortController(), entries = new Map(this.targets);
|
|
56188
|
+
const reading = {
|
|
56189
|
+
controller,
|
|
56190
|
+
entries
|
|
56191
|
+
};
|
|
56192
|
+
this.reading = reading;
|
|
56193
|
+
const signal = AbortSignal.any([this.controller.signal, controller.signal]);
|
|
55952
56194
|
const operation = (async () => {
|
|
55953
56195
|
let failed = false;
|
|
55954
|
-
const entries = new Map(this.targets);
|
|
55955
56196
|
const targets = [...entries.values()].map((item) => item.target);
|
|
55956
56197
|
for (let offset = 0; offset < targets.length; offset += 50) {
|
|
55957
56198
|
const batch = targets.slice(offset, offset + 50);
|
|
@@ -55960,7 +56201,8 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55960
56201
|
const page = await this.transport({
|
|
55961
56202
|
action: "query",
|
|
55962
56203
|
accountKey: scope,
|
|
55963
|
-
targets: batch
|
|
56204
|
+
targets: batch,
|
|
56205
|
+
actorPresentation: "deferred"
|
|
55964
56206
|
}, signal);
|
|
55965
56207
|
if (signal.aborted) return;
|
|
55966
56208
|
const returned = new Set(page.items.map((item) => item.target_id));
|
|
@@ -55973,8 +56215,25 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55973
56215
|
}
|
|
55974
56216
|
for (const item of page.items) if (entries.has(item.target_id) && this.targets.get(item.target_id) === entries.get(item.target_id)) {
|
|
55975
56217
|
const previous = this.states.get(item.target_id);
|
|
55976
|
-
if (!previous || previous.mine.revision <= item.mine.revision)
|
|
56218
|
+
if (!previous || previous.mine.revision <= item.mine.revision) {
|
|
56219
|
+
const known = new Map((Date.now() - (this.actorRefreshAt.get(item.target_id) ?? 0) < 6e4 ? previous?.groups : void 0)?.flatMap((group) => group.actors ?? []).filter((actor) => !actor.presentationPending).map((actor) => [actor.userId, actor]));
|
|
56220
|
+
const resolve = this.targets.get(item.target_id)?.target.resolveActor;
|
|
56221
|
+
this.states.set(item.target_id, {
|
|
56222
|
+
...item,
|
|
56223
|
+
groups: item.groups.map((group) => ({
|
|
56224
|
+
...group,
|
|
56225
|
+
actors: (group.actors ?? []).map((actor) => resolve?.(actor) ?? (actor.presentationPending && known.has(actor.userId) ? {
|
|
56226
|
+
...actor,
|
|
56227
|
+
...known.get(actor.userId),
|
|
56228
|
+
...actor.memberRef ? { memberRef: actor.memberRef } : {},
|
|
56229
|
+
presentationPending: false
|
|
56230
|
+
} : actor))
|
|
56231
|
+
}))
|
|
56232
|
+
});
|
|
56233
|
+
}
|
|
55977
56234
|
}
|
|
56235
|
+
if (before !== JSON.stringify(batch.map((t) => [this.states.get(t.id), this.failures.get(t.id)]))) this.publish();
|
|
56236
|
+
traceReactionApplied(page, "browser-facts-published");
|
|
55978
56237
|
} catch (error) {
|
|
55979
56238
|
if (signal.aborted) return;
|
|
55980
56239
|
failed = true;
|
|
@@ -55983,7 +56242,52 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55983
56242
|
this.failures.set(target.id, error instanceof Error ? error.message : "表态加载失败");
|
|
55984
56243
|
}
|
|
55985
56244
|
}
|
|
55986
|
-
if (!signal.aborted && before !== JSON.stringify(batch.map((t) => [this.states.get(t.id), this.failures.get(t.id)]))) this.publish();
|
|
56245
|
+
if (failed && !signal.aborted && before !== JSON.stringify(batch.map((t) => [this.states.get(t.id), this.failures.get(t.id)]))) this.publish();
|
|
56246
|
+
const missing = batch.filter((target) => this.states.get(target.id)?.groups.some((group) => group.actors?.some((actor) => actor.presentationPending)));
|
|
56247
|
+
if (missing.length && !signal.aborted) {
|
|
56248
|
+
const initial = new Map(missing.map((target) => [target.id, this.states.get(target.id)]));
|
|
56249
|
+
try {
|
|
56250
|
+
const enriched = await this.transport({
|
|
56251
|
+
action: "query",
|
|
56252
|
+
accountKey: scope,
|
|
56253
|
+
targets: missing
|
|
56254
|
+
}, signal);
|
|
56255
|
+
if (signal.aborted) return;
|
|
56256
|
+
for (const item of enriched.items) {
|
|
56257
|
+
const current = this.states.get(item.target_id);
|
|
56258
|
+
if (!current || current !== initial.get(item.target_id) || this.targets.get(item.target_id) !== entries.get(item.target_id)) continue;
|
|
56259
|
+
this.actorRefreshAt.set(item.target_id, Date.now());
|
|
56260
|
+
if (!item.actors_visible) {
|
|
56261
|
+
this.states.set(item.target_id, {
|
|
56262
|
+
...current,
|
|
56263
|
+
actors_visible: false,
|
|
56264
|
+
private: item.private,
|
|
56265
|
+
groups: current.groups.map((group) => ({
|
|
56266
|
+
...group,
|
|
56267
|
+
actors: []
|
|
56268
|
+
}))
|
|
56269
|
+
});
|
|
56270
|
+
continue;
|
|
56271
|
+
}
|
|
56272
|
+
const actors = new Map(item.groups.flatMap((group) => group.actors ?? []).map((actor) => [actor.userId, actor]));
|
|
56273
|
+
const resolve = this.targets.get(item.target_id)?.target.resolveActor;
|
|
56274
|
+
this.states.set(item.target_id, {
|
|
56275
|
+
...current,
|
|
56276
|
+
groups: current.groups.map((group) => ({
|
|
56277
|
+
...group,
|
|
56278
|
+
actors: (group.actors ?? []).map((actor) => resolve?.(actor) ?? (actor.presentationPending && actors.has(actor.userId) ? {
|
|
56279
|
+
...actor,
|
|
56280
|
+
...actors.get(actor.userId),
|
|
56281
|
+
...actor.memberRef ? { memberRef: actor.memberRef } : {},
|
|
56282
|
+
presentationPending: false
|
|
56283
|
+
} : actor))
|
|
56284
|
+
}))
|
|
56285
|
+
});
|
|
56286
|
+
}
|
|
56287
|
+
this.publish();
|
|
56288
|
+
traceReactionApplied(enriched, "browser-actors-published");
|
|
56289
|
+
} catch {}
|
|
56290
|
+
}
|
|
55987
56291
|
}
|
|
55988
56292
|
if (!signal.aborted) this.retryMillis = failed ? Math.min(12e4, this.retryMillis * 2) : 2e3;
|
|
55989
56293
|
})();
|
|
@@ -55991,6 +56295,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55991
56295
|
try {
|
|
55992
56296
|
await operation;
|
|
55993
56297
|
} finally {
|
|
56298
|
+
if (this.reading === reading) this.reading = void 0;
|
|
55994
56299
|
if (this.refreshing === operation) {
|
|
55995
56300
|
this.refreshing = void 0;
|
|
55996
56301
|
if (this.refreshAgain) {
|
|
@@ -56158,7 +56463,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
56158
56463
|
users = 0;
|
|
56159
56464
|
error = "";
|
|
56160
56465
|
hasMore = false;
|
|
56161
|
-
constructor(transport =
|
|
56466
|
+
constructor(transport = callReaction) {
|
|
56162
56467
|
this.transport = transport;
|
|
56163
56468
|
}
|
|
56164
56469
|
subscribe = (fn) => {
|
|
@@ -56279,6 +56584,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
56279
56584
|
limit: 50
|
|
56280
56585
|
}, signal);
|
|
56281
56586
|
if (signal.aborted) return;
|
|
56587
|
+
traceReactionApplied(page, "browser-notifications-received");
|
|
56282
56588
|
rows.push(...page.items);
|
|
56283
56589
|
hasMore = page.has_more;
|
|
56284
56590
|
if (!page.has_more) break;
|
|
@@ -56940,30 +57246,51 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
56940
57246
|
}
|
|
56941
57247
|
};
|
|
56942
57248
|
//#endregion
|
|
56943
|
-
//#region src/client/recognized-speaker-
|
|
56944
|
-
const
|
|
56945
|
-
|
|
56946
|
-
|
|
56947
|
-
|
|
56948
|
-
|
|
56949
|
-
|
|
56950
|
-
|
|
57249
|
+
//#region src/client/recognized-speaker-directory.ts
|
|
57250
|
+
const loaders = {
|
|
57251
|
+
summary: (input, signal) => callArkme("speaker-directory.summary", input, signal),
|
|
57252
|
+
list: (input, signal) => callArkme("speaker-directory.list", { ...input }, signal),
|
|
57253
|
+
seen: (throughCursor, signal) => callArkme("speaker-directory.seen", { throughCursor }, signal),
|
|
57254
|
+
open: (detailRef, signal) => callArkme("speaker-directory.open", { detailRef }, signal),
|
|
57255
|
+
avatars: (detailRefs, signal) => callArkme("speaker-directory.avatars", { detailRefs }, signal)
|
|
57256
|
+
};
|
|
57257
|
+
var SpeakerReadDeferred = class extends Error {
|
|
57258
|
+
retryAt;
|
|
57259
|
+
constructor(retryAt, cause) {
|
|
57260
|
+
super(cause instanceof Error ? cause.message : "说话人目录暂不可用", { cause });
|
|
57261
|
+
this.retryAt = retryAt;
|
|
56951
57262
|
}
|
|
56952
57263
|
};
|
|
56953
|
-
function
|
|
56954
|
-
|
|
57264
|
+
function directoryErrorCode(error) {
|
|
57265
|
+
const value = error;
|
|
57266
|
+
return value?.body?.code ?? value?.code ?? "";
|
|
56955
57267
|
}
|
|
56956
|
-
|
|
56957
|
-
|
|
56958
|
-
|
|
56959
|
-
|
|
56960
|
-
|
|
56961
|
-
|
|
56962
|
-
|
|
56963
|
-
|
|
57268
|
+
function speakerRetryDelay(error) {
|
|
57269
|
+
if (error instanceof SpeakerReadDeferred) return Math.max(1e3, error.retryAt - Date.now());
|
|
57270
|
+
const value = error;
|
|
57271
|
+
if (directoryErrorCode(error) === "arkme-code-1001" || value?.body?.retryable === false || value?.retryable === false) return void 0;
|
|
57272
|
+
return Math.max(1e3, value?.body?.retryAfterMillis ?? value?.retryAfterMillis ?? 15e3);
|
|
57273
|
+
}
|
|
57274
|
+
const directoryVisible = () => typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
57275
|
+
const normalizeDirectoryQuery = (query) => query.trim().toLowerCase();
|
|
57276
|
+
function directoryQueryValid(query) {
|
|
57277
|
+
return new TextEncoder().encode(normalizeDirectoryQuery(query)).length <= 256;
|
|
57278
|
+
}
|
|
57279
|
+
const queryKey = (query) => JSON.stringify([
|
|
57280
|
+
query.filter,
|
|
57281
|
+
query.sort,
|
|
57282
|
+
normalizeDirectoryQuery(query.query)
|
|
57283
|
+
]);
|
|
57284
|
+
const empty$4 = Object.freeze({});
|
|
57285
|
+
/** Shared summary and immutable same-version pages. No traversal or local new-person inference. */
|
|
57286
|
+
var RecognizedSpeakerDirectory = class {
|
|
57287
|
+
api;
|
|
57288
|
+
now;
|
|
57289
|
+
accounts = /* @__PURE__ */ new Map();
|
|
56964
57290
|
listeners = /* @__PURE__ */ new Set();
|
|
56965
|
-
constructor(
|
|
56966
|
-
this.
|
|
57291
|
+
constructor(api = loaders, now = Date.now) {
|
|
57292
|
+
this.api = api;
|
|
57293
|
+
this.now = now;
|
|
56967
57294
|
}
|
|
56968
57295
|
subscribe = (listener) => {
|
|
56969
57296
|
this.listeners.add(listener);
|
|
@@ -56971,439 +57298,347 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
56971
57298
|
this.listeners.delete(listener);
|
|
56972
57299
|
};
|
|
56973
57300
|
};
|
|
56974
|
-
get = (account) => account === void 0 ? empty$4 : this.
|
|
56975
|
-
emit(
|
|
56976
|
-
this.
|
|
56977
|
-
for (const listener of this.listeners) listener();
|
|
56978
|
-
}
|
|
56979
|
-
read(account) {
|
|
56980
|
-
if (this.records.has(account)) return this.records.get(account);
|
|
56981
|
-
try {
|
|
56982
|
-
const value = JSON.parse(this.getStorage()?.getItem(storageKey$4(account)) ?? "null");
|
|
56983
|
-
if (value !== null && [
|
|
56984
|
-
"known",
|
|
56985
|
-
"current",
|
|
56986
|
-
"pending"
|
|
56987
|
-
].every((key) => {
|
|
56988
|
-
const list = value[key];
|
|
56989
|
-
return Array.isArray(list) && list.length <= 2e4 && list.every((item) => typeof item === "string" && item.length <= 256);
|
|
56990
|
-
})) {
|
|
56991
|
-
this.records.set(account, value);
|
|
56992
|
-
return value;
|
|
56993
|
-
}
|
|
56994
|
-
} catch {}
|
|
56995
|
-
}
|
|
56996
|
-
save(account, value) {
|
|
56997
|
-
this.records.set(account, value);
|
|
56998
|
-
try {
|
|
56999
|
-
this.getStorage()?.setItem(storageKey$4(account), JSON.stringify(value));
|
|
57000
|
-
} catch {}
|
|
57001
|
-
}
|
|
57002
|
-
setTotal(account, total) {
|
|
57003
|
-
if (!Number.isSafeInteger(total) || total < 0) return;
|
|
57004
|
-
const previous = this.get(account);
|
|
57005
|
-
this.emit(account, previous.total === total ? {
|
|
57006
|
-
...previous,
|
|
57007
|
-
total
|
|
57008
|
-
} : {
|
|
57009
|
-
total,
|
|
57010
|
-
checkedAt: 0
|
|
57011
|
-
});
|
|
57301
|
+
get = (account) => account === void 0 ? empty$4 : this.accounts.get(account)?.snapshot ?? empty$4;
|
|
57302
|
+
emit() {
|
|
57303
|
+
this.listeners.forEach((listener) => listener());
|
|
57012
57304
|
}
|
|
57013
|
-
|
|
57014
|
-
|
|
57015
|
-
|
|
57016
|
-
|
|
57017
|
-
|
|
57018
|
-
|
|
57305
|
+
account(key) {
|
|
57306
|
+
let found = this.accounts.get(key);
|
|
57307
|
+
if (!found) {
|
|
57308
|
+
found = {
|
|
57309
|
+
controller: new AbortController(),
|
|
57310
|
+
snapshot: empty$4,
|
|
57311
|
+
summaryAt: 0,
|
|
57312
|
+
retryAt: 0,
|
|
57313
|
+
failures: 0,
|
|
57314
|
+
flights: /* @__PURE__ */ new Map(),
|
|
57315
|
+
lists: /* @__PURE__ */ new Map(),
|
|
57316
|
+
pendingSeen: /* @__PURE__ */ new Set(),
|
|
57317
|
+
confirmedSeen: /* @__PURE__ */ new Set(),
|
|
57318
|
+
expiredSeen: /* @__PURE__ */ new Set(),
|
|
57319
|
+
revision: 0
|
|
57320
|
+
};
|
|
57321
|
+
this.accounts.set(key, found);
|
|
57322
|
+
}
|
|
57323
|
+
return found;
|
|
57019
57324
|
}
|
|
57020
|
-
|
|
57021
|
-
|
|
57022
|
-
if (
|
|
57023
|
-
|
|
57024
|
-
|
|
57025
|
-
|
|
57026
|
-
|
|
57027
|
-
|
|
57028
|
-
|
|
57029
|
-
|
|
57325
|
+
current(account, value) {
|
|
57326
|
+
value.controller.signal.throwIfAborted();
|
|
57327
|
+
if (this.accounts.get(account) !== value) throw new DOMException("账号已切换", "AbortError");
|
|
57328
|
+
}
|
|
57329
|
+
async request(account, key, load) {
|
|
57330
|
+
const value = this.account(account);
|
|
57331
|
+
this.current(account, value);
|
|
57332
|
+
key = `${value.revision}:${key}`;
|
|
57333
|
+
const pending = value.flights.get(key);
|
|
57334
|
+
if (pending) return pending;
|
|
57335
|
+
if (this.now() < value.retryAt) throw new SpeakerReadDeferred(value.retryAt, /* @__PURE__ */ new Error("请求较频繁或网络暂不可用,请稍后重试"));
|
|
57336
|
+
const promise = Promise.resolve().then(() => load(value.controller.signal)).then((result) => {
|
|
57337
|
+
this.current(account, value);
|
|
57338
|
+
value.failures = 0;
|
|
57339
|
+
return result;
|
|
57340
|
+
}).catch((error) => {
|
|
57341
|
+
this.current(account, value);
|
|
57342
|
+
const delay = speakerRetryDelay(error);
|
|
57343
|
+
if (delay !== void 0) {
|
|
57344
|
+
value.failures += 1;
|
|
57345
|
+
value.retryAt = this.now() + Math.max(delay, Math.min(3e5, 1e3 * 2 ** Math.min(8, value.failures)));
|
|
57346
|
+
throw new SpeakerReadDeferred(value.retryAt, error);
|
|
57347
|
+
}
|
|
57348
|
+
throw error;
|
|
57349
|
+
}).finally(() => {
|
|
57350
|
+
if (value.flights.get(key) === promise) value.flights.delete(key);
|
|
57030
57351
|
});
|
|
57352
|
+
value.flights.set(key, promise);
|
|
57353
|
+
return promise;
|
|
57031
57354
|
}
|
|
57032
|
-
|
|
57033
|
-
const
|
|
57034
|
-
if (
|
|
57035
|
-
|
|
57036
|
-
|
|
57355
|
+
async summary(account, force = false) {
|
|
57356
|
+
const state = this.account(account), cached = state.snapshot.summary, revision = state.revision;
|
|
57357
|
+
if (!force && cached && (cached.state === "disabled" || this.now() < state.summaryAt)) return cached;
|
|
57358
|
+
try {
|
|
57359
|
+
const result = await this.request(account, "summary", (signal) => this.api.summary(cached && cached.snapshotVersion ? {
|
|
57360
|
+
snapshotVersion: cached.snapshotVersion,
|
|
57361
|
+
seenVersion: cached.seenVersion
|
|
57362
|
+
} : {}, signal));
|
|
57363
|
+
this.current(account, state);
|
|
57364
|
+
if (revision !== state.revision) return this.summary(account, force);
|
|
57365
|
+
state.snapshot = { summary: result };
|
|
57366
|
+
state.summaryAt = this.now() + (result.retryAfterMs > 0 ? result.retryAfterMs : 3e4);
|
|
57367
|
+
this.emit();
|
|
57368
|
+
return result;
|
|
57369
|
+
} catch (error) {
|
|
57370
|
+
this.current(account, state);
|
|
57371
|
+
state.snapshot = {
|
|
57372
|
+
...state.snapshot,
|
|
57373
|
+
error: error instanceof Error ? error.message : "目录暂不可用"
|
|
57374
|
+
};
|
|
57375
|
+
this.emit();
|
|
57376
|
+
throw error;
|
|
57037
57377
|
}
|
|
57038
|
-
const current = [.../* @__PURE__ */ new Set([...marked, ...candidates.map((candidate) => `u:${candidate.identityKey}`)])];
|
|
57039
|
-
const previous = this.read(account);
|
|
57040
|
-
const known = new Set(previous?.known ?? []);
|
|
57041
|
-
const currentSet = new Set(current);
|
|
57042
|
-
const removed = previous?.current.some((key) => !currentSet.has(key)) ?? false;
|
|
57043
|
-
const additions = previous === void 0 || removed ? [] : current.filter((key) => !known.has(key));
|
|
57044
|
-
const pending = viewed ? [] : [.../* @__PURE__ */ new Set([...(previous?.pending ?? []).filter((key) => currentSet.has(key)), ...additions])];
|
|
57045
|
-
current.forEach((key) => known.add(key));
|
|
57046
|
-
const record = known.size > 2e4 ? {
|
|
57047
|
-
known: current,
|
|
57048
|
-
current,
|
|
57049
|
-
pending: []
|
|
57050
|
-
} : {
|
|
57051
|
-
known: [...known],
|
|
57052
|
-
current,
|
|
57053
|
-
pending
|
|
57054
|
-
};
|
|
57055
|
-
this.save(account, record);
|
|
57056
|
-
this.emit(account, {
|
|
57057
|
-
total: current.length,
|
|
57058
|
-
newCount: record.pending.length,
|
|
57059
|
-
checkedAt: Date.now()
|
|
57060
|
-
});
|
|
57061
57378
|
}
|
|
57062
|
-
|
|
57063
|
-
this.
|
|
57064
|
-
this.records.clear();
|
|
57065
|
-
for (const listener of this.listeners) listener();
|
|
57379
|
+
peek(account, query) {
|
|
57380
|
+
return this.accounts.get(account)?.lists.get(queryKey(query));
|
|
57066
57381
|
}
|
|
57067
|
-
|
|
57068
|
-
|
|
57069
|
-
|
|
57070
|
-
|
|
57071
|
-
|
|
57072
|
-
|
|
57073
|
-
|
|
57074
|
-
|
|
57075
|
-
|
|
57076
|
-
|
|
57077
|
-
|
|
57078
|
-
|
|
57079
|
-
|
|
57080
|
-
|
|
57081
|
-
|
|
57082
|
-
|
|
57083
|
-
|
|
57084
|
-
} catch {
|
|
57085
|
-
return;
|
|
57086
|
-
}
|
|
57087
|
-
}
|
|
57088
|
-
function readRecognizedSpeakerOrder(accountKey, storage = browserStorage$1()) {
|
|
57089
|
-
try {
|
|
57090
|
-
return storage?.getItem(preferenceKey$3(accountKey)) === "recent" ? "recent" : "frequent";
|
|
57091
|
-
} catch {
|
|
57092
|
-
return "frequent";
|
|
57093
|
-
}
|
|
57094
|
-
}
|
|
57095
|
-
function writeRecognizedSpeakerOrder(accountKey, order, storage = browserStorage$1()) {
|
|
57096
|
-
try {
|
|
57097
|
-
storage?.setItem(preferenceKey$3(accountKey), order);
|
|
57098
|
-
} catch {}
|
|
57099
|
-
}
|
|
57100
|
-
function positiveNumber(value) {
|
|
57101
|
-
return value !== void 0 && Number.isFinite(value) && value > 0 ? value : 0;
|
|
57102
|
-
}
|
|
57103
|
-
/** Missing statistics sort last. Ties remain stable across refreshes and filters. */
|
|
57104
|
-
function compareRecognizedSpeakers(left, right, order) {
|
|
57105
|
-
const leftDays = positiveNumber(left.dayCount), rightDays = positiveNumber(right.dayCount);
|
|
57106
|
-
const leftTime = positiveNumber(left.lastSeenAt), rightTime = positiveNumber(right.lastSeenAt);
|
|
57107
|
-
return (order === "frequent" ? rightDays - leftDays || rightTime - leftTime : rightTime - leftTime || rightDays - leftDays) || left.name.localeCompare(right.name, void 0, { numeric: true }) || left.key.localeCompare(right.key);
|
|
57108
|
-
}
|
|
57109
|
-
/** The upstream cursor has a fixed order. Read metadata pages before claiming global order.
|
|
57110
|
-
* Bound reads to the host's 2,000-candidate reference budget; never silently call a partial
|
|
57111
|
-
* traversal complete. No audio or per-speaker detail is loaded here.
|
|
57112
|
-
*/
|
|
57113
|
-
async function loadSpeakerCandidateSnapshot(loadPage, signal, onProgress) {
|
|
57114
|
-
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
57115
|
-
const rows = /* @__PURE__ */ new Map();
|
|
57116
|
-
const cursors = /* @__PURE__ */ new Set();
|
|
57117
|
-
let cursor = "";
|
|
57118
|
-
let snapshot = {
|
|
57382
|
+
async first(account, query, signal, force = false) {
|
|
57383
|
+
if (!directoryQueryValid(query.query)) throw new Error("搜索内容过长,请缩短至 256 字节以内");
|
|
57384
|
+
signal.throwIfAborted();
|
|
57385
|
+
const state = this.account(account), revision = state.revision;
|
|
57386
|
+
const summary = await this.summary(account, force);
|
|
57387
|
+
signal.throwIfAborted();
|
|
57388
|
+
const key = queryKey(query), cached = state.lists.get(key);
|
|
57389
|
+
if (!force && cached && cached.snapshotVersion === summary.snapshotVersion && !state.expiredSeen.has(cached.throughCursor)) return cached;
|
|
57390
|
+
const input = {
|
|
57391
|
+
...query,
|
|
57392
|
+
query: normalizeDirectoryQuery(query.query),
|
|
57393
|
+
cursor: "",
|
|
57394
|
+
snapshotVersion: summary.snapshotVersion,
|
|
57395
|
+
limit: 50
|
|
57396
|
+
};
|
|
57397
|
+
const page = summary.state === "disabled" || summary.coverage !== "complete" ? {
|
|
57398
|
+
...summary,
|
|
57119
57399
|
items: [],
|
|
57120
|
-
|
|
57121
|
-
|
|
57400
|
+
hasMore: false,
|
|
57401
|
+
nextCursor: "",
|
|
57402
|
+
throughCursor: ""
|
|
57403
|
+
} : await this.request(account, `list:${JSON.stringify(input)}`, (inner) => this.api.list(input, inner));
|
|
57404
|
+
signal.throwIfAborted();
|
|
57405
|
+
this.current(account, state);
|
|
57406
|
+
if (revision !== state.revision) throw new DOMException("目录已更新", "AbortError");
|
|
57407
|
+
if (page.state === "snapshot_expired") {
|
|
57408
|
+
state.summaryAt = 0;
|
|
57409
|
+
state.lists.delete(key);
|
|
57410
|
+
if (page.retryAfterMs > 0) {
|
|
57411
|
+
state.retryAt = Math.max(state.retryAt, this.now() + page.retryAfterMs);
|
|
57412
|
+
throw new SpeakerReadDeferred(state.retryAt, /* @__PURE__ */ new Error("目录正在更新,请稍后重试"));
|
|
57413
|
+
}
|
|
57414
|
+
if (force) throw new Error("目录正在更新,请稍后刷新");
|
|
57415
|
+
return this.first(account, query, signal, true);
|
|
57416
|
+
}
|
|
57417
|
+
if (page.state === "disabled") {
|
|
57418
|
+
state.snapshot = { summary: {
|
|
57419
|
+
...summary,
|
|
57420
|
+
state: "disabled"
|
|
57421
|
+
} };
|
|
57422
|
+
this.emit();
|
|
57423
|
+
}
|
|
57424
|
+
const result = {
|
|
57425
|
+
...page,
|
|
57426
|
+
query: {
|
|
57427
|
+
...query,
|
|
57428
|
+
query: input.query
|
|
57429
|
+
},
|
|
57430
|
+
requestedCursors: [""]
|
|
57122
57431
|
};
|
|
57123
|
-
|
|
57124
|
-
|
|
57125
|
-
|
|
57126
|
-
|
|
57127
|
-
if (page.section !== "unmarked-speakers") throw new Error("未标记说话人列表响应无效");
|
|
57128
|
-
if (page.cursorStale) {
|
|
57129
|
-
snapshot = {
|
|
57130
|
-
items: [],
|
|
57131
|
-
complete: false,
|
|
57132
|
-
projectionState: "stale"
|
|
57133
|
-
};
|
|
57134
|
-
onProgress(snapshot);
|
|
57135
|
-
if (attempt === 0) break;
|
|
57136
|
-
return snapshot;
|
|
57137
|
-
}
|
|
57138
|
-
for (const item of page.items) if (item.kind === "unmarked-speaker" && rows.size < 2e3) rows.set(item.candidateRef, item);
|
|
57139
|
-
snapshot = {
|
|
57140
|
-
items: [...rows.values()],
|
|
57141
|
-
complete: !page.hasMore && page.coverage !== "partial" && (page.projectionState === void 0 || page.projectionState === "fresh"),
|
|
57142
|
-
projectionState: page.projectionState
|
|
57143
|
-
};
|
|
57144
|
-
onProgress(snapshot);
|
|
57145
|
-
if (!page.hasMore || rows.size >= 2e3 || page.projectionState !== void 0 && page.projectionState !== "fresh") return snapshot;
|
|
57146
|
-
const next = page.nextCursor ?? "";
|
|
57147
|
-
if (next === "" || cursors.has(next)) return snapshot;
|
|
57148
|
-
cursors.add(next);
|
|
57149
|
-
cursor = next;
|
|
57150
|
-
if (pageIndex === 39) return snapshot;
|
|
57432
|
+
if (page.coverage === "complete" && page.state !== "disabled") {
|
|
57433
|
+
state.lists.delete(key);
|
|
57434
|
+
state.lists.set(key, result);
|
|
57435
|
+
while (state.lists.size > 12) state.lists.delete(state.lists.keys().next().value);
|
|
57151
57436
|
}
|
|
57437
|
+
return result;
|
|
57152
57438
|
}
|
|
57153
|
-
|
|
57154
|
-
items: [],
|
|
57155
|
-
complete: false,
|
|
57156
|
-
projectionState: "stale"
|
|
57157
|
-
};
|
|
57158
|
-
}
|
|
57159
|
-
//#endregion
|
|
57160
|
-
//#region src/client/recognized-speaker-directory.ts
|
|
57161
|
-
const readSpeakerOptions = (signal) => callArkme("recordings.speaker.options", {}, signal);
|
|
57162
|
-
const readSpeakerPresence = (signal) => callArkme("recordings.speaker.presence", {}, signal);
|
|
57163
|
-
const readSpeakerPage = (cursor, signal) => callArkme("directory.list", {
|
|
57164
|
-
section: "unmarked-speakers",
|
|
57165
|
-
limit: 50,
|
|
57166
|
-
...cursor === "" ? {} : { cursor }
|
|
57167
|
-
}, signal);
|
|
57168
|
-
var SpeakerReadDeferred = class extends Error {
|
|
57169
|
-
retryAt;
|
|
57170
|
-
constructor(retryAt, cause) {
|
|
57171
|
-
super(cause instanceof Error ? cause.message : "说话人列表暂时无法加载", { cause });
|
|
57172
|
-
this.retryAt = retryAt;
|
|
57173
|
-
}
|
|
57174
|
-
};
|
|
57175
|
-
function speakerRetryDelay(error) {
|
|
57176
|
-
return error instanceof SpeakerReadDeferred ? Math.max(1e3, error.retryAt - Date.now()) : void 0;
|
|
57177
|
-
}
|
|
57178
|
-
/** Per-account shared read. A short release grace lets entry -> list hand off the same
|
|
57179
|
-
* request; leaving both cancels it. A late/aborted response can never update the cache.
|
|
57180
|
-
*/
|
|
57181
|
-
var SharedRead = class {
|
|
57182
|
-
ttl;
|
|
57183
|
-
load;
|
|
57184
|
-
now;
|
|
57185
|
-
value;
|
|
57186
|
-
freshUntil = 0;
|
|
57187
|
-
retryAt = 0;
|
|
57188
|
-
failures = 0;
|
|
57189
|
-
error;
|
|
57190
|
-
pending;
|
|
57191
|
-
listeners = /* @__PURE__ */ new Set();
|
|
57192
|
-
releaseTimer;
|
|
57193
|
-
constructor(ttl, load, now) {
|
|
57194
|
-
this.ttl = ttl;
|
|
57195
|
-
this.load = load;
|
|
57196
|
-
this.now = now;
|
|
57197
|
-
}
|
|
57198
|
-
read(signal, progress = () => {}) {
|
|
57439
|
+
async more(account, previous, signal) {
|
|
57199
57440
|
signal.throwIfAborted();
|
|
57200
|
-
if (
|
|
57201
|
-
|
|
57202
|
-
if (
|
|
57203
|
-
|
|
57204
|
-
|
|
57205
|
-
|
|
57206
|
-
|
|
57207
|
-
|
|
57208
|
-
|
|
57209
|
-
|
|
57210
|
-
|
|
57211
|
-
|
|
57212
|
-
|
|
57213
|
-
|
|
57214
|
-
|
|
57215
|
-
|
|
57216
|
-
|
|
57217
|
-
|
|
57218
|
-
|
|
57219
|
-
|
|
57220
|
-
|
|
57221
|
-
|
|
57222
|
-
|
|
57223
|
-
|
|
57224
|
-
|
|
57225
|
-
|
|
57226
|
-
|
|
57227
|
-
|
|
57228
|
-
|
|
57229
|
-
|
|
57230
|
-
|
|
57231
|
-
|
|
57232
|
-
|
|
57233
|
-
|
|
57234
|
-
|
|
57441
|
+
if (!previous.hasMore) return previous;
|
|
57442
|
+
const state = this.account(account), revision = state.revision;
|
|
57443
|
+
if (!state.lists.has(queryKey(previous.query))) return this.first(account, previous.query, signal, true);
|
|
57444
|
+
const input = {
|
|
57445
|
+
...previous.query,
|
|
57446
|
+
limit: 50,
|
|
57447
|
+
cursor: previous.nextCursor,
|
|
57448
|
+
snapshotVersion: previous.snapshotVersion
|
|
57449
|
+
};
|
|
57450
|
+
const page = await this.request(account, `list:${JSON.stringify(input)}`, (inner) => this.api.list(input, inner));
|
|
57451
|
+
signal.throwIfAborted();
|
|
57452
|
+
this.current(account, state);
|
|
57453
|
+
if (revision !== state.revision) throw new DOMException("目录已更新", "AbortError");
|
|
57454
|
+
if (page.state === "snapshot_expired") {
|
|
57455
|
+
state.lists.delete(queryKey(previous.query));
|
|
57456
|
+
state.summaryAt = 0;
|
|
57457
|
+
if (page.retryAfterMs > 0) {
|
|
57458
|
+
state.retryAt = Math.max(state.retryAt, this.now() + page.retryAfterMs);
|
|
57459
|
+
throw new SpeakerReadDeferred(state.retryAt, /* @__PURE__ */ new Error("目录正在更新,请稍后刷新"));
|
|
57460
|
+
}
|
|
57461
|
+
return this.first(account, previous.query, signal, true);
|
|
57462
|
+
}
|
|
57463
|
+
if (page.state === "disabled") {
|
|
57464
|
+
const summary = state.snapshot.summary;
|
|
57465
|
+
if (summary) {
|
|
57466
|
+
state.snapshot = { summary: {
|
|
57467
|
+
...summary,
|
|
57468
|
+
state: "disabled"
|
|
57469
|
+
} };
|
|
57470
|
+
this.emit();
|
|
57471
|
+
}
|
|
57472
|
+
return {
|
|
57473
|
+
...previous,
|
|
57474
|
+
state: "disabled",
|
|
57475
|
+
hasMore: false
|
|
57235
57476
|
};
|
|
57236
57477
|
}
|
|
57237
|
-
|
|
57238
|
-
|
|
57239
|
-
|
|
57240
|
-
|
|
57241
|
-
|
|
57242
|
-
|
|
57243
|
-
|
|
57244
|
-
|
|
57245
|
-
|
|
57246
|
-
|
|
57247
|
-
|
|
57248
|
-
}, 250);
|
|
57249
|
-
};
|
|
57250
|
-
const abort = () => {
|
|
57251
|
-
cleanup();
|
|
57252
|
-
reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
57253
|
-
};
|
|
57254
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
57255
|
-
pending.promise.then((value) => {
|
|
57256
|
-
cleanup();
|
|
57257
|
-
if (!signal.aborted) resolve(value);
|
|
57258
|
-
}, (error) => {
|
|
57259
|
-
cleanup();
|
|
57260
|
-
if (!signal.aborted) reject(error);
|
|
57261
|
-
});
|
|
57262
|
-
});
|
|
57263
|
-
}
|
|
57264
|
-
invalidate() {
|
|
57265
|
-
clearTimeout(this.releaseTimer);
|
|
57266
|
-
this.pending?.controller.abort();
|
|
57267
|
-
this.pending = void 0;
|
|
57268
|
-
this.freshUntil = 0;
|
|
57269
|
-
}
|
|
57270
|
-
dispose() {
|
|
57271
|
-
this.invalidate();
|
|
57272
|
-
this.listeners.clear();
|
|
57273
|
-
this.value = void 0;
|
|
57274
|
-
}
|
|
57275
|
-
};
|
|
57276
|
-
function pause(milliseconds, signal) {
|
|
57277
|
-
if (milliseconds <= 0) return Promise.resolve();
|
|
57278
|
-
return new Promise((resolve, reject) => {
|
|
57279
|
-
const abort = () => {
|
|
57280
|
-
clearTimeout(timer);
|
|
57281
|
-
reject(signal.reason);
|
|
57478
|
+
if (page.snapshotVersion !== previous.snapshotVersion || page.coverage !== "complete" || page.hasMore && (page.nextCursor === previous.nextCursor || previous.requestedCursors.includes(page.nextCursor))) throw new Error("目录版本已变化,请刷新列表");
|
|
57479
|
+
const keys = new Set(previous.items.map((item) => item.personKey));
|
|
57480
|
+
const result = {
|
|
57481
|
+
...page,
|
|
57482
|
+
query: previous.query,
|
|
57483
|
+
requestedCursors: [...previous.requestedCursors, previous.nextCursor],
|
|
57484
|
+
items: [...previous.items, ...page.items.filter((item) => {
|
|
57485
|
+
if (keys.has(item.personKey)) return false;
|
|
57486
|
+
keys.add(item.personKey);
|
|
57487
|
+
return true;
|
|
57488
|
+
})]
|
|
57282
57489
|
};
|
|
57283
|
-
|
|
57284
|
-
|
|
57285
|
-
resolve();
|
|
57286
|
-
}, milliseconds);
|
|
57287
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
57288
|
-
if (signal.aborted) abort();
|
|
57289
|
-
});
|
|
57290
|
-
}
|
|
57291
|
-
var RecognizedSpeakerDirectory = class {
|
|
57292
|
-
loaders;
|
|
57293
|
-
pageGapMs;
|
|
57294
|
-
now;
|
|
57295
|
-
accounts = /* @__PURE__ */ new Map();
|
|
57296
|
-
constructor(loaders = {
|
|
57297
|
-
marked: readSpeakerOptions,
|
|
57298
|
-
page: readSpeakerPage,
|
|
57299
|
-
presence: readSpeakerPresence
|
|
57300
|
-
}, pageGapMs = 750, now = Date.now) {
|
|
57301
|
-
this.loaders = loaders;
|
|
57302
|
-
this.pageGapMs = pageGapMs;
|
|
57303
|
-
this.now = now;
|
|
57490
|
+
state.lists.set(queryKey(previous.query), result);
|
|
57491
|
+
return result;
|
|
57304
57492
|
}
|
|
57305
|
-
|
|
57306
|
-
|
|
57307
|
-
|
|
57308
|
-
|
|
57309
|
-
|
|
57310
|
-
|
|
57311
|
-
state =
|
|
57312
|
-
|
|
57313
|
-
|
|
57314
|
-
|
|
57315
|
-
|
|
57316
|
-
|
|
57317
|
-
|
|
57318
|
-
|
|
57319
|
-
|
|
57320
|
-
|
|
57321
|
-
|
|
57322
|
-
|
|
57323
|
-
|
|
57324
|
-
|
|
57325
|
-
|
|
57326
|
-
|
|
57327
|
-
|
|
57328
|
-
|
|
57329
|
-
|
|
57330
|
-
|
|
57331
|
-
} else if (page.projectionState === void 0 || page.projectionState === "fresh") pages.set(cursor, page);
|
|
57332
|
-
return page;
|
|
57333
|
-
}, signal, (snapshot) => {
|
|
57334
|
-
const first = pages.get("");
|
|
57335
|
-
total = first?.coverage !== "partial" ? first?.total : void 0;
|
|
57336
|
-
if (!state.candidates.value?.complete || snapshot.complete) emit({
|
|
57337
|
-
...snapshot,
|
|
57338
|
-
total
|
|
57339
|
-
});
|
|
57340
|
-
});
|
|
57341
|
-
completed = result.complete;
|
|
57342
|
-
if (!result.complete) {
|
|
57343
|
-
if (!state.candidates.value?.complete) emit({
|
|
57344
|
-
...result,
|
|
57345
|
-
total
|
|
57346
|
-
});
|
|
57347
|
-
throw new Error("说话人列表尚未完整,请稍后重试");
|
|
57493
|
+
async confirmDisplayed(account, list) {
|
|
57494
|
+
if (!directoryVisible() || list.query.filter !== "all" || list.query.query !== "" || list.coverage !== "complete" || ![
|
|
57495
|
+
"fresh",
|
|
57496
|
+
"stale",
|
|
57497
|
+
"failed"
|
|
57498
|
+
].includes(list.state) || !list.throughCursor) return;
|
|
57499
|
+
const state = this.account(account);
|
|
57500
|
+
if (state.confirmedSeen.has(list.throughCursor) || state.expiredSeen.has(list.throughCursor) || state.snapshot.summary?.state === "disabled") return;
|
|
57501
|
+
state.pendingSeen.add(list.throughCursor);
|
|
57502
|
+
await this.flushSeen(account);
|
|
57503
|
+
}
|
|
57504
|
+
async flushSeen(account) {
|
|
57505
|
+
const state = this.account(account);
|
|
57506
|
+
if (!directoryVisible() || state.snapshot.summary?.state === "disabled") return;
|
|
57507
|
+
for (const cursor of state.pendingSeen) {
|
|
57508
|
+
let result;
|
|
57509
|
+
try {
|
|
57510
|
+
result = await this.request(account, `seen:${cursor}`, (signal) => this.api.seen(cursor, signal));
|
|
57511
|
+
} catch (error) {
|
|
57512
|
+
if (directoryErrorCode(error) === "arkme-code-1001") {
|
|
57513
|
+
state.pendingSeen.delete(cursor);
|
|
57514
|
+
state.expiredSeen.add(cursor);
|
|
57515
|
+
state.lists.clear();
|
|
57516
|
+
state.summaryAt = 0;
|
|
57517
|
+
this.emit();
|
|
57518
|
+
continue;
|
|
57348
57519
|
}
|
|
57349
|
-
|
|
57350
|
-
|
|
57351
|
-
|
|
57352
|
-
|
|
57353
|
-
|
|
57354
|
-
|
|
57355
|
-
|
|
57356
|
-
|
|
57357
|
-
|
|
57358
|
-
|
|
57359
|
-
|
|
57360
|
-
|
|
57361
|
-
|
|
57362
|
-
|
|
57520
|
+
throw error;
|
|
57521
|
+
}
|
|
57522
|
+
this.current(account, state);
|
|
57523
|
+
if (result.success) {
|
|
57524
|
+
state.pendingSeen.delete(cursor);
|
|
57525
|
+
state.confirmedSeen.add(cursor);
|
|
57526
|
+
await Promise.allSettled([...state.flights.entries()].filter(([key]) => key.endsWith(":summary")).map(([, promise]) => promise));
|
|
57527
|
+
await this.summary(account, true);
|
|
57528
|
+
} else if (result.state === "snapshot_expired") {
|
|
57529
|
+
state.pendingSeen.delete(cursor);
|
|
57530
|
+
state.expiredSeen.add(cursor);
|
|
57531
|
+
state.lists.clear();
|
|
57532
|
+
state.summaryAt = 0;
|
|
57533
|
+
if (result.retryAfterMs > 0) state.retryAt = Math.max(state.retryAt, this.now() + result.retryAfterMs);
|
|
57534
|
+
this.emit();
|
|
57535
|
+
} else {
|
|
57536
|
+
state.pendingSeen.clear();
|
|
57537
|
+
if (state.snapshot.summary) state.snapshot = { summary: {
|
|
57538
|
+
...state.snapshot.summary,
|
|
57539
|
+
state: "disabled"
|
|
57540
|
+
} };
|
|
57541
|
+
this.emit();
|
|
57542
|
+
return;
|
|
57543
|
+
}
|
|
57544
|
+
}
|
|
57363
57545
|
}
|
|
57364
|
-
|
|
57365
|
-
return this.accounts.get(account)?.
|
|
57546
|
+
hasPendingSeen(account) {
|
|
57547
|
+
return (this.accounts.get(account)?.pendingSeen.size ?? 0) > 0;
|
|
57366
57548
|
}
|
|
57367
|
-
|
|
57368
|
-
return this.
|
|
57549
|
+
needsReload(account, list) {
|
|
57550
|
+
return this.accounts.get(account)?.expiredSeen.has(list.throughCursor) === true;
|
|
57369
57551
|
}
|
|
57370
|
-
|
|
57371
|
-
|
|
57552
|
+
open(account, ref, signal) {
|
|
57553
|
+
signal.throwIfAborted();
|
|
57554
|
+
return this.request(account, `open:${ref}`, (inner) => this.api.open(ref, inner)).then((value) => {
|
|
57555
|
+
signal.throwIfAborted();
|
|
57556
|
+
return value;
|
|
57557
|
+
});
|
|
57372
57558
|
}
|
|
57373
|
-
|
|
57374
|
-
this.account(account)
|
|
57375
|
-
|
|
57559
|
+
async avatars(account, detailRefs, signal) {
|
|
57560
|
+
const state = this.account(account);
|
|
57561
|
+
const result = await this.api.avatars(detailRefs, AbortSignal.any([state.controller.signal, signal]));
|
|
57562
|
+
signal.throwIfAborted();
|
|
57563
|
+
this.current(account, state);
|
|
57564
|
+
return result;
|
|
57376
57565
|
}
|
|
57377
|
-
|
|
57378
|
-
|
|
57566
|
+
/** Visible consumers share one lightweight summary request, including online/focus recovery. */
|
|
57567
|
+
watch(account, changed = () => {}) {
|
|
57568
|
+
let disposed = false, busy = false, timer;
|
|
57569
|
+
const run = async () => {
|
|
57570
|
+
if (disposed || busy || !directoryVisible()) return;
|
|
57571
|
+
busy = true;
|
|
57572
|
+
let delay = 3e4;
|
|
57573
|
+
try {
|
|
57574
|
+
const summary = await this.summary(account);
|
|
57575
|
+
if (summary.state === "disabled") {
|
|
57576
|
+
changed();
|
|
57577
|
+
return;
|
|
57578
|
+
}
|
|
57579
|
+
await this.flushSeen(account);
|
|
57580
|
+
changed();
|
|
57581
|
+
delay = summary.retryAfterMs > 0 ? summary.retryAfterMs : 3e4;
|
|
57582
|
+
} catch (error) {
|
|
57583
|
+
delay = speakerRetryDelay(error) ?? 0;
|
|
57584
|
+
changed();
|
|
57585
|
+
} finally {
|
|
57586
|
+
busy = false;
|
|
57587
|
+
if (!disposed && delay > 0 && this.get(account).summary?.state !== "disabled") {
|
|
57588
|
+
clearTimeout(timer);
|
|
57589
|
+
timer = setTimeout(() => {
|
|
57590
|
+
run();
|
|
57591
|
+
}, Math.max(1e3, delay));
|
|
57592
|
+
}
|
|
57593
|
+
}
|
|
57594
|
+
};
|
|
57595
|
+
const wake = () => {
|
|
57596
|
+
if (directoryVisible()) {
|
|
57597
|
+
const value = this.account(account);
|
|
57598
|
+
value.summaryAt = 0;
|
|
57599
|
+
run();
|
|
57600
|
+
}
|
|
57601
|
+
};
|
|
57602
|
+
run();
|
|
57603
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", wake);
|
|
57604
|
+
if (typeof window !== "undefined") {
|
|
57605
|
+
window.addEventListener("online", wake);
|
|
57606
|
+
window.addEventListener("focus", wake);
|
|
57607
|
+
}
|
|
57608
|
+
return () => {
|
|
57609
|
+
disposed = true;
|
|
57610
|
+
clearTimeout(timer);
|
|
57611
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", wake);
|
|
57612
|
+
if (typeof window !== "undefined") {
|
|
57613
|
+
window.removeEventListener("online", wake);
|
|
57614
|
+
window.removeEventListener("focus", wake);
|
|
57615
|
+
}
|
|
57616
|
+
};
|
|
57379
57617
|
}
|
|
57380
57618
|
invalidate(account) {
|
|
57381
57619
|
const state = this.accounts.get(account);
|
|
57382
|
-
if (state
|
|
57383
|
-
state.
|
|
57384
|
-
state.
|
|
57385
|
-
state.
|
|
57386
|
-
|
|
57620
|
+
if (!state) return;
|
|
57621
|
+
state.revision += 1;
|
|
57622
|
+
state.summaryAt = 0;
|
|
57623
|
+
state.lists.clear();
|
|
57624
|
+
this.emit();
|
|
57387
57625
|
}
|
|
57388
57626
|
clear() {
|
|
57389
|
-
|
|
57390
|
-
state.marked.dispose();
|
|
57391
|
-
state.presence.dispose();
|
|
57392
|
-
state.candidates.dispose();
|
|
57393
|
-
}
|
|
57627
|
+
this.accounts.forEach((state) => state.controller.abort());
|
|
57394
57628
|
this.accounts.clear();
|
|
57629
|
+
this.emit();
|
|
57395
57630
|
}
|
|
57396
57631
|
};
|
|
57397
57632
|
const recognizedSpeakerDirectory = new RecognizedSpeakerDirectory();
|
|
57398
|
-
const
|
|
57633
|
+
const currentAccount$1 = () => {
|
|
57399
57634
|
const auth = arkmeAuthStore.getSnapshot().auth;
|
|
57400
57635
|
return auth?.status === "authenticated" ? `${auth.environment}:${auth.userId}` : "";
|
|
57401
57636
|
};
|
|
57402
|
-
let
|
|
57637
|
+
let account$1 = currentAccount$1();
|
|
57403
57638
|
arkmeAuthStore.subscribe(() => {
|
|
57404
|
-
const next =
|
|
57405
|
-
if (next !==
|
|
57406
|
-
|
|
57639
|
+
const next = currentAccount$1();
|
|
57640
|
+
if (next !== account$1) {
|
|
57641
|
+
account$1 = next;
|
|
57407
57642
|
recognizedSpeakerDirectory.clear();
|
|
57408
57643
|
}
|
|
57409
57644
|
});
|
|
@@ -57463,10 +57698,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
57463
57698
|
throw error;
|
|
57464
57699
|
} finally {
|
|
57465
57700
|
if (context.current()) {
|
|
57466
|
-
if (binding.account !== void 0)
|
|
57467
|
-
recognizedSpeakerTracker.uncertain(binding.account);
|
|
57468
|
-
recognizedSpeakerDirectory.invalidate(binding.account);
|
|
57469
|
-
}
|
|
57701
|
+
if (binding.account !== void 0) recognizedSpeakerDirectory.invalidate(binding.account);
|
|
57470
57702
|
recordingSpeakerOptions.reset();
|
|
57471
57703
|
recordingSpeakerOptions.invalidate();
|
|
57472
57704
|
recordingSpeakerItemContexts.reset((candidateKey) => candidateKey === key || !recordingSpeakerItemContexts.get(candidateKey).mutating);
|
|
@@ -57947,29 +58179,29 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
57947
58179
|
this.timer = void 0;
|
|
57948
58180
|
}
|
|
57949
58181
|
};
|
|
57950
|
-
const caches = /* @__PURE__ */ new Map();
|
|
58182
|
+
const caches$1 = /* @__PURE__ */ new Map();
|
|
57951
58183
|
function activateSelfTopicDirectoryAccount(account) {
|
|
57952
|
-
for (const [key, cache] of caches) {
|
|
58184
|
+
for (const [key, cache] of caches$1) {
|
|
57953
58185
|
if (key === account) continue;
|
|
57954
58186
|
cache.dispose();
|
|
57955
|
-
caches.delete(key);
|
|
58187
|
+
caches$1.delete(key);
|
|
57956
58188
|
}
|
|
57957
58189
|
}
|
|
57958
58190
|
function selfTopicDirectory(userId, environment) {
|
|
57959
58191
|
const key = `${environment}:${String(userId)}`;
|
|
57960
|
-
let cache = caches.get(key);
|
|
58192
|
+
let cache = caches$1.get(key);
|
|
57961
58193
|
if (!cache) {
|
|
57962
58194
|
cache = new SelfTopicDirectoryCache(userId, environment);
|
|
57963
|
-
caches.set(key, cache);
|
|
58195
|
+
caches$1.set(key, cache);
|
|
57964
58196
|
}
|
|
57965
58197
|
return cache;
|
|
57966
58198
|
}
|
|
57967
58199
|
function invalidateSelfTopicDirectories(hard = false) {
|
|
57968
|
-
for (const cache of caches.values()) cache.invalidate(hard);
|
|
58200
|
+
for (const cache of caches$1.values()) cache.invalidate(hard);
|
|
57969
58201
|
}
|
|
57970
58202
|
function resetSelfTopicDirectories() {
|
|
57971
|
-
for (const cache of caches.values()) cache.dispose();
|
|
57972
|
-
caches.clear();
|
|
58203
|
+
for (const cache of caches$1.values()) cache.dispose();
|
|
58204
|
+
caches$1.clear();
|
|
57973
58205
|
}
|
|
57974
58206
|
//#endregion
|
|
57975
58207
|
//#region src/client/provider-instance-runtime.ts
|
|
@@ -118596,7 +118828,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
118596
118828
|
displayName: actorGroupNickname?.trim() || actorName,
|
|
118597
118829
|
...actorGroupNickname ? { groupNickname: actorGroupNickname } : {},
|
|
118598
118830
|
...actorAvatarRef ? { avatarRef: actorAvatarRef } : {}
|
|
118599
|
-
} : actor;
|
|
118831
|
+
} : target.resolveActor?.(actor) ?? actor;
|
|
118600
118832
|
const name = identity.displayName;
|
|
118601
118833
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [index > 0 && "、", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
118602
118834
|
type: "button",
|
|
@@ -120961,14 +121193,17 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
120961
121193
|
scope,
|
|
120962
121194
|
roles: [],
|
|
120963
121195
|
loading: true,
|
|
121196
|
+
loaded: false,
|
|
120964
121197
|
error: ""
|
|
120965
121198
|
});
|
|
120966
121199
|
const visibleState = roleState.scope === scope ? roleState : {
|
|
120967
121200
|
scope,
|
|
120968
121201
|
roles: [],
|
|
120969
121202
|
loading: true,
|
|
121203
|
+
loaded: false,
|
|
120970
121204
|
error: ""
|
|
120971
121205
|
};
|
|
121206
|
+
const initialLoading = visibleState.loading && !visibleState.loaded;
|
|
120972
121207
|
const [refreshRevision, setRefreshRevision] = (0, react$1.useState)(0);
|
|
120973
121208
|
(0, react$1.useEffect)(() => {
|
|
120974
121209
|
if (typeof window === "undefined") return;
|
|
@@ -120986,6 +121221,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
120986
121221
|
const [saving, setSaving] = (0, react$1.useState)(false);
|
|
120987
121222
|
const [formError, setFormError] = (0, react$1.useState)("");
|
|
120988
121223
|
const fileInputRef = (0, react$1.useRef)(null);
|
|
121224
|
+
const listControllerRef = (0, react$1.useRef)();
|
|
120989
121225
|
const saveControllerRef = (0, react$1.useRef)();
|
|
120990
121226
|
(0, react$1.useEffect)(() => {
|
|
120991
121227
|
setMenuOpen(false);
|
|
@@ -121004,31 +121240,37 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121004
121240
|
}, [scope]);
|
|
121005
121241
|
(0, react$1.useEffect)(() => {
|
|
121006
121242
|
const controller = new AbortController();
|
|
121007
|
-
|
|
121243
|
+
listControllerRef.current = controller;
|
|
121244
|
+
setRoleState((current) => ({
|
|
121008
121245
|
scope,
|
|
121009
|
-
roles:
|
|
121246
|
+
roles: current.scope === scope ? current.roles : [],
|
|
121247
|
+
loaded: current.scope === scope && current.loaded,
|
|
121010
121248
|
loading: true,
|
|
121011
121249
|
error: ""
|
|
121012
|
-
});
|
|
121250
|
+
}));
|
|
121013
121251
|
callArkme("self-roles.list", { expectedUserId: userId }, controller.signal).then((roles) => {
|
|
121014
121252
|
if (controller.signal.aborted || scopeRef.current !== scope) return;
|
|
121015
121253
|
setRoleState({
|
|
121016
121254
|
scope,
|
|
121017
121255
|
roles,
|
|
121018
121256
|
loading: false,
|
|
121257
|
+
loaded: true,
|
|
121019
121258
|
error: ""
|
|
121020
121259
|
});
|
|
121260
|
+
for (const ref of new Set(roles.map((role) => role.avatarRef?.trim()).filter((ref) => !!ref))) arkmeAvatarImages.load(ref).catch(() => void 0);
|
|
121021
121261
|
}).catch((caught) => {
|
|
121022
121262
|
if (controller.signal.aborted || scopeRef.current !== scope) return;
|
|
121023
121263
|
setRoleState((current) => ({
|
|
121024
121264
|
scope,
|
|
121025
121265
|
roles: current.scope === scope ? current.roles : [],
|
|
121266
|
+
loaded: current.scope === scope && current.loaded,
|
|
121026
121267
|
loading: false,
|
|
121027
121268
|
error: caught instanceof Error ? caught.message : "角色加载失败,请重试"
|
|
121028
121269
|
}));
|
|
121029
121270
|
});
|
|
121030
121271
|
return () => {
|
|
121031
121272
|
controller.abort();
|
|
121273
|
+
if (listControllerRef.current === controller) listControllerRef.current = void 0;
|
|
121032
121274
|
};
|
|
121033
121275
|
}, [
|
|
121034
121276
|
scope,
|
|
@@ -121071,7 +121313,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121071
121313
|
const createRole = async (event) => {
|
|
121072
121314
|
event.preventDefault();
|
|
121073
121315
|
const roleName = name.trim();
|
|
121074
|
-
if (disabled || saveControllerRef.current !== void 0 ||
|
|
121316
|
+
if (disabled || saveControllerRef.current !== void 0 || initialLoading || visibleState.error !== "" || editingRole === void 0 && visibleState.roles.length >= MAX_ROLES || !roleName || Array.from(roleName).length > MAX_NAME_LENGTH) return;
|
|
121075
121317
|
const controller = new AbortController();
|
|
121076
121318
|
saveControllerRef.current = controller;
|
|
121077
121319
|
const submittingScope = scope;
|
|
@@ -121087,8 +121329,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121087
121329
|
...avatarRef === void 0 ? {} : { avatarRef }
|
|
121088
121330
|
}, controller.signal);
|
|
121089
121331
|
if (controller.signal.aborted || scopeRef.current !== submittingScope) return;
|
|
121332
|
+
listControllerRef.current?.abort();
|
|
121090
121333
|
setRoleState((current) => current.scope === submittingScope ? {
|
|
121091
121334
|
...current,
|
|
121335
|
+
loading: false,
|
|
121336
|
+
loaded: true,
|
|
121337
|
+
error: "",
|
|
121092
121338
|
roles: [...current.roles.filter((role) => role.roleId !== created.roleId), created]
|
|
121093
121339
|
} : current);
|
|
121094
121340
|
setCreateOpen(false);
|
|
@@ -121120,7 +121366,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121120
121366
|
event.stopPropagation();
|
|
121121
121367
|
},
|
|
121122
121368
|
onClick: () => {
|
|
121123
|
-
if (!menuOpen) setRefreshRevision((value) => value + 1);
|
|
121369
|
+
if (!menuOpen && !visibleState.loading) setRefreshRevision((value) => value + 1);
|
|
121124
121370
|
setMenuOpen((value) => !value);
|
|
121125
121371
|
},
|
|
121126
121372
|
children: [
|
|
@@ -121168,8 +121414,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121168
121414
|
roleId: role.roleId
|
|
121169
121415
|
}).then(() => {
|
|
121170
121416
|
if (scopeRef.current !== scope) return;
|
|
121417
|
+
listControllerRef.current?.abort();
|
|
121171
121418
|
setRoleState((current) => current.scope === scope ? {
|
|
121172
121419
|
...current,
|
|
121420
|
+
loading: false,
|
|
121421
|
+
loaded: true,
|
|
121422
|
+
error: "",
|
|
121173
121423
|
roles: current.roles.filter((item) => item.roleId !== role.roleId)
|
|
121174
121424
|
} : current);
|
|
121175
121425
|
setRefreshRevision((value) => value + 1);
|
|
@@ -121219,7 +121469,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121219
121469
|
onSelect: () => deleteRole(role)
|
|
121220
121470
|
}]
|
|
121221
121471
|
})),
|
|
121222
|
-
...
|
|
121472
|
+
...initialLoading ? [{
|
|
121223
121473
|
type: "label",
|
|
121224
121474
|
id: "role-loading",
|
|
121225
121475
|
text: "正在加载角色…"
|
|
@@ -121242,7 +121492,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121242
121492
|
{
|
|
121243
121493
|
id: "role-create",
|
|
121244
121494
|
label: "+ 创建角色",
|
|
121245
|
-
disabled:
|
|
121495
|
+
disabled: initialLoading || visibleState.error !== "" || visibleState.roles.length >= MAX_ROLES,
|
|
121246
121496
|
onSelect: () => {
|
|
121247
121497
|
setMenuOpen(false);
|
|
121248
121498
|
setEditingRole(void 0);
|
|
@@ -126598,11 +126848,11 @@ body[data-ds-dark-theme] .arkme-mention-all-avatar [data-arkme-theme-image="dark
|
|
|
126598
126848
|
}
|
|
126599
126849
|
const MAX_PREFERENCE = 4096;
|
|
126600
126850
|
const PADDING = 12;
|
|
126601
|
-
const preferenceKey$
|
|
126851
|
+
const preferenceKey$3 = (account) => `dsh-arkme:calendar-height:v1:${encodeURIComponent(account)}`;
|
|
126602
126852
|
function readCalendarHeight(account) {
|
|
126603
126853
|
if (!account) return void 0;
|
|
126604
126854
|
try {
|
|
126605
|
-
const value = Number(localStorage.getItem(preferenceKey$
|
|
126855
|
+
const value = Number(localStorage.getItem(preferenceKey$3(account)));
|
|
126606
126856
|
return Number.isFinite(value) && value >= 360 && value <= MAX_PREFERENCE ? value : void 0;
|
|
126607
126857
|
} catch {
|
|
126608
126858
|
return;
|
|
@@ -126611,7 +126861,7 @@ body[data-ds-dark-theme] .arkme-mention-all-avatar [data-arkme-theme-image="dark
|
|
|
126611
126861
|
function writeCalendarHeight(account, height) {
|
|
126612
126862
|
if (!account || !Number.isFinite(height)) return;
|
|
126613
126863
|
try {
|
|
126614
|
-
localStorage.setItem(preferenceKey$
|
|
126864
|
+
localStorage.setItem(preferenceKey$3(account), String(Math.round(Math.max(360, Math.min(MAX_PREFERENCE, height)))));
|
|
126615
126865
|
} catch {}
|
|
126616
126866
|
}
|
|
126617
126867
|
function calendarPopoverLayout(anchor, width, height, preferred) {
|
|
@@ -138133,14 +138383,14 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
138133
138383
|
return;
|
|
138134
138384
|
}
|
|
138135
138385
|
}
|
|
138136
|
-
function preferenceKey$
|
|
138386
|
+
function preferenceKey$2(userId) {
|
|
138137
138387
|
return Number.isSafeInteger(userId) && (userId ?? 0) > 0 ? `${STORAGE_KEY_PREFIX$3}${String(userId)}` : void 0;
|
|
138138
138388
|
}
|
|
138139
138389
|
function isSelfTopicSort(value) {
|
|
138140
138390
|
return value === "latest" || value === "most" || value === "custom";
|
|
138141
138391
|
}
|
|
138142
138392
|
function readSelfTopicSortPreference(userId, storage) {
|
|
138143
|
-
const key = preferenceKey$
|
|
138393
|
+
const key = preferenceKey$2(userId);
|
|
138144
138394
|
const target = preferenceStorage$1(storage);
|
|
138145
138395
|
if (key === void 0 || target === void 0) return DEFAULT_SELF_TOPIC_SORT;
|
|
138146
138396
|
try {
|
|
@@ -138151,7 +138401,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
138151
138401
|
}
|
|
138152
138402
|
}
|
|
138153
138403
|
function writeSelfTopicSortPreference(userId, sort, storage) {
|
|
138154
|
-
const key = preferenceKey$
|
|
138404
|
+
const key = preferenceKey$2(userId);
|
|
138155
138405
|
const target = preferenceStorage$1(storage);
|
|
138156
138406
|
if (key === void 0 || target === void 0) return;
|
|
138157
138407
|
try {
|
|
@@ -143575,7 +143825,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
143575
143825
|
return;
|
|
143576
143826
|
}
|
|
143577
143827
|
}
|
|
143578
|
-
function preferenceKey(userId) {
|
|
143828
|
+
function preferenceKey$1(userId) {
|
|
143579
143829
|
return Number.isSafeInteger(userId) && (userId ?? 0) > 0 ? `${STORAGE_KEY_PREFIX$2}user:${String(userId)}` : `${STORAGE_KEY_PREFIX$2}anonymous`;
|
|
143580
143830
|
}
|
|
143581
143831
|
function isMarketplaceSort(value) {
|
|
@@ -143585,7 +143835,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
143585
143835
|
const target = preferenceStorage(storage);
|
|
143586
143836
|
if (target === void 0) return DEFAULT_MARKETPLACE_SORT;
|
|
143587
143837
|
try {
|
|
143588
|
-
const value = target.getItem(preferenceKey(userId));
|
|
143838
|
+
const value = target.getItem(preferenceKey$1(userId));
|
|
143589
143839
|
return isMarketplaceSort(value) ? value : DEFAULT_MARKETPLACE_SORT;
|
|
143590
143840
|
} catch {
|
|
143591
143841
|
return DEFAULT_MARKETPLACE_SORT;
|
|
@@ -143595,7 +143845,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
143595
143845
|
const target = preferenceStorage(storage);
|
|
143596
143846
|
if (target === void 0) return;
|
|
143597
143847
|
try {
|
|
143598
|
-
target.setItem(preferenceKey(userId), sort);
|
|
143848
|
+
target.setItem(preferenceKey$1(userId), sort);
|
|
143599
143849
|
} catch {}
|
|
143600
143850
|
}
|
|
143601
143851
|
//#endregion
|
|
@@ -155138,7 +155388,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155138
155388
|
* Wrap `React.useLayoutEffect` which will not throw warning message in test env
|
|
155139
155389
|
*/
|
|
155140
155390
|
const useInternalLayoutEffect = canUseDom() ? react.useLayoutEffect : react.useEffect;
|
|
155141
|
-
const useLayoutEffect$
|
|
155391
|
+
const useLayoutEffect$25 = (callback, deps) => {
|
|
155142
155392
|
const firstMountRef = react.useRef(true);
|
|
155143
155393
|
useInternalLayoutEffect(() => {
|
|
155144
155394
|
return callback(firstMountRef.current);
|
|
@@ -155182,7 +155432,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155182
155432
|
function useControlledState(defaultStateValue, value) {
|
|
155183
155433
|
const [innerValue, setInnerValue] = (0, react.useState)(defaultStateValue);
|
|
155184
155434
|
const mergedValue = value !== void 0 ? value : innerValue;
|
|
155185
|
-
useLayoutEffect$
|
|
155435
|
+
useLayoutEffect$25((mount) => {
|
|
155186
155436
|
if (!mount) setInnerValue(value);
|
|
155187
155437
|
}, [value]);
|
|
155188
155438
|
return [mergedValue, setInnerValue];
|
|
@@ -155245,7 +155495,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155245
155495
|
};
|
|
155246
155496
|
//#endregion
|
|
155247
155497
|
//#region node_modules/@rc-component/util/es/hooks/useMemo.js
|
|
155248
|
-
function useMemo$
|
|
155498
|
+
function useMemo$36(getValue, condition, shouldUpdate) {
|
|
155249
155499
|
const cacheRef = react.useRef({});
|
|
155250
155500
|
if (!("value" in cacheRef.current) || shouldUpdate(cacheRef.current.condition, condition)) {
|
|
155251
155501
|
cacheRef.current.value = getValue();
|
|
@@ -155358,7 +155608,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
155358
155608
|
};
|
|
155359
155609
|
};
|
|
155360
155610
|
const useComposeRef = (...refs) => {
|
|
155361
|
-
return useMemo$
|
|
155611
|
+
return useMemo$36(() => composeRef(...refs), refs, (prev, next) => prev.length !== next.length || prev.every((ref, i) => ref !== next[i]));
|
|
155362
155612
|
};
|
|
155363
155613
|
const supportRef = (nodeOrComponent) => {
|
|
155364
155614
|
if (!nodeOrComponent) return false;
|
|
@@ -156248,13 +156498,13 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
156248
156498
|
ele.parentElement?.removeChild(ele);
|
|
156249
156499
|
appendedRef.current = false;
|
|
156250
156500
|
}
|
|
156251
|
-
useLayoutEffect$
|
|
156501
|
+
useLayoutEffect$25(() => {
|
|
156252
156502
|
if (render) if (queueCreate) queueCreate(append);
|
|
156253
156503
|
else append();
|
|
156254
156504
|
else cleanup();
|
|
156255
156505
|
return cleanup;
|
|
156256
156506
|
}, [render]);
|
|
156257
|
-
useLayoutEffect$
|
|
156507
|
+
useLayoutEffect$25(() => {
|
|
156258
156508
|
if (queue.length) {
|
|
156259
156509
|
queue.forEach((appendFn) => appendFn());
|
|
156260
156510
|
setQueue(EMPTY_LIST);
|
|
@@ -156280,7 +156530,7 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
156280
156530
|
uuid$1 += 1;
|
|
156281
156531
|
return `${UNIQUE_ID}_${uuid$1}`;
|
|
156282
156532
|
});
|
|
156283
|
-
useLayoutEffect$
|
|
156533
|
+
useLayoutEffect$25(() => {
|
|
156284
156534
|
if (mergedLock) {
|
|
156285
156535
|
const scrollbarSize = getTargetScrollBarSize(document.body).width;
|
|
156286
156536
|
updateCSS(`
|
|
@@ -157223,7 +157473,7 @@ html body {
|
|
|
157223
157473
|
]);
|
|
157224
157474
|
const getPopupContainerNeedParams = getPopupContainer?.length > 0;
|
|
157225
157475
|
const [show, setShow] = react.useState(!getPopupContainer || !getPopupContainerNeedParams);
|
|
157226
|
-
useLayoutEffect$
|
|
157476
|
+
useLayoutEffect$25(() => {
|
|
157227
157477
|
if (!show && getPopupContainerNeedParams && target) setShow(true);
|
|
157228
157478
|
}, [
|
|
157229
157479
|
show,
|
|
@@ -157775,8 +158025,8 @@ html body {
|
|
|
157775
158025
|
ready: false
|
|
157776
158026
|
}));
|
|
157777
158027
|
};
|
|
157778
|
-
useLayoutEffect$
|
|
157779
|
-
useLayoutEffect$
|
|
158028
|
+
useLayoutEffect$25(resetReady, [placement]);
|
|
158029
|
+
useLayoutEffect$25(() => {
|
|
157780
158030
|
if (!open) resetReady();
|
|
157781
158031
|
}, [open]);
|
|
157782
158032
|
return [
|
|
@@ -157820,7 +158070,7 @@ html body {
|
|
|
157820
158070
|
//#endregion
|
|
157821
158071
|
//#region node_modules/@rc-component/trigger/es/hooks/useWatch.js
|
|
157822
158072
|
function useWatch(open, target, popup, onAlign, onScroll) {
|
|
157823
|
-
useLayoutEffect$
|
|
158073
|
+
useLayoutEffect$25(() => {
|
|
157824
158074
|
if (open && target && popup) {
|
|
157825
158075
|
const targetElement = target;
|
|
157826
158076
|
const popupElement = popup;
|
|
@@ -157975,7 +158225,7 @@ html body {
|
|
|
157975
158225
|
id,
|
|
157976
158226
|
onEsc
|
|
157977
158227
|
}));
|
|
157978
|
-
useLayoutEffect$
|
|
158228
|
+
useLayoutEffect$25(() => {
|
|
157979
158229
|
if (uniqueContext && unique && targetEle && !openUncontrolled && !parentContext) if (mergedOpen) uniqueContext.show(getUniqueOptions(mouseEnterDelay), isOpen);
|
|
157980
158230
|
else uniqueContext.hide(mouseLeaveDelay);
|
|
157981
158231
|
}, [mergedOpen, targetEle]);
|
|
@@ -158011,7 +158261,7 @@ html body {
|
|
|
158011
158261
|
if (top) triggerOpen(false);
|
|
158012
158262
|
}
|
|
158013
158263
|
const [inMotion, setInMotion] = react.useState(false);
|
|
158014
|
-
useLayoutEffect$
|
|
158264
|
+
useLayoutEffect$25((firstMount) => {
|
|
158015
158265
|
if (!firstMount || mergedOpen) setInMotion(true);
|
|
158016
158266
|
}, [mergedOpen]);
|
|
158017
158267
|
const [motionPrepareResolve, setMotionPrepareResolve] = react.useState(null);
|
|
@@ -158030,10 +158280,10 @@ html body {
|
|
|
158030
158280
|
if (openRef.current && alignPoint && clickToHide) triggerOpen(false);
|
|
158031
158281
|
};
|
|
158032
158282
|
useWatch(mergedOpen, targetEle, popupEle, triggerAlign, onScroll);
|
|
158033
|
-
useLayoutEffect$
|
|
158283
|
+
useLayoutEffect$25(() => {
|
|
158034
158284
|
triggerAlign();
|
|
158035
158285
|
}, [mousePos, popupPlacement]);
|
|
158036
|
-
useLayoutEffect$
|
|
158286
|
+
useLayoutEffect$25(() => {
|
|
158037
158287
|
if (mergedOpen && !builtinPlacements?.[popupPlacement]) triggerAlign();
|
|
158038
158288
|
}, [JSON.stringify(popupAlign)]);
|
|
158039
158289
|
const alignedClassName = react.useMemo(() => {
|
|
@@ -158073,7 +158323,7 @@ html body {
|
|
|
158073
158323
|
syncTargetSize();
|
|
158074
158324
|
setMotionPrepareResolve(() => resolve);
|
|
158075
158325
|
});
|
|
158076
|
-
useLayoutEffect$
|
|
158326
|
+
useLayoutEffect$25(() => {
|
|
158077
158327
|
if (motionPrepareResolve) {
|
|
158078
158328
|
onAlign();
|
|
158079
158329
|
motionPrepareResolve();
|
|
@@ -158280,7 +158530,7 @@ html body {
|
|
|
158280
158530
|
}
|
|
158281
158531
|
function useTarget(target, open, gap, scrollIntoViewOptions, inlineMode, placeholderRef) {
|
|
158282
158532
|
const [targetElement, setTargetElement] = (0, react.useState)(void 0);
|
|
158283
|
-
useLayoutEffect$
|
|
158533
|
+
useLayoutEffect$25(() => {
|
|
158284
158534
|
const nextElement = typeof target === "function" ? target() : target;
|
|
158285
158535
|
setTargetElement(nextElement || null);
|
|
158286
158536
|
});
|
|
@@ -158310,7 +158560,7 @@ html body {
|
|
|
158310
158560
|
} else setPosInfo(null);
|
|
158311
158561
|
});
|
|
158312
158562
|
const getGapOffset = (index) => (Array.isArray(gap?.offset) ? gap?.offset[index] : gap?.offset) ?? 6;
|
|
158313
|
-
useLayoutEffect$
|
|
158563
|
+
useLayoutEffect$25(() => {
|
|
158314
158564
|
updatePos();
|
|
158315
158565
|
window.addEventListener("resize", updatePos);
|
|
158316
158566
|
window.addEventListener("scroll", updatePos);
|
|
@@ -158600,7 +158850,7 @@ html body {
|
|
|
158600
158850
|
const mergedOpen = mergedCurrent < 0 || mergedCurrent >= steps.length ? false : internalOpen ?? true;
|
|
158601
158851
|
const [hasOpened, setHasOpened] = react.useState(mergedOpen);
|
|
158602
158852
|
const openRef = react.useRef(mergedOpen);
|
|
158603
|
-
useLayoutEffect$
|
|
158853
|
+
useLayoutEffect$25(() => {
|
|
158604
158854
|
if (mergedOpen) {
|
|
158605
158855
|
if (!openRef.current) setMergedCurrent(0);
|
|
158606
158856
|
setHasOpened(true);
|
|
@@ -158617,7 +158867,7 @@ html body {
|
|
|
158617
158867
|
const mergedPlacement = getPlacement(targetElement, placement, stepPlacement);
|
|
158618
158868
|
const mergedArrow = targetElement ? typeof stepArrow === "undefined" ? arrow : stepArrow : false;
|
|
158619
158869
|
const arrowPointAtCenter = typeof mergedArrow === "object" ? mergedArrow.pointAtCenter : false;
|
|
158620
|
-
useLayoutEffect$
|
|
158870
|
+
useLayoutEffect$25(() => {
|
|
158621
158871
|
triggerRef.current?.forceAlign();
|
|
158622
158872
|
}, [arrowPointAtCenter, mergedCurrent]);
|
|
158623
158873
|
const onInternalChange = (nextCurrent) => {
|
|
@@ -158655,7 +158905,7 @@ html body {
|
|
|
158655
158905
|
return;
|
|
158656
158906
|
}
|
|
158657
158907
|
});
|
|
158658
|
-
useLayoutEffect$
|
|
158908
|
+
useLayoutEffect$25(() => {
|
|
158659
158909
|
if (!mergedOpen) return;
|
|
158660
158910
|
window.addEventListener("keydown", keyboardHandler);
|
|
158661
158911
|
return () => {
|
|
@@ -166140,7 +166390,7 @@ html body {
|
|
|
166140
166390
|
//#endregion
|
|
166141
166391
|
//#region src/client/self-topic-expansion-preference.ts
|
|
166142
166392
|
const EMPTY$1 = /* @__PURE__ */ new Set();
|
|
166143
|
-
function browserStorage() {
|
|
166393
|
+
function browserStorage$1() {
|
|
166144
166394
|
try {
|
|
166145
166395
|
return typeof window === "undefined" ? void 0 : window.localStorage;
|
|
166146
166396
|
} catch {
|
|
@@ -166159,7 +166409,7 @@ html body {
|
|
|
166159
166409
|
storage;
|
|
166160
166410
|
value;
|
|
166161
166411
|
listeners = /* @__PURE__ */ new Set();
|
|
166162
|
-
constructor(key, storage = browserStorage()) {
|
|
166412
|
+
constructor(key, storage = browserStorage$1()) {
|
|
166163
166413
|
this.key = key;
|
|
166164
166414
|
this.storage = storage;
|
|
166165
166415
|
this.value = this.read();
|
|
@@ -178696,73 +178946,19 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
178696
178946
|
const p$2 = e$36;
|
|
178697
178947
|
//#endregion
|
|
178698
178948
|
//#region src/client/recordings/RecognizedSpeakerEntry.tsx
|
|
178699
|
-
function RecognizedSpeakerEntry({ accountKey, active, onOpen, style,
|
|
178949
|
+
function RecognizedSpeakerEntry({ accountKey, active, onOpen, style, directory = recognizedSpeakerDirectory }) {
|
|
178700
178950
|
useArkmeLocale();
|
|
178701
|
-
const
|
|
178702
|
-
marked: readMarked,
|
|
178703
|
-
page: readPage,
|
|
178704
|
-
presence: readSpeakerPresence
|
|
178705
|
-
}, 0)), [
|
|
178706
|
-
providedDirectory,
|
|
178707
|
-
readMarked,
|
|
178708
|
-
readPage
|
|
178709
|
-
]);
|
|
178710
|
-
const snapshot = (0, react$1.useSyncExternalStore)(recognizedSpeakerTracker.subscribe, () => recognizedSpeakerTracker.get(accountKey), () => recognizedSpeakerTracker.get(accountKey));
|
|
178951
|
+
const snapshot = (0, react$1.useSyncExternalStore)(directory.subscribe, () => directory.get(accountKey), () => directory.get(accountKey));
|
|
178711
178952
|
(0, react$1.useEffect)(() => {
|
|
178712
|
-
if (
|
|
178713
|
-
const controller = new AbortController();
|
|
178714
|
-
let busy = false;
|
|
178715
|
-
let retryTimer;
|
|
178716
|
-
const refresh = async () => {
|
|
178717
|
-
if (busy || controller.signal.aborted || typeof document !== "undefined" && document.visibilityState === "hidden") return;
|
|
178718
|
-
busy = true;
|
|
178719
|
-
try {
|
|
178720
|
-
let marked;
|
|
178721
|
-
const updateTotal = () => {
|
|
178722
|
-
const value = directory.peekCandidates(accountKey);
|
|
178723
|
-
if (marked !== void 0 && value?.total !== void 0 && !controller.signal.aborted) recognizedSpeakerTracker.setTotal(accountKey, markedSpeakerKeys(marked).length + value.total);
|
|
178724
|
-
};
|
|
178725
|
-
const [, result] = await Promise.all([directory.readMarked(accountKey, controller.signal).then((value) => {
|
|
178726
|
-
marked = value;
|
|
178727
|
-
updateTotal();
|
|
178728
|
-
}), directory.readCandidates(accountKey, controller.signal, updateTotal)]);
|
|
178729
|
-
if (controller.signal.aborted) return;
|
|
178730
|
-
if (result.complete && marked !== void 0) recognizedSpeakerTracker.observe(accountKey, marked, result.items);
|
|
178731
|
-
else recognizedSpeakerTracker.uncertain(accountKey);
|
|
178732
|
-
} catch (error) {
|
|
178733
|
-
if (!controller.signal.aborted) {
|
|
178734
|
-
recognizedSpeakerTracker.uncertain(accountKey);
|
|
178735
|
-
const delay = speakerRetryDelay(error);
|
|
178736
|
-
if (delay !== void 0) {
|
|
178737
|
-
clearTimeout(retryTimer);
|
|
178738
|
-
retryTimer = setTimeout(() => {
|
|
178739
|
-
refresh();
|
|
178740
|
-
}, delay);
|
|
178741
|
-
}
|
|
178742
|
-
}
|
|
178743
|
-
} finally {
|
|
178744
|
-
busy = false;
|
|
178745
|
-
}
|
|
178746
|
-
};
|
|
178747
|
-
refresh();
|
|
178748
|
-
const timer = setInterval(() => {
|
|
178749
|
-
refresh();
|
|
178750
|
-
}, 6e4);
|
|
178751
|
-
const onVisible = () => {
|
|
178752
|
-
refresh();
|
|
178753
|
-
};
|
|
178754
|
-
if (typeof document !== "undefined") document.addEventListener("visibilitychange", onVisible);
|
|
178755
|
-
return () => {
|
|
178756
|
-
controller.abort();
|
|
178757
|
-
clearInterval(timer);
|
|
178758
|
-
clearTimeout(retryTimer);
|
|
178759
|
-
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", onVisible);
|
|
178760
|
-
};
|
|
178953
|
+
if (active && accountKey !== void 0) return directory.watch(accountKey);
|
|
178761
178954
|
}, [
|
|
178762
178955
|
accountKey,
|
|
178763
178956
|
active,
|
|
178764
178957
|
directory
|
|
178765
178958
|
]);
|
|
178959
|
+
const summary = snapshot.summary;
|
|
178960
|
+
const count = summary?.state === "disabled" ? null : summary?.totalCount;
|
|
178961
|
+
const hint = summary?.state === "disabled" ? "目录暂不可用" : count == null ? summary?.state === "building" ? "整理中…" : snapshot.error || summary?.state === "failed" ? "暂时无法更新" : "" : (summary?.unseenCount ?? 0) > 0 ? tr$1("新识别 {v0} 个", { v0: summary.unseenCount }) : "";
|
|
178766
178962
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
178767
178963
|
"data-arkme-feedback": "recording-action",
|
|
178768
178964
|
type: "button",
|
|
@@ -178796,12 +178992,12 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
178796
178992
|
},
|
|
178797
178993
|
children: tr$1("已识别说话人")
|
|
178798
178994
|
}),
|
|
178799
|
-
|
|
178995
|
+
count != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
178800
178996
|
style: {
|
|
178801
178997
|
flexShrink: 0,
|
|
178802
178998
|
fontVariantNumeric: "tabular-nums"
|
|
178803
178999
|
},
|
|
178804
|
-
children:
|
|
179000
|
+
children: count
|
|
178805
179001
|
}),
|
|
178806
179002
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$21, {
|
|
178807
179003
|
size: 12,
|
|
@@ -178809,14 +179005,14 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
178809
179005
|
"aria-hidden": true
|
|
178810
179006
|
})
|
|
178811
179007
|
]
|
|
178812
|
-
}),
|
|
179008
|
+
}), hint && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
178813
179009
|
style: {
|
|
178814
179010
|
fontSize: 11,
|
|
178815
179011
|
lineHeight: "15px",
|
|
178816
179012
|
fontWeight: 400
|
|
178817
179013
|
},
|
|
178818
179014
|
"aria-live": "polite",
|
|
178819
|
-
children: tr$1(
|
|
179015
|
+
children: tr$1(hint)
|
|
178820
179016
|
})]
|
|
178821
179017
|
});
|
|
178822
179018
|
}
|
|
@@ -191153,6 +191349,28 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191153
191349
|
});
|
|
191154
191350
|
}
|
|
191155
191351
|
//#endregion
|
|
191352
|
+
//#region src/client/recognized-speaker-order.ts
|
|
191353
|
+
const preferenceKey = (accountKey) => `dsh-arkme:recognized-speaker-order:v1:${accountKey}`;
|
|
191354
|
+
function browserStorage() {
|
|
191355
|
+
try {
|
|
191356
|
+
return typeof window === "undefined" ? void 0 : window.localStorage;
|
|
191357
|
+
} catch {
|
|
191358
|
+
return;
|
|
191359
|
+
}
|
|
191360
|
+
}
|
|
191361
|
+
function readRecognizedSpeakerOrder(accountKey, storage = browserStorage()) {
|
|
191362
|
+
try {
|
|
191363
|
+
return storage?.getItem(preferenceKey(accountKey)) === "recent" ? "recent" : "frequent";
|
|
191364
|
+
} catch {
|
|
191365
|
+
return "frequent";
|
|
191366
|
+
}
|
|
191367
|
+
}
|
|
191368
|
+
function writeRecognizedSpeakerOrder(accountKey, order, storage = browserStorage()) {
|
|
191369
|
+
try {
|
|
191370
|
+
storage?.setItem(preferenceKey(accountKey), order);
|
|
191371
|
+
} catch {}
|
|
191372
|
+
}
|
|
191373
|
+
//#endregion
|
|
191156
191374
|
//#region src/client/recordings/SpeakerSelfGuide.tsx
|
|
191157
191375
|
const loadVoiceprint = (signal) => callArkme("voiceprint.status", {}, signal);
|
|
191158
191376
|
function SpeakerSelfGuide({ onOpenRecordings, readVoiceprint = loadVoiceprint }) {
|
|
@@ -191175,7 +191393,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191175
191393
|
if (state.loading) return null;
|
|
191176
191394
|
const pending = state.value?.enrollmentPending === true;
|
|
191177
191395
|
const hasVoiceprint = state.value?.hasVoiceprint === true;
|
|
191178
|
-
const title = pending ? "你的声纹正在处理中" : hasVoiceprint ? "已录入声纹,暂未在录音中匹配到你" : "还没有标记你的声音";
|
|
191396
|
+
const title = state.value === void 0 ? "声纹状态暂不可用" : pending ? "你的声纹正在处理中" : hasVoiceprint ? "已录入声纹,暂未在录音中匹配到你" : "还没有标记你的声音";
|
|
191179
191397
|
const actionStyle = {
|
|
191180
191398
|
border: 0,
|
|
191181
191399
|
padding: 0,
|
|
@@ -191230,39 +191448,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191230
191448
|
}
|
|
191231
191449
|
//#endregion
|
|
191232
191450
|
//#region src/client/ArkmeRecognizedSpeakersSurface.tsx
|
|
191233
|
-
/** Group only by a stable owner identity, never by a shared name or speaker number. */
|
|
191234
|
-
function identifiedSpeakerRows(options, candidates) {
|
|
191235
|
-
const marked = /* @__PURE__ */ new Map();
|
|
191236
|
-
for (const option of options) {
|
|
191237
|
-
if (option.kind !== "speaker") continue;
|
|
191238
|
-
const key = option.personKey || option.optionKey;
|
|
191239
|
-
if (marked.has(key)) continue;
|
|
191240
|
-
marked.set(key, {
|
|
191241
|
-
kind: "marked",
|
|
191242
|
-
key,
|
|
191243
|
-
optionKey: option.optionKey,
|
|
191244
|
-
speakerRef: option.speakerRef,
|
|
191245
|
-
name: option.label.trim() || "未命名说话人",
|
|
191246
|
-
...option.avatarRef === void 0 ? {} : { avatarRef: option.avatarRef },
|
|
191247
|
-
isCurrentUser: option.isCurrentUser
|
|
191248
|
-
});
|
|
191249
|
-
}
|
|
191250
|
-
const unmarked = /* @__PURE__ */ new Map();
|
|
191251
|
-
for (const candidate of candidates) {
|
|
191252
|
-
if (unmarked.has(candidate.candidateRef)) continue;
|
|
191253
|
-
unmarked.set(candidate.candidateRef, {
|
|
191254
|
-
kind: "unmarked",
|
|
191255
|
-
key: candidate.candidateRef,
|
|
191256
|
-
name: tr$1("说话人 {v0}", { v0: candidate.speakerToken?.trim() || candidate.displayName }),
|
|
191257
|
-
token: candidate.speakerToken?.trim() || "",
|
|
191258
|
-
subtitle: candidate.subtitle,
|
|
191259
|
-
candidateRef: candidate.candidateRef,
|
|
191260
|
-
dayCount: candidate.appearanceDays,
|
|
191261
|
-
lastSeenAt: candidate.latestAtMillis
|
|
191262
|
-
});
|
|
191263
|
-
}
|
|
191264
|
-
return [...[...marked.values()].sort((left, right) => left.name.localeCompare(right.name)), ...unmarked.values()];
|
|
191265
|
-
}
|
|
191266
191451
|
const styles$20 = {
|
|
191267
191452
|
root: {
|
|
191268
191453
|
flex: 1,
|
|
@@ -191450,87 +191635,133 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191450
191635
|
borderBottom: `1px solid ${arkmeTheme.borderSoft}`
|
|
191451
191636
|
}
|
|
191452
191637
|
};
|
|
191453
|
-
const defaultLoadMarkedMembers =
|
|
191638
|
+
const defaultLoadMarkedMembers = (speakerRef, signal, expectedVersion) => callArkme("recordings.speaker.members", {
|
|
191454
191639
|
speakerRef,
|
|
191455
191640
|
...expectedVersion === void 0 ? {} : { expectedVersion }
|
|
191456
191641
|
}, signal);
|
|
191457
|
-
|
|
191458
|
-
|
|
191459
|
-
|
|
191460
|
-
|
|
191461
|
-
if (
|
|
191462
|
-
|
|
191463
|
-
|
|
191464
|
-
|
|
191465
|
-
|
|
191466
|
-
|
|
191467
|
-
|
|
191468
|
-
|
|
191469
|
-
|
|
191470
|
-
|
|
191471
|
-
|
|
191472
|
-
})
|
|
191473
|
-
|
|
191474
|
-
|
|
191475
|
-
|
|
191476
|
-
|
|
191477
|
-
|
|
191478
|
-
|
|
191479
|
-
loading: true,
|
|
191480
|
-
error: ""
|
|
191642
|
+
const failureMessage = (error) => error instanceof Error ? error.message : tr$1("说话人列表暂时无法加载");
|
|
191643
|
+
const nameSegmenter = new Intl.Segmenter("zh-CN", { granularity: "grapheme" });
|
|
191644
|
+
function speakerNameAvatarFallback(row) {
|
|
191645
|
+
const initial = nameSegmenter.segment(row.displayName.trim())[Symbol.iterator]().next().value?.segment;
|
|
191646
|
+
if (!initial) return void 0;
|
|
191647
|
+
let hash = 0;
|
|
191648
|
+
for (const character of row.personKey) hash = Math.imul(hash, 31) + character.codePointAt(0) >>> 0;
|
|
191649
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
191650
|
+
"aria-hidden": true,
|
|
191651
|
+
style: {
|
|
191652
|
+
width: "100%",
|
|
191653
|
+
height: "100%",
|
|
191654
|
+
display: "grid",
|
|
191655
|
+
placeItems: "center",
|
|
191656
|
+
borderRadius: "50%",
|
|
191657
|
+
background: `color-mix(in srgb, ${recordingSpeakerColor(hash % 15)} 30%, ${arkmeTheme.base})`,
|
|
191658
|
+
color: arkmeTheme.text,
|
|
191659
|
+
fontSize: 17,
|
|
191660
|
+
fontWeight: 600,
|
|
191661
|
+
lineHeight: 1
|
|
191662
|
+
},
|
|
191663
|
+
children: initial
|
|
191481
191664
|
});
|
|
191665
|
+
}
|
|
191666
|
+
function personStats(row) {
|
|
191667
|
+
const recent = row.lastSeenAt > 0 ? new Intl.DateTimeFormat(arkmeIntlLocale(), {
|
|
191668
|
+
year: "numeric",
|
|
191669
|
+
month: "2-digit",
|
|
191670
|
+
day: "2-digit",
|
|
191671
|
+
hour: "2-digit",
|
|
191672
|
+
minute: "2-digit",
|
|
191673
|
+
hour12: false
|
|
191674
|
+
}).format(row.lastSeenAt) : tr$1("时间未知");
|
|
191675
|
+
return tr$1("出现 {v0} 天 · 最近 {v1}", {
|
|
191676
|
+
v0: row.dayCount,
|
|
191677
|
+
v1: recent
|
|
191678
|
+
});
|
|
191679
|
+
}
|
|
191680
|
+
function statusText(status) {
|
|
191681
|
+
if (status?.state === "disabled") return tr$1("说话人目录暂不可用,请稍后再试。");
|
|
191682
|
+
if (status?.coverage === "unknown") return status.state === "failed" ? tr$1("说话人目录暂不可用,请稍后刷新。") : tr$1("正在整理说话人目录…");
|
|
191683
|
+
if (status?.state === "failed") return tr$1("更新暂未完成,当前显示上次整理的目录。");
|
|
191684
|
+
if (status?.state === "stale") return tr$1("正在更新,当前显示已整理的目录。");
|
|
191685
|
+
if (status && (status.processingSessionCount > 0 || status.pendingIdentityAggregationCount > 0 || status.insufficientEvidenceCount > 0 || status.scanTruncated)) return tr$1("部分录音仍在整理,人物可能继续更新。");
|
|
191686
|
+
return "";
|
|
191687
|
+
}
|
|
191688
|
+
function PersonDetail({ row, accountKey, directory, loadMembers, onChanged }) {
|
|
191689
|
+
const [detail, setDetail] = (0, react$1.useState)();
|
|
191690
|
+
const [members, setMembers] = (0, react$1.useState)();
|
|
191691
|
+
const [error, setError] = (0, react$1.useState)("");
|
|
191692
|
+
const [revision, setRevision] = (0, react$1.useState)(0);
|
|
191482
191693
|
(0, react$1.useEffect)(() => {
|
|
191483
191694
|
const controller = new AbortController();
|
|
191484
|
-
|
|
191485
|
-
|
|
191486
|
-
|
|
191487
|
-
|
|
191488
|
-
|
|
191489
|
-
|
|
191490
|
-
|
|
191491
|
-
|
|
191695
|
+
let retry;
|
|
191696
|
+
setDetail(void 0);
|
|
191697
|
+
setMembers(void 0);
|
|
191698
|
+
setError("");
|
|
191699
|
+
directory.open(accountKey, row.detailRef, controller.signal).then(async (value) => {
|
|
191700
|
+
if (controller.signal.aborted) return;
|
|
191701
|
+
setDetail(value);
|
|
191702
|
+
if (value.type === "speaker") {
|
|
191703
|
+
const result = await loadMembers(value.speakerRef, controller.signal, value.expectedVersion);
|
|
191492
191704
|
if (controller.signal.aborted) return;
|
|
191493
|
-
|
|
191494
|
-
|
|
191495
|
-
|
|
191496
|
-
|
|
191497
|
-
});
|
|
191498
|
-
if (result.state === "stale" && result.version !== void 0 && result.version !== version) onVersionChanged();
|
|
191499
|
-
if (result.state !== "fresh") timer = setTimeout(() => {
|
|
191500
|
-
load();
|
|
191705
|
+
setMembers(result);
|
|
191706
|
+
if (result.state === "stale") onChanged();
|
|
191707
|
+
else if (result.state !== "fresh") retry = setTimeout(() => {
|
|
191708
|
+
if (directoryVisible()) setRevision((value) => value + 1);
|
|
191501
191709
|
}, Math.max(5e3, result.retryAfterMs ?? 1e4));
|
|
191502
|
-
} catch (error) {
|
|
191503
|
-
if (!controller.signal.aborted) setState({
|
|
191504
|
-
loading: false,
|
|
191505
|
-
error: failureMessage(error)
|
|
191506
|
-
});
|
|
191507
191710
|
}
|
|
191508
|
-
}
|
|
191509
|
-
|
|
191711
|
+
}).catch((error) => {
|
|
191712
|
+
if (controller.signal.aborted) return;
|
|
191713
|
+
if (directoryErrorCode(error) === "unmarked-candidate-not-found") onChanged();
|
|
191714
|
+
else setError(failureMessage(error));
|
|
191715
|
+
});
|
|
191510
191716
|
return () => {
|
|
191511
|
-
clearTimeout(timer);
|
|
191512
191717
|
controller.abort();
|
|
191718
|
+
clearTimeout(retry);
|
|
191513
191719
|
};
|
|
191514
191720
|
}, [
|
|
191721
|
+
row.detailRef,
|
|
191515
191722
|
accountKey,
|
|
191516
|
-
|
|
191723
|
+
directory,
|
|
191517
191724
|
loadMembers,
|
|
191518
|
-
|
|
191519
|
-
|
|
191725
|
+
onChanged,
|
|
191726
|
+
revision
|
|
191520
191727
|
]);
|
|
191728
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
191729
|
+
role: "alert",
|
|
191730
|
+
style: styles$20.error,
|
|
191731
|
+
children: [
|
|
191732
|
+
error,
|
|
191733
|
+
" ",
|
|
191734
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
191735
|
+
style: styles$20.button,
|
|
191736
|
+
onClick: () => setRevision((value) => value + 1),
|
|
191737
|
+
children: tr$1("重试")
|
|
191738
|
+
})
|
|
191739
|
+
]
|
|
191740
|
+
});
|
|
191741
|
+
if (!detail) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191742
|
+
role: "status",
|
|
191743
|
+
style: styles$20.state,
|
|
191744
|
+
children: tr$1("正在加载人物详情…")
|
|
191745
|
+
});
|
|
191746
|
+
if (detail.type === "candidate") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerDetail, {
|
|
191747
|
+
accountKey,
|
|
191748
|
+
candidateRef: detail.candidateRef,
|
|
191749
|
+
onDirectoryRefresh: onChanged,
|
|
191750
|
+
onCandidateCleared: onChanged
|
|
191751
|
+
});
|
|
191521
191752
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
191522
191753
|
"aria-label": tr$1("已标记说话人详情"),
|
|
191523
191754
|
children: [
|
|
191524
191755
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
|
|
191525
191756
|
style: styles$20.detailTitle,
|
|
191526
|
-
children: [
|
|
191757
|
+
children: [row.displayName, row.isSelf ? ` · ${tr$1("我")}` : ""]
|
|
191527
191758
|
}),
|
|
191528
191759
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
191529
191760
|
style: {
|
|
191530
191761
|
...styles$20.meta,
|
|
191531
191762
|
margin: 0
|
|
191532
191763
|
},
|
|
191533
|
-
children:
|
|
191764
|
+
children: personStats(row)
|
|
191534
191765
|
}),
|
|
191535
191766
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
191536
191767
|
style: styles$20.detailSection,
|
|
@@ -191539,30 +191770,20 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191539
191770
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
191540
191771
|
style: {
|
|
191541
191772
|
...styles$20.meta,
|
|
191542
|
-
margin: "0 0 8px",
|
|
191543
191773
|
whiteSpace: "normal"
|
|
191544
191774
|
},
|
|
191545
191775
|
children: tr$1("展示全部历史已转写片段中可核实的关联。")
|
|
191546
191776
|
}),
|
|
191547
|
-
|
|
191777
|
+
!members || members.state !== "fresh" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191548
191778
|
role: "status",
|
|
191549
191779
|
style: styles$20.state,
|
|
191550
|
-
children: tr$1("
|
|
191551
|
-
}) :
|
|
191552
|
-
role: "alert",
|
|
191553
|
-
style: styles$20.error,
|
|
191554
|
-
children: state.error || tr$1("出现统计暂不可用")
|
|
191555
|
-
}) : state.result?.state === "stale" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191556
|
-
role: "status",
|
|
191557
|
-
style: styles$20.state,
|
|
191558
|
-
children: tr$1("出现统计更新中")
|
|
191559
|
-
}) : state.result?.items.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191560
|
-
role: "status",
|
|
191780
|
+
children: members?.state === "failed" ? tr$1("出现统计暂不可用") : tr$1("出现统计整理中")
|
|
191781
|
+
}) : members.items.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191561
191782
|
style: styles$20.state,
|
|
191562
|
-
children:
|
|
191783
|
+
children: tr$1("暂无可核实的关联说话人。")
|
|
191563
191784
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
191564
191785
|
style: styles$20.list,
|
|
191565
|
-
children:
|
|
191786
|
+
children: members.items.map((member) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
191566
191787
|
style: styles$20.memberRow,
|
|
191567
191788
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerTokenAvatar, {
|
|
191568
191789
|
token: member.token,
|
|
@@ -191583,274 +191804,251 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191583
191804
|
]
|
|
191584
191805
|
});
|
|
191585
191806
|
}
|
|
191586
|
-
function ArkmeRecognizedSpeakersSurface(
|
|
191807
|
+
function ArkmeRecognizedSpeakersSurface(props) {
|
|
191808
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DirectorySurface, { ...props }, props.accountKey);
|
|
191809
|
+
}
|
|
191810
|
+
function DirectorySurface({ accountKey, onBack, directory = recognizedSpeakerDirectory, loadMarkedMembers = defaultLoadMarkedMembers }) {
|
|
191587
191811
|
useArkmeLocale();
|
|
191588
|
-
const directory = (0, react$1.useMemo)(() => providedDirectory ?? (loadMarked === readSpeakerOptions && loadUnmarked === readSpeakerPage && loadPresence === readSpeakerPresence ? recognizedSpeakerDirectory : new RecognizedSpeakerDirectory({
|
|
191589
|
-
marked: loadMarked,
|
|
191590
|
-
page: loadUnmarked,
|
|
191591
|
-
presence: loadPresence
|
|
191592
|
-
}, 0)), [
|
|
191593
|
-
providedDirectory,
|
|
191594
|
-
loadMarked,
|
|
191595
|
-
loadUnmarked,
|
|
191596
|
-
loadPresence
|
|
191597
|
-
]);
|
|
191598
191812
|
const [filter, setFilter] = (0, react$1.useState)("all");
|
|
191599
|
-
const [
|
|
191600
|
-
const [
|
|
191601
|
-
|
|
191602
|
-
|
|
191603
|
-
|
|
191604
|
-
|
|
191605
|
-
|
|
191606
|
-
|
|
191607
|
-
|
|
191608
|
-
|
|
191609
|
-
|
|
191610
|
-
|
|
191611
|
-
|
|
191612
|
-
|
|
191613
|
-
|
|
191614
|
-
|
|
191615
|
-
|
|
191616
|
-
const [
|
|
191617
|
-
|
|
191618
|
-
|
|
191619
|
-
|
|
191620
|
-
|
|
191621
|
-
|
|
191622
|
-
|
|
191623
|
-
|
|
191624
|
-
|
|
191625
|
-
|
|
191626
|
-
|
|
191627
|
-
|
|
191628
|
-
|
|
191629
|
-
|
|
191630
|
-
|
|
191631
|
-
|
|
191813
|
+
const [input, setInput] = (0, react$1.useState)(""), [queryText, setQueryText] = (0, react$1.useState)("");
|
|
191814
|
+
const [sort, setSort] = (0, react$1.useState)(() => readRecognizedSpeakerOrder(accountKey));
|
|
191815
|
+
const query = (0, react$1.useMemo)(() => ({
|
|
191816
|
+
filter,
|
|
191817
|
+
sort,
|
|
191818
|
+
query: queryText
|
|
191819
|
+
}), [
|
|
191820
|
+
filter,
|
|
191821
|
+
sort,
|
|
191822
|
+
queryText
|
|
191823
|
+
]);
|
|
191824
|
+
const [list, setList] = (0, react$1.useState)();
|
|
191825
|
+
const listRef = (0, react$1.useRef)(list);
|
|
191826
|
+
listRef.current = list;
|
|
191827
|
+
const [loading, setLoading] = (0, react$1.useState)(true), [moreLoading, setMoreLoading] = (0, react$1.useState)(false);
|
|
191828
|
+
const [error, setError] = (0, react$1.useState)(""), [seenError, setSeenError] = (0, react$1.useState)("");
|
|
191829
|
+
const [selected, setSelected] = (0, react$1.useState)();
|
|
191830
|
+
const [avatars, setAvatars] = (0, react$1.useState)({});
|
|
191831
|
+
const rootRef = (0, react$1.useRef)(null), listScroll = (0, react$1.useRef)(0), hadSelection = (0, react$1.useRef)(false);
|
|
191832
|
+
(0, react$1.useLayoutEffect)(() => {
|
|
191833
|
+
const root = rootRef.current;
|
|
191834
|
+
if (root && root.clientWidth <= 680) {
|
|
191835
|
+
if (selected && !hadSelection.current) {
|
|
191836
|
+
listScroll.current = root.scrollTop;
|
|
191837
|
+
root.scrollTop = 0;
|
|
191838
|
+
} else if (!selected && hadSelection.current) root.scrollTop = listScroll.current;
|
|
191839
|
+
}
|
|
191840
|
+
hadSelection.current = selected !== void 0;
|
|
191841
|
+
}, [selected]);
|
|
191842
|
+
const [revision, setRevision] = (0, react$1.useState)(0);
|
|
191843
|
+
const force = (0, react$1.useRef)(false), recoveryAttempts = (0, react$1.useRef)(0);
|
|
191844
|
+
const controllerRef = (0, react$1.useRef)();
|
|
191845
|
+
const snapshot = (0, react$1.useSyncExternalStore)(directory.subscribe, () => directory.get(accountKey), () => directory.get(accountKey));
|
|
191846
|
+
const summary = snapshot.summary;
|
|
191847
|
+
const queryValid = directoryQueryValid(input);
|
|
191848
|
+
const queryPending = normalizeDirectoryQuery(input) !== queryText;
|
|
191849
|
+
const listMatches = list?.query.filter === filter && list.query.sort === sort && list.query.query === queryText;
|
|
191632
191850
|
(0, react$1.useEffect)(() => {
|
|
191633
|
-
|
|
191851
|
+
if (!directory.hasPendingSeen(accountKey)) setSeenError("");
|
|
191634
191852
|
}, [
|
|
191853
|
+
directory,
|
|
191635
191854
|
accountKey,
|
|
191636
|
-
|
|
191637
|
-
query,
|
|
191638
|
-
order
|
|
191855
|
+
snapshot
|
|
191639
191856
|
]);
|
|
191857
|
+
(0, react$1.useEffect)(() => {
|
|
191858
|
+
const timer = setTimeout(() => setQueryText(normalizeDirectoryQuery(input)), 300);
|
|
191859
|
+
return () => clearTimeout(timer);
|
|
191860
|
+
}, [input]);
|
|
191861
|
+
const refresh = (0, react$1.useCallback)(() => {
|
|
191862
|
+
force.current = true;
|
|
191863
|
+
directory.invalidate(accountKey);
|
|
191864
|
+
setRevision((value) => value + 1);
|
|
191865
|
+
}, [directory, accountKey]);
|
|
191640
191866
|
(0, react$1.useEffect)(() => {
|
|
191641
191867
|
const controller = new AbortController();
|
|
191642
|
-
|
|
191643
|
-
|
|
191644
|
-
|
|
191645
|
-
|
|
191646
|
-
|
|
191647
|
-
|
|
191648
|
-
|
|
191649
|
-
|
|
191650
|
-
|
|
191651
|
-
|
|
191652
|
-
|
|
191653
|
-
|
|
191654
|
-
|
|
191655
|
-
|
|
191656
|
-
|
|
191657
|
-
|
|
191658
|
-
|
|
191659
|
-
|
|
191660
|
-
});
|
|
191661
|
-
setUnmarked({
|
|
191662
|
-
loading: true,
|
|
191663
|
-
complete: false,
|
|
191664
|
-
items: [],
|
|
191665
|
-
projectionState: void 0,
|
|
191666
|
-
error: ""
|
|
191667
|
-
});
|
|
191668
|
-
setOrderPreference({
|
|
191669
|
-
accountKey,
|
|
191670
|
-
value: readRecognizedSpeakerOrder(accountKey)
|
|
191671
|
-
});
|
|
191672
|
-
setQuery("");
|
|
191673
|
-
setSelectedMarked(void 0);
|
|
191674
|
-
setSelectedCandidate(void 0);
|
|
191675
|
-
}
|
|
191676
|
-
setMarked((previous) => ({
|
|
191677
|
-
...previous,
|
|
191678
|
-
loading: true,
|
|
191679
|
-
error: ""
|
|
191680
|
-
}));
|
|
191681
|
-
setPresence((previous) => ({
|
|
191682
|
-
...previous,
|
|
191683
|
-
loading: true,
|
|
191684
|
-
error: ""
|
|
191685
|
-
}));
|
|
191686
|
-
setUnmarked((previous) => ({
|
|
191687
|
-
...previous,
|
|
191688
|
-
loading: true,
|
|
191689
|
-
complete: false,
|
|
191690
|
-
error: ""
|
|
191691
|
-
}));
|
|
191692
|
-
const cachedMarked = directory.peekMarked(accountKey);
|
|
191693
|
-
if (cachedMarked !== void 0) setMarked({
|
|
191694
|
-
loading: false,
|
|
191695
|
-
items: cachedMarked,
|
|
191696
|
-
error: ""
|
|
191697
|
-
});
|
|
191698
|
-
const readMarked = () => {
|
|
191699
|
-
directory.readMarked(accountKey, controller.signal).then((items) => {
|
|
191700
|
-
if (!controller.signal.aborted) setMarked({
|
|
191701
|
-
loading: false,
|
|
191702
|
-
items,
|
|
191703
|
-
error: ""
|
|
191704
|
-
});
|
|
191705
|
-
}).catch((error) => {
|
|
191868
|
+
controllerRef.current = controller;
|
|
191869
|
+
let retry;
|
|
191870
|
+
let busy = false;
|
|
191871
|
+
const cached = directory.peek(accountKey, query);
|
|
191872
|
+
setList(cached);
|
|
191873
|
+
setSelected(void 0);
|
|
191874
|
+
setError("");
|
|
191875
|
+
setMoreLoading(false);
|
|
191876
|
+
const load = async () => {
|
|
191877
|
+
if (busy || !directoryVisible() || controller.signal.aborted) return;
|
|
191878
|
+
if (!directoryQueryValid(query.query)) {
|
|
191879
|
+
setLoading(false);
|
|
191880
|
+
return;
|
|
191881
|
+
}
|
|
191882
|
+
busy = true;
|
|
191883
|
+
setLoading(true);
|
|
191884
|
+
try {
|
|
191885
|
+
const result = await directory.first(accountKey, query, controller.signal, force.current);
|
|
191706
191886
|
if (!controller.signal.aborted) {
|
|
191707
|
-
|
|
191708
|
-
|
|
191709
|
-
|
|
191710
|
-
error: failureMessage(error)
|
|
191711
|
-
}));
|
|
191712
|
-
retry(error, readMarked);
|
|
191887
|
+
force.current = false;
|
|
191888
|
+
setList(result);
|
|
191889
|
+
setError("");
|
|
191713
191890
|
}
|
|
191714
|
-
})
|
|
191891
|
+
} catch (error) {
|
|
191892
|
+
if (controller.signal.aborted) return;
|
|
191893
|
+
setError(failureMessage(error));
|
|
191894
|
+
const delay = speakerRetryDelay(error);
|
|
191895
|
+
if (delay !== void 0) retry = setTimeout(() => {
|
|
191896
|
+
load();
|
|
191897
|
+
}, delay);
|
|
191898
|
+
} finally {
|
|
191899
|
+
busy = false;
|
|
191900
|
+
if (!controller.signal.aborted) setLoading(false);
|
|
191901
|
+
}
|
|
191715
191902
|
};
|
|
191716
|
-
|
|
191717
|
-
const
|
|
191718
|
-
|
|
191719
|
-
|
|
191720
|
-
|
|
191721
|
-
error: ""
|
|
191903
|
+
load();
|
|
191904
|
+
const unwatch = directory.watch(accountKey, () => {
|
|
191905
|
+
if (controller.signal.aborted) return;
|
|
191906
|
+
const current = listRef.current;
|
|
191907
|
+
if (!current || current.coverage === "unknown" || directory.needsReload(accountKey, current)) load();
|
|
191722
191908
|
});
|
|
191723
|
-
|
|
191724
|
-
|
|
191725
|
-
|
|
191726
|
-
|
|
191727
|
-
result,
|
|
191728
|
-
error: ""
|
|
191729
|
-
});
|
|
191730
|
-
}).catch((error) => {
|
|
191731
|
-
if (!controller.signal.aborted) {
|
|
191732
|
-
setPresence((previous) => ({
|
|
191733
|
-
...previous,
|
|
191734
|
-
loading: false,
|
|
191735
|
-
error: failureMessage(error)
|
|
191736
|
-
}));
|
|
191737
|
-
retry(error, readPresence);
|
|
191738
|
-
}
|
|
191739
|
-
});
|
|
191909
|
+
return () => {
|
|
191910
|
+
controller.abort();
|
|
191911
|
+
clearTimeout(retry);
|
|
191912
|
+
unwatch();
|
|
191740
191913
|
};
|
|
191741
|
-
|
|
191742
|
-
|
|
191743
|
-
|
|
191744
|
-
|
|
191745
|
-
|
|
191746
|
-
|
|
191747
|
-
|
|
191748
|
-
|
|
191749
|
-
|
|
191750
|
-
|
|
191751
|
-
|
|
191752
|
-
|
|
191753
|
-
|
|
191754
|
-
|
|
191755
|
-
loading: false,
|
|
191756
|
-
error: ""
|
|
191757
|
-
});
|
|
191758
|
-
}).catch((error) => {
|
|
191759
|
-
if (!controller.signal.aborted) {
|
|
191760
|
-
setUnmarked((previous) => ({
|
|
191761
|
-
...previous,
|
|
191762
|
-
loading: false,
|
|
191763
|
-
complete: false,
|
|
191764
|
-
error: failureMessage(error)
|
|
191765
|
-
}));
|
|
191766
|
-
retry(error, readCandidates);
|
|
191914
|
+
}, [
|
|
191915
|
+
accountKey,
|
|
191916
|
+
directory,
|
|
191917
|
+
query,
|
|
191918
|
+
revision
|
|
191919
|
+
]);
|
|
191920
|
+
(0, react$1.useEffect)(() => {
|
|
191921
|
+
if (!list || loading || queryPending || list.query.filter !== filter || list.query.query !== queryText) return;
|
|
191922
|
+
let disposed = false;
|
|
191923
|
+
const confirm = () => {
|
|
191924
|
+
if (directoryVisible()) directory.confirmDisplayed(accountKey, list).then(() => {
|
|
191925
|
+
if (!disposed) {
|
|
191926
|
+
setSeenError("");
|
|
191927
|
+
if (directory.needsReload(accountKey, list)) refresh();
|
|
191767
191928
|
}
|
|
191929
|
+
}).catch(() => {
|
|
191930
|
+
if (!disposed) setSeenError(tr$1("查看状态暂未同步,联网后自动重试。"));
|
|
191768
191931
|
});
|
|
191769
191932
|
};
|
|
191770
|
-
|
|
191933
|
+
confirm();
|
|
191934
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", confirm);
|
|
191771
191935
|
return () => {
|
|
191772
|
-
|
|
191773
|
-
|
|
191936
|
+
disposed = true;
|
|
191937
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", confirm);
|
|
191774
191938
|
};
|
|
191775
191939
|
}, [
|
|
191776
191940
|
accountKey,
|
|
191777
|
-
|
|
191778
|
-
|
|
191941
|
+
directory,
|
|
191942
|
+
list,
|
|
191943
|
+
loading,
|
|
191944
|
+
queryPending,
|
|
191945
|
+
filter,
|
|
191946
|
+
queryText,
|
|
191947
|
+
refresh
|
|
191779
191948
|
]);
|
|
191949
|
+
const recoverDetail = (0, react$1.useCallback)(() => {
|
|
191950
|
+
if (!selected || recoveryAttempts.current >= 1) {
|
|
191951
|
+
setSelected(void 0);
|
|
191952
|
+
refresh();
|
|
191953
|
+
return;
|
|
191954
|
+
}
|
|
191955
|
+
recoveryAttempts.current += 1;
|
|
191956
|
+
const controller = controllerRef.current;
|
|
191957
|
+
if (!controller) return;
|
|
191958
|
+
directory.first(accountKey, query, controller.signal, true).then((next) => {
|
|
191959
|
+
if (controller.signal.aborted) return;
|
|
191960
|
+
setList(next);
|
|
191961
|
+
setSelected(next.items.find((item) => item.personKey === selected.personKey));
|
|
191962
|
+
}).catch((error) => {
|
|
191963
|
+
if (!controller.signal.aborted) {
|
|
191964
|
+
setSelected(void 0);
|
|
191965
|
+
setError(failureMessage(error));
|
|
191966
|
+
}
|
|
191967
|
+
});
|
|
191968
|
+
}, [
|
|
191969
|
+
accountKey,
|
|
191970
|
+
directory,
|
|
191971
|
+
selected,
|
|
191972
|
+
query,
|
|
191973
|
+
refresh
|
|
191974
|
+
]);
|
|
191975
|
+
const loadMore = async () => {
|
|
191976
|
+
const controller = controllerRef.current;
|
|
191977
|
+
if (!list || !controller || moreLoading || queryPending) return;
|
|
191978
|
+
setMoreLoading(true);
|
|
191979
|
+
setError("");
|
|
191980
|
+
try {
|
|
191981
|
+
const next = await directory.more(accountKey, list, controller.signal);
|
|
191982
|
+
if (!controller.signal.aborted) setList(next);
|
|
191983
|
+
} catch (error) {
|
|
191984
|
+
if (!controller.signal.aborted) setError(failureMessage(error));
|
|
191985
|
+
} finally {
|
|
191986
|
+
if (!controller.signal.aborted) setMoreLoading(false);
|
|
191987
|
+
}
|
|
191988
|
+
};
|
|
191989
|
+
const disabled = summary?.state === "disabled" || list?.state === "disabled";
|
|
191990
|
+
const rows = disabled || queryPending || !listMatches ? [] : list?.items ?? [];
|
|
191991
|
+
const avatarBatch = JSON.stringify(rows.filter((row) => row.type === "marked" && avatars[row.detailRef] === void 0).slice(0, 50).map((row) => row.detailRef));
|
|
191780
191992
|
(0, react$1.useEffect)(() => {
|
|
191781
|
-
const
|
|
191782
|
-
if (
|
|
191993
|
+
const refs = JSON.parse(avatarBatch);
|
|
191994
|
+
if (refs.length === 0) return;
|
|
191783
191995
|
const controller = new AbortController();
|
|
191784
|
-
|
|
191785
|
-
|
|
191786
|
-
|
|
191787
|
-
|
|
191788
|
-
|
|
191789
|
-
|
|
191790
|
-
|
|
191791
|
-
|
|
191792
|
-
|
|
191996
|
+
let retry;
|
|
191997
|
+
let busy = false, retryAt = 0;
|
|
191998
|
+
const load = async () => {
|
|
191999
|
+
if (!directoryVisible() || controller.signal.aborted || busy) return;
|
|
192000
|
+
if (retryAt > Date.now()) {
|
|
192001
|
+
clearTimeout(retry);
|
|
192002
|
+
retry = setTimeout(() => {
|
|
192003
|
+
load();
|
|
192004
|
+
}, retryAt - Date.now());
|
|
192005
|
+
return;
|
|
192006
|
+
}
|
|
192007
|
+
busy = true;
|
|
192008
|
+
try {
|
|
192009
|
+
const result = await directory.avatars(accountKey, refs, controller.signal);
|
|
192010
|
+
if (controller.signal.aborted) return;
|
|
192011
|
+
const resolved = new Map(result.map((item) => [item.detailRef, item.avatarRef]));
|
|
192012
|
+
setAvatars((previous) => ({
|
|
191793
192013
|
...previous,
|
|
191794
|
-
|
|
191795
|
-
error: failureMessage(error)
|
|
192014
|
+
...Object.fromEntries(refs.map((ref) => [ref, resolved.get(ref) || null]))
|
|
191796
192015
|
}));
|
|
191797
|
-
})
|
|
191798
|
-
|
|
192016
|
+
} catch (error) {
|
|
192017
|
+
if (controller.signal.aborted) return;
|
|
192018
|
+
const delay = speakerRetryDelay(error);
|
|
192019
|
+
if (delay !== void 0) {
|
|
192020
|
+
retryAt = Date.now() + Math.max(15e3, delay);
|
|
192021
|
+
retry = setTimeout(() => {
|
|
192022
|
+
load();
|
|
192023
|
+
}, retryAt - Date.now());
|
|
192024
|
+
}
|
|
192025
|
+
} finally {
|
|
192026
|
+
busy = false;
|
|
192027
|
+
}
|
|
192028
|
+
};
|
|
192029
|
+
const wake = () => {
|
|
192030
|
+
clearTimeout(retry);
|
|
192031
|
+
load();
|
|
192032
|
+
};
|
|
192033
|
+
load();
|
|
192034
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", wake);
|
|
192035
|
+
if (typeof window !== "undefined") window.addEventListener("online", wake);
|
|
191799
192036
|
return () => {
|
|
191800
|
-
clearTimeout(timer);
|
|
191801
192037
|
controller.abort();
|
|
192038
|
+
clearTimeout(retry);
|
|
192039
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", wake);
|
|
192040
|
+
if (typeof window !== "undefined") window.removeEventListener("online", wake);
|
|
191802
192041
|
};
|
|
191803
192042
|
}, [
|
|
191804
192043
|
accountKey,
|
|
191805
|
-
refreshRevision,
|
|
191806
192044
|
directory,
|
|
191807
|
-
|
|
191808
|
-
presence.error,
|
|
191809
|
-
presence.result
|
|
191810
|
-
]);
|
|
191811
|
-
const refreshPresenceVersion = (0, react$1.useCallback)(() => {
|
|
191812
|
-
setPresence({
|
|
191813
|
-
loading: false,
|
|
191814
|
-
result: {
|
|
191815
|
-
state: "stale",
|
|
191816
|
-
scope: "all-history",
|
|
191817
|
-
items: [],
|
|
191818
|
-
retryAfterMs: 1e3
|
|
191819
|
-
},
|
|
191820
|
-
error: ""
|
|
191821
|
-
});
|
|
191822
|
-
}, []);
|
|
191823
|
-
const rows = (0, react$1.useMemo)(() => identifiedSpeakerRows(marked.items, unmarked.items), [marked.items, unmarked.items]);
|
|
191824
|
-
const hasSelf = rows.some((row) => row.kind === "marked" && row.isCurrentUser);
|
|
191825
|
-
(0, react$1.useEffect)(() => {
|
|
191826
|
-
if (readAccount.current !== accountKey || marked.loading || marked.error !== "") return;
|
|
191827
|
-
if (rows.length > 0 || !unmarked.loading && unmarked.complete) recognizedSpeakerTracker.acknowledge(accountKey);
|
|
191828
|
-
if (!unmarked.loading && unmarked.complete && unmarked.error === "") recognizedSpeakerTracker.observe(accountKey, marked.items, unmarked.items, true);
|
|
191829
|
-
}, [
|
|
191830
|
-
accountKey,
|
|
191831
|
-
marked.loading,
|
|
191832
|
-
marked.error,
|
|
191833
|
-
marked.items,
|
|
191834
|
-
unmarked.loading,
|
|
191835
|
-
unmarked.complete,
|
|
191836
|
-
unmarked.error,
|
|
191837
|
-
unmarked.items,
|
|
191838
|
-
rows.length
|
|
192045
|
+
avatarBatch
|
|
191839
192046
|
]);
|
|
191840
|
-
const
|
|
191841
|
-
const
|
|
191842
|
-
const
|
|
191843
|
-
const stat = row.kind === "marked" ? presenceByOption.get(row.optionKey) : unmarked.projectionState === void 0 || unmarked.projectionState === "fresh" ? row : void 0;
|
|
191844
|
-
return {
|
|
191845
|
-
key: `${row.kind}:${row.key}`,
|
|
191846
|
-
name: row.name,
|
|
191847
|
-
dayCount: stat?.dayCount,
|
|
191848
|
-
lastSeenAt: stat?.lastSeenAt
|
|
191849
|
-
};
|
|
191850
|
-
};
|
|
191851
|
-
const visible = rows.filter((row) => (filter === "all" || row.kind === filter) && (normalizedQuery === "" || row.name.toLocaleLowerCase().includes(normalizedQuery) || row.kind === "unmarked" && row.subtitle.toLocaleLowerCase().includes(normalizedQuery))).sort((left, right) => Number(right.kind === "marked" && right.isCurrentUser) - Number(left.kind === "marked" && left.isCurrentUser) || compareRecognizedSpeakers(orderValue(left), orderValue(right), order));
|
|
191852
|
-
const loading = marked.loading || unmarked.loading;
|
|
192047
|
+
const state = disabled ? tr$1("说话人目录暂不可用,请稍后再试。") : statusText(summary?.snapshotVersion === list?.snapshotVersion ? summary : list?.coverage === "complete" ? list : summary);
|
|
192048
|
+
const hasNewVersion = list?.coverage === "complete" && summary?.snapshotVersion && summary.snapshotVersion !== list.snapshotVersion;
|
|
192049
|
+
const selfMissing = listMatches && filter === "all" && queryText === "" && !queryPending && list?.coverage === "complete" && list.state === "fresh" && !list.items.some((row) => row.isSelf);
|
|
191853
192050
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192051
|
+
ref: rootRef,
|
|
191854
192052
|
style: styles$20.root,
|
|
191855
192053
|
"data-arkme-owned": "recognized-speakers-surface",
|
|
191856
192054
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
|
|
@@ -191890,6 +192088,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191890
192088
|
marginLeft: "auto"
|
|
191891
192089
|
},
|
|
191892
192090
|
onClick: refresh,
|
|
192091
|
+
disabled: loading,
|
|
191893
192092
|
children: tr$1("刷新")
|
|
191894
192093
|
})
|
|
191895
192094
|
]
|
|
@@ -191898,41 +192097,44 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191898
192097
|
style: styles$20.filters,
|
|
191899
192098
|
children: [
|
|
191900
192099
|
[
|
|
191901
|
-
[
|
|
191902
|
-
|
|
191903
|
-
|
|
191904
|
-
|
|
192100
|
+
[
|
|
192101
|
+
"all",
|
|
192102
|
+
"全部",
|
|
192103
|
+
summary?.totalCount
|
|
192104
|
+
],
|
|
192105
|
+
[
|
|
192106
|
+
"marked",
|
|
192107
|
+
"已标记",
|
|
192108
|
+
summary?.markedCount
|
|
192109
|
+
],
|
|
192110
|
+
[
|
|
192111
|
+
"unmarked",
|
|
192112
|
+
"未标记",
|
|
192113
|
+
summary?.unmarkedCount
|
|
192114
|
+
]
|
|
192115
|
+
].map(([kind, label, count]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
191905
192116
|
type: "button",
|
|
191906
192117
|
"aria-pressed": filter === kind,
|
|
191907
192118
|
style: {
|
|
191908
192119
|
...styles$20.filter,
|
|
191909
192120
|
...filter === kind ? styles$20.selectedFilter : {}
|
|
191910
192121
|
},
|
|
191911
|
-
onClick: () =>
|
|
191912
|
-
|
|
191913
|
-
setSelectedCandidate(void 0);
|
|
191914
|
-
setSelectedMarked(void 0);
|
|
191915
|
-
},
|
|
191916
|
-
children: tr$1(label)
|
|
192122
|
+
onClick: () => setFilter(kind),
|
|
192123
|
+
children: [tr$1(label), !disabled && count != null ? ` ${count}` : ""]
|
|
191917
192124
|
}, kind)),
|
|
191918
192125
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
191919
192126
|
"aria-label": tr$1("搜索说话人"),
|
|
191920
|
-
placeholder: tr$1("
|
|
191921
|
-
value:
|
|
191922
|
-
onChange: (event) =>
|
|
191923
|
-
setQuery(event.target.value);
|
|
191924
|
-
},
|
|
192127
|
+
placeholder: tr$1("搜索名称或编号"),
|
|
192128
|
+
value: input,
|
|
192129
|
+
onChange: (event) => setInput(event.target.value),
|
|
191925
192130
|
style: styles$20.search
|
|
191926
192131
|
}),
|
|
191927
192132
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
191928
192133
|
"aria-label": tr$1("说话人排序"),
|
|
191929
|
-
value:
|
|
192134
|
+
value: sort,
|
|
191930
192135
|
onChange: (event) => {
|
|
191931
192136
|
const next = event.target.value === "recent" ? "recent" : "frequent";
|
|
191932
|
-
|
|
191933
|
-
accountKey,
|
|
191934
|
-
value: next
|
|
191935
|
-
});
|
|
192137
|
+
setSort(next);
|
|
191936
192138
|
writeRecognizedSpeakerOrder(accountKey, next);
|
|
191937
192139
|
},
|
|
191938
192140
|
style: styles$20.sort,
|
|
@@ -191946,186 +192148,115 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
191946
192148
|
})
|
|
191947
192149
|
]
|
|
191948
192150
|
}),
|
|
191949
|
-
!
|
|
192151
|
+
!queryValid && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192152
|
+
role: "alert",
|
|
192153
|
+
style: styles$20.error,
|
|
192154
|
+
children: tr$1("搜索内容过长,请缩短至 256 字节以内。")
|
|
192155
|
+
}),
|
|
192156
|
+
selfMissing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SpeakerSelfGuide, { onOpenRecordings: onBack }, accountKey),
|
|
192157
|
+
hasNewVersion && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192158
|
+
role: "status",
|
|
192159
|
+
style: styles$20.note,
|
|
192160
|
+
children: tr$1("目录有更新,刷新后查看最新人物。")
|
|
192161
|
+
}),
|
|
192162
|
+
state && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192163
|
+
role: "status",
|
|
192164
|
+
style: styles$20.note,
|
|
192165
|
+
children: state
|
|
192166
|
+
}),
|
|
192167
|
+
seenError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
192168
|
+
role: "status",
|
|
192169
|
+
style: styles$20.note,
|
|
192170
|
+
children: seenError
|
|
192171
|
+
}),
|
|
192172
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192173
|
+
role: "alert",
|
|
192174
|
+
style: styles$20.error,
|
|
192175
|
+
children: error
|
|
192176
|
+
}),
|
|
191950
192177
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
191951
192178
|
className: "arkme-recognized-speakers-grid",
|
|
191952
|
-
"data-detail-open":
|
|
191953
|
-
children: [
|
|
191954
|
-
|
|
191955
|
-
|
|
191956
|
-
|
|
191957
|
-
|
|
191958
|
-
|
|
191959
|
-
|
|
191960
|
-
|
|
191961
|
-
|
|
191962
|
-
|
|
191963
|
-
|
|
191964
|
-
|
|
191965
|
-
|
|
191966
|
-
|
|
191967
|
-
marked.error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
191968
|
-
role: "alert",
|
|
191969
|
-
style: styles$20.error,
|
|
191970
|
-
children: [
|
|
191971
|
-
tr$1("已标记说话人读取失败:"),
|
|
191972
|
-
" ",
|
|
191973
|
-
marked.error
|
|
191974
|
-
]
|
|
191975
|
-
}),
|
|
191976
|
-
unmarked.error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
191977
|
-
role: "alert",
|
|
191978
|
-
style: styles$20.error,
|
|
191979
|
-
children: [
|
|
191980
|
-
tr$1("未标记说话人读取失败:"),
|
|
191981
|
-
" ",
|
|
191982
|
-
unmarked.error
|
|
191983
|
-
]
|
|
191984
|
-
}),
|
|
191985
|
-
unmarked.projectionState === "building" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191986
|
-
role: "status",
|
|
191987
|
-
style: styles$20.state,
|
|
191988
|
-
children: tr$1("未标记说话人正在整理,结果可能不完整。")
|
|
191989
|
-
}),
|
|
191990
|
-
unmarked.projectionState === "stale" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191991
|
-
role: "status",
|
|
191992
|
-
style: styles$20.state,
|
|
191993
|
-
children: tr$1("未标记说话人正在更新,结果可能不完整。")
|
|
191994
|
-
}),
|
|
191995
|
-
unmarked.projectionState === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
191996
|
-
role: "alert",
|
|
191997
|
-
style: styles$20.error,
|
|
191998
|
-
children: tr$1("未标记说话人整理失败,请稍后刷新。")
|
|
191999
|
-
}),
|
|
192000
|
-
loading && rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192001
|
-
role: "status",
|
|
192002
|
-
style: styles$20.state,
|
|
192003
|
-
children: tr$1("正在加载说话人…")
|
|
192004
|
-
}) : visible.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192005
|
-
role: "status",
|
|
192006
|
-
style: styles$20.state,
|
|
192007
|
-
children: loading ? tr$1("正在更新说话人…") : rows.length === 0 && marked.error === "" && unmarked.error === "" && (unmarked.projectionState === void 0 || unmarked.projectionState === "fresh") ? tr$1("暂无已识别说话人") : tr$1("暂无可显示的说话人")
|
|
192008
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
192009
|
-
style: styles$20.list,
|
|
192010
|
-
children: visible.slice(0, visibleCount).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: row.kind === "unmarked" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
192011
|
-
type: "button",
|
|
192012
|
-
className: "arkme-recognized-speakers-row",
|
|
192013
|
-
"aria-current": selectedCandidate === row.candidateRef ? "true" : void 0,
|
|
192014
|
-
style: {
|
|
192015
|
-
...styles$20.row,
|
|
192016
|
-
cursor: "pointer"
|
|
192017
|
-
},
|
|
192018
|
-
onClick: () => {
|
|
192019
|
-
setSelectedCandidate(row.candidateRef);
|
|
192020
|
-
setSelectedMarked(void 0);
|
|
192021
|
-
},
|
|
192022
|
-
children: [
|
|
192023
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerTokenAvatar, {
|
|
192024
|
-
token: row.token,
|
|
192025
|
-
size: 38,
|
|
192026
|
-
label: row.name
|
|
192027
|
-
}),
|
|
192028
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192029
|
-
style: styles$20.copy,
|
|
192030
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192031
|
-
style: styles$20.name,
|
|
192032
|
-
children: row.name
|
|
192033
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192034
|
-
style: styles$20.meta,
|
|
192035
|
-
children: row.subtitle
|
|
192036
|
-
})]
|
|
192037
|
-
}),
|
|
192038
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192039
|
-
style: styles$20.badge,
|
|
192040
|
-
children: [tr$1("未标记"), " ›"]
|
|
192041
|
-
})
|
|
192042
|
-
]
|
|
192043
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
192044
|
-
type: "button",
|
|
192045
|
-
className: "arkme-recognized-speakers-row",
|
|
192046
|
-
"aria-current": selectedMarked?.key === row.key ? "true" : void 0,
|
|
192047
|
-
style: {
|
|
192048
|
-
...styles$20.row,
|
|
192049
|
-
cursor: "pointer"
|
|
192050
|
-
},
|
|
192051
|
-
onClick: () => {
|
|
192052
|
-
setSelectedMarked(row);
|
|
192053
|
-
setSelectedCandidate(void 0);
|
|
192054
|
-
},
|
|
192055
|
-
children: [
|
|
192056
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeUserAvatar, {
|
|
192057
|
-
...row.avatarRef === void 0 ? {} : { avatarRef: row.avatarRef },
|
|
192058
|
-
size: 38,
|
|
192059
|
-
label: row.name
|
|
192060
|
-
}),
|
|
192061
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192062
|
-
style: styles$20.copy,
|
|
192063
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192064
|
-
style: styles$20.name,
|
|
192065
|
-
children: [row.name, row.isCurrentUser ? ` · ${tr$1("我")}` : ""]
|
|
192066
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192067
|
-
style: styles$20.meta,
|
|
192068
|
-
children: markedPresenceLabel(presenceByOption.get(row.optionKey), presence.result, presence.loading, presence.error)
|
|
192069
|
-
})]
|
|
192070
|
-
}),
|
|
192071
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192072
|
-
style: styles$20.badge,
|
|
192073
|
-
children: [tr$1("已标记"), " ›"]
|
|
192074
|
-
})
|
|
192075
|
-
]
|
|
192076
|
-
}) }, `${row.kind}:${row.key}`))
|
|
192077
|
-
}),
|
|
192078
|
-
visible.length > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192079
|
-
type: "button",
|
|
192080
|
-
style: {
|
|
192081
|
-
...styles$20.button,
|
|
192082
|
-
marginTop: 14
|
|
192083
|
-
},
|
|
192084
|
-
onClick: () => {
|
|
192085
|
-
setVisibleCount((count) => count + 100);
|
|
192086
|
-
},
|
|
192087
|
-
children: tr$1("显示更多说话人")
|
|
192088
|
-
})
|
|
192089
|
-
]
|
|
192090
|
-
}),
|
|
192091
|
-
selectedCandidate !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192092
|
-
style: styles$20.detail,
|
|
192093
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192179
|
+
"data-detail-open": selected !== void 0 ? "true" : "false",
|
|
192180
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192181
|
+
className: "arkme-recognized-speakers-list",
|
|
192182
|
+
"aria-busy": loading || queryPending,
|
|
192183
|
+
children: [!disabled && (loading || queryPending) && rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192184
|
+
role: "status",
|
|
192185
|
+
style: styles$20.state,
|
|
192186
|
+
children: tr$1("正在加载说话人…")
|
|
192187
|
+
}) : !disabled && !error && rows.length === 0 && list?.coverage === "complete" && !queryPending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
192188
|
+
role: "status",
|
|
192189
|
+
style: styles$20.state,
|
|
192190
|
+
children: tr$1(queryText ? "没有匹配的说话人" : filter === "all" ? "暂无已识别说话人" : "该分类暂无说话人")
|
|
192191
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
192192
|
+
style: styles$20.list,
|
|
192193
|
+
children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
192094
192194
|
type: "button",
|
|
192095
|
-
className: "arkme-recognized-speakers-
|
|
192096
|
-
|
|
192097
|
-
|
|
192098
|
-
|
|
192195
|
+
className: "arkme-recognized-speakers-row",
|
|
192196
|
+
"aria-current": selected?.personKey === row.personKey ? "true" : void 0,
|
|
192197
|
+
style: {
|
|
192198
|
+
...styles$20.row,
|
|
192199
|
+
cursor: "pointer"
|
|
192099
192200
|
},
|
|
192100
|
-
children: tr$1("‹ 返回列表")
|
|
192101
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerDetail, {
|
|
192102
|
-
accountKey,
|
|
192103
|
-
candidateRef: selectedCandidate,
|
|
192104
|
-
onDirectoryRefresh: refresh,
|
|
192105
|
-
onCandidateCleared: () => {
|
|
192106
|
-
setSelectedCandidate(void 0);
|
|
192107
|
-
}
|
|
192108
|
-
}, `${accountKey}:${selectedCandidate}`)]
|
|
192109
|
-
}),
|
|
192110
|
-
selectedMarked !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192111
|
-
style: styles$20.detail,
|
|
192112
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192113
|
-
type: "button",
|
|
192114
|
-
className: "arkme-recognized-speakers-mobile-back",
|
|
192115
|
-
style: styles$20.button,
|
|
192116
192201
|
onClick: () => {
|
|
192117
|
-
|
|
192202
|
+
recoveryAttempts.current = 0;
|
|
192203
|
+
setSelected(row);
|
|
192118
192204
|
},
|
|
192119
|
-
children:
|
|
192120
|
-
|
|
192121
|
-
|
|
192122
|
-
|
|
192123
|
-
|
|
192124
|
-
|
|
192125
|
-
|
|
192126
|
-
|
|
192127
|
-
|
|
192128
|
-
|
|
192205
|
+
children: [
|
|
192206
|
+
row.type === "unmarked" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UnmarkedSpeakerTokenAvatar, {
|
|
192207
|
+
token: row.displayNumber > 0 ? String(row.displayNumber) : "",
|
|
192208
|
+
size: 38,
|
|
192209
|
+
label: row.displayName
|
|
192210
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeUserAvatar, {
|
|
192211
|
+
...avatars[row.detailRef] ? { avatarRef: avatars[row.detailRef] } : {},
|
|
192212
|
+
fallbackContent: speakerNameAvatarFallback(row),
|
|
192213
|
+
size: 38,
|
|
192214
|
+
label: row.displayName
|
|
192215
|
+
}),
|
|
192216
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192217
|
+
style: styles$20.copy,
|
|
192218
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192219
|
+
style: styles$20.name,
|
|
192220
|
+
children: [row.displayName, row.isSelf ? ` · ${tr$1("我")}` : ""]
|
|
192221
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
192222
|
+
style: styles$20.meta,
|
|
192223
|
+
children: personStats(row)
|
|
192224
|
+
})]
|
|
192225
|
+
}),
|
|
192226
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
192227
|
+
style: styles$20.badge,
|
|
192228
|
+
children: [tr$1(row.type === "marked" ? "已标记" : "未标记"), " ›"]
|
|
192229
|
+
})
|
|
192230
|
+
]
|
|
192231
|
+
}) }, row.personKey))
|
|
192232
|
+
}), !disabled && !queryPending && list?.hasMore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192233
|
+
type: "button",
|
|
192234
|
+
disabled: moreLoading || loading,
|
|
192235
|
+
style: {
|
|
192236
|
+
...styles$20.button,
|
|
192237
|
+
marginTop: 14
|
|
192238
|
+
},
|
|
192239
|
+
onClick: () => {
|
|
192240
|
+
loadMore();
|
|
192241
|
+
},
|
|
192242
|
+
children: tr$1(moreLoading ? "正在加载…" : "加载更多说话人")
|
|
192243
|
+
})]
|
|
192244
|
+
}), selected && !disabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192245
|
+
style: styles$20.detail,
|
|
192246
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
192247
|
+
type: "button",
|
|
192248
|
+
className: "arkme-recognized-speakers-mobile-back",
|
|
192249
|
+
style: styles$20.button,
|
|
192250
|
+
onClick: () => setSelected(void 0),
|
|
192251
|
+
children: tr$1("‹ 返回列表")
|
|
192252
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonDetail, {
|
|
192253
|
+
row: selected,
|
|
192254
|
+
accountKey,
|
|
192255
|
+
directory,
|
|
192256
|
+
loadMembers: loadMarkedMembers,
|
|
192257
|
+
onChanged: recoverDetail
|
|
192258
|
+
}, selected.detailRef)]
|
|
192259
|
+
})]
|
|
192129
192260
|
})
|
|
192130
192261
|
]
|
|
192131
192262
|
})]
|
|
@@ -212533,7 +212664,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
212533
212664
|
const c$3 = e$20;
|
|
212534
212665
|
//#endregion
|
|
212535
212666
|
//#region package.json
|
|
212536
|
-
var version = "0.1.
|
|
212667
|
+
var version = "0.1.87";
|
|
212537
212668
|
//#endregion
|
|
212538
212669
|
//#region src/client/arkme-membership.ts
|
|
212539
212670
|
function membershipLabel(state) {
|
|
@@ -234417,7 +234548,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
234417
234548
|
return result;
|
|
234418
234549
|
}, { signal }), controller.signal);
|
|
234419
234550
|
page = refreshWindow === void 0 ? await readPage(cursor) : await readConversationTimelineWindow(refreshWindow, readPage, controller.signal);
|
|
234420
|
-
if (refreshWindow === void 0 && intent !== "return-to-latest") await prepareTimelineReactions(page.items, controller.signal);
|
|
234421
234551
|
} catch (caught) {
|
|
234422
234552
|
if (isArkmeRequestAbort(caught, controller.signal)) return;
|
|
234423
234553
|
throw caught;
|
|
@@ -234510,7 +234640,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
234510
234640
|
acknowledgeRead,
|
|
234511
234641
|
confirmedSendRetention,
|
|
234512
234642
|
interwovenMoments,
|
|
234513
|
-
prepareTimelineReactions,
|
|
234514
234643
|
source,
|
|
234515
234644
|
sourceIsChat,
|
|
234516
234645
|
sourceProjectionRevision
|
|
@@ -236422,6 +236551,43 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
236422
236551
|
return projected.isMuted === true;
|
|
236423
236552
|
}, [updateSourceProjection]);
|
|
236424
236553
|
const conversationMemberByRef = (0, react$1.useMemo)(() => new Map(conversationMembers.map((member) => [member.memberRef, member])), [conversationMembers]);
|
|
236554
|
+
const localReactionActors = (0, react$1.useMemo)(() => {
|
|
236555
|
+
const names = /* @__PURE__ */ new Map();
|
|
236556
|
+
for (const item of items) if (item.memberRef && !item.selfRole && item.senderKind !== "bot") names.set(item.memberRef, {
|
|
236557
|
+
displayName: arkmeTimelineSenderName(item, selfProfile),
|
|
236558
|
+
...item.avatarRef ? { avatarRef: item.avatarRef } : {}
|
|
236559
|
+
});
|
|
236560
|
+
for (const member of conversationMembers) if (member.status === "active" && member.displayName.trim() && member.displayName !== "群成员") names.set(member.memberRef, {
|
|
236561
|
+
displayName: member.displayName,
|
|
236562
|
+
...member.avatarRef ? { avatarRef: member.avatarRef } : {}
|
|
236563
|
+
});
|
|
236564
|
+
return names;
|
|
236565
|
+
}, [
|
|
236566
|
+
items,
|
|
236567
|
+
selfProfile,
|
|
236568
|
+
conversationMembers
|
|
236569
|
+
]);
|
|
236570
|
+
const resolveReactionActor = (0, react$1.useCallback)((actor) => {
|
|
236571
|
+
const self = conversationMembers.find((member) => member.isSelf);
|
|
236572
|
+
const local = actor.userId === authenticatedUserId ? {
|
|
236573
|
+
displayName: (source?.kind === "group_chat" ? self?.memberName : void 0) || selfProfile?.displayName || selfProfile?.nickname || "我",
|
|
236574
|
+
...selfProfile?.avatarRef ? { avatarRef: selfProfile.avatarRef } : {}
|
|
236575
|
+
} : source?.kind === "private_chat" && actor.userId === source.peerUserId ? {
|
|
236576
|
+
displayName: source.displayName,
|
|
236577
|
+
...source.avatarRef ? { avatarRef: source.avatarRef } : {}
|
|
236578
|
+
} : actor.memberRef ? localReactionActors.get(actor.memberRef) : void 0;
|
|
236579
|
+
return local ? {
|
|
236580
|
+
...actor,
|
|
236581
|
+
...local,
|
|
236582
|
+
presentationPending: false
|
|
236583
|
+
} : void 0;
|
|
236584
|
+
}, [
|
|
236585
|
+
authenticatedUserId,
|
|
236586
|
+
source,
|
|
236587
|
+
selfProfile,
|
|
236588
|
+
conversationMembers,
|
|
236589
|
+
localReactionActors
|
|
236590
|
+
]);
|
|
236425
236591
|
const composerMentionsEnabled = source?.kind === "group_chat" || source?.kind === "private_chat";
|
|
236426
236592
|
const mentionCandidates = (0, react$1.useMemo)(() => {
|
|
236427
236593
|
if (!composerMentionsEnabled || mentionTrigger === void 0) return [];
|
|
@@ -238971,6 +239137,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
238971
239137
|
},
|
|
238972
239138
|
children: [!isSharedRecordingCard && !isExtensionMessage && messageHeader, (() => {
|
|
238973
239139
|
const reactionTarget = {
|
|
239140
|
+
resolveActor: resolveReactionActor,
|
|
238974
239141
|
sourceKey: source.sourceKey,
|
|
238975
239142
|
itemUid: item.itemUid,
|
|
238976
239143
|
id: `${conversationKey}:${arkmeTimelineOccurrenceKey(item)}`,
|
|
@@ -239215,6 +239382,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
239215
239382
|
selfProfile,
|
|
239216
239383
|
selfConversationMember,
|
|
239217
239384
|
conversationMemberByRef,
|
|
239385
|
+
resolveReactionActor,
|
|
239218
239386
|
activeSelectMode,
|
|
239219
239387
|
archiveReadOnly,
|
|
239220
239388
|
authenticatedAccountKey,
|
|
@@ -241885,7 +242053,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
241885
242053
|
};
|
|
241886
242054
|
});
|
|
241887
242055
|
const foreground = arkmeRealtimeTimelineDeliveryAllowed(browserDocument?.visibilityState, browserDocument?.hasFocus?.() ?? true);
|
|
241888
|
-
if (
|
|
242056
|
+
if (timelineUpdates.length > 0) arkmeChatTimelineDelta.publish(timelineUpdates);
|
|
241889
242057
|
for (const dateStamp of arkmeChatDeltaCalendarDateStamps(update)) arkmeCalendarInvalidations.publish({ dateStamp });
|
|
241890
242058
|
if (foreground && arkmeSelectedBotAffectedByChatDelta(arkmeUi.getSnapshot().selectedBot, update)) arkmeUi.chatChanged();
|
|
241891
242059
|
for (const sourceKey of arkmeChatDeltaSourceKeys(update)) arkmeInterwovenInvalidation.invalidate(sourceKey);
|