@kodelyth/matrix 2026.5.39 → 2026.6.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.
- package/dist/account-selection-Y50DNJ2l.js +158 -0
- package/dist/active-client-CmFdvPdO.js +20 -0
- package/dist/api.js +12 -0
- package/dist/approval-handler.runtime-BIi4fL0R.js +377 -0
- package/dist/approval-ids-BGHK7PnZ.js +7 -0
- package/dist/approval-reaction-auth-CL0-nCNV.js +27 -0
- package/dist/approval-reactions-nDm2x-K5.js +162 -0
- package/dist/async-lock-SsmtFXtt.js +19 -0
- package/dist/auth-presence.js +26 -0
- package/dist/backup-health-3BHbHxyd.js +60 -0
- package/dist/channel-C0kCyTNB.js +1380 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-CdrdEN-0.js +250 -0
- package/dist/cli-FtY6Nuzw.js +1338 -0
- package/dist/cli-metadata-Dkwua7CB.js +22 -0
- package/dist/cli-metadata.js +2 -0
- package/dist/client-BnohYygh.js +25 -0
- package/dist/client-PhrTwuC4.js +30 -0
- package/dist/client-bootstrap-Mcj8ChJ5.js +114 -0
- package/dist/config-paths-DVvt6vM3.js +114 -0
- package/dist/config-schema-BMGOlhdI.js +308 -0
- package/dist/config-secret-input.runtime-Dv_4Br_f.js +2 -0
- package/dist/contract-api.js +8 -0
- package/dist/create-client-J0htTaRj.js +64 -0
- package/dist/credentials-B7GsBbgQ.js +56 -0
- package/dist/credentials-read-8fE4qoWs.js +112 -0
- package/dist/credentials-write.runtime-BibplB4Y.js +17 -0
- package/dist/crypto-node.runtime-D9qxgRPa.js +12 -0
- package/dist/crypto-runtime-1pKW4O2F.js +1214 -0
- package/dist/deps-DVpDS81G.js +208 -0
- package/dist/device-health-Ct2wDSPG.js +16 -0
- package/dist/directory-live-i3T8uORc.js +150 -0
- package/dist/doctor-contract-BLzYHl_9.js +246 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/doctor-diR5gE7D.js +153 -0
- package/dist/draft-stream-HpPJ_VJt.js +143 -0
- package/dist/encryption-guidance-BNEgckrZ.js +15 -0
- package/dist/env-auth-UFiTGkDM.js +63 -0
- package/dist/env-vars-EQKQv-FE.js +63 -0
- package/dist/errors-BETj3zr9.js +17 -0
- package/dist/exec-approval-resolver-BxPorU_t.js +15 -0
- package/dist/helper-api.js +4 -0
- package/dist/http-client-DoQgbQsU.js +331 -0
- package/dist/index.js +46 -0
- package/dist/legacy-crypto-inspector-zK0hDCbt.js +41 -0
- package/dist/legacy-crypto-restore-DSFIXuDo.js +85 -0
- package/dist/logging-Df7aPD1z.js +99 -0
- package/dist/matrix-migration.runtime-BNoT1Prt.js +525 -0
- package/dist/media-text-ZhGA8Pcs.js +146 -0
- package/dist/messages-CRA9WGg0.js +140 -0
- package/dist/migration-snapshot-backup-BR-xD7Ew.js +69 -0
- package/dist/migration-snapshot.runtime-BLcy_Nvw.js +2 -0
- package/dist/monitor-DQm7_13y.js +4331 -0
- package/dist/plugin-entry.handlers.runtime.js +51 -0
- package/dist/probe.runtime-CjJS53Kz.js +3 -0
- package/dist/profile-update-DqkPgZ1P.js +68 -0
- package/dist/reaction-common-CmVLzP-u.js +71 -0
- package/dist/reaction-events-D0nUJuZV.js +121 -0
- package/dist/record-shared-DGvSFn5M.js +2 -0
- package/dist/resolve-targets-ChECUzD2.js +140 -0
- package/dist/resolver.runtime-hdY3n0GO.js +5 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/route-xRKj_ESW.js +161 -0
- package/dist/runtime-B-Fyrmxo.js +8 -0
- package/dist/runtime-api-BYXXkxq2.js +24 -0
- package/dist/runtime-api.js +25 -0
- package/dist/runtime-heavy-api.js +3 -0
- package/dist/runtime-lwTSy9Yt.js +6 -0
- package/dist/runtime-setter-api.js +2 -0
- package/dist/sdk-Jhq7mLtD.js +1704 -0
- package/dist/secret-contract-DEMcDsjl.js +120 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/send-CJunc6QM.js +1517 -0
- package/dist/setup-bootstrap-rJ0qZWPe.js +62 -0
- package/dist/setup-core-BEYoXF3J.js +677 -0
- package/dist/setup-entry.js +19 -0
- package/dist/setup-plugin-api.js +43 -0
- package/dist/setup-surface-c28ON6jq.js +537 -0
- package/dist/shared-D6MFMnpG.js +642 -0
- package/dist/startup-abort-B2J3MU_h.js +109 -0
- package/dist/startup-verification-CkD4Cwce.js +132 -0
- package/dist/storage-nyO0DOFE.js +281 -0
- package/dist/storage-paths-BTAketfg.js +52 -0
- package/dist/subagent-hooks-api-Dr_xnMRG.js +170 -0
- package/dist/subagent-hooks-api.js +2 -0
- package/dist/sync-state-Bx0gPaGA.js +12 -0
- package/dist/target-ids-Bsazo8si.js +77 -0
- package/dist/test-api.js +4 -0
- package/dist/thread-binding-api-IGU0-L70.js +17 -0
- package/dist/thread-binding-api.js +2 -0
- package/dist/thread-bindings-FjAZmDUP.js +352 -0
- package/dist/thread-bindings-runtime.js +2 -0
- package/dist/thread-bindings-shared-fvfP7jVs.js +97 -0
- package/dist/timeout-abort-signal-DpSHDHhR.js +2 -0
- package/dist/tool-actions.runtime-Cbo7YcYZ.js +532 -0
- package/dist/url-validation-DlrXNjAE.js +36 -0
- package/dist/verification-7tDPRpJU.js +345 -0
- package/package.json +19 -7
- package/api.js +0 -7
- package/auth-presence.js +0 -7
- package/channel-plugin-api.js +0 -7
- package/cli-metadata.js +0 -7
- package/contract-api.js +0 -7
- package/doctor-contract-api.js +0 -7
- package/helper-api.js +0 -7
- package/index.js +0 -7
- package/plugin-entry.handlers.runtime.js +0 -7
- package/runtime-api.js +0 -7
- package/runtime-heavy-api.js +0 -7
- package/runtime-setter-api.js +0 -7
- package/secret-contract-api.js +0 -7
- package/setup-entry.js +0 -7
- package/setup-plugin-api.js +0 -7
- package/subagent-hooks-api.js +0 -7
- package/test-api.js +0 -7
- package/thread-binding-api.js +0 -7
- package/thread-bindings-runtime.js +0 -7
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import { a as resolveMatrixDefaultOrOnlyAccountId, i as resolveMatrixChannelConfig, n as requiresExplicitMatrixDefaultAccount, o as resolveMatrixAccountStringValues, r as resolveConfiguredMatrixAccountIds, t as findMatrixAccountEntry } from "./account-selection-Y50DNJ2l.js";
|
|
2
|
+
import { i as resolveScopedMatrixEnvConfig, n as resolveGlobalMatrixEnvConfig } from "./env-auth-UFiTGkDM.js";
|
|
3
|
+
import { a as resolveMatrixCredentialsPath, n as resolveMatrixAccountStorageRoot, s as resolveMatrixLegacyFlatStoragePaths } from "./storage-paths-BTAketfg.js";
|
|
4
|
+
import { t as formatMatrixErrorMessage } from "./errors-BETj3zr9.js";
|
|
5
|
+
import "./migration-snapshot-backup-BR-xD7Ew.js";
|
|
6
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "klaw/plugin-sdk/account-id";
|
|
7
|
+
import { normalizeOptionalString } from "klaw/plugin-sdk/string-coerce-runtime";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { resolveStateDir } from "klaw/plugin-sdk/state-paths";
|
|
12
|
+
import { loadJsonFile, writeJsonFileAtomically } from "klaw/plugin-sdk/json-store";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
//#region extensions/matrix/src/migration-config.ts
|
|
15
|
+
function clean(value) {
|
|
16
|
+
return normalizeOptionalString(value) ?? "";
|
|
17
|
+
}
|
|
18
|
+
function resolveMatrixAccountConfigEntry(cfg, accountId) {
|
|
19
|
+
return findMatrixAccountEntry(cfg, accountId);
|
|
20
|
+
}
|
|
21
|
+
function resolveMatrixFlatStoreSelectionNote(cfg, accountId) {
|
|
22
|
+
if (resolveConfiguredMatrixAccountIds(cfg).length <= 1) return;
|
|
23
|
+
return `Legacy Matrix flat store uses one shared on-disk state, so it will be migrated into account "${accountId}".`;
|
|
24
|
+
}
|
|
25
|
+
function resolveMatrixMigrationConfigFields(params) {
|
|
26
|
+
const channel = resolveMatrixChannelConfig(params.cfg);
|
|
27
|
+
const account = resolveMatrixAccountConfigEntry(params.cfg, params.accountId);
|
|
28
|
+
const scopedEnv = resolveScopedMatrixEnvConfig(params.accountId, params.env);
|
|
29
|
+
const globalEnv = resolveGlobalMatrixEnvConfig(params.env);
|
|
30
|
+
const resolvedStrings = resolveMatrixAccountStringValues({
|
|
31
|
+
accountId: normalizeAccountId(params.accountId),
|
|
32
|
+
account: {
|
|
33
|
+
homeserver: clean(account?.homeserver),
|
|
34
|
+
userId: clean(account?.userId),
|
|
35
|
+
accessToken: clean(account?.accessToken)
|
|
36
|
+
},
|
|
37
|
+
scopedEnv,
|
|
38
|
+
channel: {
|
|
39
|
+
homeserver: clean(channel?.homeserver),
|
|
40
|
+
userId: clean(channel?.userId),
|
|
41
|
+
accessToken: clean(channel?.accessToken)
|
|
42
|
+
},
|
|
43
|
+
globalEnv
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
homeserver: resolvedStrings.homeserver,
|
|
47
|
+
userId: resolvedStrings.userId,
|
|
48
|
+
accessToken: resolvedStrings.accessToken
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function loadStoredMatrixCredentials(env, accountId) {
|
|
52
|
+
const credentialsPath = resolveMatrixCredentialsPath({
|
|
53
|
+
stateDir: resolveStateDir(env, os.homedir),
|
|
54
|
+
accountId: normalizeAccountId(accountId)
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
if (!fs.existsSync(credentialsPath)) return null;
|
|
58
|
+
const parsed = JSON.parse(fs.readFileSync(credentialsPath, "utf8"));
|
|
59
|
+
if (typeof parsed.homeserver !== "string" || typeof parsed.userId !== "string" || typeof parsed.accessToken !== "string") return null;
|
|
60
|
+
return {
|
|
61
|
+
homeserver: parsed.homeserver,
|
|
62
|
+
userId: parsed.userId,
|
|
63
|
+
accessToken: parsed.accessToken,
|
|
64
|
+
deviceId: typeof parsed.deviceId === "string" ? parsed.deviceId : void 0
|
|
65
|
+
};
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function credentialsMatchResolvedIdentity(stored, identity) {
|
|
71
|
+
if (!stored || !identity.homeserver) return false;
|
|
72
|
+
if (!identity.userId) {
|
|
73
|
+
if (!identity.accessToken) return false;
|
|
74
|
+
return stored.homeserver === identity.homeserver && stored.accessToken === identity.accessToken;
|
|
75
|
+
}
|
|
76
|
+
return stored.homeserver === identity.homeserver && stored.userId === identity.userId;
|
|
77
|
+
}
|
|
78
|
+
function resolveMatrixMigrationAccountTarget(params) {
|
|
79
|
+
const stored = loadStoredMatrixCredentials(params.env, params.accountId);
|
|
80
|
+
const resolved = resolveMatrixMigrationConfigFields(params);
|
|
81
|
+
const matchingStored = credentialsMatchResolvedIdentity(stored, {
|
|
82
|
+
homeserver: resolved.homeserver,
|
|
83
|
+
userId: resolved.userId,
|
|
84
|
+
accessToken: resolved.accessToken
|
|
85
|
+
}) ? stored : null;
|
|
86
|
+
const homeserver = resolved.homeserver;
|
|
87
|
+
const userId = resolved.userId || matchingStored?.userId || "";
|
|
88
|
+
const accessToken = resolved.accessToken || matchingStored?.accessToken || "";
|
|
89
|
+
if (!homeserver || !userId || !accessToken) return null;
|
|
90
|
+
const { rootDir } = resolveMatrixAccountStorageRoot({
|
|
91
|
+
stateDir: resolveStateDir(params.env, os.homedir),
|
|
92
|
+
homeserver,
|
|
93
|
+
userId,
|
|
94
|
+
accessToken,
|
|
95
|
+
accountId: params.accountId
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
accountId: params.accountId,
|
|
99
|
+
homeserver,
|
|
100
|
+
userId,
|
|
101
|
+
accessToken,
|
|
102
|
+
rootDir,
|
|
103
|
+
storedDeviceId: matchingStored?.deviceId ?? null
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function resolveLegacyMatrixFlatStoreTarget(params) {
|
|
107
|
+
if (!resolveMatrixChannelConfig(params.cfg)) return { warning: `Legacy Matrix ${params.detectedKind} detected at ${params.detectedPath}, but channels.matrix is not configured yet. Configure Matrix, then rerun "klaw doctor --fix" or restart the gateway.` };
|
|
108
|
+
if (requiresExplicitMatrixDefaultAccount(params.cfg)) return { warning: `Legacy Matrix ${params.detectedKind} detected at ${params.detectedPath}, but multiple Matrix accounts are configured and channels.matrix.defaultAccount is not set. Set "channels.matrix.defaultAccount" to the intended target account before rerunning "klaw doctor --fix" or restarting the gateway.` };
|
|
109
|
+
const accountId = resolveMatrixDefaultOrOnlyAccountId(params.cfg);
|
|
110
|
+
const target = resolveMatrixMigrationAccountTarget({
|
|
111
|
+
cfg: params.cfg,
|
|
112
|
+
env: params.env,
|
|
113
|
+
accountId
|
|
114
|
+
});
|
|
115
|
+
if (!target) {
|
|
116
|
+
const targetDescription = params.detectedKind === "state" ? "the new account-scoped target" : "the account-scoped target";
|
|
117
|
+
return { warning: `Legacy Matrix ${params.detectedKind} detected at ${params.detectedPath}, but ${targetDescription} could not be resolved yet (need homeserver, userId, and access token for channels.matrix${accountId === DEFAULT_ACCOUNT_ID ? "" : `.accounts.${accountId}`}). Start the gateway once with a working Matrix login, or rerun "klaw doctor --fix" after cached credentials are available.` };
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
...target,
|
|
121
|
+
selectionNote: resolveMatrixFlatStoreSelectionNote(params.cfg, accountId)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region extensions/matrix/src/legacy-state.ts
|
|
126
|
+
function resolveLegacyMatrixPaths(env) {
|
|
127
|
+
return resolveMatrixLegacyFlatStoragePaths(resolveStateDir(env, os.homedir));
|
|
128
|
+
}
|
|
129
|
+
function resolveMatrixMigrationPlan(params) {
|
|
130
|
+
const legacy = resolveLegacyMatrixPaths(params.env);
|
|
131
|
+
if (!fs.existsSync(legacy.storagePath) && !fs.existsSync(legacy.cryptoPath)) return null;
|
|
132
|
+
const target = resolveLegacyMatrixFlatStoreTarget({
|
|
133
|
+
cfg: params.cfg,
|
|
134
|
+
env: params.env,
|
|
135
|
+
detectedPath: legacy.rootDir,
|
|
136
|
+
detectedKind: "state"
|
|
137
|
+
});
|
|
138
|
+
if ("warning" in target) return target;
|
|
139
|
+
return {
|
|
140
|
+
accountId: target.accountId,
|
|
141
|
+
legacyStoragePath: legacy.storagePath,
|
|
142
|
+
legacyCryptoPath: legacy.cryptoPath,
|
|
143
|
+
targetRootDir: target.rootDir,
|
|
144
|
+
targetStoragePath: path.join(target.rootDir, "bot-storage.json"),
|
|
145
|
+
targetCryptoPath: path.join(target.rootDir, "crypto"),
|
|
146
|
+
selectionNote: target.selectionNote
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function detectLegacyMatrixState(params) {
|
|
150
|
+
return resolveMatrixMigrationPlan({
|
|
151
|
+
cfg: params.cfg,
|
|
152
|
+
env: params.env ?? process.env
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function moveLegacyPath(params) {
|
|
156
|
+
if (!fs.existsSync(params.sourcePath)) return;
|
|
157
|
+
if (fs.existsSync(params.targetPath)) {
|
|
158
|
+
params.warnings.push(`Matrix legacy ${params.label} not migrated because the target already exists (${params.targetPath}).`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
fs.mkdirSync(path.dirname(params.targetPath), { recursive: true });
|
|
163
|
+
fs.renameSync(params.sourcePath, params.targetPath);
|
|
164
|
+
params.changes.push(`Migrated Matrix legacy ${params.label}: ${params.sourcePath} -> ${params.targetPath}`);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
params.warnings.push(`Failed migrating Matrix legacy ${params.label} (${params.sourcePath} -> ${params.targetPath}): ${String(err)}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function autoMigrateLegacyMatrixState(params) {
|
|
170
|
+
const env = params.env ?? process.env;
|
|
171
|
+
const detection = detectLegacyMatrixState({
|
|
172
|
+
cfg: params.cfg,
|
|
173
|
+
env
|
|
174
|
+
});
|
|
175
|
+
if (!detection) return {
|
|
176
|
+
migrated: false,
|
|
177
|
+
changes: [],
|
|
178
|
+
warnings: []
|
|
179
|
+
};
|
|
180
|
+
if ("warning" in detection) {
|
|
181
|
+
params.log?.warn?.(`matrix: ${detection.warning}`);
|
|
182
|
+
return {
|
|
183
|
+
migrated: false,
|
|
184
|
+
changes: [],
|
|
185
|
+
warnings: [detection.warning]
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const changes = [];
|
|
189
|
+
const warnings = [];
|
|
190
|
+
moveLegacyPath({
|
|
191
|
+
sourcePath: detection.legacyStoragePath,
|
|
192
|
+
targetPath: detection.targetStoragePath,
|
|
193
|
+
label: "sync store",
|
|
194
|
+
changes,
|
|
195
|
+
warnings
|
|
196
|
+
});
|
|
197
|
+
moveLegacyPath({
|
|
198
|
+
sourcePath: detection.legacyCryptoPath,
|
|
199
|
+
targetPath: detection.targetCryptoPath,
|
|
200
|
+
label: "crypto store",
|
|
201
|
+
changes,
|
|
202
|
+
warnings
|
|
203
|
+
});
|
|
204
|
+
if (changes.length > 0) {
|
|
205
|
+
const details = [
|
|
206
|
+
...changes.map((entry) => `- ${entry}`),
|
|
207
|
+
...detection.selectionNote ? [`- ${detection.selectionNote}`] : [],
|
|
208
|
+
"- No user action required."
|
|
209
|
+
];
|
|
210
|
+
params.log?.info?.(`matrix: plugin upgraded in place for account "${detection.accountId}".\n${details.join("\n")}`);
|
|
211
|
+
}
|
|
212
|
+
if (warnings.length > 0) params.log?.warn?.(`matrix: legacy state migration warnings:\n${warnings.map((entry) => `- ${entry}`).join("\n")}`);
|
|
213
|
+
return {
|
|
214
|
+
migrated: changes.length > 0,
|
|
215
|
+
changes,
|
|
216
|
+
warnings
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region extensions/matrix/src/legacy-crypto-inspector-availability.ts
|
|
221
|
+
const LEGACY_CRYPTO_INSPECTOR_FILE = "legacy-crypto-inspector.js";
|
|
222
|
+
const LEGACY_CRYPTO_INSPECTOR_CHUNK_PREFIX = "legacy-crypto-inspector-";
|
|
223
|
+
const LEGACY_CRYPTO_INSPECTOR_HELPER_CHUNK_PREFIX = "availability-";
|
|
224
|
+
const JAVASCRIPT_MODULE_SUFFIX = ".js";
|
|
225
|
+
function isLegacyCryptoInspectorArtifactName(name) {
|
|
226
|
+
if (name === LEGACY_CRYPTO_INSPECTOR_FILE) return true;
|
|
227
|
+
if (!name.startsWith(LEGACY_CRYPTO_INSPECTOR_CHUNK_PREFIX) || !name.endsWith(JAVASCRIPT_MODULE_SUFFIX)) return false;
|
|
228
|
+
const chunkSuffix = name.slice(24, -3);
|
|
229
|
+
return chunkSuffix.length > 0 && chunkSuffix !== "availability" && !chunkSuffix.startsWith(LEGACY_CRYPTO_INSPECTOR_HELPER_CHUNK_PREFIX);
|
|
230
|
+
}
|
|
231
|
+
function hasSourceInspectorArtifact(currentDir) {
|
|
232
|
+
return [path.resolve(currentDir, "matrix", "legacy-crypto-inspector.ts"), path.resolve(currentDir, "matrix", "legacy-crypto-inspector.js")].some((candidate) => fs.existsSync(candidate));
|
|
233
|
+
}
|
|
234
|
+
function hasBuiltInspectorArtifact(currentDir) {
|
|
235
|
+
if (fs.existsSync(path.join(currentDir, "legacy-crypto-inspector.js"))) return true;
|
|
236
|
+
if (fs.existsSync(path.join(currentDir, "extensions", "matrix", "legacy-crypto-inspector.js"))) return true;
|
|
237
|
+
return fs.readdirSync(currentDir, { withFileTypes: true }).some((entry) => entry.isFile() && isLegacyCryptoInspectorArtifactName(entry.name));
|
|
238
|
+
}
|
|
239
|
+
function isMatrixLegacyCryptoInspectorAvailable() {
|
|
240
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
241
|
+
if (hasSourceInspectorArtifact(currentDir)) return true;
|
|
242
|
+
try {
|
|
243
|
+
return hasBuiltInspectorArtifact(currentDir);
|
|
244
|
+
} catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region extensions/matrix/src/legacy-crypto.ts
|
|
250
|
+
const MATRIX_LEGACY_CRYPTO_INSPECTOR_UNAVAILABLE_MESSAGE = "Legacy Matrix encrypted state was detected, but the Matrix crypto inspector is unavailable.";
|
|
251
|
+
async function loadMatrixLegacyCryptoInspector() {
|
|
252
|
+
return (await import("./legacy-crypto-inspector-zK0hDCbt.js")).inspectLegacyMatrixCryptoStore;
|
|
253
|
+
}
|
|
254
|
+
function detectLegacyBotSdkCryptoStore(cryptoRootDir) {
|
|
255
|
+
try {
|
|
256
|
+
if (!fs.statSync(cryptoRootDir).isDirectory()) return {
|
|
257
|
+
detected: false,
|
|
258
|
+
warning: `Legacy Matrix encrypted state path exists but is not a directory: ${cryptoRootDir}. Klaw skipped automatic crypto migration for that path.`
|
|
259
|
+
};
|
|
260
|
+
} catch (err) {
|
|
261
|
+
return {
|
|
262
|
+
detected: false,
|
|
263
|
+
warning: `Failed reading legacy Matrix encrypted state path (${cryptoRootDir}): ${String(err)}. Klaw skipped automatic crypto migration for that path.`
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
return { detected: fs.existsSync(path.join(cryptoRootDir, "bot-sdk.json")) || fs.existsSync(path.join(cryptoRootDir, "matrix-sdk-crypto.sqlite3")) || fs.readdirSync(cryptoRootDir, { withFileTypes: true }).some((entry) => entry.isDirectory() && fs.existsSync(path.join(cryptoRootDir, entry.name, "matrix-sdk-crypto.sqlite3"))) };
|
|
268
|
+
} catch (err) {
|
|
269
|
+
return {
|
|
270
|
+
detected: false,
|
|
271
|
+
warning: `Failed scanning legacy Matrix encrypted state path (${cryptoRootDir}): ${String(err)}. Klaw skipped automatic crypto migration for that path.`
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function resolveMatrixAccountIds(cfg) {
|
|
276
|
+
return resolveConfiguredMatrixAccountIds(cfg);
|
|
277
|
+
}
|
|
278
|
+
function resolveLegacyMatrixFlatStorePlan(params) {
|
|
279
|
+
const legacy = resolveMatrixLegacyFlatStoragePaths(resolveStateDir(params.env, os.homedir));
|
|
280
|
+
if (!fs.existsSync(legacy.cryptoPath)) return null;
|
|
281
|
+
const legacyStore = detectLegacyBotSdkCryptoStore(legacy.cryptoPath);
|
|
282
|
+
if (legacyStore.warning) return { warning: legacyStore.warning };
|
|
283
|
+
if (!legacyStore.detected) return null;
|
|
284
|
+
const target = resolveLegacyMatrixFlatStoreTarget({
|
|
285
|
+
cfg: params.cfg,
|
|
286
|
+
env: params.env,
|
|
287
|
+
detectedPath: legacy.cryptoPath,
|
|
288
|
+
detectedKind: "encrypted state"
|
|
289
|
+
});
|
|
290
|
+
if ("warning" in target) return target;
|
|
291
|
+
const metadata = loadLegacyBotSdkMetadata(legacy.cryptoPath);
|
|
292
|
+
return {
|
|
293
|
+
accountId: target.accountId,
|
|
294
|
+
rootDir: target.rootDir,
|
|
295
|
+
recoveryKeyPath: path.join(target.rootDir, "recovery-key.json"),
|
|
296
|
+
statePath: path.join(target.rootDir, "legacy-crypto-migration.json"),
|
|
297
|
+
legacyCryptoPath: legacy.cryptoPath,
|
|
298
|
+
homeserver: target.homeserver,
|
|
299
|
+
userId: target.userId,
|
|
300
|
+
accessToken: target.accessToken,
|
|
301
|
+
deviceId: metadata.deviceId ?? target.storedDeviceId
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function loadLegacyBotSdkMetadata(cryptoRootDir) {
|
|
305
|
+
const metadataPath = path.join(cryptoRootDir, "bot-sdk.json");
|
|
306
|
+
const fallback = { deviceId: null };
|
|
307
|
+
const parsed = loadJsonFile(metadataPath);
|
|
308
|
+
return { deviceId: typeof parsed?.deviceId === "string" && parsed.deviceId.trim() ? parsed.deviceId : fallback.deviceId };
|
|
309
|
+
}
|
|
310
|
+
function resolveMatrixLegacyCryptoPlans(params) {
|
|
311
|
+
const warnings = [];
|
|
312
|
+
const plans = [];
|
|
313
|
+
const flatPlan = resolveLegacyMatrixFlatStorePlan(params);
|
|
314
|
+
if (flatPlan) if ("warning" in flatPlan) warnings.push(flatPlan.warning);
|
|
315
|
+
else plans.push(flatPlan);
|
|
316
|
+
for (const accountId of resolveMatrixAccountIds(params.cfg)) {
|
|
317
|
+
const target = resolveMatrixMigrationAccountTarget({
|
|
318
|
+
cfg: params.cfg,
|
|
319
|
+
env: params.env,
|
|
320
|
+
accountId
|
|
321
|
+
});
|
|
322
|
+
if (!target) continue;
|
|
323
|
+
const legacyCryptoPath = path.join(target.rootDir, "crypto");
|
|
324
|
+
if (!fs.existsSync(legacyCryptoPath)) continue;
|
|
325
|
+
const detectedStore = detectLegacyBotSdkCryptoStore(legacyCryptoPath);
|
|
326
|
+
if (detectedStore.warning) {
|
|
327
|
+
warnings.push(detectedStore.warning);
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (!detectedStore.detected) continue;
|
|
331
|
+
if (plans.some((plan) => plan.accountId === accountId && path.resolve(plan.legacyCryptoPath) === path.resolve(legacyCryptoPath))) continue;
|
|
332
|
+
const metadata = loadLegacyBotSdkMetadata(legacyCryptoPath);
|
|
333
|
+
plans.push({
|
|
334
|
+
accountId: target.accountId,
|
|
335
|
+
rootDir: target.rootDir,
|
|
336
|
+
recoveryKeyPath: path.join(target.rootDir, "recovery-key.json"),
|
|
337
|
+
statePath: path.join(target.rootDir, "legacy-crypto-migration.json"),
|
|
338
|
+
legacyCryptoPath,
|
|
339
|
+
homeserver: target.homeserver,
|
|
340
|
+
userId: target.userId,
|
|
341
|
+
accessToken: target.accessToken,
|
|
342
|
+
deviceId: metadata.deviceId ?? target.storedDeviceId
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
plans,
|
|
347
|
+
warnings
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function loadStoredRecoveryKey(filePath) {
|
|
351
|
+
return loadJsonFile(filePath) ?? null;
|
|
352
|
+
}
|
|
353
|
+
function loadLegacyCryptoMigrationState(filePath) {
|
|
354
|
+
return loadJsonFile(filePath) ?? null;
|
|
355
|
+
}
|
|
356
|
+
async function persistLegacyMigrationState(params) {
|
|
357
|
+
await params.writeJsonFileAtomically(params.filePath, params.state);
|
|
358
|
+
}
|
|
359
|
+
function detectLegacyMatrixCrypto(params) {
|
|
360
|
+
const detection = resolveMatrixLegacyCryptoPlans({
|
|
361
|
+
cfg: params.cfg,
|
|
362
|
+
env: params.env ?? process.env
|
|
363
|
+
});
|
|
364
|
+
const inspectorAvailable = detection.plans.length === 0 || isMatrixLegacyCryptoInspectorAvailable();
|
|
365
|
+
if (!inspectorAvailable && detection.plans.length > 0) return {
|
|
366
|
+
inspectorAvailable,
|
|
367
|
+
plans: detection.plans,
|
|
368
|
+
warnings: [...detection.warnings, MATRIX_LEGACY_CRYPTO_INSPECTOR_UNAVAILABLE_MESSAGE]
|
|
369
|
+
};
|
|
370
|
+
return {
|
|
371
|
+
inspectorAvailable,
|
|
372
|
+
plans: detection.plans,
|
|
373
|
+
warnings: detection.warnings
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
async function autoPrepareLegacyMatrixCrypto(params) {
|
|
377
|
+
const env = params.env ?? process.env;
|
|
378
|
+
const detection = params.deps?.inspectLegacyStore ? resolveMatrixLegacyCryptoPlans({
|
|
379
|
+
cfg: params.cfg,
|
|
380
|
+
env
|
|
381
|
+
}) : detectLegacyMatrixCrypto({
|
|
382
|
+
cfg: params.cfg,
|
|
383
|
+
env
|
|
384
|
+
});
|
|
385
|
+
const inspectorAvailable = "inspectorAvailable" in detection ? detection.inspectorAvailable : true;
|
|
386
|
+
const warnings = [...detection.warnings];
|
|
387
|
+
const changes = [];
|
|
388
|
+
const writeJsonFileAtomically$1 = params.deps?.writeJsonFileAtomically ?? writeJsonFileAtomically;
|
|
389
|
+
if (detection.plans.length === 0) {
|
|
390
|
+
if (warnings.length > 0) params.log?.warn?.(`matrix: legacy encrypted-state warnings:\n${warnings.map((entry) => `- ${entry}`).join("\n")}`);
|
|
391
|
+
return {
|
|
392
|
+
migrated: false,
|
|
393
|
+
changes,
|
|
394
|
+
warnings
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
if (!params.deps?.inspectLegacyStore && !inspectorAvailable) {
|
|
398
|
+
if (warnings.length > 0) params.log?.warn?.(`matrix: legacy encrypted-state warnings:\n${warnings.map((entry) => `- ${entry}`).join("\n")}`);
|
|
399
|
+
return {
|
|
400
|
+
migrated: false,
|
|
401
|
+
changes,
|
|
402
|
+
warnings
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
let inspectLegacyStore = params.deps?.inspectLegacyStore;
|
|
406
|
+
if (!inspectLegacyStore) try {
|
|
407
|
+
inspectLegacyStore = await loadMatrixLegacyCryptoInspector();
|
|
408
|
+
} catch (err) {
|
|
409
|
+
const message = formatMatrixErrorMessage(err);
|
|
410
|
+
if (!warnings.includes(message)) warnings.push(message);
|
|
411
|
+
if (warnings.length > 0) params.log?.warn?.(`matrix: legacy encrypted-state warnings:\n${warnings.map((entry) => `- ${entry}`).join("\n")}`);
|
|
412
|
+
return {
|
|
413
|
+
migrated: false,
|
|
414
|
+
changes,
|
|
415
|
+
warnings
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
if (!inspectLegacyStore) return {
|
|
419
|
+
migrated: false,
|
|
420
|
+
changes,
|
|
421
|
+
warnings
|
|
422
|
+
};
|
|
423
|
+
for (const plan of detection.plans) {
|
|
424
|
+
if (loadLegacyCryptoMigrationState(plan.statePath)?.version === 1) continue;
|
|
425
|
+
if (!plan.deviceId) {
|
|
426
|
+
warnings.push(`Legacy Matrix encrypted state detected at ${plan.legacyCryptoPath}, but no device ID was found for account "${plan.accountId}". Klaw will continue, but old encrypted history cannot be recovered automatically.`);
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
let summary;
|
|
430
|
+
try {
|
|
431
|
+
summary = await inspectLegacyStore({
|
|
432
|
+
cryptoRootDir: plan.legacyCryptoPath,
|
|
433
|
+
userId: plan.userId,
|
|
434
|
+
deviceId: plan.deviceId,
|
|
435
|
+
log: params.log?.info
|
|
436
|
+
});
|
|
437
|
+
} catch (err) {
|
|
438
|
+
warnings.push(`Failed inspecting legacy Matrix encrypted state for account "${plan.accountId}" (${plan.legacyCryptoPath}): ${String(err)}`);
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
let decryptionKeyImported = false;
|
|
442
|
+
if (summary.decryptionKeyBase64) {
|
|
443
|
+
const existingRecoveryKey = loadStoredRecoveryKey(plan.recoveryKeyPath);
|
|
444
|
+
if (existingRecoveryKey?.privateKeyBase64 && existingRecoveryKey.privateKeyBase64 !== summary.decryptionKeyBase64) warnings.push(`Legacy Matrix backup key was found for account "${plan.accountId}", but ${plan.recoveryKeyPath} already contains a different recovery key. Leaving the existing file unchanged.`);
|
|
445
|
+
else if (!existingRecoveryKey?.privateKeyBase64) {
|
|
446
|
+
const payload = {
|
|
447
|
+
version: 1,
|
|
448
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
449
|
+
keyId: null,
|
|
450
|
+
privateKeyBase64: summary.decryptionKeyBase64
|
|
451
|
+
};
|
|
452
|
+
try {
|
|
453
|
+
await writeJsonFileAtomically$1(plan.recoveryKeyPath, payload);
|
|
454
|
+
changes.push(`Imported Matrix legacy backup key for account "${plan.accountId}": ${plan.recoveryKeyPath}`);
|
|
455
|
+
decryptionKeyImported = true;
|
|
456
|
+
} catch (err) {
|
|
457
|
+
warnings.push(`Failed writing Matrix recovery key for account "${plan.accountId}" (${plan.recoveryKeyPath}): ${String(err)}`);
|
|
458
|
+
}
|
|
459
|
+
} else decryptionKeyImported = true;
|
|
460
|
+
}
|
|
461
|
+
const localOnlyKeys = summary.roomKeyCounts && summary.roomKeyCounts.total > summary.roomKeyCounts.backedUp ? summary.roomKeyCounts.total - summary.roomKeyCounts.backedUp : 0;
|
|
462
|
+
if (localOnlyKeys > 0) warnings.push(`Legacy Matrix encrypted state for account "${plan.accountId}" contains ${localOnlyKeys} room key(s) that were never backed up. Backed-up keys can be restored automatically, but local-only encrypted history may remain unavailable after upgrade.`);
|
|
463
|
+
if (!summary.decryptionKeyBase64 && (summary.roomKeyCounts?.backedUp ?? 0) > 0) warnings.push(`Legacy Matrix encrypted state for account "${plan.accountId}" has backed-up room keys, but no local backup decryption key was found. Ask the operator to run "klaw matrix verify backup restore --recovery-key <key>" after upgrade if they have the recovery key.`);
|
|
464
|
+
if (!summary.decryptionKeyBase64 && (summary.roomKeyCounts?.total ?? 0) > 0) warnings.push(`Legacy Matrix encrypted state for account "${plan.accountId}" cannot be fully converted automatically because the old rust crypto store does not expose all local room keys for export.`);
|
|
465
|
+
if (summary.decryptionKeyBase64 && !decryptionKeyImported && !loadStoredRecoveryKey(plan.recoveryKeyPath)) continue;
|
|
466
|
+
const state = {
|
|
467
|
+
version: 1,
|
|
468
|
+
source: "matrix-bot-sdk-rust",
|
|
469
|
+
accountId: plan.accountId,
|
|
470
|
+
deviceId: summary.deviceId,
|
|
471
|
+
roomKeyCounts: summary.roomKeyCounts,
|
|
472
|
+
backupVersion: summary.backupVersion,
|
|
473
|
+
decryptionKeyImported,
|
|
474
|
+
restoreStatus: decryptionKeyImported ? "pending" : "manual-action-required",
|
|
475
|
+
detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
476
|
+
lastError: null
|
|
477
|
+
};
|
|
478
|
+
try {
|
|
479
|
+
await persistLegacyMigrationState({
|
|
480
|
+
filePath: plan.statePath,
|
|
481
|
+
state,
|
|
482
|
+
writeJsonFileAtomically: writeJsonFileAtomically$1
|
|
483
|
+
});
|
|
484
|
+
changes.push(`Prepared Matrix legacy encrypted-state migration for account "${plan.accountId}": ${plan.statePath}`);
|
|
485
|
+
} catch (err) {
|
|
486
|
+
warnings.push(`Failed writing Matrix legacy encrypted-state migration record for account "${plan.accountId}" (${plan.statePath}): ${String(err)}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (changes.length > 0) params.log?.info?.(`matrix: prepared encrypted-state upgrade.\n${changes.map((entry) => `- ${entry}`).join("\n")}`);
|
|
490
|
+
if (warnings.length > 0) params.log?.warn?.(`matrix: legacy encrypted-state warnings:\n${warnings.map((entry) => `- ${entry}`).join("\n")}`);
|
|
491
|
+
return {
|
|
492
|
+
migrated: changes.length > 0,
|
|
493
|
+
changes,
|
|
494
|
+
warnings
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
//#endregion
|
|
498
|
+
//#region extensions/matrix/src/migration-snapshot.ts
|
|
499
|
+
function resolveMatrixMigrationStatus(params) {
|
|
500
|
+
const env = params.env ?? process.env;
|
|
501
|
+
const legacyState = detectLegacyMatrixState({
|
|
502
|
+
cfg: params.cfg,
|
|
503
|
+
env
|
|
504
|
+
});
|
|
505
|
+
const legacyCrypto = detectLegacyMatrixCrypto({
|
|
506
|
+
cfg: params.cfg,
|
|
507
|
+
env
|
|
508
|
+
});
|
|
509
|
+
const actionableLegacyState = legacyState !== null && !("warning" in legacyState);
|
|
510
|
+
const actionableLegacyCrypto = legacyCrypto.plans.length > 0 && legacyCrypto.inspectorAvailable;
|
|
511
|
+
return {
|
|
512
|
+
legacyState,
|
|
513
|
+
legacyCrypto,
|
|
514
|
+
pending: legacyState !== null || legacyCrypto.plans.length > 0 || legacyCrypto.warnings.length > 0,
|
|
515
|
+
actionable: actionableLegacyState || actionableLegacyCrypto
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function hasPendingMatrixMigration(params) {
|
|
519
|
+
return resolveMatrixMigrationStatus(params).pending;
|
|
520
|
+
}
|
|
521
|
+
function hasActionableMatrixMigration(params) {
|
|
522
|
+
return resolveMatrixMigrationStatus(params).actionable;
|
|
523
|
+
}
|
|
524
|
+
//#endregion
|
|
525
|
+
export { detectLegacyMatrixCrypto as a, autoPrepareLegacyMatrixCrypto as i, hasPendingMatrixMigration as n, autoMigrateLegacyMatrixState as o, resolveMatrixMigrationStatus as r, detectLegacyMatrixState as s, hasActionableMatrixMigration as t };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { C as formatPollResultsAsText, D as parsePollStartContent, O as resolvePollReferenceEventId, S as formatPollAsText, T as isPollStartType, w as isPollEventType, x as buildPollResultsSummary } from "./send-CJunc6QM.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region extensions/matrix/src/matrix/poll-summary.ts
|
|
4
|
+
function resolveMatrixPollRootEventId(event) {
|
|
5
|
+
if (isPollStartType(event.type)) {
|
|
6
|
+
const eventId = event.event_id?.trim();
|
|
7
|
+
return eventId ? eventId : null;
|
|
8
|
+
}
|
|
9
|
+
return resolvePollReferenceEventId(event.content);
|
|
10
|
+
}
|
|
11
|
+
async function readAllPollRelations(client, roomId, pollEventId) {
|
|
12
|
+
const relationEvents = [];
|
|
13
|
+
let nextBatch;
|
|
14
|
+
do {
|
|
15
|
+
const page = await client.getRelations(roomId, pollEventId, "m.reference", void 0, { from: nextBatch });
|
|
16
|
+
relationEvents.push(...page.events);
|
|
17
|
+
nextBatch = page.nextBatch ?? void 0;
|
|
18
|
+
} while (nextBatch);
|
|
19
|
+
return relationEvents;
|
|
20
|
+
}
|
|
21
|
+
async function fetchMatrixPollSnapshot(client, roomId, event) {
|
|
22
|
+
if (!isPollEventType(event.type)) return null;
|
|
23
|
+
const pollEventId = resolveMatrixPollRootEventId(event);
|
|
24
|
+
if (!pollEventId) return null;
|
|
25
|
+
const rootEvent = isPollStartType(event.type) ? event : await client.getEvent(roomId, pollEventId);
|
|
26
|
+
if (!isPollStartType(rootEvent.type)) return null;
|
|
27
|
+
const pollStartContent = rootEvent.content;
|
|
28
|
+
const pollSummary = parsePollStartContent(pollStartContent);
|
|
29
|
+
if (!pollSummary) return null;
|
|
30
|
+
const relationEvents = await readAllPollRelations(client, roomId, pollEventId);
|
|
31
|
+
const pollResults = buildPollResultsSummary({
|
|
32
|
+
pollEventId,
|
|
33
|
+
roomId,
|
|
34
|
+
sender: rootEvent.sender,
|
|
35
|
+
senderName: rootEvent.sender,
|
|
36
|
+
content: pollStartContent,
|
|
37
|
+
relationEvents
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
pollEventId,
|
|
41
|
+
triggerEvent: event,
|
|
42
|
+
rootEvent,
|
|
43
|
+
text: pollResults ? formatPollResultsAsText(pollResults) : formatPollAsText(pollSummary)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async function fetchMatrixPollMessageSummary(client, roomId, event) {
|
|
47
|
+
const snapshot = await fetchMatrixPollSnapshot(client, roomId, event);
|
|
48
|
+
if (!snapshot) return null;
|
|
49
|
+
return {
|
|
50
|
+
eventId: snapshot.pollEventId,
|
|
51
|
+
sender: snapshot.rootEvent.sender,
|
|
52
|
+
body: snapshot.text,
|
|
53
|
+
msgtype: "m.text",
|
|
54
|
+
timestamp: snapshot.triggerEvent.origin_server_ts || snapshot.rootEvent.origin_server_ts
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region extensions/matrix/src/matrix/media-text.ts
|
|
59
|
+
const MATRIX_MEDIA_KINDS = {
|
|
60
|
+
"m.audio": "audio",
|
|
61
|
+
"m.file": "file",
|
|
62
|
+
"m.image": "image",
|
|
63
|
+
"m.sticker": "sticker",
|
|
64
|
+
"m.video": "video"
|
|
65
|
+
};
|
|
66
|
+
function resolveMatrixMediaKind(msgtype) {
|
|
67
|
+
return MATRIX_MEDIA_KINDS[msgtype ?? ""] ?? null;
|
|
68
|
+
}
|
|
69
|
+
function resolveMatrixMediaLabel(kind, fallback = "media") {
|
|
70
|
+
return `${kind ?? fallback} attachment`;
|
|
71
|
+
}
|
|
72
|
+
function formatMatrixAttachmentMarker(params) {
|
|
73
|
+
const label = resolveMatrixMediaLabel(params.kind);
|
|
74
|
+
if (params.tooLarge) return `[matrix ${label} too large]`;
|
|
75
|
+
return params.unavailable ? `[matrix ${label} unavailable]` : `[matrix ${label}]`;
|
|
76
|
+
}
|
|
77
|
+
function isLikelyBareFilename(text) {
|
|
78
|
+
const trimmed = text.trim();
|
|
79
|
+
if (!trimmed || trimmed.includes("\n") || /\s/.test(trimmed)) return false;
|
|
80
|
+
if (path.basename(trimmed) !== trimmed) return false;
|
|
81
|
+
return path.extname(trimmed).length > 1;
|
|
82
|
+
}
|
|
83
|
+
function resolveCaptionOrFilename(params) {
|
|
84
|
+
const body = params.body?.trim() ?? "";
|
|
85
|
+
const filename = params.filename?.trim() ?? "";
|
|
86
|
+
if (filename) {
|
|
87
|
+
if (!body || body === filename) return { filename };
|
|
88
|
+
return {
|
|
89
|
+
caption: body,
|
|
90
|
+
filename
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (!body) return {};
|
|
94
|
+
if (isLikelyBareFilename(body)) return { filename: body };
|
|
95
|
+
return { caption: body };
|
|
96
|
+
}
|
|
97
|
+
function resolveMatrixMessageAttachment(params) {
|
|
98
|
+
const kind = resolveMatrixMediaKind(params.msgtype);
|
|
99
|
+
if (!kind) return;
|
|
100
|
+
const resolved = resolveCaptionOrFilename(params);
|
|
101
|
+
return {
|
|
102
|
+
kind,
|
|
103
|
+
caption: resolved.caption,
|
|
104
|
+
filename: resolved.filename
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function resolveMatrixMessageBody(params) {
|
|
108
|
+
const attachment = resolveMatrixMessageAttachment(params);
|
|
109
|
+
if (!attachment) return (params.body?.trim() ?? "") || void 0;
|
|
110
|
+
return attachment.caption;
|
|
111
|
+
}
|
|
112
|
+
function formatMatrixAttachmentText(params) {
|
|
113
|
+
if (!params.attachment) return;
|
|
114
|
+
return formatMatrixAttachmentMarker({
|
|
115
|
+
kind: params.attachment.kind,
|
|
116
|
+
tooLarge: params.tooLarge,
|
|
117
|
+
unavailable: params.unavailable
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function formatMatrixMessageText(params) {
|
|
121
|
+
const body = params.body?.trim() ?? "";
|
|
122
|
+
const marker = formatMatrixAttachmentText({
|
|
123
|
+
attachment: params.attachment,
|
|
124
|
+
tooLarge: params.tooLarge,
|
|
125
|
+
unavailable: params.unavailable
|
|
126
|
+
});
|
|
127
|
+
if (!marker) return body || void 0;
|
|
128
|
+
if (!body) return marker;
|
|
129
|
+
return `${body}\n\n${marker}`;
|
|
130
|
+
}
|
|
131
|
+
function formatMatrixMediaUnavailableText(params) {
|
|
132
|
+
return formatMatrixMessageText({
|
|
133
|
+
body: resolveMatrixMessageBody(params),
|
|
134
|
+
attachment: resolveMatrixMessageAttachment(params),
|
|
135
|
+
unavailable: true
|
|
136
|
+
}) ?? "";
|
|
137
|
+
}
|
|
138
|
+
function formatMatrixMediaTooLargeText(params) {
|
|
139
|
+
return formatMatrixMessageText({
|
|
140
|
+
body: resolveMatrixMessageBody(params),
|
|
141
|
+
attachment: resolveMatrixMessageAttachment(params),
|
|
142
|
+
tooLarge: true
|
|
143
|
+
}) ?? "";
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { resolveMatrixMessageBody as a, resolveMatrixPollRootEventId as c, resolveMatrixMessageAttachment as i, formatMatrixMediaUnavailableText as n, fetchMatrixPollMessageSummary as o, formatMatrixMessageText as r, fetchMatrixPollSnapshot as s, formatMatrixMediaTooLargeText as t };
|