@openclaw/nextcloud-talk 2026.6.5-beta.2 → 2026.6.5-beta.3
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/api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as nextcloudTalkPlugin } from "./channel-
|
|
1
|
+
import { t as nextcloudTalkPlugin } from "./channel-Cg-iYKsC.js";
|
|
2
2
|
export { nextcloudTalkPlugin };
|
|
@@ -28,14 +28,16 @@ import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
|
|
|
28
28
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
29
29
|
import { requireChannelOpenAllowFrom, resolveLoggerBackedRuntime, runStoppablePassiveMonitor, safeParseJsonWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
30
30
|
import { z } from "zod";
|
|
31
|
+
import fs from "node:fs/promises";
|
|
31
32
|
import os from "node:os";
|
|
33
|
+
import path from "node:path";
|
|
34
|
+
import { createClaimableDedupe, migratePersistentDedupeLegacyJsonFile } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
35
|
+
import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
|
|
32
36
|
import { channelIngressRoutes, resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
33
37
|
import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
|
|
34
38
|
import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "openclaw/plugin-sdk/channel-targets";
|
|
35
39
|
import { createServer } from "node:http";
|
|
36
40
|
import { WEBHOOK_RATE_LIMIT_DEFAULTS, createAuthRateLimiter, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-ingress";
|
|
37
|
-
import path from "node:path";
|
|
38
|
-
import { createClaimableDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
39
41
|
import { jsonResult, readStringParam, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
|
|
40
42
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, buildOutboundBaseSessionKey, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
|
|
41
43
|
import { applyAccountNameToChannelSection, createSetupTranslator, createStandardChannelSetupStatus, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
@@ -424,7 +426,91 @@ const NextcloudTalkConfigSchema = NextcloudTalkAccountSchemaBase.extend({
|
|
|
424
426
|
});
|
|
425
427
|
});
|
|
426
428
|
//#endregion
|
|
429
|
+
//#region extensions/nextcloud-talk/src/replay-guard.ts
|
|
430
|
+
const NEXTCLOUD_TALK_PLUGIN_ID = "nextcloud-talk";
|
|
431
|
+
const NEXTCLOUD_TALK_REPLAY_DEDUPE_NAMESPACE_PREFIX = "replay-dedupe";
|
|
432
|
+
const DEFAULT_REPLAY_TTL_MS = 1440 * 60 * 1e3;
|
|
433
|
+
const DEFAULT_MEMORY_MAX_SIZE = 1e3;
|
|
434
|
+
const DEFAULT_STATE_MAX_ENTRIES = 1e4;
|
|
435
|
+
function buildReplayKey(params) {
|
|
436
|
+
const roomToken = params.roomToken.trim();
|
|
437
|
+
const messageId = params.messageId.trim();
|
|
438
|
+
if (!roomToken || !messageId) return null;
|
|
439
|
+
return `${roomToken}:${messageId}`;
|
|
440
|
+
}
|
|
441
|
+
function createNextcloudTalkReplayGuard(options) {
|
|
442
|
+
const stateDir = options.stateDir?.trim();
|
|
443
|
+
const baseOptions = {
|
|
444
|
+
ttlMs: options.ttlMs ?? DEFAULT_REPLAY_TTL_MS,
|
|
445
|
+
memoryMaxSize: options.memoryMaxSize ?? DEFAULT_MEMORY_MAX_SIZE
|
|
446
|
+
};
|
|
447
|
+
const dedupe = createClaimableDedupe(stateDir ? {
|
|
448
|
+
...baseOptions,
|
|
449
|
+
pluginId: NEXTCLOUD_TALK_PLUGIN_ID,
|
|
450
|
+
namespacePrefix: NEXTCLOUD_TALK_REPLAY_DEDUPE_NAMESPACE_PREFIX,
|
|
451
|
+
stateMaxEntries: options.stateMaxEntries ?? options.fileMaxEntries ?? DEFAULT_STATE_MAX_ENTRIES,
|
|
452
|
+
env: {
|
|
453
|
+
...process.env,
|
|
454
|
+
OPENCLAW_STATE_DIR: stateDir
|
|
455
|
+
},
|
|
456
|
+
onDiskError: options.onDiskError
|
|
457
|
+
} : baseOptions);
|
|
458
|
+
return {
|
|
459
|
+
claimMessage: async ({ accountId, roomToken, messageId }) => {
|
|
460
|
+
const replayKey = buildReplayKey({
|
|
461
|
+
roomToken,
|
|
462
|
+
messageId
|
|
463
|
+
});
|
|
464
|
+
if (!replayKey) return "invalid";
|
|
465
|
+
return (await dedupe.claim(replayKey, { namespace: accountId })).kind;
|
|
466
|
+
},
|
|
467
|
+
commitMessage: async ({ accountId, roomToken, messageId }) => {
|
|
468
|
+
const replayKey = buildReplayKey({
|
|
469
|
+
roomToken,
|
|
470
|
+
messageId
|
|
471
|
+
});
|
|
472
|
+
if (!replayKey) return true;
|
|
473
|
+
return await dedupe.commit(replayKey, { namespace: accountId });
|
|
474
|
+
},
|
|
475
|
+
releaseMessage: ({ accountId, roomToken, messageId, error }) => {
|
|
476
|
+
const replayKey = buildReplayKey({
|
|
477
|
+
roomToken,
|
|
478
|
+
messageId
|
|
479
|
+
});
|
|
480
|
+
if (!replayKey) return;
|
|
481
|
+
dedupe.release(replayKey, {
|
|
482
|
+
namespace: accountId,
|
|
483
|
+
error
|
|
484
|
+
});
|
|
485
|
+
},
|
|
486
|
+
shouldProcessMessage: async ({ accountId, roomToken, messageId }) => {
|
|
487
|
+
const replayKey = buildReplayKey({
|
|
488
|
+
roomToken,
|
|
489
|
+
messageId
|
|
490
|
+
});
|
|
491
|
+
if (!replayKey) return true;
|
|
492
|
+
if ((await dedupe.claim(replayKey, { namespace: accountId })).kind !== "claimed") return false;
|
|
493
|
+
return await dedupe.commit(replayKey, { namespace: accountId });
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
//#endregion
|
|
427
498
|
//#region extensions/nextcloud-talk/src/doctor.ts
|
|
499
|
+
const REPLAY_DEDUPE_TTL_MS = 1440 * 60 * 1e3;
|
|
500
|
+
const REPLAY_DEDUPE_MAX_ENTRIES = 1e4;
|
|
501
|
+
function sanitizeLegacyReplaySegment(value) {
|
|
502
|
+
const trimmed = value.trim();
|
|
503
|
+
if (!trimmed) return "default";
|
|
504
|
+
return trimmed.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
505
|
+
}
|
|
506
|
+
async function fileExists(filePath) {
|
|
507
|
+
try {
|
|
508
|
+
await fs.access(filePath);
|
|
509
|
+
return true;
|
|
510
|
+
} catch {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
428
514
|
async function collectNextcloudTalkBotResponseWarnings(params) {
|
|
429
515
|
const warnings = [];
|
|
430
516
|
for (const accountId of listNextcloudTalkAccountIds(params.cfg)) {
|
|
@@ -441,10 +527,51 @@ async function collectNextcloudTalkBotResponseWarnings(params) {
|
|
|
441
527
|
}
|
|
442
528
|
return warnings;
|
|
443
529
|
}
|
|
530
|
+
async function repairNextcloudTalkReplayDedupeState(params) {
|
|
531
|
+
const changes = [];
|
|
532
|
+
const warnings = [];
|
|
533
|
+
const env = params.env ?? process.env;
|
|
534
|
+
const stateDir = resolveStateDir(env, os.homedir);
|
|
535
|
+
const replayDir = path.join(stateDir, "nextcloud-talk", "replay-dedupe");
|
|
536
|
+
for (const accountId of listNextcloudTalkAccountIds(params.cfg)) {
|
|
537
|
+
const legacyPath = path.join(replayDir, `${sanitizeLegacyReplaySegment(accountId)}.json`);
|
|
538
|
+
if (!await fileExists(legacyPath)) continue;
|
|
539
|
+
try {
|
|
540
|
+
const result = await migratePersistentDedupeLegacyJsonFile({
|
|
541
|
+
filePath: legacyPath,
|
|
542
|
+
namespace: accountId,
|
|
543
|
+
ttlMs: REPLAY_DEDUPE_TTL_MS,
|
|
544
|
+
memoryMaxSize: 0,
|
|
545
|
+
pluginId: NEXTCLOUD_TALK_PLUGIN_ID,
|
|
546
|
+
namespacePrefix: NEXTCLOUD_TALK_REPLAY_DEDUPE_NAMESPACE_PREFIX,
|
|
547
|
+
stateMaxEntries: REPLAY_DEDUPE_MAX_ENTRIES,
|
|
548
|
+
env
|
|
549
|
+
});
|
|
550
|
+
changes.push(`Migrated Nextcloud Talk replay dedupe cache for account "${accountId}" to SQLite (${result.imported} imported, ${result.skippedExpired} expired, ${result.skippedExisting} already current).`);
|
|
551
|
+
} catch (error) {
|
|
552
|
+
warnings.push(`Skipped Nextcloud Talk replay dedupe cache for account "${accountId}": ${String(error)}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return {
|
|
556
|
+
changes,
|
|
557
|
+
warnings
|
|
558
|
+
};
|
|
559
|
+
}
|
|
444
560
|
const nextcloudTalkDoctor = {
|
|
445
561
|
legacyConfigRules,
|
|
446
562
|
normalizeCompatibilityConfig,
|
|
447
|
-
collectPreviewWarnings: async ({ cfg }) => await collectNextcloudTalkBotResponseWarnings({ cfg })
|
|
563
|
+
collectPreviewWarnings: async ({ cfg }) => await collectNextcloudTalkBotResponseWarnings({ cfg }),
|
|
564
|
+
repairConfig: async ({ cfg, env }) => {
|
|
565
|
+
const repair = await repairNextcloudTalkReplayDedupeState({
|
|
566
|
+
cfg,
|
|
567
|
+
...env ? { env } : {}
|
|
568
|
+
});
|
|
569
|
+
return {
|
|
570
|
+
config: cfg,
|
|
571
|
+
changes: repair.changes,
|
|
572
|
+
warnings: repair.warnings
|
|
573
|
+
};
|
|
574
|
+
}
|
|
448
575
|
};
|
|
449
576
|
//#endregion
|
|
450
577
|
//#region extensions/nextcloud-talk/src/policy.ts
|
|
@@ -1318,73 +1445,6 @@ function createNextcloudTalkWebhookServer(opts) {
|
|
|
1318
1445
|
};
|
|
1319
1446
|
}
|
|
1320
1447
|
//#endregion
|
|
1321
|
-
//#region extensions/nextcloud-talk/src/replay-guard.ts
|
|
1322
|
-
const DEFAULT_REPLAY_TTL_MS = 1440 * 60 * 1e3;
|
|
1323
|
-
const DEFAULT_MEMORY_MAX_SIZE = 1e3;
|
|
1324
|
-
const DEFAULT_FILE_MAX_ENTRIES = 1e4;
|
|
1325
|
-
function sanitizeSegment(value) {
|
|
1326
|
-
const trimmed = value.trim();
|
|
1327
|
-
if (!trimmed) return "default";
|
|
1328
|
-
return trimmed.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1329
|
-
}
|
|
1330
|
-
function buildReplayKey(params) {
|
|
1331
|
-
const roomToken = params.roomToken.trim();
|
|
1332
|
-
const messageId = params.messageId.trim();
|
|
1333
|
-
if (!roomToken || !messageId) return null;
|
|
1334
|
-
return `${roomToken}:${messageId}`;
|
|
1335
|
-
}
|
|
1336
|
-
function createNextcloudTalkReplayGuard(options) {
|
|
1337
|
-
const stateDir = options.stateDir?.trim();
|
|
1338
|
-
const baseOptions = {
|
|
1339
|
-
ttlMs: options.ttlMs ?? DEFAULT_REPLAY_TTL_MS,
|
|
1340
|
-
memoryMaxSize: options.memoryMaxSize ?? DEFAULT_MEMORY_MAX_SIZE
|
|
1341
|
-
};
|
|
1342
|
-
const dedupe = createClaimableDedupe(stateDir ? {
|
|
1343
|
-
...baseOptions,
|
|
1344
|
-
fileMaxEntries: options.fileMaxEntries ?? DEFAULT_FILE_MAX_ENTRIES,
|
|
1345
|
-
resolveFilePath: (namespace) => path.join(stateDir, "nextcloud-talk", "replay-dedupe", `${sanitizeSegment(namespace)}.json`),
|
|
1346
|
-
onDiskError: options.onDiskError
|
|
1347
|
-
} : baseOptions);
|
|
1348
|
-
return {
|
|
1349
|
-
claimMessage: async ({ accountId, roomToken, messageId }) => {
|
|
1350
|
-
const replayKey = buildReplayKey({
|
|
1351
|
-
roomToken,
|
|
1352
|
-
messageId
|
|
1353
|
-
});
|
|
1354
|
-
if (!replayKey) return "invalid";
|
|
1355
|
-
return (await dedupe.claim(replayKey, { namespace: accountId })).kind;
|
|
1356
|
-
},
|
|
1357
|
-
commitMessage: async ({ accountId, roomToken, messageId }) => {
|
|
1358
|
-
const replayKey = buildReplayKey({
|
|
1359
|
-
roomToken,
|
|
1360
|
-
messageId
|
|
1361
|
-
});
|
|
1362
|
-
if (!replayKey) return true;
|
|
1363
|
-
return await dedupe.commit(replayKey, { namespace: accountId });
|
|
1364
|
-
},
|
|
1365
|
-
releaseMessage: ({ accountId, roomToken, messageId, error }) => {
|
|
1366
|
-
const replayKey = buildReplayKey({
|
|
1367
|
-
roomToken,
|
|
1368
|
-
messageId
|
|
1369
|
-
});
|
|
1370
|
-
if (!replayKey) return;
|
|
1371
|
-
dedupe.release(replayKey, {
|
|
1372
|
-
namespace: accountId,
|
|
1373
|
-
error
|
|
1374
|
-
});
|
|
1375
|
-
},
|
|
1376
|
-
shouldProcessMessage: async ({ accountId, roomToken, messageId }) => {
|
|
1377
|
-
const replayKey = buildReplayKey({
|
|
1378
|
-
roomToken,
|
|
1379
|
-
messageId
|
|
1380
|
-
});
|
|
1381
|
-
if (!replayKey) return true;
|
|
1382
|
-
if ((await dedupe.claim(replayKey, { namespace: accountId })).kind !== "claimed") return false;
|
|
1383
|
-
return await dedupe.commit(replayKey, { namespace: accountId });
|
|
1384
|
-
}
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
//#endregion
|
|
1388
1448
|
//#region extensions/nextcloud-talk/src/monitor-runtime.ts
|
|
1389
1449
|
const DEFAULT_WEBHOOK_PORT = 8788;
|
|
1390
1450
|
const DEFAULT_WEBHOOK_HOST = "0.0.0.0";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as nextcloudTalkPlugin } from "./channel-
|
|
1
|
+
import { t as nextcloudTalkPlugin } from "./channel-Cg-iYKsC.js";
|
|
2
2
|
export { nextcloudTalkPlugin };
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/nextcloud-talk",
|
|
3
|
-
"version": "2026.6.5-beta.
|
|
3
|
+
"version": "2026.6.5-beta.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/nextcloud-talk",
|
|
9
|
-
"version": "2026.6.5-beta.
|
|
9
|
+
"version": "2026.6.5-beta.3",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"zod": "4.4.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"openclaw": ">=2026.6.5-beta.
|
|
14
|
+
"openclaw": ">=2026.6.5-beta.3"
|
|
15
15
|
},
|
|
16
16
|
"peerDependenciesMeta": {
|
|
17
17
|
"openclaw": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/nextcloud-talk",
|
|
3
|
-
"version": "2026.6.5-beta.
|
|
3
|
+
"version": "2026.6.5-beta.3",
|
|
4
4
|
"description": "OpenClaw Nextcloud Talk channel plugin for conversations.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"openclaw": ">=2026.6.5-beta.
|
|
11
|
+
"openclaw": ">=2026.6.5-beta.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependenciesMeta": {
|
|
14
14
|
"openclaw": {
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"minHostVersion": ">=2026.4.10"
|
|
41
41
|
},
|
|
42
42
|
"compat": {
|
|
43
|
-
"pluginApi": ">=2026.6.5-beta.
|
|
43
|
+
"pluginApi": ">=2026.6.5-beta.3"
|
|
44
44
|
},
|
|
45
45
|
"build": {
|
|
46
|
-
"openclawVersion": "2026.6.5-beta.
|
|
46
|
+
"openclawVersion": "2026.6.5-beta.3"
|
|
47
47
|
},
|
|
48
48
|
"release": {
|
|
49
49
|
"publishToClawHub": true,
|