@openclaw/matrix 2026.7.1-beta.6 → 2026.7.2-beta.1

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 (87) hide show
  1. package/dist/{account-selection-5e4mHR1m.js → account-selection-Bz00QTmQ.js} +4 -3
  2. package/dist/api.js +8 -8
  3. package/dist/{approval-handler.runtime-DI5x9r8I.js → approval-handler.runtime--Ei44Vo2.js} +27 -17
  4. package/dist/{approval-ids-ZgqbspmS.js → approval-ids-C_2kSMdJ.js} +1 -1
  5. package/dist/{approval-reaction-auth-D9LijQhr.js → approval-reaction-auth-TdVPcgxP.js} +2 -2
  6. package/dist/approval-reactions-BgU51JGd.js +202 -0
  7. package/dist/auth-presence.js +1 -1
  8. package/dist/{channel-jUTBsjHU.js → channel-CxqDh7mS.js} +102 -143
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/{channel.runtime-DO1Nv9ed.js → channel.runtime-wNfJc57I.js} +7 -7
  11. package/dist/{cli-metadata-CfiEO-CE.js → cli-metadata-Gf3HSJ2c.js} +1 -1
  12. package/dist/cli-metadata.js +1 -1
  13. package/dist/{cli-CEfWwCKx.js → cli-o00oTJhx.js} +12 -12
  14. package/dist/{client-FRuyCNju.js → client-ClHisZbf.js} +2 -2
  15. package/dist/{client-tgnlQJk4.js → client-DP0nmFxK.js} +4 -4
  16. package/dist/{client-bootstrap-DjFJ7e0N.js → client-bootstrap-PqYOS-mO.js} +1 -1
  17. package/dist/{config-schema-DtnhNYd-.js → config-schema-CG9goLWp.js} +21 -55
  18. package/dist/contract-api.js +2 -2
  19. package/dist/{create-client-CNakT7zF.js → create-client-D9z9RjCM.js} +3 -3
  20. package/dist/{credentials-Ds9V1mn2.js → credentials-DnhsLAuR.js} +1 -1
  21. package/dist/{credentials-read-BlkvsNFg.js → credentials-read-BtS-HRT5.js} +3 -3
  22. package/dist/{credentials-write.runtime-CTqqxcut.js → credentials-write.runtime-J_EUt5WP.js} +1 -1
  23. package/dist/{crypto-runtime-B74cTS6A.js → crypto-runtime-BHcxauC4.js} +75 -45
  24. package/dist/{deps-CdjHvnmh.js → deps-DDbghaZH.js} +23 -90
  25. package/dist/{directory-live-Ufd4qSpX.js → directory-live-DPy2aaPF.js} +3 -3
  26. package/dist/doctor-BGTs609f.js +64 -0
  27. package/dist/{doctor-contract-BAja_fmb.js → doctor-contract-D2qTLe-C.js} +72 -6
  28. package/dist/doctor-contract-api.js +323 -45
  29. package/dist/{draft-stream-D4EH25gv.js → draft-stream-De7uikGn.js} +1 -1
  30. package/dist/{encryption-guidance-D8walY04.js → encryption-guidance-BFfgq7c7.js} +1 -1
  31. package/dist/{env-auth-DIzOApj0.js → env-auth-CQsYbz-p.js} +1 -1
  32. package/dist/{env-vars-KzaYveuy.js → env-vars-B0NxQnPk.js} +3 -1
  33. package/dist/{exec-approval-resolver-f9j6staN.js → exec-approval-resolver-BCgqRtZS.js} +2 -1
  34. package/dist/{file-sync-store-DVm0ACml.js → file-sync-store-Cxb0ckyX.js} +4 -5
  35. package/dist/helper-api.js +4 -4
  36. package/dist/{http-client-nSmFiVgk.js → http-client-W4TJQM6r.js} +17 -33
  37. package/dist/{idb-persistence-BHm97th-.js → idb-persistence-iUZoHZkp.js} +2 -2
  38. package/dist/inbound-dedupe-DcMs0YXL.js +67 -0
  39. package/dist/index.js +1 -1
  40. package/dist/{logger-D0GCSDQq.js → logger-BMClpI5b.js} +1 -1
  41. package/dist/{logging-QH-48Gr6.js → logging-CFJrbDAN.js} +1 -1
  42. package/dist/{media-text-p-LP21qs.js → media-text-DWaotsZB.js} +1 -1
  43. package/dist/{messages-DRKkiEY-.js → messages-Dm3K4ZvM.js} +3 -3
  44. package/dist/{monitor-CsGOGdwu.js → monitor-C_kgPPeV.js} +44 -382
  45. package/dist/plugin-entry.handlers.runtime.js +1 -1
  46. package/dist/probe.runtime-Dry8PTWC.js +3 -0
  47. package/dist/{profile-update-Ucc8RrJL.js → profile-update-iUHCoks3.js} +3 -3
  48. package/dist/{reaction-events-DentrVii.js → reaction-events-0tubdHRM.js} +60 -10
  49. package/dist/record-shared-CvzjvHRn.js +2 -0
  50. package/dist/{recovery-key-store-DSeLFvNx.js → recovery-key-store-Bx0zTJcB.js} +2 -2
  51. package/dist/{resolve-targets-DcV_KfgX.js → resolve-targets-DlLrfWDy.js} +1 -1
  52. package/dist/{resolver.runtime-Hr6bO5zl.js → resolver.runtime-MeaT1zXx.js} +1 -1
  53. package/dist/room-info-B6vKD5DF.js +86 -0
  54. package/dist/{runtime-6S3DNFNv.js → runtime-CveSqMOP.js} +1 -1
  55. package/dist/{runtime-api-CsBoesCU.js → runtime-api-D1xI_cvh.js} +3 -3
  56. package/dist/runtime-api.js +6 -6
  57. package/dist/runtime-setter-api.js +1 -1
  58. package/dist/{sdk-AZYVl34z.js → sdk-CI8E2TKg.js} +12 -17
  59. package/dist/{secret-contract-DTgQyQxc.js → secret-contract-OZoQf0kI.js} +7 -48
  60. package/dist/secret-contract-api.js +1 -1
  61. package/dist/{send-D92v6Yy0.js → send-C7xuGWpv.js} +10 -4
  62. package/dist/session-binding-contract-api.js +2 -2
  63. package/dist/{setup-bootstrap-Da564w5f.js → setup-bootstrap-CCsexWTZ.js} +2 -2
  64. package/dist/{setup-core-BGgbrdaJ.js → setup-core-DlmTyIP0.js} +9 -7
  65. package/dist/setup-plugin-api.js +3 -3
  66. package/dist/{setup-surface-iJ6pd-t5.js → setup-surface-2SS94JV0.js} +7 -7
  67. package/dist/{shared-DkFfq7mH.js → shared-DgvN5rBx.js} +14 -9
  68. package/dist/{startup-verification-BKMAXvcV.js → startup-verification-CbIyF7z1.js} +3 -4
  69. package/dist/storage-BtSOar8T.js +718 -0
  70. package/dist/{storage-paths-BWo_ZEMC.js → storage-paths-B4_I9iqO.js} +1 -12
  71. package/dist/{thread-bindings-BX5nmWpw.js → thread-bindings-BI8MHWp9.js} +4 -5
  72. package/dist/{tool-actions.runtime-C1d5fxE_.js → tool-actions.runtime-CnyhVPoY.js} +242 -53
  73. package/dist/{verification-BGCMiO1p.js → verification-DLSe3sP7.js} +2 -2
  74. package/npm-shrinkwrap.json +3 -3
  75. package/openclaw.plugin.json +66 -55
  76. package/package.json +4 -4
  77. package/dist/approval-reactions-BdUaUXVw.js +0 -113
  78. package/dist/crypto-state-store-Jy3qwhdy.js +0 -352
  79. package/dist/doctor-DfaOqFtr.js +0 -167
  80. package/dist/legacy-crypto-inspector-vzXSkm18.js +0 -42
  81. package/dist/legacy-crypto-restore-CIBfOmLn.js +0 -93
  82. package/dist/matrix-migration.runtime-BMCyrANT.js +0 -524
  83. package/dist/migration-snapshot-backup-YcCrSjbE.js +0 -69
  84. package/dist/migration-snapshot.runtime-VGD4QfeS.js +0 -2
  85. package/dist/probe.runtime-2MZLc6ng.js +0 -3
  86. package/dist/runtime-heavy-api.js +0 -3
  87. package/dist/storage-CQdyKcGg.js +0 -430
@@ -1,12 +1,12 @@
1
1
  import { a as resolveMatrixAccountConfig } from "./account-config-BZWN9tGS.js";
2
- import { g as resolveMatrixAccount, h as resolveDefaultMatrixAccountId, p as listMatrixAccountIds } from "./setup-core-BGgbrdaJ.js";
2
+ import { g as resolveMatrixAccount, h as resolveDefaultMatrixAccountId, p as listMatrixAccountIds } from "./setup-core-DlmTyIP0.js";
3
3
  import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
4
+ import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
4
5
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
5
6
  import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1 } from "openclaw/plugin-sdk/account-id";
6
7
  import { resolveAllowlistMatchByCandidates } from "openclaw/plugin-sdk/allow-from";
7
8
  import { normalizeStringEntries as normalizeStringEntries$1 } from "openclaw/plugin-sdk/string-normalization-runtime";
8
- import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
9
- import { AllowFromListSchema, ContextVisibilityModeSchema, GroupPolicySchema, MarkdownConfigSchema, MentionPatternsPolicySchema, ToolPolicySchema, buildNestedDmConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
9
+ import { AllowFromListSchema, BlockStreamingCoalesceSchema, ContextVisibilityModeSchema, GroupPolicySchema, MarkdownConfigSchema, MentionPatternsPolicySchema, ToolPolicySchema, buildChannelConfigSchema, buildNestedDmConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
10
10
  import { buildSecretInputSchema } from "openclaw/plugin-sdk/secret-input";
11
11
  import { z } from "zod";
12
12
  //#region extensions/matrix/src/matrix/monitor/allowlist.ts
@@ -102,22 +102,14 @@ const matrixConfigAdapter = createScopedChannelConfigAdapter({
102
102
  //#endregion
103
103
  //#region extensions/matrix/src/config-ui-hints.ts
104
104
  const matrixChannelConfigUiHints = {
105
- mentionPatterns: {
106
- label: "Matrix Mention Pattern Policy",
107
- help: "Scopes configured groupChat mentionPatterns to selected Matrix room IDs. Native Matrix mention evidence still triggers even when regex patterns are denied."
108
- },
109
- "mentionPatterns.mode": {
110
- label: "Matrix Mention Pattern Mode",
111
- help: "\"allow\" enables configured regex mention patterns unless denyIn matches; \"deny\" disables them unless allowIn matches."
112
- },
113
- "mentionPatterns.allowIn": {
114
- label: "Matrix Mention Pattern Allowlist",
115
- help: "Matrix room IDs where configured regex mention patterns are enabled when mode is deny."
116
- },
117
- "mentionPatterns.denyIn": {
118
- label: "Matrix Mention Pattern Denylist",
119
- help: "Matrix room IDs where configured regex mention patterns are disabled. Native mention evidence still triggers."
120
- },
105
+ ...createChannelConfigUiHints({
106
+ channelLabel: "Matrix",
107
+ mentionPatterns: {
108
+ targetDescription: "Matrix room IDs",
109
+ policyNote: "Native Matrix mention evidence still triggers even when regex patterns are denied.",
110
+ denyNote: "Native mention evidence still triggers."
111
+ }
112
+ }),
121
113
  allowBots: {
122
114
  label: "Matrix Allow Bot Messages",
123
115
  help: "Allow messages from other configured Matrix bot accounts to trigger replies (default: false). Set \"mentions\" to require a visible room mention."
@@ -146,30 +138,10 @@ const matrixChannelConfigUiHints = {
146
138
  label: "Matrix Display Name Matching",
147
139
  help: "Compatibility opt-in for resolving Matrix display names and joined room names in allowlists. Prefer full @user:server IDs and room IDs or aliases because names are mutable."
148
140
  },
149
- "streaming.progress.label": {
150
- label: "Matrix Progress Label",
151
- help: "Initial progress draft title. Use \"auto\" for built-in single-word labels, a custom string, or false to hide the title."
152
- },
153
- "streaming.progress.labels": {
154
- label: "Matrix Progress Label Pool",
155
- help: "Candidate labels for streaming.progress.label=\"auto\". Leave unset to use OpenClaw built-in progress labels."
156
- },
157
- "streaming.progress.maxLines": {
158
- label: "Matrix Progress Max Lines",
159
- help: "Maximum number of compact progress lines to keep below the draft label (default: 8)."
160
- },
161
- "streaming.progress.maxLineChars": {
162
- label: "Matrix Progress Max Line Chars",
163
- help: "Maximum characters per compact progress line before truncation (default: 120). Prose cuts at word boundaries; commands and paths keep useful suffixes."
164
- },
165
- "streaming.progress.toolProgress": {
166
- label: "Matrix Progress Tool Lines",
167
- help: "Show compact tool/progress lines in progress draft mode (default: true). Set false to keep only the label until final delivery."
168
- },
169
- "streaming.progress.commandText": {
170
- label: "Matrix Progress Command Text",
171
- help: "Command/exec detail in progress draft lines: \"raw\" preserves released behavior; \"status\" shows only the tool label."
172
- }
141
+ ...createChannelConfigUiHints({
142
+ channelLabel: "Matrix",
143
+ progress: {}
144
+ })
173
145
  };
174
146
  //#endregion
175
147
  //#region extensions/matrix/src/config-schema.ts
@@ -228,6 +200,11 @@ const matrixStreamingSchema = z.object({
228
200
  "progress",
229
201
  "off"
230
202
  ]).optional(),
203
+ chunkMode: z.enum(["length", "newline"]).optional(),
204
+ block: z.object({
205
+ enabled: z.boolean().optional(),
206
+ coalesce: BlockStreamingCoalesceSchema.optional()
207
+ }).strict().optional(),
231
208
  progress: z.object({
232
209
  label: z.union([z.string(), z.literal(false)]).optional(),
233
210
  labels: z.array(z.string()).optional(),
@@ -261,17 +238,7 @@ const MatrixChannelConfigSchema = buildChannelConfigSchema(z.object({
261
238
  groupPolicy: GroupPolicySchema.optional(),
262
239
  mentionPatterns: MentionPatternsPolicySchema.optional(),
263
240
  contextVisibility: ContextVisibilityModeSchema.optional(),
264
- blockStreaming: z.boolean().optional(),
265
- streaming: z.union([
266
- z.enum([
267
- "partial",
268
- "quiet",
269
- "progress",
270
- "off"
271
- ]),
272
- z.boolean(),
273
- matrixStreamingSchema
274
- ]).optional(),
241
+ streaming: matrixStreamingSchema.optional(),
275
242
  replyToMode: z.enum([
276
243
  "off",
277
244
  "first",
@@ -284,7 +251,6 @@ const MatrixChannelConfigSchema = buildChannelConfigSchema(z.object({
284
251
  "always"
285
252
  ]).optional(),
286
253
  textChunkLimit: z.number().optional(),
287
- chunkMode: z.enum(["length", "newline"]).optional(),
288
254
  responsePrefix: z.string().optional(),
289
255
  ackReaction: z.string().optional(),
290
256
  ackReactionScope: z.enum([
@@ -1,3 +1,3 @@
1
- import { d as resolveSingleAccountPromotionTarget, f as singleAccountKeysToMove, n as matrixSetupAdapter, u as namedAccountPromotionKeys } from "./setup-core-BGgbrdaJ.js";
2
- import { n as matrixOnboardingAdapter } from "./setup-surface-iJ6pd-t5.js";
1
+ import { d as resolveSingleAccountPromotionTarget, f as singleAccountKeysToMove, n as matrixSetupAdapter, u as namedAccountPromotionKeys } from "./setup-core-DlmTyIP0.js";
2
+ import { n as matrixOnboardingAdapter } from "./setup-surface-2SS94JV0.js";
3
3
  export { matrixSetupAdapter, matrixOnboardingAdapter as matrixSetupWizard, namedAccountPromotionKeys, resolveSingleAccountPromotionTarget, singleAccountKeysToMove };
@@ -1,14 +1,14 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
2
  import { t as resolveValidatedMatrixHomeserverUrl } from "./url-validation-GRHde6lq.js";
3
- import { d as writeStorageMeta, l as resolveMatrixStoragePaths, r as maybeMigrateLegacyStorage } from "./storage-CQdyKcGg.js";
4
- import "./shared-DkFfq7mH.js";
3
+ import { d as writeStorageMeta, l as resolveMatrixStoragePaths, r as maybeMigrateLegacyStorage } from "./storage-BtSOar8T.js";
4
+ import "./shared-DgvN5rBx.js";
5
5
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
6
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import fs from "node:fs";
8
8
  import { ssrfPolicyFromDangerouslyAllowPrivateNetwork } from "openclaw/plugin-sdk/ssrf-runtime";
9
9
  //#region extensions/matrix/src/matrix/client/create-client.ts
10
10
  var create_client_exports = /* @__PURE__ */ __exportAll({ createMatrixClient: () => createMatrixClient });
11
- const loadMatrixCreateClientRuntimeDeps = createLazyRuntimeModule(() => Promise.all([import("./sdk-AZYVl34z.js"), import("./logging-QH-48Gr6.js")]).then(([sdkModule, loggingModule]) => ({
11
+ const loadMatrixCreateClientRuntimeDeps = createLazyRuntimeModule(() => Promise.all([import("./sdk-CI8E2TKg.js"), import("./logging-CFJrbDAN.js")]).then(([sdkModule, loggingModule]) => ({
12
12
  MatrixClient: sdkModule.MatrixClient,
13
13
  ensureMatrixSdkLoggingConfigured: loggingModule.ensureMatrixSdkLoggingConfigured
14
14
  })));
@@ -1,4 +1,4 @@
1
- import { a as resolveMatrixCredentialsDir, i as loadMatrixCredentials, n as credentialsMatchConfig, o as resolveMatrixCredentialsPath, t as clearMatrixCredentials } from "./credentials-read-BlkvsNFg.js";
1
+ import { a as resolveMatrixCredentialsDir, i as loadMatrixCredentials, n as credentialsMatchConfig, o as resolveMatrixCredentialsPath, t as clearMatrixCredentials } from "./credentials-read-BtS-HRT5.js";
2
2
  import { t as createAsyncLock } from "./async-lock-BcLS4KOc.js";
3
3
  import { writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
4
4
  //#region extensions/matrix/src/matrix/credentials.ts
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { a as resolveMatrixDefaultOrOnlyAccountId, n as requiresExplicitMatrixDefaultAccount } from "./account-selection-5e4mHR1m.js";
3
- import { t as getMatrixRuntime } from "./runtime-6S3DNFNv.js";
4
- import { a as resolveMatrixCredentialsPath$1, r as resolveMatrixCredentialsDir$1 } from "./storage-paths-BWo_ZEMC.js";
2
+ import { a as resolveMatrixDefaultOrOnlyAccountId, n as requiresExplicitMatrixDefaultAccount } from "./account-selection-Bz00QTmQ.js";
3
+ import { t as getMatrixRuntime } from "./runtime-CveSqMOP.js";
4
+ import { a as resolveMatrixCredentialsPath$1, r as resolveMatrixCredentialsDir$1 } from "./storage-paths-B4_I9iqO.js";
5
5
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
6
6
  import fs from "node:fs";
7
7
  import os from "node:os";
@@ -1,6 +1,6 @@
1
1
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
2
2
  //#region extensions/matrix/src/matrix/credentials-write.runtime.ts
3
- const loadMatrixCredentialsRuntime = createLazyRuntimeModule(() => import("./credentials-Ds9V1mn2.js"));
3
+ const loadMatrixCredentialsRuntime = createLazyRuntimeModule(() => import("./credentials-DnhsLAuR.js"));
4
4
  async function saveMatrixCredentials(...args) {
5
5
  return (await loadMatrixCredentialsRuntime()).saveMatrixCredentials(...args);
6
6
  }
@@ -1,54 +1,47 @@
1
1
  import { t as formatMatrixErrorMessage } from "./errors-C47hvAF8.js";
2
- import { t as ensureMatrixCryptoRuntime } from "./deps-CdjHvnmh.js";
3
- import { n as LogService, r as noop } from "./logger-D0GCSDQq.js";
4
- import { i as restoreIdbFromDisk, n as persistIdbToDisk } from "./idb-persistence-BHm97th-.js";
5
- import { n as isRepairableSecretStorageAccessError } from "./recovery-key-store-DSeLFvNx.js";
2
+ import { t as ensureMatrixCryptoRuntime } from "./deps-DDbghaZH.js";
3
+ import { n as LogService, r as noop } from "./logger-BMClpI5b.js";
4
+ import { i as restoreIdbFromDisk, n as persistIdbToDisk } from "./idb-persistence-iUZoHZkp.js";
5
+ import { n as isRepairableSecretStorageAccessError } from "./recovery-key-store-Bx0zTJcB.js";
6
6
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
7
7
  import { resolveDateTimestampMs, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
8
8
  import { MatrixEventEvent } from "matrix-js-sdk/lib/matrix.js";
9
+ import { IDBDatabase } from "fake-indexeddb";
9
10
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
10
11
  import { VerificationMethod } from "matrix-js-sdk/lib/types.js";
11
12
  import "fake-indexeddb/auto";
12
13
  import { CryptoEvent } from "matrix-js-sdk/lib/crypto-api/CryptoEvent.js";
13
14
  import { DecryptionFailureCode } from "matrix-js-sdk/lib/crypto-api/index.js";
14
15
  import { VerificationPhase, VerificationRequestEvent, VerifierEvent } from "matrix-js-sdk/lib/crypto-api/verification.js";
16
+ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
15
17
  //#region extensions/matrix/src/matrix/sdk/fake-indexeddb-prune.ts
16
18
  const MATRIX_CRYPTO_DATABASE_SUFFIXES = ["::matrix-sdk-crypto", "::matrix-sdk-crypto-meta"];
17
19
  const PRUNER_INSTALLED = Symbol.for("openclaw.matrix.fakeIndexedDbTransactionPruner");
18
- function getRawDatabase(value) {
19
- if (!value || typeof value !== "object") return;
20
- const rawDatabase = value["_rawDatabase"];
21
- if (!rawDatabase || typeof rawDatabase !== "object") return;
22
- return rawDatabase;
23
- }
24
20
  function isMatrixCryptoDatabase(rawDatabase) {
25
- if (!rawDatabase || !Array.isArray(rawDatabase.transactions)) return false;
26
- const databaseName = rawDatabase.name;
27
- return typeof databaseName === "string" && MATRIX_CRYPTO_DATABASE_SUFFIXES.some((suffix) => databaseName.endsWith(suffix));
21
+ return MATRIX_CRYPTO_DATABASE_SUFFIXES.some((suffix) => rawDatabase.name.endsWith(suffix));
28
22
  }
29
23
  function pruneFinishedFakeIndexedDbTransactions(rawDatabase) {
30
- const matrixRawDatabase = rawDatabase;
31
- if (!isMatrixCryptoDatabase(matrixRawDatabase)) return 0;
32
- const transactions = matrixRawDatabase.transactions;
33
- const activeTransactions = transactions.filter((transaction) => transaction?.["_state"] !== "finished");
24
+ if (!isMatrixCryptoDatabase(rawDatabase)) return 0;
25
+ const transactions = rawDatabase.transactions;
26
+ const activeTransactions = transactions.filter((transaction) => transaction["_state"] !== "finished");
34
27
  const removed = transactions.length - activeTransactions.length;
35
28
  if (removed > 0) transactions.splice(0, transactions.length, ...activeTransactions);
36
29
  return removed;
37
30
  }
38
31
  function installFakeIndexedDbTransactionPruner() {
39
- const databasePrototype = globalThis.IDBDatabase?.prototype;
40
- const originalTransaction = databasePrototype?.transaction;
41
- if (!databasePrototype || typeof originalTransaction !== "function" || databasePrototype[PRUNER_INSTALLED]) return;
32
+ const databasePrototype = IDBDatabase.prototype;
33
+ if (databasePrototype[PRUNER_INSTALLED]) return;
42
34
  Object.defineProperty(databasePrototype, PRUNER_INSTALLED, {
43
35
  configurable: false,
44
36
  enumerable: false,
45
37
  value: true
46
38
  });
39
+ const originalTransaction = Object.getOwnPropertyDescriptor(databasePrototype, "transaction")?.value;
47
40
  databasePrototype.transaction = function patchedMatrixFakeIndexedDbTransaction(...args) {
48
- pruneFinishedFakeIndexedDbTransactions(getRawDatabase(this));
41
+ const rawDatabase = this["_rawDatabase"];
42
+ pruneFinishedFakeIndexedDbTransactions(rawDatabase);
49
43
  const transaction = originalTransaction.apply(this, args);
50
- const rawDatabase = getRawDatabase(transaction?.db) ?? getRawDatabase(this);
51
- if (isMatrixCryptoDatabase(rawDatabase) && typeof transaction?.addEventListener === "function") {
44
+ if (isMatrixCryptoDatabase(rawDatabase)) {
52
45
  const prune = () => {
53
46
  pruneFinishedFakeIndexedDbTransactions(rawDatabase);
54
47
  };
@@ -464,21 +457,15 @@ function createMatrixCryptoFacade(deps) {
464
457
  const MATRIX_DECRYPT_RETRY_BASE_DELAY_MS = 1500;
465
458
  const MATRIX_DECRYPT_RETRY_MAX_DELAY_MS = 3e4;
466
459
  const MATRIX_DECRYPT_RETRY_MAX_ATTEMPTS = 8;
460
+ const MATRIX_DECRYPT_EXHAUSTED_RETRY_TTL_MS = 60 * 6e4;
461
+ const MATRIX_DECRYPT_EXHAUSTED_RETRY_MAX_ENTRIES = 512;
467
462
  function resolveDecryptRetryKey(roomId, eventId) {
468
463
  if (!roomId || !eventId) return null;
469
464
  return `${roomId}|${eventId}`;
470
465
  }
471
- function isDecryptionFailure(event) {
472
- return typeof event.isDecryptionFailure === "function" && event.isDecryptionFailure();
473
- }
474
- function getDecryptionFailureReason(event) {
475
- const reason = event.decryptionFailureReason;
476
- return typeof reason === "string" && reason in DecryptionFailureCode ? reason : null;
477
- }
478
466
  function shouldRetryDecryptionFailure(event) {
479
- if (!isDecryptionFailure(event)) return false;
480
- const reason = getDecryptionFailureReason(event);
481
- if (!reason) return true;
467
+ if (!event.isDecryptionFailure()) return false;
468
+ const reason = event.decryptionFailureReason;
482
469
  return reason === DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID || reason === DecryptionFailureCode.OLM_UNKNOWN_MESSAGE_INDEX || reason === DecryptionFailureCode.UNKNOWN_ERROR;
483
470
  }
484
471
  var MatrixDecryptBridge = class {
@@ -488,10 +475,11 @@ var MatrixDecryptBridge = class {
488
475
  this.decryptedMessageDedupe = /* @__PURE__ */ new Map();
489
476
  this.decryptRetries = /* @__PURE__ */ new Map();
490
477
  this.failedDecryptionsNotified = /* @__PURE__ */ new Set();
491
- this.exhaustedDecryptRetries = /* @__PURE__ */ new Set();
478
+ this.exhaustedDecryptRetries = /* @__PURE__ */ new Map();
492
479
  this.activeRetryRuns = 0;
493
480
  this.retryIdleResolvers = /* @__PURE__ */ new Set();
494
481
  this.cryptoRetrySignalsBound = false;
482
+ this.stopped = false;
495
483
  }
496
484
  shouldEmitUnencryptedMessage(roomId, eventId) {
497
485
  if (!eventId) return true;
@@ -501,6 +489,7 @@ var MatrixDecryptBridge = class {
501
489
  return false;
502
490
  }
503
491
  attachEncryptedEvent(event, roomId) {
492
+ if (this.stopped) return;
504
493
  if (this.trackedEncryptedEvents.has(event)) return;
505
494
  this.trackedEncryptedEvents.add(event);
506
495
  event.on(MatrixEventEvent.Decrypted, (decryptedEvent, err) => {
@@ -520,7 +509,21 @@ var MatrixDecryptBridge = class {
520
509
  });
521
510
  }
522
511
  }
523
- retryPendingNow(reason) {
512
+ retryPendingNow(reason, options) {
513
+ if (this.stopped) return;
514
+ if (options?.includeExhausted) {
515
+ this.pruneExhaustedDecryptRetries(Date.now());
516
+ for (const [retryKey, state] of this.exhaustedDecryptRetries) {
517
+ if (this.decryptRetries.has(retryKey)) continue;
518
+ this.exhaustedDecryptRetries.delete(retryKey);
519
+ this.decryptRetries.set(retryKey, {
520
+ ...state,
521
+ attempts: 0,
522
+ inFlight: false,
523
+ timer: null
524
+ });
525
+ }
526
+ }
524
527
  const pending = Array.from(this.decryptRetries.entries());
525
528
  if (pending.length === 0) return;
526
529
  LogService.debug("MatrixClientLite", `Retrying pending decryptions due to ${reason}`);
@@ -536,14 +539,14 @@ var MatrixDecryptBridge = class {
536
539
  bindCryptoRetrySignals(crypto) {
537
540
  if (!crypto || this.cryptoRetrySignalsBound) return;
538
541
  this.cryptoRetrySignalsBound = true;
539
- const trigger = (reason) => {
540
- this.retryPendingNow(reason);
542
+ const trigger = (reason, options) => {
543
+ this.retryPendingNow(reason, options);
541
544
  };
542
545
  crypto.on(CryptoEvent.KeyBackupDecryptionKeyCached, () => {
543
- trigger("crypto.keyBackupDecryptionKeyCached");
546
+ trigger("crypto.keyBackupDecryptionKeyCached", { includeExhausted: true });
544
547
  });
545
548
  crypto.on(CryptoEvent.RehydrationCompleted, () => {
546
- trigger("dehydration.RehydrationCompleted");
549
+ trigger("dehydration.RehydrationCompleted", { includeExhausted: true });
547
550
  });
548
551
  crypto.on(CryptoEvent.DevicesUpdated, () => {
549
552
  trigger("crypto.devicesUpdated");
@@ -553,7 +556,9 @@ var MatrixDecryptBridge = class {
553
556
  });
554
557
  }
555
558
  stop() {
559
+ this.stopped = true;
556
560
  for (const retryKey of this.decryptRetries.keys()) this.clearDecryptRetry(retryKey);
561
+ this.exhaustedDecryptRetries.clear();
557
562
  }
558
563
  async drainPendingDecryptions(reason) {
559
564
  for (let attempts = 0; attempts < MATRIX_DECRYPT_RETRY_MAX_ATTEMPTS; attempts += 1) {
@@ -564,6 +569,7 @@ var MatrixDecryptBridge = class {
564
569
  }
565
570
  }
566
571
  handleEncryptedEventDecrypted(params) {
572
+ if (this.stopped) return;
567
573
  const decryptedRoomId = params.decryptedEvent.getRoomId() || params.roomId;
568
574
  const decryptedRaw = this.deps.toRaw(params.decryptedEvent);
569
575
  const retryEventId = decryptedRaw.event_id || params.encryptedEvent.getId() || "";
@@ -578,7 +584,7 @@ var MatrixDecryptBridge = class {
578
584
  else if (retryKey) this.clearDecryptRetry(retryKey);
579
585
  return;
580
586
  }
581
- if (isDecryptionFailure(params.decryptedEvent)) {
587
+ if (params.decryptedEvent.isDecryptionFailure()) {
582
588
  this.emitFailedDecryptionOnce(retryKey, decryptedRoomId, decryptedRaw, /* @__PURE__ */ new Error("Matrix event failed to decrypt"));
583
589
  if (shouldRetryDecryptionFailure(params.decryptedEvent)) this.scheduleDecryptRetry({
584
590
  event: params.encryptedEvent,
@@ -601,6 +607,7 @@ var MatrixDecryptBridge = class {
601
607
  this.deps.emitFailedDecryption(roomId, event, error);
602
608
  }
603
609
  scheduleDecryptRetry(params) {
610
+ if (this.stopped) return;
604
611
  const retryKey = resolveDecryptRetryKey(params.roomId, params.eventId);
605
612
  if (!retryKey) return;
606
613
  const existing = this.decryptRetries.get(retryKey);
@@ -611,7 +618,17 @@ var MatrixDecryptBridge = class {
611
618
  const retry = this.decryptRetries.get(retryKey);
612
619
  if (retry?.timer) clearTimeout(retry.timer);
613
620
  this.decryptRetries.delete(retryKey);
614
- this.exhaustedDecryptRetries.add(retryKey);
621
+ const exhaustedAt = Date.now();
622
+ this.exhaustedDecryptRetries.set(retryKey, {
623
+ event: params.event,
624
+ roomId: params.roomId,
625
+ eventId: params.eventId,
626
+ attempts: attempts - 1,
627
+ inFlight: false,
628
+ timer: null,
629
+ exhaustedAt
630
+ });
631
+ this.pruneExhaustedDecryptRetries(exhaustedAt);
615
632
  LogService.debug("MatrixClientLite", `Giving up decryption retry for ${params.eventId} in ${params.roomId} after ${attempts - 1} attempts`);
616
633
  return;
617
634
  }
@@ -635,21 +652,26 @@ var MatrixDecryptBridge = class {
635
652
  state.inFlight = true;
636
653
  state.timer = null;
637
654
  this.activeRetryRuns += 1;
638
- if (!(typeof this.deps.client.decryptEventIfNeeded === "function")) {
655
+ const retryEvent = state.event;
656
+ const retryCrypto = this.deps.client.getCrypto?.();
657
+ const canAttemptDecryption = retryCrypto !== void 0 && retryCrypto !== null && typeof retryEvent.attemptDecryption === "function";
658
+ if (!(canAttemptDecryption || typeof this.deps.client.decryptEventIfNeeded === "function")) {
639
659
  this.clearDecryptRetry(retryKey);
640
660
  this.activeRetryRuns = Math.max(0, this.activeRetryRuns - 1);
641
661
  this.resolveRetryIdleIfNeeded();
642
662
  return;
643
663
  }
644
664
  try {
645
- await this.deps.client.decryptEventIfNeeded?.(state.event, { isRetry: true });
665
+ if (canAttemptDecryption) await retryEvent.attemptDecryption?.(retryCrypto, { isRetry: true });
666
+ else await this.deps.client.decryptEventIfNeeded?.(state.event, { isRetry: true });
646
667
  } catch {} finally {
647
668
  state.inFlight = false;
648
669
  this.activeRetryRuns = Math.max(0, this.activeRetryRuns - 1);
649
670
  this.resolveRetryIdleIfNeeded();
650
671
  }
651
672
  if (this.decryptRetries.get(retryKey) !== state) return;
652
- if (isDecryptionFailure(state.event)) {
673
+ if (this.stopped) return;
674
+ if (state.event.isDecryptionFailure()) {
653
675
  if (!shouldRetryDecryptionFailure(state.event)) {
654
676
  this.clearDecryptRetry(retryKey);
655
677
  return;
@@ -670,6 +692,14 @@ var MatrixDecryptBridge = class {
670
692
  this.exhaustedDecryptRetries.delete(retryKey);
671
693
  this.failedDecryptionsNotified.delete(retryKey);
672
694
  }
695
+ pruneExhaustedDecryptRetries(now) {
696
+ for (const [retryKey, state] of this.exhaustedDecryptRetries) if (now - state.exhaustedAt > MATRIX_DECRYPT_EXHAUSTED_RETRY_TTL_MS) this.exhaustedDecryptRetries.delete(retryKey);
697
+ while (this.exhaustedDecryptRetries.size > MATRIX_DECRYPT_EXHAUSTED_RETRY_MAX_ENTRIES) {
698
+ const oldest = this.exhaustedDecryptRetries.keys().next().value;
699
+ if (oldest === void 0) break;
700
+ this.exhaustedDecryptRetries.delete(oldest);
701
+ }
702
+ }
673
703
  rememberDecryptedMessage(roomId, eventId) {
674
704
  if (!eventId) return;
675
705
  const now = Date.now();
@@ -837,7 +867,7 @@ var MatrixVerificationManager = class {
837
867
  const transactionMatches = Array.from(this.verificationSessions.values()).filter((session) => {
838
868
  return this.readRequestValue(session.request, () => session.request.transactionId?.trim(), "") === id;
839
869
  });
840
- if (transactionMatches.length === 1) return transactionMatches[0];
870
+ if (transactionMatches.length === 1) return expectDefined(transactionMatches[0], "single Matrix verification session");
841
871
  if (transactionMatches.length > 1) throw new Error(`Matrix verification request id is ambiguous for transaction ${id}; use the verification id instead`);
842
872
  throw new Error(`Matrix verification request not found: ${id}`);
843
873
  }
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
5
- import { spawn } from "node:child_process";
5
+ import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
6
6
  //#region extensions/matrix/src/matrix/deps.ts
7
7
  const REQUIRED_MATRIX_PACKAGES = [
8
8
  "matrix-js-sdk",
@@ -11,7 +11,6 @@ const REQUIRED_MATRIX_PACKAGES = [
11
11
  ];
12
12
  const MIN_MATRIX_CRYPTO_NATIVE_BINDING_BYTES = 1e6;
13
13
  const MATRIX_COMMAND_OUTPUT_TAIL_BYTES = 64 * 1024;
14
- const MATRIX_STREAM_ERROR_KILL_GRACE_MS = 1e3;
15
14
  function resolveMissingMatrixPackages(resolveFn) {
16
15
  const resolve = resolveFn ?? defaultResolveFn;
17
16
  return REQUIRED_MATRIX_PACKAGES.filter((pkg) => {
@@ -30,99 +29,33 @@ function buildMatrixDepsMissingMessage(missing) {
30
29
  return [`Matrix plugin dependencies are missing: ${missing.join(", ")}.`, "Repair this plugin with `openclaw plugins update matrix` or run `openclaw doctor --fix`."].join(" ");
31
30
  }
32
31
  let defaultMatrixCryptoRuntimeEnsurePromise = null;
33
- function appendBoundedOutputTail(current, chunk) {
34
- const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
35
- if (chunkBuffer.byteLength >= 65536) return chunkBuffer.subarray(chunkBuffer.byteLength - MATRIX_COMMAND_OUTPUT_TAIL_BYTES).toString("utf8");
36
- const currentBuffer = Buffer.from(current);
37
- if (currentBuffer.byteLength + chunkBuffer.byteLength <= 65536) return `${current}${chunkBuffer.toString("utf8")}`;
38
- const currentTailBytes = MATRIX_COMMAND_OUTPUT_TAIL_BYTES - chunkBuffer.byteLength;
39
- const currentTail = currentBuffer.subarray(currentBuffer.byteLength - currentTailBytes);
40
- return Buffer.concat([currentTail, chunkBuffer], MATRIX_COMMAND_OUTPUT_TAIL_BYTES).toString("utf8");
41
- }
42
32
  async function runFixedCommandWithTimeout(params) {
43
- return await new Promise((resolve) => {
44
- const [command, ...args] = params.argv;
45
- if (!command) {
46
- resolve({
47
- code: 1,
48
- stdout: "",
49
- stderr: "command is required"
50
- });
51
- return;
52
- }
53
- const proc = spawn(command, args, {
33
+ if (!params.argv[0]) return {
34
+ code: 1,
35
+ stdout: "",
36
+ stderr: "command is required"
37
+ };
38
+ try {
39
+ const result = await runCommandWithTimeout(params.argv, {
54
40
  cwd: params.cwd,
55
- env: {
56
- ...process.env,
57
- ...params.env
58
- },
59
- stdio: [
60
- "ignore",
61
- "pipe",
62
- "pipe"
63
- ]
41
+ env: params.env,
42
+ killProcessTree: true,
43
+ maxOutputBytes: MATRIX_COMMAND_OUTPUT_TAIL_BYTES,
44
+ outputCapture: "tail",
45
+ timeoutMs: params.timeoutMs
64
46
  });
65
- let stdout = "";
66
- let stderr = "";
67
- let settled = false;
68
- let timer = null;
69
- let streamKillTimer = null;
70
- let streamErrorMessage = null;
71
- const killChildOnExit = () => {
72
- if (!settled && proc.exitCode === null) proc.kill("SIGTERM");
47
+ return {
48
+ code: result.termination === "timeout" ? 124 : result.code ?? 1,
49
+ stdout: result.stdout,
50
+ stderr: result.stderr || (result.termination === "timeout" ? `command timed out after ${params.timeoutMs}ms` : "")
73
51
  };
74
- const finalize = (result) => {
75
- if (settled) return;
76
- settled = true;
77
- if (timer) clearTimeout(timer);
78
- if (streamKillTimer) clearTimeout(streamKillTimer);
79
- process.off("exit", killChildOnExit);
80
- resolve(result);
81
- };
82
- process.once("exit", killChildOnExit);
83
- proc.stdout?.on("data", (chunk) => {
84
- stdout = appendBoundedOutputTail(stdout, chunk);
85
- });
86
- proc.stderr?.on("data", (chunk) => {
87
- stderr = appendBoundedOutputTail(stderr, chunk);
88
- });
89
- const failReadableStream = (streamName) => (error) => {
90
- if (settled || streamErrorMessage) return;
91
- streamErrorMessage = `${streamName} stream failed: ${formatErrorMessage(error)}`;
92
- if (proc.exitCode === null) proc.kill("SIGTERM");
93
- streamKillTimer = setTimeout(() => {
94
- if (!settled && proc.exitCode === null) proc.kill("SIGKILL");
95
- }, MATRIX_STREAM_ERROR_KILL_GRACE_MS);
96
- streamKillTimer.unref?.();
52
+ } catch (error) {
53
+ return {
54
+ code: 1,
55
+ stdout: "",
56
+ stderr: error instanceof Error ? error.message : String(error)
97
57
  };
98
- proc.stdout?.on("error", failReadableStream("stdout"));
99
- proc.stderr?.on("error", failReadableStream("stderr"));
100
- timer = setTimeout(() => {
101
- proc.kill("SIGKILL");
102
- if (streamErrorMessage) return;
103
- finalize({
104
- code: 124,
105
- stdout,
106
- stderr: stderr || `command timed out after ${params.timeoutMs}ms`
107
- });
108
- }, params.timeoutMs);
109
- proc.on("error", (err) => {
110
- if (streamErrorMessage) return;
111
- finalize({
112
- code: 1,
113
- stdout,
114
- stderr: err.message
115
- });
116
- });
117
- proc.on("close", (code) => {
118
- const streamErrorStderr = streamErrorMessage ? stderr ? appendBoundedOutputTail(stderr, `\n${streamErrorMessage}`) : streamErrorMessage : stderr;
119
- finalize({
120
- code: streamErrorMessage ? 1 : code ?? 1,
121
- stdout,
122
- stderr: streamErrorStderr
123
- });
124
- });
125
- });
58
+ }
126
59
  }
127
60
  function defaultRequireFn(id) {
128
61
  return createRequire(import.meta.url)(id);
@@ -1,8 +1,8 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
2
  import { n as normalizeMatrixMessagingTarget, t as isMatrixQualifiedUserId } from "./target-ids-B-5aQxwn.js";
3
- import { f as resolveMatrixAuth } from "./shared-DkFfq7mH.js";
4
- import "./client-tgnlQJk4.js";
5
- import { t as MatrixAuthedHttpClient } from "./http-client-nSmFiVgk.js";
3
+ import { f as resolveMatrixAuth } from "./shared-DgvN5rBx.js";
4
+ import "./client-DP0nmFxK.js";
5
+ import { t as MatrixAuthedHttpClient } from "./http-client-W4TJQM6r.js";
6
6
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  //#region extensions/matrix/src/directory-live.ts
8
8
  var directory_live_exports = /* @__PURE__ */ __exportAll({
@@ -0,0 +1,64 @@
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-D2qTLe-C.js";
2
+ import { detectPluginInstallPathIssue, formatPluginInstallPathIssue, removePluginFromConfig } from "openclaw/plugin-sdk/runtime-doctor";
3
+ //#region extensions/matrix/src/doctor.ts
4
+ async function collectMatrixInstallPathWarnings(cfg) {
5
+ const issue = await detectPluginInstallPathIssue({
6
+ pluginId: "matrix",
7
+ install: cfg.plugins?.installs?.matrix
8
+ });
9
+ if (!issue) return [];
10
+ return formatPluginInstallPathIssue({
11
+ issue,
12
+ pluginLabel: "Matrix",
13
+ defaultInstallCommand: "openclaw plugins install @openclaw/matrix"
14
+ }).map((entry) => `- ${entry}`);
15
+ }
16
+ async function cleanStaleMatrixPluginConfig(cfg) {
17
+ const issue = await detectPluginInstallPathIssue({
18
+ pluginId: "matrix",
19
+ install: cfg.plugins?.installs?.matrix
20
+ });
21
+ if (!issue || issue.kind !== "missing-path") return {
22
+ config: cfg,
23
+ changes: []
24
+ };
25
+ const { config, actions } = removePluginFromConfig(cfg, "matrix");
26
+ const removed = [];
27
+ if (actions.install) removed.push("install record");
28
+ if (actions.loadPath) removed.push("load path");
29
+ if (actions.entry) removed.push("plugin entry");
30
+ if (actions.allowlist) removed.push("allowlist entry");
31
+ if (removed.length === 0) return {
32
+ config: cfg,
33
+ changes: []
34
+ };
35
+ return {
36
+ config,
37
+ changes: [`Removed stale Matrix plugin references (${removed.join(", ")}). The previous install path no longer exists: ${issue.path}`]
38
+ };
39
+ }
40
+ async function runMatrixDoctorSequence(params) {
41
+ const warningNotes = [];
42
+ const installWarnings = await collectMatrixInstallPathWarnings(params.cfg);
43
+ if (installWarnings.length > 0) warningNotes.push(installWarnings.join("\n"));
44
+ return {
45
+ changeNotes: [],
46
+ warningNotes
47
+ };
48
+ }
49
+ const matrixDoctor = {
50
+ dmAllowFromMode: "nestedOnly",
51
+ groupModel: "sender",
52
+ groupAllowFromFallbackToAllowFrom: false,
53
+ warnOnEmptyGroupSenderAllowlist: true,
54
+ legacyConfigRules,
55
+ normalizeCompatibilityConfig,
56
+ runConfigSequence: async ({ cfg, env, shouldRepair }) => await runMatrixDoctorSequence({
57
+ cfg,
58
+ env,
59
+ shouldRepair
60
+ }),
61
+ cleanStaleConfig: async ({ cfg }) => await cleanStaleMatrixPluginConfig(cfg)
62
+ };
63
+ //#endregion
64
+ export { cleanStaleMatrixPluginConfig, collectMatrixInstallPathWarnings, matrixDoctor, runMatrixDoctorSequence };