@openclaw/nextcloud-talk 2026.7.2-beta.5 → 2026.8.1-beta.2
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 +1 -1
- package/dist/{channel-D6MTjGj3.js → channel-CojgyJSq.js} +83 -87
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{doctor-contract-fNhK1wag.js → doctor-contract-Bda_xc6V.js} +1 -2
- package/dist/doctor-contract-api.js +1 -1
- package/dist/secret-contract-Bvm0PmP3.js +15 -0
- package/dist/secret-contract-api.js +1 -1
- package/openclaw.plugin.json +101 -0
- package/package.json +8 -5
- package/dist/secret-contract-DGgvfVqm.js +0 -45
package/dist/api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as nextcloudTalkPlugin } from "./channel-
|
|
1
|
+
import { t as nextcloudTalkPlugin } from "./channel-CojgyJSq.js";
|
|
2
2
|
export { nextcloudTalkPlugin };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as fetchWithSsrFGuard, c as resolveDefaultGroupPolicy, i as deliverFormattedTextWithAttachments, l as warnMissingProviderGroupPolicyFallbackOnce, o as logInboundDrop, r as createChannelPairingController, s as resolveAllowlistProviderRuntimeGroupPolicy, t as GROUP_POLICY_BLOCKED_LABEL, u as getNextcloudTalkRuntime } from "./runtime-api-BKsxTw4J.js";
|
|
2
|
-
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-
|
|
3
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-
|
|
2
|
+
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Bda_xc6V.js";
|
|
3
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Bvm0PmP3.js";
|
|
4
4
|
import { createAccountListHelpers, describeWebhookAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
5
5
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
6
6
|
import { createLoggedPairingApprovalNotifier, createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
|
@@ -8,14 +8,15 @@ import { createAllowlistProviderRouteAllowlistWarningCollector, resolveScopeRequ
|
|
|
8
8
|
import { buildWebhookChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
9
9
|
import { FormatCapabilityProfile, convertMarkdownTables, renderMarkdownWithMarkers, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
10
10
|
import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
11
|
-
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
11
|
+
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, readNonEmptyStringPreservingWhitespace } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
12
12
|
import { DEFAULT_ACCOUNT_ID, hasConfiguredAccountValue, normalizeAccountId, resolveAccountWithDefaultFallback } from "openclaw/plugin-sdk/account-core";
|
|
13
|
+
import { isTruthyEnvValue } from "openclaw/plugin-sdk/runtime-env";
|
|
13
14
|
import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
|
|
14
15
|
import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
15
16
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
16
17
|
import { parseStrictNonNegativeInteger, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
17
18
|
import { readProviderJsonResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
18
|
-
import {
|
|
19
|
+
import { resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
|
|
19
20
|
import { bindIngressLifecycleToReplyOptions, createAccountStatusSink, createChannelIngressMonitor, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, resolveChannelStreamingBlockEnabled, runPassiveAccountLifecycle } from "openclaw/plugin-sdk/channel-outbound";
|
|
20
21
|
import { ssrfPolicyFromPrivateNetworkOptIn, ssrfPolicyFromPrivateNetworkOptIn as ssrfPolicyFromPrivateNetworkOptIn$1 } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
21
22
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
@@ -33,12 +34,14 @@ import os from "node:os";
|
|
|
33
34
|
import path from "node:path";
|
|
34
35
|
import { migratePersistentDedupeLegacyJsonFile, resolvePersistentDedupePluginStateNamespace } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
35
36
|
import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
|
|
37
|
+
import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
36
38
|
import { channelIngressRoutes, resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
37
39
|
import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback } from "openclaw/plugin-sdk/channel-targets";
|
|
38
40
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
39
41
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
40
42
|
import { createServer } from "node:http";
|
|
41
43
|
import { WEBHOOK_RATE_LIMIT_DEFAULTS, createAuthRateLimiter, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-ingress";
|
|
44
|
+
import { isRecord } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
42
45
|
import { jsonResult, readStringParam, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
|
|
43
46
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, buildOutboundBaseSessionKey, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
|
|
44
47
|
import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
|
|
@@ -78,10 +81,6 @@ function resolveNextcloudTalkApiCredentials(params) {
|
|
|
78
81
|
}
|
|
79
82
|
//#endregion
|
|
80
83
|
//#region extensions/nextcloud-talk/src/accounts.ts
|
|
81
|
-
function isTruthyEnvValue(value) {
|
|
82
|
-
const normalized = normalizeLowercaseStringOrEmpty(value);
|
|
83
|
-
return normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on";
|
|
84
|
-
}
|
|
85
84
|
const debugAccounts = (...args) => {
|
|
86
85
|
if (isTruthyEnvValue(process.env.OPENCLAW_DEBUG_NEXTCLOUD_TALK_ACCOUNTS)) console.warn("[nextcloud-talk:accounts]", ...args);
|
|
87
86
|
};
|
|
@@ -397,6 +396,7 @@ dangerouslyAllowPrivateNetwork: z.boolean().optional() }).strict().optional();
|
|
|
397
396
|
const NextcloudTalkConfigSchema = buildMultiAccountChannelSchema(z.object({
|
|
398
397
|
name: z.string().optional(),
|
|
399
398
|
enabled: z.boolean().optional(),
|
|
399
|
+
configWrites: z.boolean().optional(),
|
|
400
400
|
markdown: MarkdownConfigSchema,
|
|
401
401
|
baseUrl: z.string().optional(),
|
|
402
402
|
botSecret: buildSecretInputSchema().optional(),
|
|
@@ -595,10 +595,6 @@ function cacheRoomInfo(key, value) {
|
|
|
595
595
|
roomCache.set(key, value);
|
|
596
596
|
pruneMapToMaxSize(roomCache, ROOM_CACHE_MAX_ENTRIES);
|
|
597
597
|
}
|
|
598
|
-
function coerceRoomType(value) {
|
|
599
|
-
if (typeof value === "number" && Number.isSafeInteger(value) && value > 0) return value;
|
|
600
|
-
return parseStrictPositiveInteger(value);
|
|
601
|
-
}
|
|
602
598
|
function resolveRoomKindFromType(type) {
|
|
603
599
|
if (!type) return;
|
|
604
600
|
if (type === 1 || type === 5 || type === 6) return "direct";
|
|
@@ -650,7 +646,7 @@ async function resolveNextcloudTalkRoomKind(params) {
|
|
|
650
646
|
runtime?.log?.(`nextcloud-talk: room lookup failed (${response.status}) token=${roomToken}`);
|
|
651
647
|
return;
|
|
652
648
|
}
|
|
653
|
-
const kind = resolveRoomKindFromType(
|
|
649
|
+
const kind = resolveRoomKindFromType(parseStrictPositiveInteger((await readProviderJsonResponse(response, "Nextcloud Talk room info failed")).ocs?.data?.type));
|
|
654
650
|
cacheRoomInfo(key, {
|
|
655
651
|
fetchedAt: Date.now(),
|
|
656
652
|
kind
|
|
@@ -989,7 +985,7 @@ async function handleNextcloudTalkInbound(params) {
|
|
|
989
985
|
const allowFrom = normalizeStringEntries(account.config.allowFrom);
|
|
990
986
|
const outerGroupAllowFrom = account.config.groupAllowFrom?.length ? normalizeStringEntries(account.config.groupAllowFrom) : allowFrom;
|
|
991
987
|
const roomAllowFrom = normalizeStringEntries(roomConfig?.allowFrom);
|
|
992
|
-
const resolveAccess = async (wasMentioned) => await resolveStableChannelMessageIngress({
|
|
988
|
+
const resolveAccess = async (wasMentioned, contextBinding) => await resolveStableChannelMessageIngress({
|
|
993
989
|
channelId: CHANNEL_ID,
|
|
994
990
|
accountId: account.accountId,
|
|
995
991
|
identity: {
|
|
@@ -1005,6 +1001,7 @@ async function handleNextcloudTalkInbound(params) {
|
|
|
1005
1001
|
kind: isGroup ? "group" : "direct",
|
|
1006
1002
|
id: isGroup ? roomToken : senderId
|
|
1007
1003
|
},
|
|
1004
|
+
contextBinding,
|
|
1008
1005
|
route: roomRoutes({
|
|
1009
1006
|
isGroup,
|
|
1010
1007
|
groupPolicy,
|
|
@@ -1092,11 +1089,6 @@ async function handleNextcloudTalkInbound(params) {
|
|
|
1092
1089
|
}
|
|
1093
1090
|
const mentionRegexes = core.channel.mentions.buildMentionRegexes(config);
|
|
1094
1091
|
const wasMentioned = mentionRegexes.length ? core.channel.mentions.matchesMentionPatterns(rawBody, mentionRegexes) : false;
|
|
1095
|
-
if (isGroup) access = await resolveAccess(wasMentioned);
|
|
1096
|
-
if (isGroup && access.activationAccess.shouldSkip) {
|
|
1097
|
-
runtime.log?.(`nextcloud-talk: drop room ${roomToken} (no mention)`);
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
1092
|
const { route, buildEnvelope } = resolveChannelInboundRouteEnvelope({
|
|
1101
1093
|
cfg: config,
|
|
1102
1094
|
channel: CHANNEL_ID,
|
|
@@ -1106,6 +1098,16 @@ async function handleNextcloudTalkInbound(params) {
|
|
|
1106
1098
|
id: isGroup ? roomToken : senderId
|
|
1107
1099
|
}
|
|
1108
1100
|
});
|
|
1101
|
+
access = await resolveAccess(isGroup ? wasMentioned : void 0, {
|
|
1102
|
+
agentId: route.agentId,
|
|
1103
|
+
sessionKey: route.sessionKey,
|
|
1104
|
+
messageId: message.messageId,
|
|
1105
|
+
inboundEventKind: "user_request"
|
|
1106
|
+
});
|
|
1107
|
+
if (access.ingress.admission !== "dispatch") {
|
|
1108
|
+
runtime.log?.(isGroup && access.activationAccess.shouldSkip ? `nextcloud-talk: drop room ${roomToken} (no mention)` : `nextcloud-talk: drop ${isGroup ? "room" : "DM"} ${roomToken} (authorization changed)`);
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1109
1111
|
const fromLabel = isGroup ? `room:${roomName || roomToken}` : senderName || `user:${senderId}`;
|
|
1110
1112
|
const body = buildEnvelope({
|
|
1111
1113
|
channel: "Nextcloud Talk",
|
|
@@ -1115,7 +1117,8 @@ async function handleNextcloudTalkInbound(params) {
|
|
|
1115
1117
|
});
|
|
1116
1118
|
const groupSystemPrompt = normalizeOptionalString(roomConfig?.systemPrompt);
|
|
1117
1119
|
const blockStreamingEnabled = resolveChannelStreamingBlockEnabled(account.config);
|
|
1118
|
-
const ctxPayload =
|
|
1120
|
+
const ctxPayload = core.channel.inbound.buildContext({
|
|
1121
|
+
channelIngress: access,
|
|
1119
1122
|
channel: CHANNEL_ID,
|
|
1120
1123
|
accountId: route.accountId,
|
|
1121
1124
|
messageId: message.messageId,
|
|
@@ -1127,7 +1130,7 @@ async function handleNextcloudTalkInbound(params) {
|
|
|
1127
1130
|
},
|
|
1128
1131
|
conversation: {
|
|
1129
1132
|
kind: isGroup ? "group" : "direct",
|
|
1130
|
-
id: roomToken,
|
|
1133
|
+
id: isGroup ? roomToken : senderId,
|
|
1131
1134
|
label: fromLabel
|
|
1132
1135
|
},
|
|
1133
1136
|
route: {
|
|
@@ -1202,9 +1205,6 @@ var NextcloudTalkWebhookPayloadError = class extends Error {
|
|
|
1202
1205
|
this.name = "NextcloudTalkWebhookPayloadError";
|
|
1203
1206
|
}
|
|
1204
1207
|
};
|
|
1205
|
-
function isRecord(value) {
|
|
1206
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1207
|
-
}
|
|
1208
1208
|
function parseRawObject(rawEvent) {
|
|
1209
1209
|
let parsed;
|
|
1210
1210
|
try {
|
|
@@ -1268,6 +1268,8 @@ async function migrateNextcloudTalkLegacyReplayState(params) {
|
|
|
1268
1268
|
//#region extensions/nextcloud-talk/src/monitor.ts
|
|
1269
1269
|
const DEFAULT_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
|
|
1270
1270
|
const PREAUTH_WEBHOOK_MAX_BODY_BYTES = 64 * 1024;
|
|
1271
|
+
const NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_HEADER = "x-openclaw-delivery-accepted";
|
|
1272
|
+
const NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_VALUE = "durable";
|
|
1271
1273
|
const PREAUTH_WEBHOOK_BODY_TIMEOUT_MS = 5e3;
|
|
1272
1274
|
const HEALTH_PATH = "/healthz";
|
|
1273
1275
|
const WEBHOOK_AUTH_RATE_LIMIT_SCOPE = "nextcloud-talk-webhook-auth";
|
|
@@ -1279,10 +1281,6 @@ const WEBHOOK_ERRORS = {
|
|
|
1279
1281
|
payloadTooLarge: "Payload too large",
|
|
1280
1282
|
internalServerError: "Internal server error"
|
|
1281
1283
|
};
|
|
1282
|
-
function formatError(err) {
|
|
1283
|
-
if (err instanceof Error) return err.message;
|
|
1284
|
-
return typeof err === "string" ? err : JSON.stringify(err);
|
|
1285
|
-
}
|
|
1286
1284
|
function writeJsonResponse(res, status, body) {
|
|
1287
1285
|
if (body) {
|
|
1288
1286
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
@@ -1376,7 +1374,7 @@ function createNextcloudTalkWebhookServer(opts) {
|
|
|
1376
1374
|
clientIp,
|
|
1377
1375
|
authRateLimiter: webhookAuthRateLimiter
|
|
1378
1376
|
})) return;
|
|
1379
|
-
await onWebhook(body);
|
|
1377
|
+
if (await onWebhook(body) === "accepted") res.setHeader(NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_HEADER, NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_VALUE);
|
|
1380
1378
|
writeJsonResponse(res, 200);
|
|
1381
1379
|
} catch (err) {
|
|
1382
1380
|
if (isRequestBodyLimitError(err, "PAYLOAD_TOO_LARGE")) {
|
|
@@ -1391,7 +1389,7 @@ function createNextcloudTalkWebhookServer(opts) {
|
|
|
1391
1389
|
writeWebhookError(res, 400, WEBHOOK_ERRORS.invalidPayloadFormat);
|
|
1392
1390
|
return;
|
|
1393
1391
|
}
|
|
1394
|
-
const error = err instanceof Error ? err : new Error(
|
|
1392
|
+
const error = err instanceof Error ? err : new Error(formatErrorMessage(err));
|
|
1395
1393
|
onError?.(error);
|
|
1396
1394
|
writeWebhookError(res, 500, WEBHOOK_ERRORS.internalServerError);
|
|
1397
1395
|
}
|
|
@@ -1438,11 +1436,6 @@ function createNextcloudTalkWebhookServer(opts) {
|
|
|
1438
1436
|
//#endregion
|
|
1439
1437
|
//#region extensions/nextcloud-talk/src/webhook-spool.ts
|
|
1440
1438
|
const NEXTCLOUD_TALK_INGRESS_POLL_INTERVAL_MS = 500;
|
|
1441
|
-
const NEXTCLOUD_TALK_INGRESS_PRUNE_INTERVAL_MS = 3600 * 1e3;
|
|
1442
|
-
const NEXTCLOUD_TALK_INGRESS_COMPLETED_TTL_MS = 720 * 60 * 60 * 1e3;
|
|
1443
|
-
const NEXTCLOUD_TALK_INGRESS_COMPLETED_MAX_ENTRIES = 1e4;
|
|
1444
|
-
const NEXTCLOUD_TALK_INGRESS_FAILED_TTL_MS = 720 * 60 * 60 * 1e3;
|
|
1445
|
-
const NEXTCLOUD_TALK_INGRESS_FAILED_MAX_ENTRIES = 1e4;
|
|
1446
1439
|
const NextcloudTalkWebhookPayloadSchema = z.object({
|
|
1447
1440
|
type: z.enum([
|
|
1448
1441
|
"Create",
|
|
@@ -1544,15 +1537,12 @@ function createNextcloudTalkWebhookSpool(options) {
|
|
|
1544
1537
|
await options.deliver(message, lifecycle);
|
|
1545
1538
|
},
|
|
1546
1539
|
pollIntervalMs: options.pollIntervalMs ?? NEXTCLOUD_TALK_INGRESS_POLL_INTERVAL_MS,
|
|
1547
|
-
waitForDeliveryIdleBeforeRepump: true,
|
|
1548
1540
|
retention: {
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
completedMaxEntries: NEXTCLOUD_TALK_INGRESS_COMPLETED_MAX_ENTRIES,
|
|
1552
|
-
failedTtlMs: NEXTCLOUD_TALK_INGRESS_FAILED_TTL_MS,
|
|
1553
|
-
failedMaxEntries: NEXTCLOUD_TALK_INGRESS_FAILED_MAX_ENTRIES
|
|
1541
|
+
completedMaxEntries: 1e4,
|
|
1542
|
+
failedMaxEntries: 1e4
|
|
1554
1543
|
},
|
|
1555
1544
|
drain: {
|
|
1545
|
+
startLimit: 32,
|
|
1556
1546
|
resolveNonRetryableFailure,
|
|
1557
1547
|
...options.adoptionStallTimeoutMs === void 0 ? {} : { adoptionStallTimeoutMs: options.adoptionStallTimeoutMs },
|
|
1558
1548
|
onLog: (message) => options.runtime.log?.(`nextcloud-talk ${message}`)
|
|
@@ -1683,6 +1673,7 @@ async function monitorNextcloudTalkProvider(opts) {
|
|
|
1683
1673
|
await stop();
|
|
1684
1674
|
return { stop };
|
|
1685
1675
|
}
|
|
1676
|
+
opts.statusSink?.(channelReadyPatch());
|
|
1686
1677
|
const publicUrl = account.config.webhookPublicUrl ?? `http://${host === "0.0.0.0" ? "localhost" : host}:${port}${path}`;
|
|
1687
1678
|
logger.info(`[nextcloud-talk:${account.accountId}] webhook listening on ${publicUrl}`);
|
|
1688
1679
|
return { stop };
|
|
@@ -1785,6 +1776,11 @@ const nextcloudTalkMessageActions = {
|
|
|
1785
1776
|
handleAction: async ({ action, params, cfg, accountId, toolContext }) => {
|
|
1786
1777
|
if (action === "send") throw new Error("Send should be handled by outbound, not actions handler.");
|
|
1787
1778
|
if (action === "react") {
|
|
1779
|
+
const account = resolveNextcloudTalkAccount({
|
|
1780
|
+
cfg,
|
|
1781
|
+
accountId
|
|
1782
|
+
});
|
|
1783
|
+
if (!isAccountConfigured(account)) throw new Error(`Nextcloud Talk account "${account.accountId}" is disabled or not configured.`);
|
|
1788
1784
|
const target = readStringParam(params, "to", {
|
|
1789
1785
|
required: true,
|
|
1790
1786
|
label: "to (room token)"
|
|
@@ -1863,9 +1859,6 @@ function resolveNextcloudTalkOutboundSessionRoute(params) {
|
|
|
1863
1859
|
//#region extensions/nextcloud-talk/src/setup-core.ts
|
|
1864
1860
|
const t$1 = createSetupTranslator$1();
|
|
1865
1861
|
const channel$1 = "nextcloud-talk";
|
|
1866
|
-
function readOptionalString(value) {
|
|
1867
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1868
|
-
}
|
|
1869
1862
|
function normalizeNextcloudTalkBaseUrl(value) {
|
|
1870
1863
|
return value?.trim().replace(/\/+$/, "") ?? "";
|
|
1871
1864
|
}
|
|
@@ -1930,46 +1923,6 @@ const nextcloudTalkDmPolicy = createChannelDmPolicy({
|
|
|
1930
1923
|
applyPatch: ({ cfg, account, patch }) => setNextcloudTalkAccountConfig(cfg, account.accountId, patch),
|
|
1931
1924
|
promptAllowFrom: promptNextcloudTalkAllowFromForAccount
|
|
1932
1925
|
});
|
|
1933
|
-
const nextcloudTalkSetupAdapter = {
|
|
1934
|
-
singleAccountKeysToMove: ["rooms"],
|
|
1935
|
-
resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
|
|
1936
|
-
prepareAccountConfigInput: ({ input }) => {
|
|
1937
|
-
const setupInput = input;
|
|
1938
|
-
return {
|
|
1939
|
-
...setupInput,
|
|
1940
|
-
baseUrl: setupInput.baseUrl ?? readOptionalString(setupInput.url),
|
|
1941
|
-
secret: setupInput.secret ?? readOptionalString(setupInput.token) ?? readOptionalString(setupInput.password),
|
|
1942
|
-
secretFile: setupInput.secretFile ?? readOptionalString(setupInput.tokenFile)
|
|
1943
|
-
};
|
|
1944
|
-
},
|
|
1945
|
-
applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
|
|
1946
|
-
cfg,
|
|
1947
|
-
channelKey: channel$1,
|
|
1948
|
-
accountId,
|
|
1949
|
-
name
|
|
1950
|
-
}),
|
|
1951
|
-
validateInput: createSetupInputPresenceValidator({
|
|
1952
|
-
defaultAccountOnlyEnvError: "NEXTCLOUD_TALK_BOT_SECRET can only be used for the default account.",
|
|
1953
|
-
validate: ({ input }) => {
|
|
1954
|
-
const setupInput = input;
|
|
1955
|
-
if (!setupInput.useEnv && !setupInput.secret && !setupInput.secretFile) return "Nextcloud Talk requires bot secret or --secret-file (or --use-env).";
|
|
1956
|
-
if (!setupInput.baseUrl) return "Nextcloud Talk requires --base-url.";
|
|
1957
|
-
return null;
|
|
1958
|
-
}
|
|
1959
|
-
}),
|
|
1960
|
-
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
1961
|
-
const setupInput = input;
|
|
1962
|
-
return setNextcloudTalkAccountConfig(applyAccountNameToChannelSection({
|
|
1963
|
-
cfg,
|
|
1964
|
-
channelKey: channel$1,
|
|
1965
|
-
accountId,
|
|
1966
|
-
name: setupInput.name
|
|
1967
|
-
}), accountId, {
|
|
1968
|
-
baseUrl: normalizeNextcloudTalkBaseUrl(setupInput.baseUrl),
|
|
1969
|
-
...setupInput.useEnv ? {} : setupInput.secretFile ? { botSecretFile: setupInput.secretFile } : setupInput.secret ? { botSecret: setupInput.secret } : {}
|
|
1970
|
-
}, setupInput.useEnv ? ["botSecret", "botSecretFile"] : void 0);
|
|
1971
|
-
}
|
|
1972
|
-
};
|
|
1973
1926
|
const nextcloudTalkSetupContract = defineChannelSetupContract({
|
|
1974
1927
|
fields: {
|
|
1975
1928
|
baseUrl: {
|
|
@@ -2031,10 +1984,53 @@ const nextcloudTalkSetupContract = defineChannelSetupContract({
|
|
|
2031
1984
|
cli: {
|
|
2032
1985
|
flags: "--use-env",
|
|
2033
1986
|
description: "Use Nextcloud Talk environment credentials"
|
|
2034
|
-
}
|
|
1987
|
+
},
|
|
1988
|
+
envVars: ["NEXTCLOUD_TALK_BOT_SECRET"]
|
|
2035
1989
|
}
|
|
2036
1990
|
},
|
|
2037
|
-
legacyAdapter:
|
|
1991
|
+
legacyAdapter: {
|
|
1992
|
+
singleAccountKeysToMove: ["rooms"],
|
|
1993
|
+
resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
|
|
1994
|
+
prepareAccountConfigInput: ({ input }) => {
|
|
1995
|
+
const setupInput = input;
|
|
1996
|
+
return {
|
|
1997
|
+
...setupInput,
|
|
1998
|
+
baseUrl: setupInput.baseUrl ?? readNonEmptyStringPreservingWhitespace(setupInput.url),
|
|
1999
|
+
secret: setupInput.secret ?? readNonEmptyStringPreservingWhitespace(setupInput.token) ?? readNonEmptyStringPreservingWhitespace(setupInput.password),
|
|
2000
|
+
secretFile: setupInput.secretFile ?? readNonEmptyStringPreservingWhitespace(setupInput.tokenFile)
|
|
2001
|
+
};
|
|
2002
|
+
},
|
|
2003
|
+
applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
|
|
2004
|
+
cfg,
|
|
2005
|
+
channelKey: channel$1,
|
|
2006
|
+
accountId,
|
|
2007
|
+
name
|
|
2008
|
+
}),
|
|
2009
|
+
validateInput: createSetupInputPresenceValidator({
|
|
2010
|
+
defaultAccountOnlyEnvError: "NEXTCLOUD_TALK_BOT_SECRET can only be used for the default account.",
|
|
2011
|
+
validate: ({ input }) => {
|
|
2012
|
+
const setupInput = input;
|
|
2013
|
+
if (!setupInput.useEnv && !setupInput.secret && !setupInput.secretFile) return "Nextcloud Talk requires bot secret or --secret-file (or --use-env).";
|
|
2014
|
+
const normalizedBaseUrl = normalizeNextcloudTalkBaseUrl(setupInput.baseUrl);
|
|
2015
|
+
if (!normalizedBaseUrl) return "Nextcloud Talk requires --base-url.";
|
|
2016
|
+
const baseUrlError = validateNextcloudTalkBaseUrl(normalizedBaseUrl);
|
|
2017
|
+
if (baseUrlError) return baseUrlError;
|
|
2018
|
+
return null;
|
|
2019
|
+
}
|
|
2020
|
+
}),
|
|
2021
|
+
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
2022
|
+
const setupInput = input;
|
|
2023
|
+
return setNextcloudTalkAccountConfig(applyAccountNameToChannelSection({
|
|
2024
|
+
cfg,
|
|
2025
|
+
channelKey: channel$1,
|
|
2026
|
+
accountId,
|
|
2027
|
+
name: setupInput.name
|
|
2028
|
+
}), accountId, {
|
|
2029
|
+
baseUrl: normalizeNextcloudTalkBaseUrl(setupInput.baseUrl),
|
|
2030
|
+
...setupInput.useEnv ? {} : setupInput.secretFile ? { botSecretFile: setupInput.secretFile } : setupInput.secret ? { botSecret: setupInput.secret } : {}
|
|
2031
|
+
}, setupInput.useEnv ? ["botSecret", "botSecretFile"] : void 0);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2038
2034
|
});
|
|
2039
2035
|
//#endregion
|
|
2040
2036
|
//#region extensions/nextcloud-talk/src/setup-surface.ts
|
|
@@ -2238,6 +2234,7 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
|
|
|
2238
2234
|
"nc"
|
|
2239
2235
|
],
|
|
2240
2236
|
normalizeTarget: normalizeNextcloudTalkMessagingTarget,
|
|
2237
|
+
inferTargetChatType: ({ to }) => normalizeNextcloudTalkMessagingTarget(to) ? "group" : void 0,
|
|
2241
2238
|
resolveOutboundSessionRoute: (params) => resolveNextcloudTalkOutboundSessionRoute(params),
|
|
2242
2239
|
targetResolver: {
|
|
2243
2240
|
looksLikeId: looksLikeNextcloudTalkTargetId,
|
|
@@ -2248,7 +2245,6 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
|
|
|
2248
2245
|
secretTargetRegistryEntries,
|
|
2249
2246
|
collectRuntimeConfigAssignments
|
|
2250
2247
|
},
|
|
2251
|
-
setup: nextcloudTalkSetupAdapter,
|
|
2252
2248
|
setupContract: nextcloudTalkSetupContract,
|
|
2253
2249
|
status: createComputedAccountStatusAdapter({
|
|
2254
2250
|
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID$2),
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as nextcloudTalkPlugin } from "./channel-
|
|
1
|
+
import { t as nextcloudTalkPlugin } from "./channel-CojgyJSq.js";
|
|
2
2
|
export { nextcloudTalkPlugin };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { createLegacyPrivateNetworkDoctorContract } from "openclaw/plugin-sdk/
|
|
2
|
-
import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
|
|
1
|
+
import { createLegacyPrivateNetworkDoctorContract, defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor-migrations";
|
|
3
2
|
//#region extensions/nextcloud-talk/src/doctor-contract.ts
|
|
4
3
|
const networkContract = createLegacyPrivateNetworkDoctorContract({ channelKey: "nextcloud-talk" });
|
|
5
4
|
const streamingAliasMigration = defineChannelAliasMigration({
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-
|
|
1
|
+
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Bda_xc6V.js";
|
|
2
2
|
export { legacyConfigRules, normalizeCompatibilityConfig };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createSimpleChannelSecretContract } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
|
+
//#region extensions/nextcloud-talk/src/secret-contract.ts
|
|
3
|
+
const channelSecrets = createSimpleChannelSecretContract({
|
|
4
|
+
channelKey: "nextcloud-talk",
|
|
5
|
+
label: "Nextcloud Talk",
|
|
6
|
+
accountFields: ["apiPassword", "botSecret"],
|
|
7
|
+
channelFields: ["apiPassword", "botSecret"],
|
|
8
|
+
mode: {
|
|
9
|
+
kind: "surface-inheritance",
|
|
10
|
+
collectionFields: ["botSecret", "apiPassword"]
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const { secretTargetRegistryEntries, collectRuntimeConfigAssignments } = channelSecrets;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-
|
|
1
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-Bvm0PmP3.js";
|
|
2
2
|
export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "nextcloud-talk",
|
|
3
|
+
"doctorContract": {
|
|
4
|
+
"configRepair": true
|
|
5
|
+
},
|
|
3
6
|
"name": "Nextcloud Talk",
|
|
4
7
|
"description": "OpenClaw Nextcloud Talk channel plugin for conversations.",
|
|
5
8
|
"icon": "https://cdn.simpleicons.org/nextcloud",
|
|
@@ -26,6 +29,9 @@
|
|
|
26
29
|
"enabled": {
|
|
27
30
|
"type": "boolean"
|
|
28
31
|
},
|
|
32
|
+
"configWrites": {
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
29
35
|
"markdown": {
|
|
30
36
|
"type": "object",
|
|
31
37
|
"properties": {
|
|
@@ -74,6 +80,29 @@
|
|
|
74
80
|
],
|
|
75
81
|
"additionalProperties": false
|
|
76
82
|
},
|
|
83
|
+
{
|
|
84
|
+
"type": "object",
|
|
85
|
+
"properties": {
|
|
86
|
+
"source": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"const": "store"
|
|
89
|
+
},
|
|
90
|
+
"provider": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
|
|
93
|
+
},
|
|
94
|
+
"id": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"pattern": "^[A-Z][A-Z0-9_]{0,127}$"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"required": [
|
|
100
|
+
"source",
|
|
101
|
+
"provider",
|
|
102
|
+
"id"
|
|
103
|
+
],
|
|
104
|
+
"additionalProperties": false
|
|
105
|
+
},
|
|
77
106
|
{
|
|
78
107
|
"type": "object",
|
|
79
108
|
"properties": {
|
|
@@ -158,6 +187,29 @@
|
|
|
158
187
|
],
|
|
159
188
|
"additionalProperties": false
|
|
160
189
|
},
|
|
190
|
+
{
|
|
191
|
+
"type": "object",
|
|
192
|
+
"properties": {
|
|
193
|
+
"source": {
|
|
194
|
+
"type": "string",
|
|
195
|
+
"const": "store"
|
|
196
|
+
},
|
|
197
|
+
"provider": {
|
|
198
|
+
"type": "string",
|
|
199
|
+
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
|
|
200
|
+
},
|
|
201
|
+
"id": {
|
|
202
|
+
"type": "string",
|
|
203
|
+
"pattern": "^[A-Z][A-Z0-9_]{0,127}$"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"required": [
|
|
207
|
+
"source",
|
|
208
|
+
"provider",
|
|
209
|
+
"id"
|
|
210
|
+
],
|
|
211
|
+
"additionalProperties": false
|
|
212
|
+
},
|
|
161
213
|
{
|
|
162
214
|
"type": "object",
|
|
163
215
|
"properties": {
|
|
@@ -424,6 +476,9 @@
|
|
|
424
476
|
"enabled": {
|
|
425
477
|
"type": "boolean"
|
|
426
478
|
},
|
|
479
|
+
"configWrites": {
|
|
480
|
+
"type": "boolean"
|
|
481
|
+
},
|
|
427
482
|
"markdown": {
|
|
428
483
|
"type": "object",
|
|
429
484
|
"properties": {
|
|
@@ -472,6 +527,29 @@
|
|
|
472
527
|
],
|
|
473
528
|
"additionalProperties": false
|
|
474
529
|
},
|
|
530
|
+
{
|
|
531
|
+
"type": "object",
|
|
532
|
+
"properties": {
|
|
533
|
+
"source": {
|
|
534
|
+
"type": "string",
|
|
535
|
+
"const": "store"
|
|
536
|
+
},
|
|
537
|
+
"provider": {
|
|
538
|
+
"type": "string",
|
|
539
|
+
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
|
|
540
|
+
},
|
|
541
|
+
"id": {
|
|
542
|
+
"type": "string",
|
|
543
|
+
"pattern": "^[A-Z][A-Z0-9_]{0,127}$"
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
"required": [
|
|
547
|
+
"source",
|
|
548
|
+
"provider",
|
|
549
|
+
"id"
|
|
550
|
+
],
|
|
551
|
+
"additionalProperties": false
|
|
552
|
+
},
|
|
475
553
|
{
|
|
476
554
|
"type": "object",
|
|
477
555
|
"properties": {
|
|
@@ -556,6 +634,29 @@
|
|
|
556
634
|
],
|
|
557
635
|
"additionalProperties": false
|
|
558
636
|
},
|
|
637
|
+
{
|
|
638
|
+
"type": "object",
|
|
639
|
+
"properties": {
|
|
640
|
+
"source": {
|
|
641
|
+
"type": "string",
|
|
642
|
+
"const": "store"
|
|
643
|
+
},
|
|
644
|
+
"provider": {
|
|
645
|
+
"type": "string",
|
|
646
|
+
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
|
|
647
|
+
},
|
|
648
|
+
"id": {
|
|
649
|
+
"type": "string",
|
|
650
|
+
"pattern": "^[A-Z][A-Z0-9_]{0,127}$"
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
"required": [
|
|
654
|
+
"source",
|
|
655
|
+
"provider",
|
|
656
|
+
"id"
|
|
657
|
+
],
|
|
658
|
+
"additionalProperties": false
|
|
659
|
+
},
|
|
559
660
|
{
|
|
560
661
|
"type": "object",
|
|
561
662
|
"properties": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/nextcloud-talk",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.8.1-beta.2",
|
|
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.
|
|
11
|
+
"openclaw": ">=2026.8.1-beta.2"
|
|
12
12
|
},
|
|
13
13
|
"peerDependenciesMeta": {
|
|
14
14
|
"openclaw": {
|
|
@@ -113,7 +113,10 @@
|
|
|
113
113
|
"cli": {
|
|
114
114
|
"flags": "--use-env",
|
|
115
115
|
"description": "Use Nextcloud Talk environment credentials"
|
|
116
|
-
}
|
|
116
|
+
},
|
|
117
|
+
"envVars": [
|
|
118
|
+
"NEXTCLOUD_TALK_BOT_SECRET"
|
|
119
|
+
]
|
|
117
120
|
}
|
|
118
121
|
]
|
|
119
122
|
}
|
|
@@ -124,10 +127,10 @@
|
|
|
124
127
|
"minHostVersion": ">=2026.4.10"
|
|
125
128
|
},
|
|
126
129
|
"compat": {
|
|
127
|
-
"pluginApi": ">=2026.
|
|
130
|
+
"pluginApi": ">=2026.8.1-beta.2"
|
|
128
131
|
},
|
|
129
132
|
"build": {
|
|
130
|
-
"openclawVersion": "2026.
|
|
133
|
+
"openclawVersion": "2026.8.1-beta.2"
|
|
131
134
|
},
|
|
132
135
|
"release": {
|
|
133
136
|
"publishToClawHub": true,
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
|
-
//#region extensions/nextcloud-talk/src/secret-contract.ts
|
|
3
|
-
const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
|
|
4
|
-
channelKey: "nextcloud-talk",
|
|
5
|
-
account: ["apiPassword", "botSecret"],
|
|
6
|
-
channel: ["apiPassword", "botSecret"]
|
|
7
|
-
});
|
|
8
|
-
function collectRuntimeConfigAssignments(params) {
|
|
9
|
-
const resolved = getChannelSurface(params.config, "nextcloud-talk");
|
|
10
|
-
if (!resolved) return;
|
|
11
|
-
const { channel: nextcloudTalk, surface } = resolved;
|
|
12
|
-
const inheritsField = (field) => ({ account, enabled }) => enabled && !hasOwnProperty(account, field);
|
|
13
|
-
collectConditionalChannelFieldAssignments({
|
|
14
|
-
channelKey: "nextcloud-talk",
|
|
15
|
-
field: "botSecret",
|
|
16
|
-
channel: nextcloudTalk,
|
|
17
|
-
surface,
|
|
18
|
-
defaults: params.defaults,
|
|
19
|
-
context: params.context,
|
|
20
|
-
topLevelActiveWithoutAccounts: true,
|
|
21
|
-
topLevelInheritedAccountActive: inheritsField("botSecret"),
|
|
22
|
-
accountActive: ({ enabled }) => enabled,
|
|
23
|
-
topInactiveReason: "no enabled Nextcloud Talk surface inherits this top-level botSecret.",
|
|
24
|
-
accountInactiveReason: "Nextcloud Talk account is disabled."
|
|
25
|
-
});
|
|
26
|
-
collectConditionalChannelFieldAssignments({
|
|
27
|
-
channelKey: "nextcloud-talk",
|
|
28
|
-
field: "apiPassword",
|
|
29
|
-
channel: nextcloudTalk,
|
|
30
|
-
surface,
|
|
31
|
-
defaults: params.defaults,
|
|
32
|
-
context: params.context,
|
|
33
|
-
topLevelActiveWithoutAccounts: true,
|
|
34
|
-
topLevelInheritedAccountActive: inheritsField("apiPassword"),
|
|
35
|
-
accountActive: ({ enabled }) => enabled,
|
|
36
|
-
topInactiveReason: "no enabled Nextcloud Talk surface inherits this top-level apiPassword.",
|
|
37
|
-
accountInactiveReason: "Nextcloud Talk account is disabled."
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
const channelSecrets = {
|
|
41
|
-
secretTargetRegistryEntries,
|
|
42
|
-
collectRuntimeConfigAssignments
|
|
43
|
-
};
|
|
44
|
-
//#endregion
|
|
45
|
-
export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
|