@senguoyun/dsh-arkme 0.1.85 → 0.1.86
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/self-role-avatar-cache.md +59 -0
- package/lib/client.js +460 -116
- 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 +22 -9
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-adGFmkIa.js → persistent-runtime-DfmCJcxH.js} +412 -121
- package/lib/sdk.js +14 -0
- package/lib/types/arkme-service.d.ts +1 -0
- package/lib/types/arkme-service.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/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/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/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/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/service.d.ts +1 -0
- package/lib/types/services/service.d.ts.map +1 -1
- 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 +1 -0
- 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}`;
|
|
@@ -54565,84 +54579,15 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54565
54579
|
});
|
|
54566
54580
|
}
|
|
54567
54581
|
//#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
54582
|
//#region src/client/avatar-image-store.ts
|
|
54583
|
+
/** These references identify immutable bytes, unlike mutable profile references. */
|
|
54584
|
+
function isImmutableAvatarRef(ref) {
|
|
54585
|
+
return /^file_asset:\/\/[A-Za-z0-9_-]{8,128}$/.test(ref) || /^arkme-self-role-image-v1\.[A-Za-z0-9_-]+$/.test(ref);
|
|
54586
|
+
}
|
|
54643
54587
|
const DEFAULT_TTL_MILLIS = 600 * 1e3;
|
|
54644
54588
|
const DEFAULT_JITTER_MILLIS$1 = 120 * 1e3;
|
|
54645
|
-
const DEFAULT_CONCURRENCY =
|
|
54589
|
+
const DEFAULT_CONCURRENCY = 3;
|
|
54590
|
+
const IMMUTABLE_CONCURRENCY = 2;
|
|
54646
54591
|
const MAX_RETAINED_AVATARS = 256;
|
|
54647
54592
|
const MAX_QUEUED_AVATARS = 512;
|
|
54648
54593
|
const AVATAR_IMAGE_SCOPE_CHANGED = "Avatar image scope changed";
|
|
@@ -54656,6 +54601,8 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54656
54601
|
jitterMillis;
|
|
54657
54602
|
concurrency;
|
|
54658
54603
|
activeDownloads = 0;
|
|
54604
|
+
activeImmutableReads = 0;
|
|
54605
|
+
activeCacheProbes = 0;
|
|
54659
54606
|
generation = 0;
|
|
54660
54607
|
scopeKey;
|
|
54661
54608
|
constructor(options) {
|
|
@@ -54709,10 +54656,26 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54709
54656
|
expiresAtMillis: 0,
|
|
54710
54657
|
pending: void 0
|
|
54711
54658
|
};
|
|
54712
|
-
const
|
|
54659
|
+
const readRemote = () => this.schedule(isImmutableAvatarRef(imageRef) ? "immutable" : "remote", async () => {
|
|
54713
54660
|
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54714
54661
|
return await this.options.reader(imageRef);
|
|
54715
|
-
})
|
|
54662
|
+
});
|
|
54663
|
+
const persistent = scopeKey !== void 0 && isImmutableAvatarRef(imageRef) ? this.options.persistentCache : void 0;
|
|
54664
|
+
const probe = isImmutableAvatarRef(imageRef) ? this.options.cachedReader : void 0;
|
|
54665
|
+
const pending = (persistent === void 0 && probe === void 0 ? readRemote() : (async () => {
|
|
54666
|
+
const cached = await persistent?.read(scopeKey, imageRef).catch(() => void 0);
|
|
54667
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54668
|
+
if (cached !== void 0) return cached;
|
|
54669
|
+
const local = probe === void 0 ? void 0 : await this.schedule("probe", async () => {
|
|
54670
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54671
|
+
return await probe(imageRef);
|
|
54672
|
+
});
|
|
54673
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54674
|
+
const payload = local ?? await readRemote();
|
|
54675
|
+
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54676
|
+
persistent?.write(scopeKey, imageRef, payload).catch(() => void 0);
|
|
54677
|
+
return payload;
|
|
54678
|
+
})()).then((payload) => {
|
|
54716
54679
|
if (generation !== this.generation) throw new Error(AVATAR_IMAGE_SCOPE_CHANGED);
|
|
54717
54680
|
const value = `data:${payload.mediaType};base64,${payload.dataBase64}`;
|
|
54718
54681
|
const previousValue = entry.value;
|
|
@@ -54751,27 +54714,35 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54751
54714
|
if (entry.pending === void 0 && !this.listeners.has(ref)) this.entries.delete(ref);
|
|
54752
54715
|
}
|
|
54753
54716
|
}
|
|
54754
|
-
schedule(load) {
|
|
54717
|
+
schedule(lane, load) {
|
|
54755
54718
|
return new Promise((resolve, reject) => {
|
|
54756
54719
|
if (this.queue.length >= MAX_QUEUED_AVATARS) {
|
|
54757
54720
|
reject(/* @__PURE__ */ new Error("Avatar loading queue is full"));
|
|
54758
54721
|
return;
|
|
54759
54722
|
}
|
|
54760
|
-
this.queue.push(
|
|
54761
|
-
|
|
54762
|
-
|
|
54763
|
-
|
|
54764
|
-
|
|
54723
|
+
this.queue.push({
|
|
54724
|
+
lane,
|
|
54725
|
+
start: () => {
|
|
54726
|
+
load().then(resolve, reject).finally(() => {
|
|
54727
|
+
if (lane === "probe") this.activeCacheProbes -= 1;
|
|
54728
|
+
else if (lane === "immutable") this.activeImmutableReads -= 1;
|
|
54729
|
+
else this.activeDownloads -= 1;
|
|
54730
|
+
this.drainQueue();
|
|
54731
|
+
});
|
|
54732
|
+
}
|
|
54765
54733
|
});
|
|
54766
54734
|
this.drainQueue();
|
|
54767
54735
|
});
|
|
54768
54736
|
}
|
|
54769
54737
|
drainQueue() {
|
|
54770
|
-
|
|
54771
|
-
const
|
|
54772
|
-
if (
|
|
54773
|
-
this.
|
|
54774
|
-
|
|
54738
|
+
for (;;) {
|
|
54739
|
+
const index = this.queue.findIndex((job) => job.lane === "probe" ? this.activeCacheProbes < 1 : job.lane === "immutable" ? this.activeImmutableReads < IMMUTABLE_CONCURRENCY : this.activeDownloads < this.concurrency);
|
|
54740
|
+
if (index === -1) return;
|
|
54741
|
+
const job = this.queue.splice(index, 1)[0];
|
|
54742
|
+
if (job.lane === "probe") this.activeCacheProbes += 1;
|
|
54743
|
+
else if (job.lane === "immutable") this.activeImmutableReads += 1;
|
|
54744
|
+
else this.activeDownloads += 1;
|
|
54745
|
+
job.start();
|
|
54775
54746
|
}
|
|
54776
54747
|
}
|
|
54777
54748
|
notify(imageRef, value) {
|
|
@@ -54779,8 +54750,185 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
54779
54750
|
}
|
|
54780
54751
|
};
|
|
54781
54752
|
//#endregion
|
|
54753
|
+
//#region src/client/avatar-persistent-cache.ts
|
|
54754
|
+
const CACHE_NAME = "arkme-immutable-avatars-v1";
|
|
54755
|
+
const MAX_ENTRIES$1 = 64;
|
|
54756
|
+
const MAX_BYTES$1 = 64 * 1024 * 1024;
|
|
54757
|
+
const MAX_BASE64_LENGTH = Math.ceil(8 * 1024 * 1024 / 3) * 4;
|
|
54758
|
+
function validPayload(value) {
|
|
54759
|
+
if (typeof value !== "object" || value === null) return false;
|
|
54760
|
+
const payload = value;
|
|
54761
|
+
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}$/, ""));
|
|
54762
|
+
}
|
|
54763
|
+
/** Validate browser-persisted bytes too: base64 syntax is not image validity. */
|
|
54764
|
+
async function decodableAvatar(payload) {
|
|
54765
|
+
try {
|
|
54766
|
+
const bytes = Uint8Array.from(atob(payload.dataBase64), (character) => character.charCodeAt(0));
|
|
54767
|
+
const blob = new Blob([bytes], { type: payload.mediaType });
|
|
54768
|
+
if (typeof createImageBitmap === "function") {
|
|
54769
|
+
(await createImageBitmap(blob)).close();
|
|
54770
|
+
return true;
|
|
54771
|
+
}
|
|
54772
|
+
if (typeof Image === "undefined") return false;
|
|
54773
|
+
const url = URL.createObjectURL(blob);
|
|
54774
|
+
try {
|
|
54775
|
+
return await new Promise((resolve) => {
|
|
54776
|
+
const image = new Image();
|
|
54777
|
+
image.onload = () => resolve(image.naturalWidth > 0 && image.naturalHeight > 0);
|
|
54778
|
+
image.onerror = () => resolve(false);
|
|
54779
|
+
image.src = url;
|
|
54780
|
+
});
|
|
54781
|
+
} finally {
|
|
54782
|
+
URL.revokeObjectURL(url);
|
|
54783
|
+
}
|
|
54784
|
+
} catch {
|
|
54785
|
+
return false;
|
|
54786
|
+
}
|
|
54787
|
+
}
|
|
54788
|
+
/** Browser bytes survive reloads. Host remains the authenticated source on misses.
|
|
54789
|
+
* No TTL for immutable refs; quota eviction and clearing site data are cache misses.
|
|
54790
|
+
* Synthetic keys are never fetched and include the environment/account scope.
|
|
54791
|
+
*/
|
|
54792
|
+
var BrowserAvatarPersistentCache = class {
|
|
54793
|
+
decode;
|
|
54794
|
+
constructor(decode = decodableAvatar) {
|
|
54795
|
+
this.decode = decode;
|
|
54796
|
+
}
|
|
54797
|
+
writes = Promise.resolve();
|
|
54798
|
+
key(scope, ref) {
|
|
54799
|
+
try {
|
|
54800
|
+
if (!scope.trim() || !isImmutableAvatarRef(ref) || typeof globalThis.caches === "undefined" || typeof globalThis.location === "undefined") return void 0;
|
|
54801
|
+
return new URL(`/arkme-self/avatar-cache/v1/${encodeURIComponent(scope)}/${encodeURIComponent(ref)}`, globalThis.location.origin).href;
|
|
54802
|
+
} catch {
|
|
54803
|
+
return;
|
|
54804
|
+
}
|
|
54805
|
+
}
|
|
54806
|
+
async read(scope, ref) {
|
|
54807
|
+
const key = this.key(scope, ref);
|
|
54808
|
+
if (key === void 0) return void 0;
|
|
54809
|
+
try {
|
|
54810
|
+
const cache = await caches.open(CACHE_NAME);
|
|
54811
|
+
const response = await cache.match(key);
|
|
54812
|
+
if (response === void 0) return void 0;
|
|
54813
|
+
const payload = await response.json().catch(() => void 0);
|
|
54814
|
+
if (validPayload(payload) && await this.decode(payload)) return payload;
|
|
54815
|
+
await cache.delete(key);
|
|
54816
|
+
} catch {}
|
|
54817
|
+
}
|
|
54818
|
+
write(scope, ref, payload) {
|
|
54819
|
+
const key = this.key(scope, ref);
|
|
54820
|
+
if (key === void 0 || !validPayload(payload)) return Promise.resolve();
|
|
54821
|
+
const operation = this.writes.then(async () => {
|
|
54822
|
+
if (!await this.decode(payload)) return;
|
|
54823
|
+
const cache = await caches.open(CACHE_NAME);
|
|
54824
|
+
const body = JSON.stringify(payload);
|
|
54825
|
+
const keys = (await cache.keys()).filter((request) => request.url !== key);
|
|
54826
|
+
const sizes = await Promise.all(keys.map(async (request) => Number((await cache.match(request))?.headers.get("Content-Length")) || 0));
|
|
54827
|
+
let bytes = sizes.reduce((sum, size) => sum + size, 0) + body.length;
|
|
54828
|
+
let count = keys.length + 1;
|
|
54829
|
+
for (let index = 0; index < keys.length && (count > MAX_ENTRIES$1 || bytes > MAX_BYTES$1); index++) {
|
|
54830
|
+
await cache.delete(keys[index]);
|
|
54831
|
+
bytes -= sizes[index];
|
|
54832
|
+
count -= 1;
|
|
54833
|
+
}
|
|
54834
|
+
await cache.put(key, new Response(body, { headers: {
|
|
54835
|
+
"Content-Type": "application/json",
|
|
54836
|
+
"Content-Length": String(body.length)
|
|
54837
|
+
} }));
|
|
54838
|
+
});
|
|
54839
|
+
this.writes = operation.catch(() => void 0);
|
|
54840
|
+
return this.writes;
|
|
54841
|
+
}
|
|
54842
|
+
};
|
|
54843
|
+
//#endregion
|
|
54844
|
+
//#region src/avatar-diagnostics.ts
|
|
54845
|
+
function record(value) {
|
|
54846
|
+
return value !== null && typeof value === "object" ? value : {};
|
|
54847
|
+
}
|
|
54848
|
+
function positiveId(value) {
|
|
54849
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
54850
|
+
}
|
|
54851
|
+
/** Decoded IDs are diagnostic hints only, never authentication or authorization inputs. */
|
|
54852
|
+
function avatarReferenceDiagnostic(imageRef) {
|
|
54853
|
+
const ref = imageRef.trim();
|
|
54854
|
+
if (!ref.startsWith("arkme-profile-image-v1.")) return { referenceKind: ref.startsWith("arkme-media-v1.") ? "media" : "other" };
|
|
54855
|
+
const context = { referenceKind: "profile" };
|
|
54856
|
+
try {
|
|
54857
|
+
const parts = ref.split(".");
|
|
54858
|
+
const encoded = parts[1] ?? "";
|
|
54859
|
+
if (parts.length !== 3 || encoded.length > 1024 || !/^[A-Za-z0-9_-]+$/.test(encoded)) return context;
|
|
54860
|
+
const base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
54861
|
+
const payload = record(JSON.parse(globalThis.atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "="))));
|
|
54862
|
+
if (payload.version !== 1) return context;
|
|
54863
|
+
const viewer = positiveId(payload.viewerUserId);
|
|
54864
|
+
const target = positiveId(payload.targetUserId);
|
|
54865
|
+
if (viewer !== void 0) context.referenceViewerUserId = viewer;
|
|
54866
|
+
if (target !== void 0) context.referenceTargetUserId = target;
|
|
54867
|
+
} catch {}
|
|
54868
|
+
return context;
|
|
54869
|
+
}
|
|
54870
|
+
function avatarScopeDiagnostic(scopeKey) {
|
|
54871
|
+
const match = /^(prod|test):([1-9][0-9]*)$/.exec(scopeKey ?? "");
|
|
54872
|
+
const viewerUserId = positiveId(Number(match?.[2]));
|
|
54873
|
+
return match === null || viewerUserId === void 0 ? {} : {
|
|
54874
|
+
environment: match[1],
|
|
54875
|
+
viewerUserId
|
|
54876
|
+
};
|
|
54877
|
+
}
|
|
54878
|
+
function safeErrorCode(value) {
|
|
54879
|
+
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;
|
|
54880
|
+
}
|
|
54881
|
+
function httpStatus(value) {
|
|
54882
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599 ? value : void 0;
|
|
54883
|
+
}
|
|
54884
|
+
function imageDownloadStatus(error) {
|
|
54885
|
+
if (error.name !== "ArkmePluginError" || error.code !== "image-download-failed" || typeof error.message !== "string") return void 0;
|
|
54886
|
+
const match = /^Arkme 图片读取返回 HTTP ([1-5][0-9]{2})$/.exec(error.message);
|
|
54887
|
+
return match === null ? void 0 : httpStatus(Number(match[1]));
|
|
54888
|
+
}
|
|
54889
|
+
function logArkmeAvatarDiagnostic(event, context, error) {
|
|
54890
|
+
try {
|
|
54891
|
+
const source = record(error);
|
|
54892
|
+
const body = record(source.body);
|
|
54893
|
+
const detail = source.name === "ArkmeClientError" ? body : source;
|
|
54894
|
+
const errorName = [
|
|
54895
|
+
"Error",
|
|
54896
|
+
"TypeError",
|
|
54897
|
+
"AbortError",
|
|
54898
|
+
"TimeoutError",
|
|
54899
|
+
"ArkmePluginError",
|
|
54900
|
+
"ArkmeClientError"
|
|
54901
|
+
].includes(String(source.name)) ? String(source.name) : "unknown";
|
|
54902
|
+
console.warn(`[ArkmeAvatarDiag] ${JSON.stringify({
|
|
54903
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54904
|
+
event,
|
|
54905
|
+
...context,
|
|
54906
|
+
...error === void 0 ? {} : { error: {
|
|
54907
|
+
name: errorName,
|
|
54908
|
+
code: safeErrorCode(detail.code),
|
|
54909
|
+
retryable: typeof detail.retryable === "boolean" ? detail.retryable : void 0,
|
|
54910
|
+
httpStatus: httpStatus(source.httpStatus),
|
|
54911
|
+
upstreamStatus: httpStatus(source.upstreamStatus) ?? imageDownloadStatus(source),
|
|
54912
|
+
causeCode: safeErrorCode(record(source.cause).code)
|
|
54913
|
+
} }
|
|
54914
|
+
})}`);
|
|
54915
|
+
} catch {}
|
|
54916
|
+
}
|
|
54917
|
+
//#endregion
|
|
54782
54918
|
//#region src/client/avatar-image-runtime.ts
|
|
54783
54919
|
const arkmeAvatarImages = new InMemoryArkmeAvatarImageStore({
|
|
54920
|
+
persistentCache: new BrowserAvatarPersistentCache(),
|
|
54921
|
+
cachedReader: async (imageRef) => {
|
|
54922
|
+
try {
|
|
54923
|
+
return await callArkme("image.read", {
|
|
54924
|
+
imageRef,
|
|
54925
|
+
cacheOnly: true
|
|
54926
|
+
});
|
|
54927
|
+
} catch (error) {
|
|
54928
|
+
if (error instanceof ArkmeClientError && error.body.code === "image-cache-miss") return void 0;
|
|
54929
|
+
throw error;
|
|
54930
|
+
}
|
|
54931
|
+
},
|
|
54784
54932
|
reader: async (imageRef) => await callArkme("image.read", { imageRef }),
|
|
54785
54933
|
onLoadFailure: ({ imageRef, scopeKey, error, ...context }) => {
|
|
54786
54934
|
logArkmeAvatarDiagnostic("image_load_failed", {
|
|
@@ -55526,6 +55674,54 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55526
55674
|
return stop;
|
|
55527
55675
|
}
|
|
55528
55676
|
//#endregion
|
|
55677
|
+
//#region src/reaction-diagnostics.ts
|
|
55678
|
+
/** Timing metadata only: no credentials, message refs, names or message bodies. */
|
|
55679
|
+
function reactionTraceId(value) {
|
|
55680
|
+
return value && /^[a-f0-9-]{36}$/.test(value) ? value : globalThis.crypto.randomUUID();
|
|
55681
|
+
}
|
|
55682
|
+
function logReactionTiming(traceId, stage, started, detail = {}) {
|
|
55683
|
+
console.info(`[ArkmeReactionTiming] ${JSON.stringify({
|
|
55684
|
+
traceId,
|
|
55685
|
+
stage,
|
|
55686
|
+
at: Date.now(),
|
|
55687
|
+
durationMs: Math.round((performance.now() - started) * 100) / 100,
|
|
55688
|
+
...detail
|
|
55689
|
+
})}`);
|
|
55690
|
+
}
|
|
55691
|
+
//#endregion
|
|
55692
|
+
//#region src/client/reaction-transport.ts
|
|
55693
|
+
const timings = /* @__PURE__ */ new WeakMap();
|
|
55694
|
+
function traceReactionApplied(value, stage) {
|
|
55695
|
+
const timing = timings.get(value);
|
|
55696
|
+
if (timing) logReactionTiming(timing.traceId, stage, timing.started);
|
|
55697
|
+
}
|
|
55698
|
+
async function callReaction(input, signal) {
|
|
55699
|
+
let diagnostics = false;
|
|
55700
|
+
try {
|
|
55701
|
+
diagnostics = globalThis.sessionStorage?.getItem("arkme.reaction.diagnostics") === "1";
|
|
55702
|
+
} catch {}
|
|
55703
|
+
if (!diagnostics) return await callArkme("reactions", input, signal);
|
|
55704
|
+
const traceId = reactionTraceId(input.traceId), started = performance.now();
|
|
55705
|
+
let ok = false;
|
|
55706
|
+
try {
|
|
55707
|
+
const value = await callArkme("reactions", {
|
|
55708
|
+
...input,
|
|
55709
|
+
traceId
|
|
55710
|
+
}, signal);
|
|
55711
|
+
ok = true;
|
|
55712
|
+
if (diagnostics && value && typeof value === "object") timings.set(value, {
|
|
55713
|
+
traceId,
|
|
55714
|
+
started
|
|
55715
|
+
});
|
|
55716
|
+
return value;
|
|
55717
|
+
} finally {
|
|
55718
|
+
if (diagnostics) logReactionTiming(traceId, "browser-request", started, {
|
|
55719
|
+
action: input.action,
|
|
55720
|
+
ok
|
|
55721
|
+
});
|
|
55722
|
+
}
|
|
55723
|
+
}
|
|
55724
|
+
//#endregion
|
|
55529
55725
|
//#region src/client/reaction-label-content.ts
|
|
55530
55726
|
const reactionHandIds = [
|
|
55531
55727
|
"ok_hand",
|
|
@@ -55778,10 +55974,12 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55778
55974
|
targets = /* @__PURE__ */ new Map();
|
|
55779
55975
|
states = /* @__PURE__ */ new Map();
|
|
55780
55976
|
inactive = /* @__PURE__ */ new Set();
|
|
55977
|
+
actorRefreshAt = /* @__PURE__ */ new Map();
|
|
55781
55978
|
knownTargets = /* @__PURE__ */ new Map();
|
|
55782
55979
|
failures = /* @__PURE__ */ new Map();
|
|
55783
55980
|
listeners = /* @__PURE__ */ new Set();
|
|
55784
55981
|
revision = 0;
|
|
55982
|
+
reading;
|
|
55785
55983
|
refreshing;
|
|
55786
55984
|
timer;
|
|
55787
55985
|
timerDue = 0;
|
|
@@ -55789,7 +55987,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55789
55987
|
retryMillis = 2e3;
|
|
55790
55988
|
pending;
|
|
55791
55989
|
writing = false;
|
|
55792
|
-
constructor(transport =
|
|
55990
|
+
constructor(transport = callReaction) {
|
|
55793
55991
|
this.transport = transport;
|
|
55794
55992
|
}
|
|
55795
55993
|
subscribe = (listener) => {
|
|
@@ -55811,6 +56009,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55811
56009
|
this.targets.clear();
|
|
55812
56010
|
this.states.clear();
|
|
55813
56011
|
this.inactive.clear();
|
|
56012
|
+
this.actorRefreshAt.clear();
|
|
55814
56013
|
this.knownTargets.clear();
|
|
55815
56014
|
this.failures.clear();
|
|
55816
56015
|
this.pending = void 0;
|
|
@@ -55823,6 +56022,11 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55823
56022
|
}
|
|
55824
56023
|
watch(scope, target) {
|
|
55825
56024
|
if (scope !== this.scope) return () => {};
|
|
56025
|
+
const resolver = target.resolveActor ?? this.knownTargets.get(target.id)?.resolveActor;
|
|
56026
|
+
if (resolver) target = {
|
|
56027
|
+
...target,
|
|
56028
|
+
resolveActor: resolver
|
|
56029
|
+
};
|
|
55826
56030
|
const existing = this.targets.get(target.id);
|
|
55827
56031
|
if (!existing && this.targets.size >= 200) {
|
|
55828
56032
|
this.failures.set(target.id, "请打开消息后刷新表态");
|
|
@@ -55851,6 +56055,8 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55851
56055
|
this.failures.delete(target.id);
|
|
55852
56056
|
this.retainInactive(target.id);
|
|
55853
56057
|
}
|
|
56058
|
+
const reading = this.reading;
|
|
56059
|
+
if (reading && ![...reading.entries].some(([id, entry]) => this.targets.get(id) === entry)) reading.controller.abort();
|
|
55854
56060
|
if (!this.targets.size) this.stop();
|
|
55855
56061
|
};
|
|
55856
56062
|
}
|
|
@@ -55862,6 +56068,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55862
56068
|
const oldest = this.inactive.values().next().value;
|
|
55863
56069
|
this.inactive.delete(oldest);
|
|
55864
56070
|
this.states.delete(oldest);
|
|
56071
|
+
this.actorRefreshAt.delete(oldest);
|
|
55865
56072
|
this.knownTargets.delete(oldest);
|
|
55866
56073
|
this.failures.delete(oldest);
|
|
55867
56074
|
}
|
|
@@ -55884,9 +56091,20 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55884
56091
|
await this.refresh();
|
|
55885
56092
|
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
56093
|
};
|
|
56094
|
+
let unsubscribe = () => {};
|
|
56095
|
+
const factsReady = new Promise((resolve) => {
|
|
56096
|
+
unsubscribe = this.subscribe(() => {
|
|
56097
|
+
if (missing.every((target) => this.states.has(target.id) || this.failures.has(target.id))) resolve();
|
|
56098
|
+
});
|
|
56099
|
+
});
|
|
55887
56100
|
try {
|
|
55888
|
-
await Promise.race([
|
|
56101
|
+
await Promise.race([
|
|
56102
|
+
load(),
|
|
56103
|
+
deadline,
|
|
56104
|
+
factsReady
|
|
56105
|
+
]);
|
|
55889
56106
|
} finally {
|
|
56107
|
+
unsubscribe();
|
|
55890
56108
|
active = false;
|
|
55891
56109
|
clearTimeout(timer);
|
|
55892
56110
|
signal.removeEventListener("abort", finish);
|
|
@@ -55947,11 +56165,17 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55947
56165
|
}
|
|
55948
56166
|
async refresh() {
|
|
55949
56167
|
if (this.refreshing) return this.refreshing;
|
|
55950
|
-
const scope = this.scope
|
|
56168
|
+
const scope = this.scope;
|
|
55951
56169
|
if (!scope) return;
|
|
56170
|
+
const controller = new AbortController(), entries = new Map(this.targets);
|
|
56171
|
+
const reading = {
|
|
56172
|
+
controller,
|
|
56173
|
+
entries
|
|
56174
|
+
};
|
|
56175
|
+
this.reading = reading;
|
|
56176
|
+
const signal = AbortSignal.any([this.controller.signal, controller.signal]);
|
|
55952
56177
|
const operation = (async () => {
|
|
55953
56178
|
let failed = false;
|
|
55954
|
-
const entries = new Map(this.targets);
|
|
55955
56179
|
const targets = [...entries.values()].map((item) => item.target);
|
|
55956
56180
|
for (let offset = 0; offset < targets.length; offset += 50) {
|
|
55957
56181
|
const batch = targets.slice(offset, offset + 50);
|
|
@@ -55960,7 +56184,8 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55960
56184
|
const page = await this.transport({
|
|
55961
56185
|
action: "query",
|
|
55962
56186
|
accountKey: scope,
|
|
55963
|
-
targets: batch
|
|
56187
|
+
targets: batch,
|
|
56188
|
+
actorPresentation: "deferred"
|
|
55964
56189
|
}, signal);
|
|
55965
56190
|
if (signal.aborted) return;
|
|
55966
56191
|
const returned = new Set(page.items.map((item) => item.target_id));
|
|
@@ -55973,8 +56198,25 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55973
56198
|
}
|
|
55974
56199
|
for (const item of page.items) if (entries.has(item.target_id) && this.targets.get(item.target_id) === entries.get(item.target_id)) {
|
|
55975
56200
|
const previous = this.states.get(item.target_id);
|
|
55976
|
-
if (!previous || previous.mine.revision <= item.mine.revision)
|
|
56201
|
+
if (!previous || previous.mine.revision <= item.mine.revision) {
|
|
56202
|
+
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]));
|
|
56203
|
+
const resolve = this.targets.get(item.target_id)?.target.resolveActor;
|
|
56204
|
+
this.states.set(item.target_id, {
|
|
56205
|
+
...item,
|
|
56206
|
+
groups: item.groups.map((group) => ({
|
|
56207
|
+
...group,
|
|
56208
|
+
actors: (group.actors ?? []).map((actor) => resolve?.(actor) ?? (actor.presentationPending && known.has(actor.userId) ? {
|
|
56209
|
+
...actor,
|
|
56210
|
+
...known.get(actor.userId),
|
|
56211
|
+
...actor.memberRef ? { memberRef: actor.memberRef } : {},
|
|
56212
|
+
presentationPending: false
|
|
56213
|
+
} : actor))
|
|
56214
|
+
}))
|
|
56215
|
+
});
|
|
56216
|
+
}
|
|
55977
56217
|
}
|
|
56218
|
+
if (before !== JSON.stringify(batch.map((t) => [this.states.get(t.id), this.failures.get(t.id)]))) this.publish();
|
|
56219
|
+
traceReactionApplied(page, "browser-facts-published");
|
|
55978
56220
|
} catch (error) {
|
|
55979
56221
|
if (signal.aborted) return;
|
|
55980
56222
|
failed = true;
|
|
@@ -55983,7 +56225,52 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55983
56225
|
this.failures.set(target.id, error instanceof Error ? error.message : "表态加载失败");
|
|
55984
56226
|
}
|
|
55985
56227
|
}
|
|
55986
|
-
if (!signal.aborted && before !== JSON.stringify(batch.map((t) => [this.states.get(t.id), this.failures.get(t.id)]))) this.publish();
|
|
56228
|
+
if (failed && !signal.aborted && before !== JSON.stringify(batch.map((t) => [this.states.get(t.id), this.failures.get(t.id)]))) this.publish();
|
|
56229
|
+
const missing = batch.filter((target) => this.states.get(target.id)?.groups.some((group) => group.actors?.some((actor) => actor.presentationPending)));
|
|
56230
|
+
if (missing.length && !signal.aborted) {
|
|
56231
|
+
const initial = new Map(missing.map((target) => [target.id, this.states.get(target.id)]));
|
|
56232
|
+
try {
|
|
56233
|
+
const enriched = await this.transport({
|
|
56234
|
+
action: "query",
|
|
56235
|
+
accountKey: scope,
|
|
56236
|
+
targets: missing
|
|
56237
|
+
}, signal);
|
|
56238
|
+
if (signal.aborted) return;
|
|
56239
|
+
for (const item of enriched.items) {
|
|
56240
|
+
const current = this.states.get(item.target_id);
|
|
56241
|
+
if (!current || current !== initial.get(item.target_id) || this.targets.get(item.target_id) !== entries.get(item.target_id)) continue;
|
|
56242
|
+
this.actorRefreshAt.set(item.target_id, Date.now());
|
|
56243
|
+
if (!item.actors_visible) {
|
|
56244
|
+
this.states.set(item.target_id, {
|
|
56245
|
+
...current,
|
|
56246
|
+
actors_visible: false,
|
|
56247
|
+
private: item.private,
|
|
56248
|
+
groups: current.groups.map((group) => ({
|
|
56249
|
+
...group,
|
|
56250
|
+
actors: []
|
|
56251
|
+
}))
|
|
56252
|
+
});
|
|
56253
|
+
continue;
|
|
56254
|
+
}
|
|
56255
|
+
const actors = new Map(item.groups.flatMap((group) => group.actors ?? []).map((actor) => [actor.userId, actor]));
|
|
56256
|
+
const resolve = this.targets.get(item.target_id)?.target.resolveActor;
|
|
56257
|
+
this.states.set(item.target_id, {
|
|
56258
|
+
...current,
|
|
56259
|
+
groups: current.groups.map((group) => ({
|
|
56260
|
+
...group,
|
|
56261
|
+
actors: (group.actors ?? []).map((actor) => resolve?.(actor) ?? (actor.presentationPending && actors.has(actor.userId) ? {
|
|
56262
|
+
...actor,
|
|
56263
|
+
...actors.get(actor.userId),
|
|
56264
|
+
...actor.memberRef ? { memberRef: actor.memberRef } : {},
|
|
56265
|
+
presentationPending: false
|
|
56266
|
+
} : actor))
|
|
56267
|
+
}))
|
|
56268
|
+
});
|
|
56269
|
+
}
|
|
56270
|
+
this.publish();
|
|
56271
|
+
traceReactionApplied(enriched, "browser-actors-published");
|
|
56272
|
+
} catch {}
|
|
56273
|
+
}
|
|
55987
56274
|
}
|
|
55988
56275
|
if (!signal.aborted) this.retryMillis = failed ? Math.min(12e4, this.retryMillis * 2) : 2e3;
|
|
55989
56276
|
})();
|
|
@@ -55991,6 +56278,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
55991
56278
|
try {
|
|
55992
56279
|
await operation;
|
|
55993
56280
|
} finally {
|
|
56281
|
+
if (this.reading === reading) this.reading = void 0;
|
|
55994
56282
|
if (this.refreshing === operation) {
|
|
55995
56283
|
this.refreshing = void 0;
|
|
55996
56284
|
if (this.refreshAgain) {
|
|
@@ -56158,7 +56446,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
56158
56446
|
users = 0;
|
|
56159
56447
|
error = "";
|
|
56160
56448
|
hasMore = false;
|
|
56161
|
-
constructor(transport =
|
|
56449
|
+
constructor(transport = callReaction) {
|
|
56162
56450
|
this.transport = transport;
|
|
56163
56451
|
}
|
|
56164
56452
|
subscribe = (fn) => {
|
|
@@ -56279,6 +56567,7 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
56279
56567
|
limit: 50
|
|
56280
56568
|
}, signal);
|
|
56281
56569
|
if (signal.aborted) return;
|
|
56570
|
+
traceReactionApplied(page, "browser-notifications-received");
|
|
56282
56571
|
rows.push(...page.items);
|
|
56283
56572
|
hasMore = page.has_more;
|
|
56284
56573
|
if (!page.has_more) break;
|
|
@@ -57947,29 +58236,29 @@ body[data-ds-dark-theme] .arkme-bot-identity {
|
|
|
57947
58236
|
this.timer = void 0;
|
|
57948
58237
|
}
|
|
57949
58238
|
};
|
|
57950
|
-
const caches = /* @__PURE__ */ new Map();
|
|
58239
|
+
const caches$1 = /* @__PURE__ */ new Map();
|
|
57951
58240
|
function activateSelfTopicDirectoryAccount(account) {
|
|
57952
|
-
for (const [key, cache] of caches) {
|
|
58241
|
+
for (const [key, cache] of caches$1) {
|
|
57953
58242
|
if (key === account) continue;
|
|
57954
58243
|
cache.dispose();
|
|
57955
|
-
caches.delete(key);
|
|
58244
|
+
caches$1.delete(key);
|
|
57956
58245
|
}
|
|
57957
58246
|
}
|
|
57958
58247
|
function selfTopicDirectory(userId, environment) {
|
|
57959
58248
|
const key = `${environment}:${String(userId)}`;
|
|
57960
|
-
let cache = caches.get(key);
|
|
58249
|
+
let cache = caches$1.get(key);
|
|
57961
58250
|
if (!cache) {
|
|
57962
58251
|
cache = new SelfTopicDirectoryCache(userId, environment);
|
|
57963
|
-
caches.set(key, cache);
|
|
58252
|
+
caches$1.set(key, cache);
|
|
57964
58253
|
}
|
|
57965
58254
|
return cache;
|
|
57966
58255
|
}
|
|
57967
58256
|
function invalidateSelfTopicDirectories(hard = false) {
|
|
57968
|
-
for (const cache of caches.values()) cache.invalidate(hard);
|
|
58257
|
+
for (const cache of caches$1.values()) cache.invalidate(hard);
|
|
57969
58258
|
}
|
|
57970
58259
|
function resetSelfTopicDirectories() {
|
|
57971
|
-
for (const cache of caches.values()) cache.dispose();
|
|
57972
|
-
caches.clear();
|
|
58260
|
+
for (const cache of caches$1.values()) cache.dispose();
|
|
58261
|
+
caches$1.clear();
|
|
57973
58262
|
}
|
|
57974
58263
|
//#endregion
|
|
57975
58264
|
//#region src/client/provider-instance-runtime.ts
|
|
@@ -118596,7 +118885,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
118596
118885
|
displayName: actorGroupNickname?.trim() || actorName,
|
|
118597
118886
|
...actorGroupNickname ? { groupNickname: actorGroupNickname } : {},
|
|
118598
118887
|
...actorAvatarRef ? { avatarRef: actorAvatarRef } : {}
|
|
118599
|
-
} : actor;
|
|
118888
|
+
} : target.resolveActor?.(actor) ?? actor;
|
|
118600
118889
|
const name = identity.displayName;
|
|
118601
118890
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [index > 0 && "、", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
118602
118891
|
type: "button",
|
|
@@ -120961,14 +121250,17 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
120961
121250
|
scope,
|
|
120962
121251
|
roles: [],
|
|
120963
121252
|
loading: true,
|
|
121253
|
+
loaded: false,
|
|
120964
121254
|
error: ""
|
|
120965
121255
|
});
|
|
120966
121256
|
const visibleState = roleState.scope === scope ? roleState : {
|
|
120967
121257
|
scope,
|
|
120968
121258
|
roles: [],
|
|
120969
121259
|
loading: true,
|
|
121260
|
+
loaded: false,
|
|
120970
121261
|
error: ""
|
|
120971
121262
|
};
|
|
121263
|
+
const initialLoading = visibleState.loading && !visibleState.loaded;
|
|
120972
121264
|
const [refreshRevision, setRefreshRevision] = (0, react$1.useState)(0);
|
|
120973
121265
|
(0, react$1.useEffect)(() => {
|
|
120974
121266
|
if (typeof window === "undefined") return;
|
|
@@ -120986,6 +121278,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
120986
121278
|
const [saving, setSaving] = (0, react$1.useState)(false);
|
|
120987
121279
|
const [formError, setFormError] = (0, react$1.useState)("");
|
|
120988
121280
|
const fileInputRef = (0, react$1.useRef)(null);
|
|
121281
|
+
const listControllerRef = (0, react$1.useRef)();
|
|
120989
121282
|
const saveControllerRef = (0, react$1.useRef)();
|
|
120990
121283
|
(0, react$1.useEffect)(() => {
|
|
120991
121284
|
setMenuOpen(false);
|
|
@@ -121004,31 +121297,37 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121004
121297
|
}, [scope]);
|
|
121005
121298
|
(0, react$1.useEffect)(() => {
|
|
121006
121299
|
const controller = new AbortController();
|
|
121007
|
-
|
|
121300
|
+
listControllerRef.current = controller;
|
|
121301
|
+
setRoleState((current) => ({
|
|
121008
121302
|
scope,
|
|
121009
|
-
roles:
|
|
121303
|
+
roles: current.scope === scope ? current.roles : [],
|
|
121304
|
+
loaded: current.scope === scope && current.loaded,
|
|
121010
121305
|
loading: true,
|
|
121011
121306
|
error: ""
|
|
121012
|
-
});
|
|
121307
|
+
}));
|
|
121013
121308
|
callArkme("self-roles.list", { expectedUserId: userId }, controller.signal).then((roles) => {
|
|
121014
121309
|
if (controller.signal.aborted || scopeRef.current !== scope) return;
|
|
121015
121310
|
setRoleState({
|
|
121016
121311
|
scope,
|
|
121017
121312
|
roles,
|
|
121018
121313
|
loading: false,
|
|
121314
|
+
loaded: true,
|
|
121019
121315
|
error: ""
|
|
121020
121316
|
});
|
|
121317
|
+
for (const ref of new Set(roles.map((role) => role.avatarRef?.trim()).filter((ref) => !!ref))) arkmeAvatarImages.load(ref).catch(() => void 0);
|
|
121021
121318
|
}).catch((caught) => {
|
|
121022
121319
|
if (controller.signal.aborted || scopeRef.current !== scope) return;
|
|
121023
121320
|
setRoleState((current) => ({
|
|
121024
121321
|
scope,
|
|
121025
121322
|
roles: current.scope === scope ? current.roles : [],
|
|
121323
|
+
loaded: current.scope === scope && current.loaded,
|
|
121026
121324
|
loading: false,
|
|
121027
121325
|
error: caught instanceof Error ? caught.message : "角色加载失败,请重试"
|
|
121028
121326
|
}));
|
|
121029
121327
|
});
|
|
121030
121328
|
return () => {
|
|
121031
121329
|
controller.abort();
|
|
121330
|
+
if (listControllerRef.current === controller) listControllerRef.current = void 0;
|
|
121032
121331
|
};
|
|
121033
121332
|
}, [
|
|
121034
121333
|
scope,
|
|
@@ -121071,7 +121370,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121071
121370
|
const createRole = async (event) => {
|
|
121072
121371
|
event.preventDefault();
|
|
121073
121372
|
const roleName = name.trim();
|
|
121074
|
-
if (disabled || saveControllerRef.current !== void 0 ||
|
|
121373
|
+
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
121374
|
const controller = new AbortController();
|
|
121076
121375
|
saveControllerRef.current = controller;
|
|
121077
121376
|
const submittingScope = scope;
|
|
@@ -121087,8 +121386,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121087
121386
|
...avatarRef === void 0 ? {} : { avatarRef }
|
|
121088
121387
|
}, controller.signal);
|
|
121089
121388
|
if (controller.signal.aborted || scopeRef.current !== submittingScope) return;
|
|
121389
|
+
listControllerRef.current?.abort();
|
|
121090
121390
|
setRoleState((current) => current.scope === submittingScope ? {
|
|
121091
121391
|
...current,
|
|
121392
|
+
loading: false,
|
|
121393
|
+
loaded: true,
|
|
121394
|
+
error: "",
|
|
121092
121395
|
roles: [...current.roles.filter((role) => role.roleId !== created.roleId), created]
|
|
121093
121396
|
} : current);
|
|
121094
121397
|
setCreateOpen(false);
|
|
@@ -121120,7 +121423,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121120
121423
|
event.stopPropagation();
|
|
121121
121424
|
},
|
|
121122
121425
|
onClick: () => {
|
|
121123
|
-
if (!menuOpen) setRefreshRevision((value) => value + 1);
|
|
121426
|
+
if (!menuOpen && !visibleState.loading) setRefreshRevision((value) => value + 1);
|
|
121124
121427
|
setMenuOpen((value) => !value);
|
|
121125
121428
|
},
|
|
121126
121429
|
children: [
|
|
@@ -121168,8 +121471,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121168
121471
|
roleId: role.roleId
|
|
121169
121472
|
}).then(() => {
|
|
121170
121473
|
if (scopeRef.current !== scope) return;
|
|
121474
|
+
listControllerRef.current?.abort();
|
|
121171
121475
|
setRoleState((current) => current.scope === scope ? {
|
|
121172
121476
|
...current,
|
|
121477
|
+
loading: false,
|
|
121478
|
+
loaded: true,
|
|
121479
|
+
error: "",
|
|
121173
121480
|
roles: current.roles.filter((item) => item.roleId !== role.roleId)
|
|
121174
121481
|
} : current);
|
|
121175
121482
|
setRefreshRevision((value) => value + 1);
|
|
@@ -121219,7 +121526,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121219
121526
|
onSelect: () => deleteRole(role)
|
|
121220
121527
|
}]
|
|
121221
121528
|
})),
|
|
121222
|
-
...
|
|
121529
|
+
...initialLoading ? [{
|
|
121223
121530
|
type: "label",
|
|
121224
121531
|
id: "role-loading",
|
|
121225
121532
|
text: "正在加载角色…"
|
|
@@ -121242,7 +121549,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
121242
121549
|
{
|
|
121243
121550
|
id: "role-create",
|
|
121244
121551
|
label: "+ 创建角色",
|
|
121245
|
-
disabled:
|
|
121552
|
+
disabled: initialLoading || visibleState.error !== "" || visibleState.roles.length >= MAX_ROLES,
|
|
121246
121553
|
onSelect: () => {
|
|
121247
121554
|
setMenuOpen(false);
|
|
121248
121555
|
setEditingRole(void 0);
|
|
@@ -212533,7 +212840,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
212533
212840
|
const c$3 = e$20;
|
|
212534
212841
|
//#endregion
|
|
212535
212842
|
//#region package.json
|
|
212536
|
-
var version = "0.1.
|
|
212843
|
+
var version = "0.1.86";
|
|
212537
212844
|
//#endregion
|
|
212538
212845
|
//#region src/client/arkme-membership.ts
|
|
212539
212846
|
function membershipLabel(state) {
|
|
@@ -234417,7 +234724,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
234417
234724
|
return result;
|
|
234418
234725
|
}, { signal }), controller.signal);
|
|
234419
234726
|
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
234727
|
} catch (caught) {
|
|
234422
234728
|
if (isArkmeRequestAbort(caught, controller.signal)) return;
|
|
234423
234729
|
throw caught;
|
|
@@ -234510,7 +234816,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
234510
234816
|
acknowledgeRead,
|
|
234511
234817
|
confirmedSendRetention,
|
|
234512
234818
|
interwovenMoments,
|
|
234513
|
-
prepareTimelineReactions,
|
|
234514
234819
|
source,
|
|
234515
234820
|
sourceIsChat,
|
|
234516
234821
|
sourceProjectionRevision
|
|
@@ -236422,6 +236727,43 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
236422
236727
|
return projected.isMuted === true;
|
|
236423
236728
|
}, [updateSourceProjection]);
|
|
236424
236729
|
const conversationMemberByRef = (0, react$1.useMemo)(() => new Map(conversationMembers.map((member) => [member.memberRef, member])), [conversationMembers]);
|
|
236730
|
+
const localReactionActors = (0, react$1.useMemo)(() => {
|
|
236731
|
+
const names = /* @__PURE__ */ new Map();
|
|
236732
|
+
for (const item of items) if (item.memberRef && !item.selfRole && item.senderKind !== "bot") names.set(item.memberRef, {
|
|
236733
|
+
displayName: arkmeTimelineSenderName(item, selfProfile),
|
|
236734
|
+
...item.avatarRef ? { avatarRef: item.avatarRef } : {}
|
|
236735
|
+
});
|
|
236736
|
+
for (const member of conversationMembers) if (member.status === "active" && member.displayName.trim() && member.displayName !== "群成员") names.set(member.memberRef, {
|
|
236737
|
+
displayName: member.displayName,
|
|
236738
|
+
...member.avatarRef ? { avatarRef: member.avatarRef } : {}
|
|
236739
|
+
});
|
|
236740
|
+
return names;
|
|
236741
|
+
}, [
|
|
236742
|
+
items,
|
|
236743
|
+
selfProfile,
|
|
236744
|
+
conversationMembers
|
|
236745
|
+
]);
|
|
236746
|
+
const resolveReactionActor = (0, react$1.useCallback)((actor) => {
|
|
236747
|
+
const self = conversationMembers.find((member) => member.isSelf);
|
|
236748
|
+
const local = actor.userId === authenticatedUserId ? {
|
|
236749
|
+
displayName: (source?.kind === "group_chat" ? self?.memberName : void 0) || selfProfile?.displayName || selfProfile?.nickname || "我",
|
|
236750
|
+
...selfProfile?.avatarRef ? { avatarRef: selfProfile.avatarRef } : {}
|
|
236751
|
+
} : source?.kind === "private_chat" && actor.userId === source.peerUserId ? {
|
|
236752
|
+
displayName: source.displayName,
|
|
236753
|
+
...source.avatarRef ? { avatarRef: source.avatarRef } : {}
|
|
236754
|
+
} : actor.memberRef ? localReactionActors.get(actor.memberRef) : void 0;
|
|
236755
|
+
return local ? {
|
|
236756
|
+
...actor,
|
|
236757
|
+
...local,
|
|
236758
|
+
presentationPending: false
|
|
236759
|
+
} : void 0;
|
|
236760
|
+
}, [
|
|
236761
|
+
authenticatedUserId,
|
|
236762
|
+
source,
|
|
236763
|
+
selfProfile,
|
|
236764
|
+
conversationMembers,
|
|
236765
|
+
localReactionActors
|
|
236766
|
+
]);
|
|
236425
236767
|
const composerMentionsEnabled = source?.kind === "group_chat" || source?.kind === "private_chat";
|
|
236426
236768
|
const mentionCandidates = (0, react$1.useMemo)(() => {
|
|
236427
236769
|
if (!composerMentionsEnabled || mentionTrigger === void 0) return [];
|
|
@@ -238971,6 +239313,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
238971
239313
|
},
|
|
238972
239314
|
children: [!isSharedRecordingCard && !isExtensionMessage && messageHeader, (() => {
|
|
238973
239315
|
const reactionTarget = {
|
|
239316
|
+
resolveActor: resolveReactionActor,
|
|
238974
239317
|
sourceKey: source.sourceKey,
|
|
238975
239318
|
itemUid: item.itemUid,
|
|
238976
239319
|
id: `${conversationKey}:${arkmeTimelineOccurrenceKey(item)}`,
|
|
@@ -239215,6 +239558,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
239215
239558
|
selfProfile,
|
|
239216
239559
|
selfConversationMember,
|
|
239217
239560
|
conversationMemberByRef,
|
|
239561
|
+
resolveReactionActor,
|
|
239218
239562
|
activeSelectMode,
|
|
239219
239563
|
archiveReadOnly,
|
|
239220
239564
|
authenticatedAccountKey,
|
|
@@ -241885,7 +242229,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
241885
242229
|
};
|
|
241886
242230
|
});
|
|
241887
242231
|
const foreground = arkmeRealtimeTimelineDeliveryAllowed(browserDocument?.visibilityState, browserDocument?.hasFocus?.() ?? true);
|
|
241888
|
-
if (
|
|
242232
|
+
if (timelineUpdates.length > 0) arkmeChatTimelineDelta.publish(timelineUpdates);
|
|
241889
242233
|
for (const dateStamp of arkmeChatDeltaCalendarDateStamps(update)) arkmeCalendarInvalidations.publish({ dateStamp });
|
|
241890
242234
|
if (foreground && arkmeSelectedBotAffectedByChatDelta(arkmeUi.getSnapshot().selectedBot, update)) arkmeUi.chatChanged();
|
|
241891
242235
|
for (const sourceKey of arkmeChatDeltaSourceKeys(update)) arkmeInterwovenInvalidation.invalidate(sourceKey);
|