@senguoyun/dsh-arkme 0.1.84 → 0.1.85

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.
Files changed (64) hide show
  1. package/docs/self-role-cross-client.md +60 -0
  2. package/lib/client.js +1397 -419
  3. package/lib/client.js.map +1 -1
  4. package/lib/harness-model-client.js +58 -0
  5. package/lib/harness-native-selection-client.js +58 -0
  6. package/lib/harness-sidebar-client.js +40 -0
  7. package/lib/index.js +135 -66
  8. package/lib/persistent-extension.js +1 -1
  9. package/lib/{persistent-runtime-CuKplHIv.js → persistent-runtime-adGFmkIa.js} +457 -93
  10. package/lib/sdk.js +40 -0
  11. package/lib/types/arkme-service.d.ts +2 -3
  12. package/lib/types/arkme-service.d.ts.map +1 -1
  13. package/lib/types/client/ArkmeCalendarSurface.d.ts.map +1 -1
  14. package/lib/types/client/ArkmeFileViewer.d.ts.map +1 -1
  15. package/lib/types/client/ArkmeLongArticleDialog.d.ts +0 -1
  16. package/lib/types/client/ArkmeLongArticleDialog.d.ts.map +1 -1
  17. package/lib/types/client/ArkmeLongArticleDraftDialog.d.ts +11 -0
  18. package/lib/types/client/ArkmeLongArticleDraftDialog.d.ts.map +1 -0
  19. package/lib/types/client/ArkmeMarkdownBody.d.ts +2 -1
  20. package/lib/types/client/ArkmeMarkdownBody.d.ts.map +1 -1
  21. package/lib/types/client/ArkmePersistentShell.d.ts.map +1 -1
  22. package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
  23. package/lib/types/client/ArkmeSelfRoleMenu.d.ts +15 -0
  24. package/lib/types/client/ArkmeSelfRoleMenu.d.ts.map +1 -0
  25. package/lib/types/client/ArkmeSelfRolePicker.d.ts.map +1 -1
  26. package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
  27. package/lib/types/client/locale.d.ts +1 -1
  28. package/lib/types/client/locale.d.ts.map +1 -1
  29. package/lib/types/client/locales/actions-en.d.ts.map +1 -1
  30. package/lib/types/client/locales/en.d.ts.map +1 -1
  31. package/lib/types/client/realtime-client-events.d.ts.map +1 -1
  32. package/lib/types/client/recordings/ArkmeRecordingTimeline.d.ts.map +1 -1
  33. package/lib/types/local-database.d.ts +8 -10
  34. package/lib/types/local-database.d.ts.map +1 -1
  35. package/lib/types/markdown.d.ts +1 -0
  36. package/lib/types/markdown.d.ts.map +1 -1
  37. package/lib/types/recording-presentation.d.ts.map +1 -1
  38. package/lib/types/sdk/index.d.ts +11 -0
  39. package/lib/types/sdk/index.d.ts.map +1 -1
  40. package/lib/types/self-role-avatar-store.d.ts +1 -6
  41. package/lib/types/self-role-avatar-store.d.ts.map +1 -1
  42. package/lib/types/self-role-contract.d.ts +13 -0
  43. package/lib/types/self-role-contract.d.ts.map +1 -0
  44. package/lib/types/self-role-sync-store.d.ts +44 -0
  45. package/lib/types/self-role-sync-store.d.ts.map +1 -0
  46. package/lib/types/services/chat-realtime-service.d.ts +1 -0
  47. package/lib/types/services/chat-realtime-service.d.ts.map +1 -1
  48. package/lib/types/services/chat-service.d.ts.map +1 -1
  49. package/lib/types/services/media-service.d.ts +15 -0
  50. package/lib/types/services/media-service.d.ts.map +1 -1
  51. package/lib/types/services/record-service.d.ts +3 -0
  52. package/lib/types/services/record-service.d.ts.map +1 -1
  53. package/lib/types/services/search-service.d.ts.map +1 -1
  54. package/lib/types/services/self-role-service.d.ts +29 -0
  55. package/lib/types/services/self-role-service.d.ts.map +1 -0
  56. package/lib/types/tools/business/index.d.ts.map +1 -1
  57. package/lib/types/tools/business/records/create.d.ts.map +1 -1
  58. package/lib/types/tools/business/records/self-roles.d.ts +2 -0
  59. package/lib/types/tools/business/records/self-roles.d.ts.map +1 -0
  60. package/lib/types/tools/ports/index.d.ts +2 -1
  61. package/lib/types/tools/ports/index.d.ts.map +1 -1
  62. package/lib/types/types.d.ts +27 -1
  63. package/lib/types/types.d.ts.map +1 -1
  64. package/package.json +5 -5
@@ -2053,6 +2053,181 @@ var ServiceRuntime = class {
2053
2053
  }
2054
2054
  };
2055
2055
  //#endregion
2056
+ //#region src/services/self-role-service.ts
2057
+ /** Account-scoped role recovery. Existing message senders only request a frozen
2058
+ * snapshot; role CRUD does not enqueue or resend message content. */
2059
+ var SelfRoleService = class {
2060
+ runtime;
2061
+ local;
2062
+ avatars;
2063
+ media;
2064
+ active = /* @__PURE__ */ new Map();
2065
+ timer;
2066
+ closed = false;
2067
+ constructor(runtime, local, avatars, media) {
2068
+ this.runtime = runtime;
2069
+ this.local = local;
2070
+ this.avatars = avatars;
2071
+ this.media = media;
2072
+ }
2073
+ start() {
2074
+ this.closed = false;
2075
+ const kick = () => {
2076
+ this.refresh().catch(() => void 0);
2077
+ };
2078
+ kick();
2079
+ this.timer = setInterval(kick, 3e4);
2080
+ this.timer.unref?.();
2081
+ return () => this.dispose();
2082
+ }
2083
+ dispose() {
2084
+ this.closed = true;
2085
+ if (this.timer) clearInterval(this.timer);
2086
+ this.timer = void 0;
2087
+ }
2088
+ async assertAccount(session) {
2089
+ if (this.closed || (await this.runtime.requireSession()).userId !== session.userId) throw new ArkmePluginError("self-role-account-changed", "账号已切换,角色操作保留待恢复", false, 409);
2090
+ }
2091
+ async asset(session, ref) {
2092
+ if (!ref) return void 0;
2093
+ if (ref.startsWith("file_asset://")) return ref.slice(13);
2094
+ const cached = this.local?.selfRoleSync.asset(session.userId, ref);
2095
+ if (cached) return cached;
2096
+ const image = await this.avatars.read(session.userId, ref);
2097
+ await this.assertAccount(session);
2098
+ const uploaded = await this.media.uploadLocalFile(this.avatars.uploadPath(session.userId, ref), {
2099
+ size: image.data.length,
2100
+ sha256: createHash("sha256").update(image.data).digest("hex"),
2101
+ mimeType: image.mediaType,
2102
+ fileName: "self-role-avatar",
2103
+ fileKind: 1
2104
+ }, {
2105
+ expectedUserId: session.userId,
2106
+ completionRecovery: {
2107
+ read: () => this.local?.selfRoleSync.pendingAvatarCompletion(session.userId, ref),
2108
+ save: (completion) => this.local?.selfRoleSync.saveAvatarCompletion(session.userId, ref, completion)
2109
+ }
2110
+ });
2111
+ await this.assertAccount(session);
2112
+ this.local?.selfRoleSync.saveAsset(session.userId, ref, uploaded.fileAssetUid);
2113
+ return uploaded.fileAssetUid;
2114
+ }
2115
+ async cloudSnapshot(session, s) {
2116
+ const uid = await this.asset(session, s.avatarRef);
2117
+ return {
2118
+ role_id: s.roleId,
2119
+ name: s.name,
2120
+ ...uid ? { avatar_file_asset_uid: uid } : {}
2121
+ };
2122
+ }
2123
+ async flush(session, roleId) {
2124
+ const local = this.local;
2125
+ if (!local) return;
2126
+ let failure;
2127
+ for (const id of roleId === void 0 ? local.selfRoleSync.dirtyRoleIds(session.userId) : [roleId]) for (let i = 0; i < 200; i++) {
2128
+ await this.assertAccount(session);
2129
+ const op = local.selfRoleSync.next(session.userId, id);
2130
+ if (!op) break;
2131
+ try {
2132
+ const snapshot = op.deletedAt > 0 ? {
2133
+ role_id: op.roleId,
2134
+ name: op.name,
2135
+ ...op.avatarRef?.startsWith("file_asset://") ? { avatar_file_asset_uid: op.avatarRef.slice(13) } : {}
2136
+ } : await this.cloudSnapshot(session, op);
2137
+ const role = await this.runtime.authenticatedPost("/api/v1/self-roles/apply", {
2138
+ ...snapshot,
2139
+ name_at: op.nameAt,
2140
+ avatar_at: op.avatarAt,
2141
+ deleted_at: op.deletedAt
2142
+ }, session);
2143
+ await this.assertAccount(session);
2144
+ local.selfRoleSync.acknowledge(session.userId, role);
2145
+ } catch (error) {
2146
+ failure ??= error;
2147
+ break;
2148
+ }
2149
+ }
2150
+ if (failure) throw failure;
2151
+ }
2152
+ async prepare(session, recordUid) {
2153
+ const local = this.local;
2154
+ if (!local) return void 0;
2155
+ const snapshot = (await local.selfRoleSnapshots(session.userId, [recordUid])).get(recordUid);
2156
+ if (!snapshot) return void 0;
2157
+ if (local.selfRoleSync.isKnownRemotely(session.userId, snapshot.roleId) && (!snapshot.avatarRef || snapshot.avatarRef.startsWith("file_asset://"))) {
2158
+ await this.assertAccount(session);
2159
+ return await this.cloudSnapshot(session, snapshot);
2160
+ }
2161
+ let prepared;
2162
+ await this.exclusive(session.userId, async () => {
2163
+ await this.assertAccount(session);
2164
+ if (!local.selfRoleSync.isKnownRemotely(session.userId, snapshot.roleId)) await this.flush(session, snapshot.roleId);
2165
+ await this.assertAccount(session);
2166
+ prepared = await this.cloudSnapshot(session, snapshot);
2167
+ });
2168
+ return prepared;
2169
+ }
2170
+ acknowledge(session, uid) {
2171
+ this.local?.selfRoleSync.acknowledgeBinding(session.userId, uid);
2172
+ }
2173
+ async exclusive(userId, work) {
2174
+ const next = (this.active.get(userId) ?? Promise.resolve()).catch(() => void 0).then(work);
2175
+ this.active.set(userId, next);
2176
+ try {
2177
+ await next;
2178
+ } finally {
2179
+ if (this.active.get(userId) === next) this.active.delete(userId);
2180
+ }
2181
+ }
2182
+ async refresh() {
2183
+ if (!this.local || this.closed) return;
2184
+ const session = await this.runtime.requireSession();
2185
+ const running = this.active.get(session.userId);
2186
+ if (running) return await running;
2187
+ await this.exclusive(session.userId, async () => {
2188
+ let failure;
2189
+ try {
2190
+ await this.flush(session);
2191
+ } catch (error) {
2192
+ failure = error;
2193
+ }
2194
+ let after = "";
2195
+ do {
2196
+ await this.assertAccount(session);
2197
+ const page = await this.runtime.authenticatedPost("/api/v1/self-roles/list", {
2198
+ after,
2199
+ limit: 100
2200
+ }, session);
2201
+ await this.assertAccount(session);
2202
+ for (const role of page.items) this.local.selfRoleSync.merge(session.userId, role);
2203
+ after = page.next_cursor;
2204
+ } while (after);
2205
+ let cursor = "";
2206
+ for (;;) {
2207
+ const batch = this.local.selfRoleSync.pendingBindings(session.userId, cursor);
2208
+ if (batch.length === 0) break;
2209
+ for (const binding of batch) {
2210
+ await this.assertAccount(session);
2211
+ try {
2212
+ const snapshot = await this.cloudSnapshot(session, binding.snapshot);
2213
+ await this.runtime.authenticatedPost("/api/v1/records/self-role/fill", {
2214
+ record_uid: binding.recordUid,
2215
+ self_role_snapshot: snapshot
2216
+ }, session);
2217
+ await this.assertAccount(session);
2218
+ this.local.selfRoleSync.acknowledgeBinding(session.userId, binding.recordUid);
2219
+ } catch (error) {
2220
+ if (!(error instanceof Error) || !error.message.includes("invalid self role")) failure ??= error;
2221
+ await this.assertAccount(session);
2222
+ }
2223
+ cursor = binding.recordUid;
2224
+ }
2225
+ }
2226
+ if (failure) throw failure;
2227
+ });
2228
+ }
2229
+ };
2230
+ //#endregion
2056
2231
  //#region src/ai-points.ts
2057
2232
  function pointsUnits(value) {
2058
2233
  if (!/^(?:0|[1-9]\d*)(?:\.\d{1,7})?$/.test(value)) throw new TypeError("Invalid exact AI points");
@@ -2242,31 +2417,9 @@ function imageType(data) {
2242
2417
  }
2243
2418
  var SelfRoleAvatarStore = class {
2244
2419
  rootDirectory;
2245
- migrationRetryAt = /* @__PURE__ */ new Map();
2246
- migrationInFlight = /* @__PURE__ */ new Map();
2247
2420
  constructor(rootDirectory) {
2248
2421
  this.rootDirectory = rootDirectory;
2249
2422
  }
2250
- migrationRetryAfter(userId, ref) {
2251
- return this.migrationRetryAt.get(`${String(userId)}:${ref}`) ?? 0;
2252
- }
2253
- deferMigration(userId, ref, retryAtMillis) {
2254
- this.migrationRetryAt.set(`${String(userId)}:${ref}`, retryAtMillis);
2255
- }
2256
- clearMigrationDelay(userId, ref) {
2257
- this.migrationRetryAt.delete(`${String(userId)}:${ref}`);
2258
- }
2259
- async runLegacyMigration(userId, migrate) {
2260
- const existing = this.migrationInFlight.get(userId);
2261
- if (existing !== void 0) return await existing;
2262
- const pending = migrate();
2263
- this.migrationInFlight.set(userId, pending);
2264
- try {
2265
- await pending;
2266
- } finally {
2267
- this.migrationInFlight.delete(userId);
2268
- }
2269
- }
2270
2423
  accountDirectory(userId) {
2271
2424
  assertUserId(userId);
2272
2425
  return join(this.rootDirectory, String(userId));
@@ -2316,6 +2469,9 @@ var SelfRoleAvatarStore = class {
2316
2469
  return false;
2317
2470
  }
2318
2471
  }
2472
+ uploadPath(userId, ref) {
2473
+ return this.avatarPath(userId, ref);
2474
+ }
2319
2475
  async read(userId, ref, maxBytes = MAX_SELF_ROLE_AVATAR_BYTES) {
2320
2476
  const path = this.avatarPath(userId, ref);
2321
2477
  const limit = Math.min(MAX_SELF_ROLE_AVATAR_BYTES, Math.max(1, Math.trunc(maxBytes)));
@@ -10005,7 +10161,7 @@ function factorySpace(effects, ok, type, max) {
10005
10161
  * } from 'micromark-util-types'
10006
10162
  */
10007
10163
  /** @type {InitialConstruct} */
10008
- const content$1 = { tokenize: initializeContent };
10164
+ const content$2 = { tokenize: initializeContent };
10009
10165
  /**
10010
10166
  * @this {TokenizeContext}
10011
10167
  * Context.
@@ -12287,7 +12443,7 @@ function subcontent(events, eventIndex) {
12287
12443
  * No name because it must not be turned off.
12288
12444
  * @type {Construct}
12289
12445
  */
12290
- const content = {
12446
+ const content$1 = {
12291
12447
  resolve: resolveContent,
12292
12448
  tokenize: tokenizeContent
12293
12449
  };
@@ -15928,7 +16084,7 @@ const flow$1 = { tokenize: initializeFlow };
15928
16084
  */
15929
16085
  function initializeFlow(effects) {
15930
16086
  const self = this;
15931
- const initial = effects.attempt(blankLine, atBlankEnding, effects.attempt(this.parser.constructs.flowInitial, afterConstruct, factorySpace(effects, effects.attempt(this.parser.constructs.flow, afterConstruct, effects.attempt(content, afterConstruct)), "linePrefix")));
16087
+ const initial = effects.attempt(blankLine, atBlankEnding, effects.attempt(this.parser.constructs.flowInitial, afterConstruct, factorySpace(effects, effects.attempt(this.parser.constructs.flow, afterConstruct, effects.attempt(content$1, afterConstruct)), "linePrefix")));
15932
16088
  return initial;
15933
16089
  /** @type {State} */
15934
16090
  function atBlankEnding(code) {
@@ -16700,7 +16856,7 @@ function parse(options) {
16700
16856
  /** @type {ParseContext} */
16701
16857
  const parser = {
16702
16858
  constructs: combineExtensions([constructs_exports, ...(options || {}).extensions || []]),
16703
- content: create(content$1),
16859
+ content: create(content$2),
16704
16860
  defined: [],
16705
16861
  document: create(document$2),
16706
16862
  flow: create(flow$1),
@@ -45769,6 +45925,7 @@ var ChatRealtimeService = class {
45769
45925
  this.notificationBaselineOwnerGeneration = 0;
45770
45926
  this.chatClientListeners.clear();
45771
45927
  }
45928
+ selfRoleInvalidation;
45772
45929
  startChatRealtime() {
45773
45930
  this.attentionStopped = false;
45774
45931
  this.realtimeStarted = true;
@@ -45829,6 +45986,7 @@ var ChatRealtimeService = class {
45829
45986
  return;
45830
45987
  }
45831
45988
  if (notice.cause === "reconcile") {
45989
+ this.selfRoleInvalidation?.().catch(() => void 0);
45832
45990
  const generation = notice.state.connectionGeneration;
45833
45991
  if (notice.connectionUserId !== void 0) this.activateAttentionOwner(notice.connectionUserId);
45834
45992
  this.notificationBaselineGeneration = 0;
@@ -45862,6 +46020,14 @@ var ChatRealtimeService = class {
45862
46020
  this.invalidateTopicDirectoryProjection();
45863
46021
  return;
45864
46022
  }
46023
+ if (notice.cause === "projection-invalidation" && notice.projectionInvalidation?.projection === "self_role") {
46024
+ this.selfRoleInvalidation?.().then(() => this.emitChatClientEvent({
46025
+ type: "projection-invalidated",
46026
+ projection: "self_role",
46027
+ revision: this.nextChatClientRevision()
46028
+ })).catch(() => void 0);
46029
+ return;
46030
+ }
45865
46031
  if (notice.cause === "projection-invalidation" && notice.projectionInvalidation?.projection === "record") {
45866
46032
  this.invalidateRecordProjection();
45867
46033
  return;
@@ -46813,6 +46979,126 @@ var ChatRealtimeService = class {
46813
46979
  }
46814
46980
  };
46815
46981
  //#endregion
46982
+ //#region src/self-role-sync-store.ts
46983
+ const desired = (r) => ({
46984
+ roleId: r.role_id,
46985
+ name: r.name,
46986
+ ...r.avatar_ref ? { avatarRef: r.avatar_ref } : {},
46987
+ nameAt: r.name_at,
46988
+ avatarAt: r.avatar_at,
46989
+ deletedAt: r.deleted_at
46990
+ });
46991
+ const content = (w) => JSON.stringify([
46992
+ w.roleId,
46993
+ w.name,
46994
+ w.avatarRef ?? "",
46995
+ w.nameAt,
46996
+ w.avatarAt,
46997
+ w.deletedAt
46998
+ ]);
46999
+ const fromCloud = (r) => ({
47000
+ roleId: r.role_id,
47001
+ name: r.name,
47002
+ ...r.avatar_file_asset_uid ? { avatarRef: `file_asset://${r.avatar_file_asset_uid}` } : {},
47003
+ nameAt: r.name_at,
47004
+ avatarAt: r.avatar_at,
47005
+ deletedAt: r.deleted_at
47006
+ });
47007
+ const newer = (time, value, oldTime, oldValue) => time > oldTime || time === oldTime && Buffer.compare(Buffer.from(value), Buffer.from(oldValue)) > 0;
47008
+ /** Attribute timestamps make retries idempotent; no persisted request or conflict state. */
47009
+ var SelfRoleSyncStore = class {
47010
+ db;
47011
+ transaction;
47012
+ constructor(db, transaction) {
47013
+ this.db = db;
47014
+ this.transaction = transaction;
47015
+ const columns = new Set(db.prepare("PRAGMA table_info(self_role)").all().map((r) => r.name));
47016
+ for (const [name, type] of Object.entries({
47017
+ deleted: "INTEGER NOT NULL DEFAULT 0",
47018
+ name_at: "INTEGER NOT NULL DEFAULT 0",
47019
+ avatar_at: "INTEGER NOT NULL DEFAULT 0",
47020
+ deleted_at: "INTEGER NOT NULL DEFAULT 0",
47021
+ cloud_payload: "TEXT"
47022
+ })) if (!columns.has(name)) db.exec(`ALTER TABLE self_role ADD COLUMN ${name} ${type}`);
47023
+ db.exec("UPDATE self_role SET name_at=updated_at_millis,avatar_at=updated_at_millis WHERE name_at=0");
47024
+ if (!new Set(db.prepare("PRAGMA table_info(self_role_record)").all().map((r) => r.name)).has("cloud_ack")) db.exec("ALTER TABLE self_role_record ADD COLUMN cloud_ack INTEGER NOT NULL DEFAULT 0");
47025
+ db.exec("CREATE TABLE IF NOT EXISTS self_role_avatar_asset (user_id INTEGER NOT NULL,local_ref TEXT NOT NULL,asset_uid TEXT NOT NULL DEFAULT '',completion_json TEXT,PRIMARY KEY(user_id,local_ref))");
47026
+ }
47027
+ dirtyRoleIds(userId) {
47028
+ return this.db.prepare("SELECT * FROM self_role WHERE user_id=? ORDER BY role_id").all(userId).filter((r) => r.cloud_payload !== content(desired(r))).map((r) => r.role_id);
47029
+ }
47030
+ isKnownRemotely(userId, roleId) {
47031
+ return this.db.prepare("SELECT 1 FROM self_role WHERE user_id=? AND role_id=? AND cloud_payload IS NOT NULL").get(userId, roleId) !== void 0;
47032
+ }
47033
+ next(userId, roleId) {
47034
+ const rows = this.db.prepare(`SELECT * FROM self_role WHERE user_id=? ${roleId === void 0 ? "" : "AND role_id=?"} ORDER BY role_id`).all(...roleId === void 0 ? [userId] : [userId, roleId]);
47035
+ for (const row of rows) {
47036
+ const op = desired(row);
47037
+ if (row.cloud_payload !== content(op)) return op;
47038
+ }
47039
+ }
47040
+ acknowledge(userId, role) {
47041
+ this.merge(userId, role);
47042
+ }
47043
+ merge(userId, role) {
47044
+ this.transaction(() => {
47045
+ const row = this.db.prepare("SELECT * FROM self_role WHERE user_id=? AND role_id=?").get(userId, role.role_id);
47046
+ const cloud = fromCloud(role);
47047
+ const local = row ? desired(row) : cloud;
47048
+ const nameWins = newer(cloud.nameAt, cloud.name, local.nameAt, local.name);
47049
+ const avatarWins = newer(cloud.avatarAt, cloud.avatarRef ?? "", local.avatarAt, local.avatarRef ?? "") || cloud.deletedAt > 0 && cloud.avatarAt === local.avatarAt && !!local.avatarRef && !local.avatarRef.startsWith("file_asset://");
47050
+ const name = nameWins ? cloud.name : local.name, avatar = avatarWins ? cloud.avatarRef : local.avatarRef;
47051
+ const nameAt = Math.max(cloud.nameAt, local.nameAt), avatarAt = Math.max(cloud.avatarAt, local.avatarAt), deletedAt = Math.max(cloud.deletedAt, local.deletedAt);
47052
+ this.db.prepare(`INSERT INTO self_role(user_id,role_id,name,avatar_ref,created_at_millis,updated_at_millis,deleted,name_at,avatar_at,deleted_at,cloud_payload)
47053
+ VALUES(?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT(user_id,role_id) DO UPDATE SET name=excluded.name,avatar_ref=excluded.avatar_ref,updated_at_millis=excluded.updated_at_millis,deleted=excluded.deleted,name_at=excluded.name_at,avatar_at=excluded.avatar_at,deleted_at=excluded.deleted_at,cloud_payload=excluded.cloud_payload`).run(userId, role.role_id, name, avatar ?? null, role.update_at, Math.max(nameAt, avatarAt, deletedAt), Number(deletedAt > 0), nameAt, avatarAt, deletedAt, content(cloud));
47054
+ });
47055
+ }
47056
+ asset(userId, ref) {
47057
+ return this.db.prepare("SELECT asset_uid FROM self_role_avatar_asset WHERE user_id=? AND local_ref=?").get(userId, ref)?.asset_uid;
47058
+ }
47059
+ pendingAvatarCompletion(userId, ref) {
47060
+ const row = this.db.prepare("SELECT completion_json FROM self_role_avatar_asset WHERE user_id=? AND local_ref=?").get(userId, ref);
47061
+ return row?.completion_json ? JSON.parse(row.completion_json) : void 0;
47062
+ }
47063
+ saveAvatarCompletion(userId, ref, completion) {
47064
+ this.db.prepare("INSERT INTO self_role_avatar_asset(user_id,local_ref,completion_json) VALUES(?,?,?) ON CONFLICT(user_id,local_ref) DO UPDATE SET completion_json=excluded.completion_json").run(userId, ref, JSON.stringify(completion));
47065
+ }
47066
+ saveAsset(userId, ref, uid) {
47067
+ this.transaction(() => {
47068
+ this.db.prepare("INSERT INTO self_role_avatar_asset(user_id,local_ref,asset_uid) VALUES(?,?,?) ON CONFLICT(user_id,local_ref) DO UPDATE SET asset_uid=excluded.asset_uid,completion_json=NULL").run(userId, ref, uid);
47069
+ this.db.prepare("UPDATE self_role SET avatar_ref=? WHERE user_id=? AND avatar_ref=?").run(`file_asset://${uid}`, userId, ref);
47070
+ this.db.prepare("UPDATE self_role_record SET avatar_ref=? WHERE user_id=? AND avatar_ref=?").run(`file_asset://${uid}`, userId, ref);
47071
+ });
47072
+ }
47073
+ pendingBindings(userId, after = "") {
47074
+ return this.db.prepare("SELECT record_uid,role_id,role_name,avatar_ref FROM self_role_record WHERE user_id=? AND cloud_ack=0 AND record_uid>? ORDER BY record_uid LIMIT 100").all(userId, after).map((r) => ({
47075
+ recordUid: r.record_uid,
47076
+ snapshot: {
47077
+ roleId: r.role_id,
47078
+ name: r.role_name,
47079
+ ...r.avatar_ref ? { avatarRef: r.avatar_ref } : {}
47080
+ }
47081
+ }));
47082
+ }
47083
+ cacheSnapshot(userId, recordUid, snapshot) {
47084
+ this.db.prepare(`INSERT INTO self_role_record(user_id,record_uid,role_id,role_name,avatar_ref,bound_at_millis,cloud_ack)
47085
+ VALUES(?,?,?,?,?,?,1) ON CONFLICT(user_id,record_uid) DO UPDATE SET role_id=excluded.role_id,role_name=excluded.role_name,avatar_ref=excluded.avatar_ref,cloud_ack=1`).run(userId, recordUid, snapshot.roleId, snapshot.name, snapshot.avatarRef ?? null, Date.now());
47086
+ }
47087
+ acknowledgeBinding(userId, recordUid) {
47088
+ this.db.prepare("UPDATE self_role_record SET cloud_ack=1 WHERE user_id=? AND record_uid=?").run(userId, recordUid);
47089
+ }
47090
+ };
47091
+ function selfRoleSnapshotFromCloud(value) {
47092
+ if (value === null || typeof value !== "object") return void 0;
47093
+ const r = value;
47094
+ if (typeof r.role_id !== "string" || !r.role_id || typeof r.name !== "string" || !r.name) return void 0;
47095
+ return {
47096
+ roleId: r.role_id,
47097
+ name: r.name,
47098
+ ...typeof r.avatar_file_asset_uid === "string" && r.avatar_file_asset_uid ? { avatarRef: `file_asset://${r.avatar_file_asset_uid}` } : {}
47099
+ };
47100
+ }
47101
+ //#endregion
46816
47102
  //#region src/services/mention-metadata-codec.ts
46817
47103
  function encodeMentionMetadata(text, mentions) {
46818
47104
  const checksum = {
@@ -48063,6 +48349,18 @@ var RecordService = class {
48063
48349
  reeditAdmissions = /* @__PURE__ */ new Map();
48064
48350
  activeRecordCommits = /* @__PURE__ */ new Set();
48065
48351
  closed = false;
48352
+ selfRoles;
48353
+ async createPersonalRecord(path, body, session, signal, options = {}) {
48354
+ const account = session ?? await this.runtime.requireSession();
48355
+ const uid = String(body.record_uid ?? "");
48356
+ const snapshot = await this.selfRoles?.prepare(account, uid);
48357
+ const result = await this.runtime.authenticatedPost(path, {
48358
+ ...body,
48359
+ ...snapshot === void 0 ? {} : { self_role_snapshot: snapshot }
48360
+ }, account, signal, options);
48361
+ if (snapshot !== void 0) this.selfRoles?.acknowledge(account, uid);
48362
+ return result;
48363
+ }
48066
48364
  constructor(runtime, media, source, privacy = new ArkmePrivacyVisibilityService(runtime), reeditFiles, onReeditCommitted, resolveReeditMentions, currentSenderSnapshot) {
48067
48365
  this.runtime = runtime;
48068
48366
  this.media = media;
@@ -49094,7 +49392,7 @@ var RecordService = class {
49094
49392
  ].includes(asset.fileKind)) throw new ArkmePluginError("record-file-asset-invalid", "附件资产参数无效", false);
49095
49393
  const hashTags = arkmeHashTagPayload(normalizedText);
49096
49394
  const senderSnapshot = await this.currentSenderSnapshot?.(session);
49097
- const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
49395
+ const data = await this.createPersonalRecord("/api/v1/records/create", {
49098
49396
  record_uid: normalizedUid,
49099
49397
  template_kind: 2,
49100
49398
  display_kind: 0,
@@ -49142,7 +49440,7 @@ var RecordService = class {
49142
49440
  length: tag.length
49143
49441
  })) : arkmeHashTagPayload(normalizedText);
49144
49442
  const senderSnapshot = await this.currentSenderSnapshot?.(session);
49145
- const data = await this.runtime.authenticatedPost("/api/v1/records/extensions/create", {
49443
+ const data = await this.createPersonalRecord("/api/v1/records/extensions/create", {
49146
49444
  parent_record_uid: normalizedParentUid,
49147
49445
  record_uid: normalizedUid,
49148
49446
  template_kind: assets.length === 0 ? 1 : 2,
@@ -49194,7 +49492,7 @@ var RecordService = class {
49194
49492
  const captureContext = pending.captureContext === void 0 ? void 0 : arkmeRecordCaptureContextPayload(pending.captureContext);
49195
49493
  const hashTags = arkmeHashTagPayload(pending.textContent);
49196
49494
  const senderSnapshot = await this.currentSenderSnapshot?.(session);
49197
- const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
49495
+ const data = await this.createPersonalRecord("/api/v1/records/create", {
49198
49496
  record_uid: pending.recordUid,
49199
49497
  template_kind: 1,
49200
49498
  title: "",
@@ -49229,6 +49527,7 @@ var RecordService = class {
49229
49527
  recordTimelineItem(item) {
49230
49528
  return {
49231
49529
  itemUid: item.recordUid,
49530
+ ...item.selfRole === void 0 ? {} : { selfRole: item.selfRole },
49232
49531
  ...item.hasManualEdit === void 0 ? {} : { hasManualEdit: item.hasManualEdit },
49233
49532
  senderName: item.senderName || "我",
49234
49533
  avatarSnapshot: true,
@@ -49266,7 +49565,7 @@ var RecordService = class {
49266
49565
  extensionParentRecordUid: parentRecordUid,
49267
49566
  extensionParent: {
49268
49567
  itemUid: parentRecordUid,
49269
- senderName: stringValue$2(previewRecord.nickname ?? previewRecord.nick_name ?? preview.nickname ?? preview.nick_name).trim() || "我",
49568
+ senderName: selfRoleSnapshotFromCloud(previewRecord.self_role_snapshot)?.name || stringValue$2(previewRecord.nickname ?? previewRecord.nick_name ?? preview.nickname ?? preview.nick_name).trim() || "我",
49270
49569
  title: stringValue$2(previewRecord.title ?? previewPayload.title),
49271
49570
  textContent: stringValue$2(previewRecord.text_content ?? previewRecord.textContent ?? previewPayload.text_content ?? previewPayload.textContent),
49272
49571
  contentBlocks: this.media.richContentBlocks({
@@ -49286,6 +49585,7 @@ var RecordService = class {
49286
49585
  return {
49287
49586
  itemUid: stringValue$2(item.record_uid ?? core.record_uid).trim(),
49288
49587
  ...recordSenderSnapshot(raw),
49588
+ ...cloudSelfRolePresentation(item.self_role_snapshot ?? core.self_role_snapshot),
49289
49589
  isMe: options.isMe ?? numberValue$20(item.creator_user_id ?? item.owner_user_id ?? core.creator_user_id ?? core.owner_user_id) === userId,
49290
49590
  ...callRecord === void 0 ? {} : { callRecord },
49291
49591
  sendAtMillis: numberValue$20(item.send_at ?? core.send_at),
@@ -49320,6 +49620,7 @@ var RecordService = class {
49320
49620
  return {
49321
49621
  recordUid,
49322
49622
  ...recordSenderSnapshot(raw),
49623
+ ...cloudSelfRolePresentation(item.self_role_snapshot ?? core.self_role_snapshot),
49323
49624
  sendAtMillis: numberValue$20(item.send_at ?? core.send_at),
49324
49625
  title: stringValue$2(core.title),
49325
49626
  textContent: stringValue$2(core.text_content),
@@ -49359,6 +49660,10 @@ var RecordService = class {
49359
49660
  };
49360
49661
  }
49361
49662
  };
49663
+ function cloudSelfRolePresentation(value) {
49664
+ const selfRole = selfRoleSnapshotFromCloud(value);
49665
+ return selfRole === void 0 ? {} : { selfRole };
49666
+ }
49362
49667
  //#endregion
49363
49668
  //#region src/record-background-sound.ts
49364
49669
  const LOCAL_FILE_REF = /^arkme-file-v1\.[0-9a-f-]{36}$/;
@@ -50107,6 +50412,7 @@ function messageCopyLinkExtensionItemFromData(value) {
50107
50412
  if (recordUid === "" || sendAtMillis <= 0 || title.trim() === "" && textContent.trim() === "" && mediaItems.length === 0 && structuredContent === void 0) return;
50108
50413
  return {
50109
50414
  recordUid,
50415
+ ...selfRoleSnapshotFromCloud(core.self_role_snapshot ?? data.self_role_snapshot) ? { selfRole: selfRoleSnapshotFromCloud(core.self_role_snapshot ?? data.self_role_snapshot) } : {},
50110
50416
  ...firstTextValue(data, ["parent_record_uid", "parentRecordUid"]) === "" ? {} : { parentRecordUid: firstTextValue(data, ["parent_record_uid", "parentRecordUid"]) },
50111
50417
  ...recordOwnerId(data.record_owner_user_id ?? data.recordOwnerUserId ?? data.user_id ?? data.userId ?? core.record_owner_user_id ?? core.recordOwnerUserId ?? core.user_id ?? core.userId) === 0 ? {} : { recordOwnerUserId: recordOwnerId(data.record_owner_user_id ?? data.recordOwnerUserId ?? data.user_id ?? data.userId ?? core.record_owner_user_id ?? core.recordOwnerUserId ?? core.user_id ?? core.userId) },
50112
50418
  level: Math.max(2, integerLikeValue(data.level) || 2),
@@ -52051,7 +52357,7 @@ var ChatService = class {
52051
52357
  });
52052
52358
  return {
52053
52359
  itemUid: parent.recordUid,
52054
- senderName: item.senderName,
52360
+ senderName: item.selfRole?.name ?? item.senderName,
52055
52361
  title: item.title,
52056
52362
  textContent: item.textContent,
52057
52363
  textFormat: item.textFormat ?? "plain",
@@ -52098,6 +52404,7 @@ var ChatService = class {
52098
52404
  const hydration = await this.media.hydrateRecordMediaPage(readable.map((node) => node.record), session, signal);
52099
52405
  const extensions = nodes.map((node) => {
52100
52406
  if (node.protectedContent) return {
52407
+ protectedContent: true,
52101
52408
  recordUid: node.recordUid,
52102
52409
  parentRecordUid: node.parentRecordUid,
52103
52410
  level: node.level,
@@ -52362,7 +52669,7 @@ var ChatService = class {
52362
52669
  size: asset.size
52363
52670
  })) }
52364
52671
  };
52365
- const data = await this.runtime.authenticatedPost("/api/v1/topics/records/extensions/create", {
52672
+ const data = await this.record.createPersonalRecord("/api/v1/topics/records/extensions/create", {
52366
52673
  topic_uid: source.ownerRef,
52367
52674
  parent_record_uid: reference.recordUid,
52368
52675
  record_uid: normalizedUid,
@@ -52687,7 +52994,7 @@ var ChatService = class {
52687
52994
  }
52688
52995
  if (targetSource.kind === "topic") {
52689
52996
  const senderSnapshot = await this.profile.recordSenderSnapshot?.(session);
52690
- const data = await this.runtime.authenticatedPost("/api/v1/topics/records/create", {
52997
+ const data = await this.record.createPersonalRecord("/api/v1/topics/records/create", {
52691
52998
  topic_uid: targetSource.ownerRef,
52692
52999
  record_uid: recordUid,
52693
53000
  template_kind: 1,
@@ -52706,7 +53013,7 @@ var ChatService = class {
52706
53013
  });
52707
53014
  }
52708
53015
  const senderSnapshot = await this.profile.recordSenderSnapshot?.(session);
52709
- const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
53016
+ const data = await this.record.createPersonalRecord("/api/v1/records/create", {
52710
53017
  record_uid: recordUid,
52711
53018
  template_kind: 1,
52712
53019
  title: "",
@@ -52760,7 +53067,7 @@ var ChatService = class {
52760
53067
  const sendAtMillis = Date.now();
52761
53068
  const senderSnapshot = await this.profile.recordSenderSnapshot?.(session);
52762
53069
  const captureContext = options.captureContext === void 0 ? void 0 : arkmeRecordCaptureContextPayload(options.captureContext);
52763
- const result = await this.runtime.authenticatedPost("/api/v1/topics/records/create", {
53070
+ const result = await this.record.createPersonalRecord("/api/v1/topics/records/create", {
52764
53071
  topic_uid: source.ownerRef,
52765
53072
  record_uid: recordUid,
52766
53073
  template_kind: 1,
@@ -53131,7 +53438,7 @@ var ChatService = class {
53131
53438
  send_at: sendAtMillis
53132
53439
  };
53133
53440
  if (source.kind === "send_to_self" || source.kind === "default_category") {
53134
- const result = await this.runtime.authenticatedPost("/api/v1/records/create", commonBody, session, options.signal, { trackWriteOutcome: true });
53441
+ const result = await this.record.createPersonalRecord("/api/v1/records/create", commonBody, session, options.signal, { trackWriteOutcome: true });
53135
53442
  await this.record.syncCreatedRecordTags?.(stringValue$2(result.record_uid).trim() || recordUid, textContent, session.userId, options.signal, input.textFormat);
53136
53443
  await this.realtime.invalidateRecordProjection({ contentOnly: true });
53137
53444
  return await this.withConfirmedSendReferences({
@@ -53153,7 +53460,7 @@ var ChatService = class {
53153
53460
  });
53154
53461
  }
53155
53462
  if (source.kind === "topic") {
53156
- const result = await this.runtime.authenticatedPost("/api/v1/topics/records/create", {
53463
+ const result = await this.record.createPersonalRecord("/api/v1/topics/records/create", {
53157
53464
  topic_uid: source.ownerRef,
53158
53465
  ...commonBody
53159
53466
  }, session, options.signal, { trackWriteOutcome: true });
@@ -87833,20 +88140,22 @@ var MediaService = class {
87833
88140
  });
87834
88141
  progress("preparing", 0);
87835
88142
  const uploadMode = metadata.size > 16 * 1024 * 1024 ? 2 : 1;
87836
- const prepared = await this.runtime.authenticatedPost("/api/v1/files/prepare-upload", {
88143
+ const pendingCompletion = options.completionRecovery?.read();
88144
+ let completionPersisted = pendingCompletion !== void 0;
88145
+ const prepared = pendingCompletion === void 0 ? await this.runtime.authenticatedPost("/api/v1/files/prepare-upload", {
87837
88146
  planned_size: metadata.size,
87838
88147
  file_hash: metadata.sha256,
87839
88148
  mime_type: metadata.mimeType || "application/octet-stream",
87840
88149
  file_kind: metadata.fileKind,
87841
88150
  upload_mode: uploadMode,
87842
88151
  display_name: metadata.fileName
87843
- }, session, options.signal);
87844
- const uploadSessionUid = stringValue$2(prepared.upload_session_uid).trim();
88152
+ }, session, options.signal) : void 0;
88153
+ const uploadSessionUid = pendingCompletion?.upload_session_uid ?? stringValue$2(prepared?.upload_session_uid).trim();
87845
88154
  if (uploadSessionUid === "") throw new ArkmePluginError("upload-prepare-invalid", "上传准备响应无效", true, 502);
87846
88155
  try {
87847
- let storageETag = "";
87848
- const completedParts = [];
87849
- if (uploadMode === 1) {
88156
+ let storageETag = pendingCompletion?.storage_etag ?? "";
88157
+ const completedParts = pendingCompletion?.multipart_parts ?? [];
88158
+ if (pendingCompletion === void 0) if (uploadMode === 1) {
87850
88159
  const uploadUrl = stringValue$2(prepared.upload_url).trim();
87851
88160
  if (uploadUrl === "") throw new ArkmePluginError("upload-url-missing", "对象存储上传地址缺失", true, 502);
87852
88161
  const signal = options.signal;
@@ -87904,12 +88213,17 @@ var MediaService = class {
87904
88213
  }
87905
88214
  if (options.expectedUserId !== void 0 && (await this.runtime.requireSession()).userId !== options.expectedUserId) throw new ArkmePluginError("file-account-changed", "账号已切换,本次上传已取消", false, 409);
87906
88215
  progress("completing", metadata.size);
87907
- const completed = await this.runtime.authenticatedPost("/api/v1/files/complete-upload", {
88216
+ const completion = {
87908
88217
  upload_session_uid: uploadSessionUid,
87909
88218
  uploaded_size: metadata.size,
87910
88219
  storage_etag: storageETag,
87911
88220
  multipart_parts: completedParts
87912
- }, session, options.signal);
88221
+ };
88222
+ if (options.completionRecovery !== void 0 && !completionPersisted) {
88223
+ options.completionRecovery.save(completion);
88224
+ completionPersisted = true;
88225
+ }
88226
+ const completed = await this.runtime.authenticatedPost("/api/v1/files/complete-upload", { ...completion }, session, options.signal);
87913
88227
  const fileAssetUid = stringValue$2(completed.file_asset_uid).trim();
87914
88228
  if (fileAssetUid === "") throw new ArkmePluginError("upload-complete-invalid", "上传完成响应无效", true, 502);
87915
88229
  if (options.expectedUserId !== void 0 && (await this.runtime.requireSession()).userId !== options.expectedUserId) throw new ArkmePluginError("file-account-changed", "账号已切换,本次上传结果已丢弃", false, 409);
@@ -87922,7 +88236,7 @@ var MediaService = class {
87922
88236
  fileKind: metadata.fileKind
87923
88237
  };
87924
88238
  } catch (error) {
87925
- await this.runtime.authenticatedPost("/api/v1/files/abort-upload", { upload_session_uid: uploadSessionUid }, session).catch(() => void 0);
88239
+ if (!completionPersisted) await this.runtime.authenticatedPost("/api/v1/files/abort-upload", { upload_session_uid: uploadSessionUid }, session).catch(() => void 0);
87926
88240
  throw error;
87927
88241
  }
87928
88242
  }
@@ -91202,12 +91516,17 @@ function normalizeStructuredTimeline(value) {
91202
91516
  const rangeMatch = TIMELINE_HEADER.exec(rawRange);
91203
91517
  const startAt = stringValue(row.start_at ?? row.startAt ?? row.start_time).trim() || rangeMatch?.[1] || "";
91204
91518
  const endAt = stringValue(row.end_at ?? row.endAt ?? row.end_time).trim() || rangeMatch?.[2] || "";
91205
- const dialoguePoints = listValue$6(row.dialogue_points ?? row.dialogues).map(objectValue);
91519
+ const dialoguePoints = listValue$6(row.dialogue_points ?? row.dialogues).map(objectValue).map(normalizeTimelineDialoguePoint).filter((point) => point.speakerName !== "" || point.summary !== "" || point.quote !== "" || point.roleDescription !== "");
91206
91520
  const participantValues = [...listValue$6(row.participants ?? row.roles).map((item) => {
91207
91521
  const participant = objectValue(item);
91208
91522
  return Object.keys(participant).length === 0 ? item : participant.name ?? participant.spk_name;
91209
- }), ...dialoguePoints.map((item) => item.spk_name ?? item.speaker_name)];
91523
+ }), ...dialoguePoints.map((item) => item.speakerName)];
91210
91524
  const tags = listValue$6(row.event_tags ?? row.tags);
91525
+ const otherInfo = normalizeTimelineDetailItems(row.other_info ?? row.otherInfo);
91526
+ const positionNote = stringValue(row.position_note ?? row.positionNote).trim();
91527
+ const environmentNote = stringValue(row.environment_note ?? row.environmentNote).trim();
91528
+ const praise = stringValue(row.praise ?? row.praise_text).trim();
91529
+ const praisePoint = optionalNumberValue(row.praise_point ?? row.praisePoint);
91211
91530
  return {
91212
91531
  eventId: stringValue(row.id ?? row.event_id).trim() || `event-${index}`,
91213
91532
  startAt,
@@ -91220,10 +91539,41 @@ function normalizeStructuredTimeline(value) {
91220
91539
  todo: stringValue(row.todo ?? row.todo_item ?? row.todos).trim(),
91221
91540
  tags: uniqueStrings(tags),
91222
91541
  participants: uniqueStrings(participantValues),
91223
- rawText: stringValue(row.raw_source).trim()
91542
+ rawText: stringValue(row.raw_source).trim(),
91543
+ ...stringValue(row.period_label ?? row.periodLabel).trim() === "" ? {} : { periodLabel: stringValue(row.period_label ?? row.periodLabel).trim() },
91544
+ ...stringValue(row.duration_text ?? row.durationText).trim() === "" ? {} : { durationText: stringValue(row.duration_text ?? row.durationText).trim() },
91545
+ ...typeof row.related_to_me === "boolean" || typeof row.relatedToMe === "boolean" ? { relatedToMe: row.related_to_me === true || row.relatedToMe === true } : {},
91546
+ ...positionNote === "" ? {} : { positionNote },
91547
+ ...environmentNote === "" ? {} : { environmentNote },
91548
+ ...praise === "" ? {} : { praise },
91549
+ ...praisePoint === void 0 ? {} : { praisePoint },
91550
+ ...stringValue(row.speaker_note ?? row.speakerNote).trim() === "" ? {} : { speakerNote: stringValue(row.speaker_note ?? row.speakerNote).trim() },
91551
+ ...dialoguePoints.length === 0 ? {} : { dialoguePoints },
91552
+ ...otherInfo.length === 0 ? {} : { otherInfo }
91224
91553
  };
91225
91554
  }).filter((item) => item.startAt !== "" || item.endAt !== "" || item.title !== "" || item.description !== "");
91226
91555
  }
91556
+ function normalizeTimelineDialoguePoint(row) {
91557
+ const rawData = listValue$6(row.raw_data_ls ?? row.rawData).map(objectValue);
91558
+ const quote = rawData.map((item) => stringValue(item.text ?? item.content).trim()).filter((value) => value !== "").join("\n");
91559
+ return {
91560
+ speakerName: stringValue(row.spk_name ?? row.speaker_name ?? row.speakerName).trim(),
91561
+ summary: stringValue(row.summary ?? row.summary_content).trim(),
91562
+ quote: stringValue(row.quote ?? row.quote_content).trim() || quote,
91563
+ roleDescription: stringValue(row.role_description ?? row.roleDescription).trim() || rawData.map((item) => stringValue(item.role_in_period ?? item.roleInPeriod).trim()).filter((value) => value !== "").filter((value, index, values) => values.indexOf(value) === index).join(";"),
91564
+ isSelf: row.is_self === true || row.isSelf === true
91565
+ };
91566
+ }
91567
+ function normalizeTimelineDetailItems(value) {
91568
+ return listValue$6(value).map(objectValue).flatMap((item) => {
91569
+ const label = stringValue(item.label ?? item.name).trim();
91570
+ const detail = stringValue(item.value ?? item.content ?? item.text).trim();
91571
+ return label !== "" && detail !== "" ? [{
91572
+ label,
91573
+ value: detail
91574
+ }] : [];
91575
+ });
91576
+ }
91227
91577
  const TIMELINE_HEADER = /^(\d{1,2}:\d{2}(?::\d{2})?)\s*[-–—~~至]\s*(\d{1,2}:\d{2}(?::\d{2})?)\s*(.*)$/;
91228
91578
  const TIMELINE_SECTION_LABELS = /* @__PURE__ */ new Set([
91229
91579
  "场景类型",
@@ -91239,9 +91589,15 @@ const TIMELINE_SECTION_LABELS = /* @__PURE__ */ new Set([
91239
91589
  "关键对话",
91240
91590
  "环境",
91241
91591
  "环境说明",
91592
+ "环境备注",
91242
91593
  "评价",
91243
91594
  "表扬",
91244
- "事件标签"
91595
+ "事件标签",
91596
+ "场景说明",
91597
+ "位置说明",
91598
+ "说话人备注",
91599
+ "说话人说明",
91600
+ "其他信息"
91245
91601
  ]);
91246
91602
  function cleanMarkdownLine(source) {
91247
91603
  return source.trim().replace(/^#{1,6}\s*/, "").replace(/^>\s*/, "").replace(/^[-*+•]\s+/, "").replace(/\*\*|__|`/g, "").trim();
@@ -91284,6 +91640,18 @@ function markdownEvent(event, index) {
91284
91640
  return sectionValue(event.lines, names);
91285
91641
  };
91286
91642
  const description = field("发生的事情", "内容描述") || unsectionedValue(event.lines);
91643
+ const quote = field("代表性原话", "关键对话");
91644
+ const speakerNote = field("说话人备注", "说话人说明");
91645
+ const positionNote = field("场景说明", "位置说明");
91646
+ const environmentNote = field("环境", "环境说明", "环境备注");
91647
+ const praise = field("评价", "表扬");
91648
+ const dialoguePoints = quote === "" ? [] : [{
91649
+ speakerName: "",
91650
+ summary: "",
91651
+ quote,
91652
+ roleDescription: "",
91653
+ isSelf: false
91654
+ }];
91287
91655
  return {
91288
91656
  eventId: `event-${index}`,
91289
91657
  startAt: event.startAt,
@@ -91296,7 +91664,12 @@ function markdownEvent(event, index) {
91296
91664
  todo: field("待办"),
91297
91665
  tags: splitLabels(field("事件标签")),
91298
91666
  participants: splitLabels(field("角色", "说话人")),
91299
- rawText: event.lines.join("\n").trim()
91667
+ rawText: event.lines.join("\n").trim(),
91668
+ ...positionNote === "" ? {} : { positionNote },
91669
+ ...environmentNote === "" ? {} : { environmentNote },
91670
+ ...praise === "" ? {} : { praise },
91671
+ ...speakerNote === "" ? {} : { speakerNote },
91672
+ ...dialoguePoints.length === 0 ? {} : { dialoguePoints }
91300
91673
  };
91301
91674
  }
91302
91675
  function parseMarkdownTimeline(markdown) {
@@ -94330,6 +94703,7 @@ var SearchService = class {
94330
94703
  const recordOwnerUserId = recordOwnerId(core.owner_user_id);
94331
94704
  return {
94332
94705
  recordUid,
94706
+ ...selfRoleSnapshotFromCloud(core.self_role_snapshot) ? { selfRole: selfRoleSnapshotFromCloud(core.self_role_snapshot) } : {},
94333
94707
  ...recordOwnerUserId !== 0 ? { recordOwnerUserId } : {},
94334
94708
  ...recordOwnerId(core.creator_user_id) !== 0 ? { recordCreatorUserId: recordOwnerId(core.creator_user_id) } : {},
94335
94709
  sourceKind: Math.trunc(numberValue$2(item.source_kind)),
@@ -98084,6 +98458,7 @@ var ArkmeService = class {
98084
98458
  linkMetadata;
98085
98459
  aiPolish;
98086
98460
  chat;
98461
+ selfRoles;
98087
98462
  recordEditHistory;
98088
98463
  relatedQuickNote;
98089
98464
  contact;
@@ -98121,6 +98496,8 @@ var ArkmeService = class {
98121
98496
  return await this.createTextForConversation(recordUid, textContent);
98122
98497
  } });
98123
98498
  this.media = new MediaService(this.runtime, this.profile, { openWorldImageRef: async (imageRef, viewerUserId) => await this.openWorldImageRef(imageRef, viewerUserId) }, { recordUid: (raw) => this.recordUid(raw) }, { openBotImageRef: async (imageRef, viewerUserId) => await this.bot.openBotImageRef(imageRef, viewerUserId) }, this.selfRoleAvatars);
98499
+ const roleLocal = this.stateStore;
98500
+ this.selfRoles = new SelfRoleService(this.runtime, roleLocal.selfRoleSync === void 0 ? void 0 : roleLocal, this.selfRoleAvatars, this.media);
98124
98501
  this.source = new SourceService(this.runtime, this.profile, {
98125
98502
  summary: async () => await this.summary(),
98126
98503
  recordItem: (raw) => this.recordItem(raw),
@@ -98138,6 +98515,7 @@ var ArkmeService = class {
98138
98515
  }, async () => {
98139
98516
  await this.realtime.invalidateRecordProjection();
98140
98517
  }, async (source, text, humans, bots, session, textFormat) => await this.chat.resolveMentions(source, text, text, humans, bots, session, void 0, textFormat), async (session) => await this.profile.recordSenderSnapshot(session));
98518
+ this.record.selfRoles = this.selfRoles;
98141
98519
  this.calendar = new CalendarService(this.runtime, this.privacy, this.media, this.record, this.source, this.callHistory);
98142
98520
  this.search = new SearchService(this.runtime, this.record, this.media, this.source, this.privacy, this.profile);
98143
98521
  if (localDshQuery !== void 0) this.search.localDshQuery = localDshQuery;
@@ -98173,6 +98551,7 @@ var ArkmeService = class {
98173
98551
  });
98174
98552
  this.realtime.refreshAttentionSummary();
98175
98553
  }, async (bots, userId) => await this.bot.restoreDirectoryBots(bots, userId));
98554
+ this.realtime.selfRoleInvalidation = async () => await this.selfRoles.refresh();
98176
98555
  this.realtime.directoryInvalidation = async (hint) => await this.directory.invalidate(hint);
98177
98556
  this.realtime.directoryAttention = async (retry) => await this.directory.attentionSummary(retry);
98178
98557
  this.realtime.directoryBaseline = async () => await this.directory.complete();
@@ -98378,7 +98757,12 @@ var ArkmeService = class {
98378
98757
  this.bot.clearAccountRefs();
98379
98758
  }
98380
98759
  startChatRealtime() {
98381
- return this.realtime.startChatRealtime();
98760
+ const stopRoles = this.selfRoles.start();
98761
+ const stopRealtime = this.realtime.startChatRealtime();
98762
+ return () => {
98763
+ stopRoles();
98764
+ stopRealtime();
98765
+ };
98382
98766
  }
98383
98767
  chatRealtimeState() {
98384
98768
  return this.realtime.chatRealtimeState();
@@ -98575,6 +98959,7 @@ var ArkmeService = class {
98575
98959
  messageReadReceipts: true,
98576
98960
  messageReport: true,
98577
98961
  userBanManagement: true,
98962
+ selfRoles: true,
98578
98963
  directMessageAdmission: true,
98579
98964
  reactionsV1: true,
98580
98965
  groupOwnerGovernance: true,
@@ -98679,6 +99064,7 @@ var ArkmeService = class {
98679
99064
  return await this.callHistory.retryCallSummary(callRef, signal);
98680
99065
  }
98681
99066
  dispose() {
99067
+ this.selfRoles.dispose();
98682
99068
  this.recordingPresenceWriter.revoke();
98683
99069
  this.commonGroups.dispose();
98684
99070
  this.desktopScreenshot.cancel();
@@ -99281,7 +99667,7 @@ var ArkmeService = class {
99281
99667
  }
99282
99668
  selfRoleName(name) {
99283
99669
  const normalized = name.trim();
99284
- if (normalized === "" || Array.from(normalized).length > 20 || /[\x00-\x1f\x7f]/.test(normalized)) throw new ArkmePluginError("self-role-name-invalid", "角色名称须为 1–20 个字符", false, 400);
99670
+ if (normalized === "" || Array.from(normalized).length > 20 || /[\x00-\x1f\x7f-\x9f]/.test(normalized)) throw new ArkmePluginError("self-role-name-invalid", "角色名称须为 1–20 个字符", false, 400);
99285
99671
  return normalized;
99286
99672
  }
99287
99673
  async selfRoleAvatarRef(userId, avatarRef) {
@@ -99291,6 +99677,10 @@ var ArkmeService = class {
99291
99677
  if (!await this.selfRoleAvatars.exists(userId, normalized)) throw new ArkmePluginError("self-role-avatar-invalid", "请选择此账号已保存的头像图片", false, 400);
99292
99678
  return normalized;
99293
99679
  }
99680
+ if (/^file_asset:\/\/[A-Za-z0-9_-]{1,128}$/.test(normalized)) {
99681
+ if ((await this.media.queryFileAssets([normalized.slice(13)])).length === 0) throw new ArkmePluginError("self-role-avatar-invalid", "头像资产不可用", false, 400);
99682
+ return normalized;
99683
+ }
99294
99684
  if (normalized !== "") throw new ArkmePluginError("self-role-avatar-invalid", "请选择此设备已保存的角色头像", false, 400);
99295
99685
  return "";
99296
99686
  }
@@ -99300,37 +99690,6 @@ var ArkmeService = class {
99300
99690
  await this.selfRoleUserId(userId);
99301
99691
  return ref;
99302
99692
  }
99303
- async migrateLegacySelfRoleAvatars(userId) {
99304
- const storage = this.stateStore;
99305
- if (typeof storage.legacySelfRoleAvatarRefs !== "function" || typeof storage.replaceSelfRoleAvatarRef !== "function") return;
99306
- await this.selfRoleAvatars.runLegacyMigration(userId, async () => {
99307
- const refs = await storage.legacySelfRoleAvatarRefs(userId);
99308
- for (const ref of refs) {
99309
- if (this.selfRoleAvatars.migrationRetryAfter(userId, ref) > Date.now()) continue;
99310
- try {
99311
- await this.selfRoleUserId(userId);
99312
- const image = await this.media.readImage(ref);
99313
- await this.selfRoleUserId(userId);
99314
- const localRef = await this.selfRoleAvatars.save(userId, image.data, image.mediaType);
99315
- await this.selfRoleUserId(userId);
99316
- await storage.replaceSelfRoleAvatarRef(userId, ref, localRef);
99317
- this.selfRoleAvatars.clearMigrationDelay(userId, ref);
99318
- } catch {
99319
- this.selfRoleAvatars.deferMigration(userId, ref, Date.now() + 5 * 6e4);
99320
- }
99321
- }
99322
- });
99323
- }
99324
- async migrateLegacySelfRoleAvatarsWithoutBlocking(userId) {
99325
- let timeout;
99326
- try {
99327
- await Promise.race([this.migrateLegacySelfRoleAvatars(userId).catch(() => void 0), new Promise((resolve) => {
99328
- timeout = setTimeout(resolve, 150);
99329
- })]);
99330
- } finally {
99331
- if (timeout !== void 0) clearTimeout(timeout);
99332
- }
99333
- }
99334
99693
  selfRoleUid(value, label) {
99335
99694
  const normalized = value.trim();
99336
99695
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalized)) throw new ArkmePluginError("self-role-uid-invalid", `${label}无效`, false, 400);
@@ -99338,7 +99697,7 @@ var ArkmeService = class {
99338
99697
  }
99339
99698
  async listSelfRoles(expectedUserId) {
99340
99699
  const userId = await this.selfRoleUserId(expectedUserId);
99341
- await this.migrateLegacySelfRoleAvatarsWithoutBlocking(userId);
99700
+ this.selfRoles.refresh().catch(() => void 0);
99342
99701
  const roles = await this.selfRoleStorage().listSelfRoles(userId);
99343
99702
  await this.selfRoleUserId(userId);
99344
99703
  return roles;
@@ -99348,7 +99707,9 @@ var ArkmeService = class {
99348
99707
  try {
99349
99708
  const verifiedAvatarRef = await this.selfRoleAvatarRef(userId, avatarRef);
99350
99709
  await this.selfRoleUserId(userId);
99351
- return await this.selfRoleStorage().createSelfRole(userId, this.selfRoleName(name), verifiedAvatarRef || void 0);
99710
+ const role = await this.selfRoleStorage().createSelfRole(userId, this.selfRoleName(name), verifiedAvatarRef || void 0);
99711
+ this.selfRoles.refresh().catch(() => void 0);
99712
+ return role;
99352
99713
  } catch (error) {
99353
99714
  if (error.message === "self-role-limit") throw new ArkmePluginError("self-role-limit", "最多可创建 20 个角色", false, 409);
99354
99715
  throw error;
@@ -99358,13 +99719,15 @@ var ArkmeService = class {
99358
99719
  const userId = await this.selfRoleUserId(expectedUserId);
99359
99720
  const verifiedAvatarRef = await this.selfRoleAvatarRef(userId, avatarRef);
99360
99721
  await this.selfRoleUserId(userId);
99361
- const updated = await this.selfRoleStorage().updateSelfRole(userId, this.selfRoleUid(roleId, "角色标识"), this.selfRoleName(name), verifiedAvatarRef);
99722
+ const updated = await this.selfRoleStorage().updateSelfRole(userId, this.selfRoleUid(roleId, "角色标识"), name === void 0 ? void 0 : this.selfRoleName(name), verifiedAvatarRef);
99362
99723
  if (updated === void 0) throw new ArkmePluginError("self-role-missing", "角色不存在", false, 404);
99724
+ this.selfRoles.refresh().catch(() => void 0);
99363
99725
  return updated;
99364
99726
  }
99365
99727
  async deleteSelfRole(expectedUserId, roleId) {
99366
99728
  const userId = await this.selfRoleUserId(expectedUserId);
99367
99729
  if (!await this.selfRoleStorage().deleteSelfRole(userId, this.selfRoleUid(roleId, "角色标识"))) throw new ArkmePluginError("self-role-missing", "角色不存在", false, 404);
99730
+ this.selfRoles.refresh().catch(() => void 0);
99368
99731
  return { ok: true };
99369
99732
  }
99370
99733
  async bindSelfRole(expectedUserId, sourceRef, recordUid, roleId) {
@@ -99401,7 +99764,7 @@ var ArkmeService = class {
99401
99764
  const storage = this.stateStore;
99402
99765
  if (typeof storage.selfRoleSnapshots !== "function") return page;
99403
99766
  if ((await this.runtime.requireSession()).userId !== userId) throw new ArkmePluginError("self-role-account-changed", "账号已切换,请重试", false, 409);
99404
- await this.migrateLegacySelfRoleAvatarsWithoutBlocking(userId);
99767
+ this.selfRoles.refresh().catch(() => void 0);
99405
99768
  const snapshots = await storage.selfRoleSnapshots(userId, page.items.filter((item) => item.isMe).map((item) => item.itemUid));
99406
99769
  await this.selfRoleUserId(userId);
99407
99770
  if (snapshots.size === 0) return page;
@@ -99409,7 +99772,7 @@ var ArkmeService = class {
99409
99772
  ...page,
99410
99773
  items: page.items.map((item) => {
99411
99774
  const snapshot = item.isMe ? snapshots.get(item.itemUid) : void 0;
99412
- return snapshot === void 0 ? item : {
99775
+ return item.selfRole !== void 0 || snapshot === void 0 ? item : {
99413
99776
  ...item,
99414
99777
  selfRole: snapshot
99415
99778
  };
@@ -99497,15 +99860,16 @@ var ArkmeService = class {
99497
99860
  if (source.kind !== "send_to_self" && source.kind !== "default_category" && source.kind !== "topic") return context;
99498
99861
  const storage = this.stateStore;
99499
99862
  if (typeof storage.selfRoleSnapshots !== "function") return context;
99500
- await this.migrateLegacySelfRoleAvatarsWithoutBlocking(session.userId);
99501
- const recordUids = context.extensions.filter((item) => item.sourceKind === "record_extension").map((item) => item.recordUid);
99863
+ this.selfRoles.refresh().catch(() => void 0);
99864
+ const recordUids = context.extensions.filter((item) => item.sourceKind === "record_extension" && item.protectedContent !== true).map((item) => item.recordUid);
99502
99865
  const snapshots = await storage.selfRoleSnapshots(session.userId, recordUids);
99503
99866
  await this.selfRoleUserId(session.userId);
99504
99867
  if (snapshots.size === 0) return context;
99505
99868
  return {
99506
99869
  ...context,
99507
99870
  extensions: context.extensions.map((item) => {
99508
- const selfRole = item.sourceKind === "record_extension" ? snapshots.get(item.recordUid) : void 0;
99871
+ if (item.protectedContent === true) return item;
99872
+ const selfRole = item.selfRole ?? (item.sourceKind === "record_extension" ? snapshots.get(item.recordUid) : void 0);
99509
99873
  return selfRole === void 0 ? item : {
99510
99874
  ...item,
99511
99875
  selfRole
@@ -101758,4 +102122,4 @@ async function invokePersistentArkmeExtension(extensionId, method, args) {
101758
102122
  return jsonValue(await handler(jsonValue(args)));
101759
102123
  }
101760
102124
  //#endregion
101761
- export { ARKME_VOICEPRINT_ENROLLMENT_MAX_AUDIO_BYTES as $, inspectNativeBundleArtifactV3 as A, ArkmeRecordReeditDraftConflict as At, ARKME_EXTENSION_ICON_MAX_BYTES as B, __require as Bt, ARKME_BUNDLE_MAX_BYTES as C, isRecentEmojiId as Ct, bundleSha256 as D, ArkmePluginError as Dt, arkmeSandboxEntryId as E, MAX_SELF_ROLE_AVATAR_BYTES as Et, assertExtensionArtifactSize as F, registerDSHAgentInputRecordSync as Ft, validateVoiceprintPcm16Wav as G, ARKME_EXTENSION_PREVIEW_MAX_BYTES as H, canonicalExtensionJson as I, createDesktopLifecycleReader as It, arkmeRequiredLinkMetadataFallback as J, arkmeExtensionShareRefFromLink as K, sha256Hex as L, __commonJSMin as Lt, packLocalNativeBundleDirectoryV3 as M, parseArkmeRecordReeditMentions as Mt, readNativeBundleTarballV3 as N, ARRANGEMENT_BOARD_CACHE_MAX_BYTES as Nt, canonicalBundleJson as O, retryAfterMillis as Ot, renderArkmeSandboxHostEntry as P, parseArrangementBoardCachePages as Pt, ARKME_PROVIDER_CONTRACT_VERSION as Q, unpackArkmeExtension as R, __esmMin as Rt, ARKME_BUNDLE_ARTIFACT_KIND as S, recordingImportFileNameKey as St, ArkmeBundleArtifactError as T, registerManagedAiProvider as Tt, ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE as U, ARKME_EXTENSION_MAX_BYTES as V, __toCommonJS as Vt, ArkmeService as W, arkmeRichBackgroundSound as X, arkmeFileBackgroundSound as Y, ARKME_DEFAULT_SHARE_WEBSITE as Z, arkmeClientContentDigest as _, isRecordingInstantOnOrAfterUnixEpoch as _t, persistentArkmeExtensionActive as a, cachedMemberItem as at, verifyExtensionResolutionSignature as b, sameRecordingImportIdentity as bt, persistentExtensionBundleDirectory as c, ARKME_RUNTIME_INSTANCE_ID as ct, readPersistentExtensionActivation as d, arkmeNormalizedFileMimeType as dt, ARKME_VOICEPRINT_ENROLLMENT_MAX_DURATION_MS as et, refreshPersistentClientWrapper as f, arkmePickedFileKind as ft, activeProfileExtensionOwnerConflicts as g, ArkmeDirectMessageAdmissionError as gt, renderArkmeBundleClientBundle as h, SecretValue as ht, invokePersistentArkmeExtension as i, applyMemberUpdate as it, packBundleFiles as j, parseArkmeRecordReeditAttachments as jt, inspectBundleArtifact as k, recordOwnerId as kt, persistentExtensionPackageIdentity as l, ARKME_TOOL_FILE_MAX_BYTES as lt, writePersistentExtensionActivation as m, ArkmeOutgoingCallError as mt, applyPersistentArkmeHostExtension as n, ARKME_WORLD_PUBLISH_MAX_IMAGES as nt, persistentArkmeExtensionRuntimeState as o, mergeMemberJoinEvents as ot, repairPersistentExtensionInstallation as p, isArkmeBotAvatarRef as pt, arkmeIsGenericLinkMetadataTitle as q, deactivatePersistentArkmeExtension as r, ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES as rt, materializePersistentExtensionBundle as s, validateMemberUpdate as st, activatePersistentArkmeExtension as t, ARKME_VOICEPRINT_ENROLLMENT_MIN_DURATION_MS as tt, quarantinePersistentExtension as u, arkmeCanInlineLocalFile as ut, arkmeClientContentDigestFromSource as v, isUnresolvedRecordingImportJob as vt, ARKME_NATIVE_BUNDLE_ARTIFACT_KIND as w, normalizeRecentEmojiIds as wt, verifyNativeBundleResolutionSignature as x, MAX_RECORDING_IMPORT_BYTES as xt, verifyBundleResolutionSignature as y, recordingImportFileKind as yt, ARKME_EXTENSION_FORMAT as z, __exportAll as zt };
102125
+ export { ARKME_VOICEPRINT_ENROLLMENT_MAX_AUDIO_BYTES as $, inspectNativeBundleArtifactV3 as A, recordOwnerId as At, ARKME_EXTENSION_ICON_MAX_BYTES as B, __exportAll as Bt, ARKME_BUNDLE_MAX_BYTES as C, recordingImportFileNameKey as Ct, bundleSha256 as D, MAX_SELF_ROLE_AVATAR_BYTES as Dt, arkmeSandboxEntryId as E, registerManagedAiProvider as Et, assertExtensionArtifactSize as F, parseArrangementBoardCachePages as Ft, validateVoiceprintPcm16Wav as G, ARKME_EXTENSION_PREVIEW_MAX_BYTES as H, __toCommonJS as Ht, canonicalExtensionJson as I, registerDSHAgentInputRecordSync as It, arkmeRequiredLinkMetadataFallback as J, arkmeExtensionShareRefFromLink as K, sha256Hex as L, createDesktopLifecycleReader as Lt, packLocalNativeBundleDirectoryV3 as M, parseArkmeRecordReeditAttachments as Mt, readNativeBundleTarballV3 as N, parseArkmeRecordReeditMentions as Nt, canonicalBundleJson as O, ArkmePluginError as Ot, renderArkmeSandboxHostEntry as P, ARRANGEMENT_BOARD_CACHE_MAX_BYTES as Pt, ARKME_PROVIDER_CONTRACT_VERSION as Q, unpackArkmeExtension as R, __commonJSMin as Rt, ARKME_BUNDLE_ARTIFACT_KIND as S, MAX_RECORDING_IMPORT_BYTES as St, ArkmeBundleArtifactError as T, normalizeRecentEmojiIds as Tt, ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE as U, ARKME_EXTENSION_MAX_BYTES as V, __require as Vt, ArkmeService as W, arkmeRichBackgroundSound as X, arkmeFileBackgroundSound as Y, ARKME_DEFAULT_SHARE_WEBSITE as Z, arkmeClientContentDigest as _, ArkmeDirectMessageAdmissionError as _t, persistentArkmeExtensionActive as a, cachedMemberItem as at, verifyExtensionResolutionSignature as b, recordingImportFileKind as bt, persistentExtensionBundleDirectory as c, SelfRoleSyncStore as ct, readPersistentExtensionActivation as d, arkmeCanInlineLocalFile as dt, ARKME_VOICEPRINT_ENROLLMENT_MAX_DURATION_MS as et, refreshPersistentClientWrapper as f, arkmeNormalizedFileMimeType as ft, activeProfileExtensionOwnerConflicts as g, SecretValue as gt, renderArkmeBundleClientBundle as h, ArkmeOutgoingCallError as ht, invokePersistentArkmeExtension as i, applyMemberUpdate as it, packBundleFiles as j, ArkmeRecordReeditDraftConflict as jt, inspectBundleArtifact as k, retryAfterMillis as kt, persistentExtensionPackageIdentity as l, ARKME_RUNTIME_INSTANCE_ID as lt, writePersistentExtensionActivation as m, isArkmeBotAvatarRef as mt, applyPersistentArkmeHostExtension as n, ARKME_WORLD_PUBLISH_MAX_IMAGES as nt, persistentArkmeExtensionRuntimeState as o, mergeMemberJoinEvents as ot, repairPersistentExtensionInstallation as p, arkmePickedFileKind as pt, arkmeIsGenericLinkMetadataTitle as q, deactivatePersistentArkmeExtension as r, ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES as rt, materializePersistentExtensionBundle as s, validateMemberUpdate as st, activatePersistentArkmeExtension as t, ARKME_VOICEPRINT_ENROLLMENT_MIN_DURATION_MS as tt, quarantinePersistentExtension as u, ARKME_TOOL_FILE_MAX_BYTES as ut, arkmeClientContentDigestFromSource as v, isRecordingInstantOnOrAfterUnixEpoch as vt, ARKME_NATIVE_BUNDLE_ARTIFACT_KIND as w, isRecentEmojiId as wt, verifyNativeBundleResolutionSignature as x, sameRecordingImportIdentity as xt, verifyBundleResolutionSignature as y, isUnresolvedRecordingImportJob as yt, ARKME_EXTENSION_FORMAT as z, __esmMin as zt };