@openclaw/nextcloud-talk 2026.10.10 → 2026.11.5-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 (61) hide show
  1. package/dist/.setup/api-BvrRSilb.mjs +2 -0
  2. package/dist/.setup/{channel-D9tHRtkv.mjs → channel-BA1-OoqO.mjs} +1695 -934
  3. package/dist/.setup/outbound-media-CpFe1Xgz.mjs +303 -0
  4. package/dist/.setup/reply-BEkv387l.mjs +64 -0
  5. package/dist/.setup/{runtime-api-DSz4xBAm.mjs → runtime-api-CGy_KpdV.mjs} +1 -2
  6. package/dist/.setup/{secret-contract-api-CKCDZ3m8.mjs → secret-contract-api-QMihLdr1.mjs} +1 -1
  7. package/dist/.setup/secret-contract-yjCLewtg.mjs +19 -0
  8. package/dist/.source-module-urls/3332e832383d54fca83a3cfe8961ecdecf361c1eec0972c99f00a876d9481d98.json +1 -1
  9. package/dist/api.js +1 -1
  10. package/dist/channel-plugin-api.js +1 -1
  11. package/dist/configured-state.js +2 -5
  12. package/dist/runtime-api.js +1 -1
  13. package/dist/secret-contract-api.js +1 -1
  14. package/dist/setup-entry.js +2 -2
  15. package/node_modules/saxes/README.md +323 -0
  16. package/node_modules/saxes/node_modules/xmlchars/LICENSE +18 -0
  17. package/node_modules/saxes/node_modules/xmlchars/README.md +33 -0
  18. package/node_modules/saxes/node_modules/xmlchars/package.json +51 -0
  19. package/node_modules/saxes/node_modules/xmlchars/xml/1.0/ed4.d.ts +31 -0
  20. package/node_modules/saxes/node_modules/xmlchars/xml/1.0/ed4.js +44 -0
  21. package/node_modules/saxes/node_modules/xmlchars/xml/1.0/ed4.js.map +1 -0
  22. package/node_modules/saxes/node_modules/xmlchars/xml/1.0/ed5.d.ts +51 -0
  23. package/node_modules/saxes/node_modules/xmlchars/xml/1.0/ed5.js +105 -0
  24. package/node_modules/saxes/node_modules/xmlchars/xml/1.0/ed5.js.map +1 -0
  25. package/node_modules/saxes/node_modules/xmlchars/xml/1.1/ed2.d.ts +73 -0
  26. package/node_modules/saxes/node_modules/xmlchars/xml/1.1/ed2.js +145 -0
  27. package/node_modules/saxes/node_modules/xmlchars/xml/1.1/ed2.js.map +1 -0
  28. package/node_modules/saxes/node_modules/xmlchars/xmlchars.d.ts +170 -0
  29. package/node_modules/saxes/node_modules/xmlchars/xmlchars.js +191 -0
  30. package/node_modules/saxes/node_modules/xmlchars/xmlchars.js.map +1 -0
  31. package/node_modules/saxes/node_modules/xmlchars/xmlns/1.0/ed3.d.ts +28 -0
  32. package/node_modules/saxes/node_modules/xmlchars/xmlns/1.0/ed3.js +65 -0
  33. package/node_modules/saxes/node_modules/xmlchars/xmlns/1.0/ed3.js.map +1 -0
  34. package/node_modules/saxes/package.json +71 -0
  35. package/node_modules/saxes/saxes.d.ts +635 -0
  36. package/node_modules/saxes/saxes.js +2053 -0
  37. package/node_modules/saxes/saxes.js.map +1 -0
  38. package/node_modules/zod/package.json +1 -1
  39. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  40. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  41. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  42. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  43. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  44. package/node_modules/zod/src/v4/core/util.ts +13 -0
  45. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  46. package/node_modules/zod/v4/core/compile.cjs +8 -0
  47. package/node_modules/zod/v4/core/compile.js +8 -0
  48. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  49. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  50. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  51. package/node_modules/zod/v4/core/schemas.js +30 -0
  52. package/node_modules/zod/v4/core/util.cjs +15 -0
  53. package/node_modules/zod/v4/core/util.d.cts +2 -0
  54. package/node_modules/zod/v4/core/util.d.ts +2 -0
  55. package/node_modules/zod/v4/core/util.js +14 -0
  56. package/node_modules/zod/v4/core/versions.cjs +1 -1
  57. package/node_modules/zod/v4/core/versions.js +1 -1
  58. package/openclaw.plugin.json +23 -1
  59. package/package.json +8 -6
  60. package/dist/.setup/api-BgnUYkO3.mjs +0 -2
  61. package/dist/.setup/secret-contract-BHyPrmz3.mjs +0 -14
@@ -0,0 +1,303 @@
1
+ import { a as resolveNextcloudTalkAccount, i as releaseNextcloudTalkGuardedResponse, n as stripNextcloudTalkTargetPrefix, o as resolveNextcloudTalkApiCredentialsResult, r as parseWebDavFileId } from "./channel-BA1-OoqO.mjs";
2
+ import { l as getOptionalNextcloudTalkRuntime, r as fetchWithSsrFGuard } from "./runtime-api-CGy_KpdV.mjs";
3
+ import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
4
+ import { createMessageReceiptFromOutboundResults, isRecentOutboundMessageIdentity, recordOutboundMessageIdentity } from "openclaw/plugin-sdk/channel-outbound";
5
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
6
+ import { convertMarkdownTables } from "openclaw/plugin-sdk/text-chunking";
7
+ import { readProviderJsonResponse, readProviderTextResponse } from "openclaw/plugin-sdk/provider-http";
8
+ import { ssrfPolicyFromPrivateNetworkOptIn } from "openclaw/plugin-sdk/ssrf-runtime";
9
+ import path from "node:path";
10
+ import { sanitizeUntrustedFileName } from "openclaw/plugin-sdk/security-runtime";
11
+ import { truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
12
+ import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
13
+ import { createHmac, randomUUID } from "node:crypto";
14
+ import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
15
+ // extensions/nextcloud-talk/src/outbound-media.ts
16
+ const OUTBOUND_FILE_PREFIX = /^openclaw-([0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})-/u;
17
+ const FILE_ID_REQUEST = "<d:propfind xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\"><d:prop><oc:fileid/></d:prop></d:propfind>";
18
+ function createFileClient(account) {
19
+ const credentials = resolveNextcloudTalkApiCredentialsResult(account.config);
20
+ if (credentials.status !== "available") throw new Error("Nextcloud Talk attachments require available apiUser and apiPassword/apiPasswordFile credentials.");
21
+ const base = new URL(account.baseUrl);
22
+ if (!/^https?:$/u.test(base.protocol) || base.username || base.password || base.search || base.hash) throw new Error("Nextcloud Talk attachment baseUrl must be an HTTP(S) URL without credentials, query, or fragment.");
23
+ const authorization = `Basic ${Buffer.from(`${credentials.value.apiUser}:${credentials.value.apiPassword}`).toString("base64")}`;
24
+ const url = (pathname) => `${base.origin}${base.pathname.replace(/\/+$/u, "")}${pathname}`;
25
+ async function request(pathname, init, read, options = {}) {
26
+ options.signal?.throwIfAborted();
27
+ const headers = new Headers(init.headers);
28
+ headers.set("Authorization", authorization);
29
+ headers.set("OCS-APIRequest", "true");
30
+ if (!headers.has("Accept")) headers.set("Accept", "application/json");
31
+ const guarded = await fetchWithSsrFGuard({
32
+ url: url(pathname),
33
+ init: {
34
+ ...init,
35
+ headers
36
+ },
37
+ maxRedirects: 0,
38
+ requireHttps: base.protocol === "https:",
39
+ policy: {
40
+ ...ssrfPolicyFromPrivateNetworkOptIn(account.config.network?.dangerouslyAllowPrivateNetwork),
41
+ hostnameAllowlist: [base.hostname]
42
+ },
43
+ timeoutMs: 12e4,
44
+ signal: options.signal,
45
+ beforeRequest: options.beforeRequest,
46
+ auditContext: "nextcloud-talk-outbound-file"
47
+ });
48
+ try {
49
+ return await read(guarded.response);
50
+ } finally {
51
+ await releaseNextcloudTalkGuardedResponse(guarded);
52
+ }
53
+ }
54
+ async function json(pathname, init, options) {
55
+ return await request(pathname, init, async (response) => {
56
+ if (!response.ok) throw new Error(`Nextcloud Talk attachment API failed (${response.status}).`);
57
+ const payload = await readProviderJsonResponse(response, "Nextcloud Talk attachment API");
58
+ if (!isRecord(payload) || !isRecord(payload.ocs)) throw new Error("Nextcloud Talk attachment API returned an invalid response.");
59
+ return payload.ocs.data;
60
+ }, options);
61
+ }
62
+ async function user(options) {
63
+ const data = await json("/ocs/v1.php/cloud/user?format=json", {}, options);
64
+ if (!isRecord(data) || typeof data.id !== "string" || !data.id || data.id === "." || data.id === ".." || data.id.includes("/") || data.id.includes("\\") || Array.from(data.id).some((character) => {
65
+ const code = character.charCodeAt(0);
66
+ return code <= 31 || code === 127;
67
+ })) throw new Error("Nextcloud Talk API account has no valid canonical user ID.");
68
+ return data.id;
69
+ }
70
+ async function history(roomToken, messageId, options) {
71
+ const query = new URLSearchParams({
72
+ lookIntoFuture: "0",
73
+ limit: messageId ? "1" : "200",
74
+ setReadMarker: "0",
75
+ noStatusUpdate: "1",
76
+ markNotificationsAsRead: "0"
77
+ });
78
+ if (messageId) {
79
+ query.set("lastKnownMessageId", messageId);
80
+ query.set("includeLastKnown", "1");
81
+ }
82
+ const data = await json(`/ocs/v2.php/apps/spreed/api/v1/chat/${encodeURIComponent(roomToken)}?${query}`, {}, options);
83
+ return Array.isArray(data) ? data : [];
84
+ }
85
+ return {
86
+ request,
87
+ json,
88
+ user,
89
+ history
90
+ };
91
+ }
92
+ function fileReference(account, roomToken, uid, fileId) {
93
+ return createHmac("sha256", account.secret).update(JSON.stringify([
94
+ "nextcloud-talk-outbound-file",
95
+ account.accountId,
96
+ roomToken,
97
+ uid,
98
+ fileId
99
+ ])).digest("hex");
100
+ }
101
+ function echoIdentity(accountId, roomToken, actor, fileId) {
102
+ return {
103
+ channel: "nextcloud-talk",
104
+ accountId,
105
+ conversationId: roomToken,
106
+ sourceId: `file:${actor.toLowerCase()}:${fileId}`
107
+ };
108
+ }
109
+ /** The bounded cache handles webhook-before-ack; exact history handles restart/backlog. */
110
+ async function isNextcloudTalkOutboundFileEcho(params) {
111
+ params.signal?.throwIfAborted();
112
+ const { account, message } = params;
113
+ const file = message.attachment;
114
+ if (!file?.fileId) return false;
115
+ if (isRecentOutboundMessageIdentity(echoIdentity(account.accountId, message.roomToken, message.senderId, file.fileId))) return true;
116
+ if (!OUTBOUND_FILE_PREFIX.test(file.name)) return false;
117
+ if (!account.secret || resolveNextcloudTalkApiCredentialsResult(account.config).status !== "available") return false;
118
+ try {
119
+ const client = createFileClient(account);
120
+ const uid = await client.user({ signal: params.signal });
121
+ if (message.senderId !== `users/${uid}`) return false;
122
+ const referenceId = fileReference(account, message.roomToken, uid, file.fileId);
123
+ const history = await client.history(message.roomToken, message.messageId, { signal: params.signal });
124
+ params.signal?.throwIfAborted();
125
+ return history.some((entry) => isRecord(entry) && String(entry.id) === message.messageId && entry.token === message.roomToken && entry.actorType === "users" && entry.actorId === uid && entry.referenceId === referenceId && isRecord(entry.messageParameters) && isRecord(entry.messageParameters.file) && String(entry.messageParameters.file.id) === file.fileId);
126
+ } catch {
127
+ params.signal?.throwIfAborted();
128
+ return false;
129
+ }
130
+ }
131
+ async function sendMediaNextcloudTalk(ctx) {
132
+ const account = resolveNextcloudTalkAccount({
133
+ cfg: ctx.cfg,
134
+ accountId: ctx.accountId
135
+ });
136
+ if (!account.enabled || !account.baseUrl || !account.secret) throw new Error("Nextcloud Talk account is disabled or not configured.");
137
+ const roomToken = stripNextcloudTalkTargetPrefix(ctx.to);
138
+ if (!roomToken) throw new Error("Room token is required for Nextcloud Talk attachments.");
139
+ if (ctx.replyToId && !/^[1-9]\d*$/u.test(ctx.replyToId)) throw new Error("Nextcloud Talk attachment replyTo must be a positive message ID.");
140
+ const client = createFileClient(account);
141
+ const assertCurrent = () => {
142
+ ctx.signal?.throwIfAborted();
143
+ ctx.assertDirectAdapterHandoff?.();
144
+ };
145
+ const options = {
146
+ signal: ctx.signal,
147
+ beforeRequest: assertCurrent
148
+ };
149
+ assertCurrent();
150
+ if (ctx.silent) {
151
+ const data = await client.json("/ocs/v2.php/cloud/capabilities?format=json", {}, options);
152
+ assertCurrent();
153
+ const spreed = isRecord(data) && isRecord(data.capabilities) ? data.capabilities.spreed : void 0;
154
+ if (!isRecord(spreed) || !Array.isArray(spreed.features) || !spreed.features.includes("media-caption")) throw new Error("Nextcloud Talk silent attachments require the server's media-caption capability. Upgrade Talk before retrying.");
155
+ }
156
+ const maxBytes = resolveChannelMediaMaxBytes({
157
+ cfg: ctx.cfg,
158
+ accountId: account.accountId,
159
+ resolveChannelLimitMb: () => account.config.mediaMaxMb
160
+ }) ?? 20971520;
161
+ const media = await loadOutboundMediaFromUrl(ctx.mediaUrl, {
162
+ maxBytes,
163
+ mediaAccess: ctx.mediaAccess,
164
+ mediaLocalRoots: ctx.mediaLocalRoots,
165
+ mediaReadFile: ctx.mediaReadFile,
166
+ optimizeImages: false
167
+ });
168
+ assertCurrent();
169
+ const asVoice = ctx.audioAsVoice === true && (media.contentType === "audio/mpeg" || media.contentType === "audio/wav");
170
+ const uid = await client.user(options);
171
+ const uploadId = randomUUID();
172
+ const prefix = `openclaw-${uploadId}-`;
173
+ const filename = sanitizeUntrustedFileName(media.fileName ?? "attachment.bin", "attachment.bin");
174
+ const nameBudget = 250 - Buffer.byteLength(prefix);
175
+ const extension = truncateUtf8Prefix(path.extname(filename), nameBudget - 4);
176
+ const stem = truncateUtf8Prefix(filename.slice(0, filename.length - path.extname(filename).length), nameBudget - Buffer.byteLength(extension));
177
+ const uploadFolderPath = `/OpenClaw/openclaw-${uploadId}`;
178
+ const filePath = `${uploadFolderPath}/${prefix}${stem}${extension}`;
179
+ const davRoot = `/remote.php/dav/files/${encodeURIComponent(uid)}`;
180
+ const uploadFolder = `${davRoot}${uploadFolderPath}`;
181
+ const davPath = `${davRoot}${filePath.split("/").map(encodeURIComponent).join("/")}`;
182
+ let uploadFolderOwned = false;
183
+ let publicationAttempted = false;
184
+ try {
185
+ await client.request(`${davRoot}/OpenClaw`, { method: "MKCOL" }, async (response) => {
186
+ if (response.status !== 201 && response.status !== 405) throw new Error(`Nextcloud Talk attachment folder creation failed (${response.status}).`);
187
+ }, options);
188
+ await client.request(uploadFolder, { method: "MKCOL" }, async (response) => {
189
+ if (response.status !== 201) throw new Error(`Nextcloud Talk private upload folder creation failed (${response.status}).`);
190
+ uploadFolderOwned = true;
191
+ }, options);
192
+ await client.request(davPath, {
193
+ method: "PUT",
194
+ headers: {
195
+ "If-None-Match": "*",
196
+ "Content-Type": media.contentType ?? "application/octet-stream"
197
+ },
198
+ body: new Uint8Array(media.buffer)
199
+ }, async (response) => {
200
+ if (response.status !== 201) {
201
+ if (response.status === 412) uploadFolderOwned = false;
202
+ const recovery = response.status === 401 ? "Check apiUser and update its app password (apiPassword/apiPasswordFile) before retrying." : response.status === 507 ? "Free Files storage or increase the API user's quota before retrying." : "Check Nextcloud server logs and the API user's Files write access.";
203
+ throw new Error(`Nextcloud Talk attachment upload failed (${response.status}). ${recovery}`);
204
+ }
205
+ }, options);
206
+ const fileId = await client.request(davPath, {
207
+ method: "PROPFIND",
208
+ headers: {
209
+ Depth: "0",
210
+ "Content-Type": "application/xml"
211
+ },
212
+ body: FILE_ID_REQUEST
213
+ }, async (response) => {
214
+ if (response.status !== 207) throw new Error("Nextcloud Talk uploaded file identity unavailable.");
215
+ const id = parseWebDavFileId(await readProviderTextResponse(response, "Nextcloud Talk uploaded file identity", { maxBytes: 65536 }));
216
+ if (!id) throw new Error("Nextcloud Talk uploaded file identity invalid.");
217
+ return id;
218
+ }, options);
219
+ const referenceId = fileReference(account, roomToken, uid, fileId);
220
+ const caption = convertMarkdownTables(ctx.text.trim(), resolveMarkdownTableMode({
221
+ cfg: ctx.cfg,
222
+ channel: "nextcloud-talk",
223
+ accountId: account.accountId
224
+ }));
225
+ const body = new URLSearchParams({
226
+ path: filePath,
227
+ shareType: "10",
228
+ shareWith: roomToken,
229
+ permissions: "1",
230
+ referenceId,
231
+ talkMetaData: JSON.stringify({
232
+ caption,
233
+ ...asVoice ? { messageType: "voice-message" } : {},
234
+ ...ctx.silent ? { silent: true } : {},
235
+ ...ctx.replyToId ? { replyTo: Number(ctx.replyToId) } : {}
236
+ })
237
+ });
238
+ await ctx.onPlatformSendDispatch?.();
239
+ assertCurrent();
240
+ recordOutboundMessageIdentity(echoIdentity(account.accountId, roomToken, `users/${uid}`, fileId));
241
+ let publicationError;
242
+ try {
243
+ await client.json("/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json", {
244
+ method: "POST",
245
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
246
+ body
247
+ }, {
248
+ ...options,
249
+ beforeRequest: () => {
250
+ assertCurrent();
251
+ publicationAttempted = true;
252
+ }
253
+ });
254
+ } catch (error) {
255
+ if (!publicationAttempted) throw error;
256
+ publicationError = error;
257
+ }
258
+ let history;
259
+ try {
260
+ history = await client.history(roomToken);
261
+ } catch (error) {
262
+ throw new Error("Nextcloud Talk attachment delivery not confirmed; uploaded file retained. Do not blindly retry.", { cause: error });
263
+ }
264
+ const message = history.find((entry) => isRecord(entry) && entry.token === roomToken && entry.actorType === "users" && entry.actorId === uid && entry.referenceId === referenceId && /^[1-9]\d*$/u.test(String(entry.id)) && isRecord(entry.messageParameters) && isRecord(entry.messageParameters.file) && String(entry.messageParameters.file.id) === fileId);
265
+ if (!isRecord(message)) throw new Error("Nextcloud Talk attachment delivery not confirmed; uploaded file retained. Do not blindly retry.", { cause: publicationError });
266
+ const messageId = String(message.id);
267
+ const replyToId = isRecord(message.parent) && String(message.parent.id) === ctx.replyToId ? ctx.replyToId : void 0;
268
+ recordOutboundMessageIdentity({
269
+ channel: "nextcloud-talk",
270
+ accountId: account.accountId,
271
+ conversationId: roomToken,
272
+ messageId
273
+ });
274
+ getOptionalNextcloudTalkRuntime()?.channel.activity.record({
275
+ channel: "nextcloud-talk",
276
+ accountId: account.accountId,
277
+ direction: "outbound"
278
+ });
279
+ return {
280
+ messageId,
281
+ roomToken,
282
+ receipt: createMessageReceiptFromOutboundResults({
283
+ results: [{
284
+ channel: "nextcloud-talk",
285
+ conversationId: roomToken,
286
+ messageId
287
+ }],
288
+ kind: asVoice && message.messageType === "voice-message" ? "voice" : "media",
289
+ ...replyToId ? { replyToId } : {}
290
+ })
291
+ };
292
+ } catch (error) {
293
+ if (uploadFolderOwned && !publicationAttempted) try {
294
+ await client.request(uploadFolder, { method: "DELETE" }, async (response) => {
295
+ if (!response.ok && response.status !== 404) throw new Error("cleanup rejected", { cause: error });
296
+ });
297
+ } catch {
298
+ throw new Error("Nextcloud Talk attachment failed before sharing; unshared upload cleanup also failed.", { cause: error });
299
+ }
300
+ throw error;
301
+ }
302
+ }
303
+ export { isNextcloudTalkOutboundFileEcho, sendMediaNextcloudTalk };
@@ -0,0 +1,64 @@
1
+ import { buildOutboundSessionContext, deliverInboundReplyWithMessageSendContext, sendDurableMessageBatch } from "openclaw/plugin-sdk/channel-outbound";
2
+ import { createAcceptedChannelDeliveryResult, createChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
3
+ // extensions/nextcloud-talk/src/reply.ts
4
+ /** Keep final runtime handoff and all payload planning with the shared owners. */
5
+ async function deliverNextcloudTalkReply(params) {
6
+ const { cfg, accountId, agentId, ctxPayload, payload, info, to } = params;
7
+ const final = await deliverInboundReplyWithMessageSendContext({
8
+ cfg,
9
+ channel: "nextcloud-talk",
10
+ accountId,
11
+ agentId,
12
+ ctxPayload,
13
+ payload,
14
+ info,
15
+ to
16
+ });
17
+ if (final.status === "handled_visible" || final.status === "handled_no_send") return final.delivery;
18
+ if (final.status === "failed") throw final.error;
19
+ const send = await sendDurableMessageBatch({
20
+ cfg,
21
+ channel: "nextcloud-talk",
22
+ accountId,
23
+ to,
24
+ payloads: [payload],
25
+ replyToId: payload.replyToId,
26
+ session: buildOutboundSessionContext({
27
+ cfg,
28
+ agentId,
29
+ sessionKey: ctxPayload.SessionKey,
30
+ policySessionKey: ctxPayload.RuntimePolicySessionKey,
31
+ conversationType: ctxPayload.ChatType,
32
+ requesterAccountId: accountId ?? ctxPayload.AccountId,
33
+ requesterSenderId: ctxPayload.SenderId ?? ctxPayload.From,
34
+ requesterSenderName: ctxPayload.SenderName,
35
+ requesterSenderUsername: ctxPayload.SenderUsername,
36
+ requesterSenderE164: ctxPayload.SenderE164
37
+ }),
38
+ gatewayClientScopes: ctxPayload.GatewayClientScopes ?? [],
39
+ signal: params.signal,
40
+ onPlatformSendDispatch: info.onPlatformSendDispatch,
41
+ assertDirectAdapterHandoff: info.assertPlatformSendAuthorized,
42
+ skipQueue: true,
43
+ durability: "best_effort"
44
+ });
45
+ if (send.status === "failed") throw send.error;
46
+ const deliveryIntent = send.deliveryIntent ? {
47
+ id: send.deliveryIntent.id,
48
+ kind: "outbound_queue",
49
+ queuePolicy: send.deliveryIntent.queuePolicy
50
+ } : void 0;
51
+ if (send.status === "suppressed") return {
52
+ visibleReplySent: false,
53
+ receipt: send.receipt,
54
+ suppression: { reason: send.reason },
55
+ ...deliveryIntent ? { deliveryIntent } : {}
56
+ };
57
+ const result = {
58
+ ...createAcceptedChannelDeliveryResult({ results: [{ receipt: send.receipt }] }),
59
+ ...deliveryIntent ? { deliveryIntent } : {}
60
+ };
61
+ if (send.status === "partial_failed") throw createChannelPartialDeliveryError(send.error, result);
62
+ return result;
63
+ }
64
+ export { deliverNextcloudTalkReply };
@@ -1,7 +1,6 @@
1
1
  import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
2
2
  import { logInboundDrop } from "openclaw/plugin-sdk/channel-inbound";
3
3
  import { GROUP_POLICY_BLOCKED_LABEL, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
4
- import { deliverFormattedTextWithAttachments } from "openclaw/plugin-sdk/reply-payload";
5
4
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
6
5
  import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
7
6
  // extensions/nextcloud-talk/src/runtime.ts
@@ -9,4 +8,4 @@ const { setRuntime: setNextcloudTalkRuntime, getRuntime: getNextcloudTalkRuntime
9
8
  pluginId: "nextcloud-talk",
10
9
  errorMessage: "Nextcloud Talk runtime not initialized"
11
10
  });
12
- export { logInboundDrop as a, warnMissingProviderGroupPolicyFallbackOnce as c, setNextcloudTalkRuntime as d, fetchWithSsrFGuard as i, getNextcloudTalkRuntime as l, createChannelPairingController as n, resolveAllowlistProviderRuntimeGroupPolicy as o, deliverFormattedTextWithAttachments as r, resolveDefaultGroupPolicy as s, GROUP_POLICY_BLOCKED_LABEL as t, getOptionalNextcloudTalkRuntime as u };
11
+ export { resolveAllowlistProviderRuntimeGroupPolicy as a, getNextcloudTalkRuntime as c, logInboundDrop as i, getOptionalNextcloudTalkRuntime as l, createChannelPairingController as n, resolveDefaultGroupPolicy as o, fetchWithSsrFGuard as r, warnMissingProviderGroupPolicyFallbackOnce as s, GROUP_POLICY_BLOCKED_LABEL as t, setNextcloudTalkRuntime as u };
@@ -1,2 +1,2 @@
1
- export { t as channelSecrets, n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-BHyPrmz3.mjs";
1
+ export { t as channelSecrets, n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-yjCLewtg.mjs";
2
2
  import "../secret-contract-api.js";
@@ -0,0 +1,19 @@
1
+ import { hasConfiguredNextcloudAccount } from "../configured-state.js";
2
+ import { collectSimpleChannelFieldAssignments, createChannelSecretContract } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
3
+ // extensions/nextcloud-talk/src/secret-contract.ts
4
+ const channelSecrets = createChannelSecretContract({
5
+ channelKey: "nextcloud-talk",
6
+ account: ["apiPassword", "botSecret"],
7
+ channel: ["apiPassword", "botSecret"],
8
+ hasImplicitDefaultAccount: ({ context }) => hasConfiguredNextcloudAccount(context.sourceConfig.channels?.["nextcloud-talk"], context.env),
9
+ collect(params) {
10
+ for (const field of ["botSecret", "apiPassword"]) collectSimpleChannelFieldAssignments({
11
+ ...params,
12
+ field,
13
+ topInactiveReason: `no enabled Nextcloud Talk surface inherits this top-level ${field}.`,
14
+ accountInactiveReason: "Nextcloud Talk account is disabled."
15
+ });
16
+ }
17
+ });
18
+ const { secretTargetRegistryEntries, collectRuntimeConfigAssignments } = channelSecrets;
19
+ export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
@@ -1 +1 @@
1
- {"version":3,"entries":[{"output":"api.js","source":"extensions/nextcloud-talk/api.ts"},{"output":"channel-plugin-api.js","source":"extensions/nextcloud-talk/channel-plugin-api.ts"},{"output":"configured-state.js","source":"extensions/nextcloud-talk/configured-state.ts"},{"output":"doctor-contract-api.js","source":"extensions/nextcloud-talk/doctor-contract-api.ts"},{"output":"index.js","source":"extensions/nextcloud-talk/index.ts"},{"output":"runtime-api.js","source":"extensions/nextcloud-talk/runtime-api.ts"},{"output":"secret-contract-api.js","source":"extensions/nextcloud-talk/secret-contract-api.ts"},{"output":"setup-entry.js","source":"extensions/nextcloud-talk/setup-entry.ts"}],"chunks":[{"output":".setup/api-BgnUYkO3.mjs","sha256":"945cc048854654a4ada1853cc1aed051db4abccd2daabf3096f074f9e81fd970","facadeSource":"extensions/nextcloud-talk/api.ts","sources":[]},{"output":".setup/channel-D9tHRtkv.mjs","sha256":"899d4001d61c145d8eb353d4b5e91260c9c3ef8f1f4cc885c76486dd6e73d5d0","facadeSource":null,"sources":["extensions/nextcloud-talk/src/accounts.ts","extensions/nextcloud-talk/src/api-credentials.ts","extensions/nextcloud-talk/src/approval-auth.ts","extensions/nextcloud-talk/src/bot-preflight.ts","extensions/nextcloud-talk/src/channel.adapters.ts","extensions/nextcloud-talk/src/channel.ts","extensions/nextcloud-talk/src/config-schema.ts","extensions/nextcloud-talk/src/doctor.ts","extensions/nextcloud-talk/src/gateway.ts","extensions/nextcloud-talk/src/guarded-response.ts","extensions/nextcloud-talk/src/inbound.ts","extensions/nextcloud-talk/src/message-actions.ts","extensions/nextcloud-talk/src/message-adapter.ts","extensions/nextcloud-talk/src/monitor-runtime.ts","extensions/nextcloud-talk/src/monitor.ts","extensions/nextcloud-talk/src/normalize.ts","extensions/nextcloud-talk/src/policy.ts","extensions/nextcloud-talk/src/replay-migration-contract.ts","extensions/nextcloud-talk/src/room-info.ts","extensions/nextcloud-talk/src/send.ts","extensions/nextcloud-talk/src/session-route.ts","extensions/nextcloud-talk/src/setup-core.ts","extensions/nextcloud-talk/src/setup-surface.ts","extensions/nextcloud-talk/src/signature.ts","extensions/nextcloud-talk/src/webhook-route.ts","extensions/nextcloud-talk/src/webhook-spool-state.ts","extensions/nextcloud-talk/src/webhook-spool.ts","packages/normalization-core/src/string-coerce.ts","src/gateway/gateway-http-route-contracts.ts","src/gateway/security-path.ts","src/gateway/server/plugins-http/path-context.ts","src/plugins/http-path-prefix.ts"]},{"output":".setup/doctor-contract-CkWQa5uZ.mjs","sha256":"b580887eb445ab10c67ee1a057982cd3be79d68e2c3440b3f2a46f2a8852c55b","facadeSource":null,"sources":["extensions/nextcloud-talk/src/doctor-contract.ts","packages/normalization-core/src/record-coerce.ts","src/config/channel-config-normalization.ts","src/plugin-sdk/legacy-webhook-listener-migration.ts"]},{"output":".setup/runtime-api-DSz4xBAm.mjs","sha256":"79e7b7e7515c5d1f25e7b68e5414e33205303525bab418b7c6dc5e213fd0720c","facadeSource":null,"sources":["extensions/nextcloud-talk/src/runtime.ts"]},{"output":".setup/secret-contract-api-CKCDZ3m8.mjs","sha256":"933a73cbc5f8e153d60c80ea144877ff4103c0c6b5f4d2fb06597a1cb8714297","facadeSource":"extensions/nextcloud-talk/secret-contract-api.ts","sources":[]},{"output":".setup/secret-contract-BHyPrmz3.mjs","sha256":"5f6db1b8c1dca4ba0353e9ab2c801f210de8e341d9d4b766f0dfda338024bd71","facadeSource":null,"sources":["extensions/nextcloud-talk/src/secret-contract.ts"]},{"output":"api.js","sha256":"62e2b17453728f9567dc0394c6ae4b5bba68a906a7f4f63071ad317d2c9d8c5c","facadeSource":"extensions/nextcloud-talk/api.ts","sources":[]},{"output":"channel-plugin-api.js","sha256":"62e2b17453728f9567dc0394c6ae4b5bba68a906a7f4f63071ad317d2c9d8c5c","facadeSource":"extensions/nextcloud-talk/channel-plugin-api.ts","sources":[]},{"output":"configured-state.js","sha256":"6b5a8e74636ef9d9248d993b87f8fc2086b5407fb6bd94e02be183293db99a2d","facadeSource":"extensions/nextcloud-talk/configured-state.ts","sources":["extensions/nextcloud-talk/configured-state.ts"]},{"output":"doctor-contract-api.js","sha256":"71237fb5c510be1302851b9fb7b264dd4e0d0095be206e50ffce4b5890ace54f","facadeSource":"extensions/nextcloud-talk/doctor-contract-api.ts","sources":[]},{"output":"index.js","sha256":"16bcc875626f7dd3bc4c1195210f856deaa9c3757abe5cea2a1d90cb2877cd22","facadeSource":"extensions/nextcloud-talk/index.ts","sources":["extensions/nextcloud-talk/index.ts"]},{"output":"runtime-api.js","sha256":"9dc767e1c55c58a1e7abbefa444b966bd60321a9bd0d23a8707d49dbdd847aee","facadeSource":"extensions/nextcloud-talk/runtime-api.ts","sources":[]},{"output":"secret-contract-api.js","sha256":"79a0a9fc59d00a3c7d8a9ccdd12ae4d7679ef97821b50bd5e40cbdb0de7a814a","facadeSource":"extensions/nextcloud-talk/secret-contract-api.ts","sources":[]},{"output":"setup-entry.js","sha256":"e8dae8c12575ca86353d6476dd9a685d4befa32fe948d12a69a89f970d1329d8","facadeSource":"extensions/nextcloud-talk/setup-entry.ts","sources":["extensions/nextcloud-talk/setup-entry.ts"]}],"unrenderedSources":["extensions/nextcloud-talk/api.ts","extensions/nextcloud-talk/channel-plugin-api.ts","extensions/nextcloud-talk/config-doctor-api.ts","extensions/nextcloud-talk/doctor-contract-api.ts","extensions/nextcloud-talk/runtime-api.ts","extensions/nextcloud-talk/secret-contract-api.ts","extensions/nextcloud-talk/src/channel-api.ts","extensions/nextcloud-talk/src/send.runtime.ts"]}
1
+ {"version":3,"entries":[{"output":"api.js","source":"extensions/nextcloud-talk/api.ts"},{"output":"channel-plugin-api.js","source":"extensions/nextcloud-talk/channel-plugin-api.ts"},{"output":"configured-state.js","source":"extensions/nextcloud-talk/configured-state.ts"},{"output":"doctor-contract-api.js","source":"extensions/nextcloud-talk/doctor-contract-api.ts"},{"output":"index.js","source":"extensions/nextcloud-talk/index.ts"},{"output":"runtime-api.js","source":"extensions/nextcloud-talk/runtime-api.ts"},{"output":"secret-contract-api.js","source":"extensions/nextcloud-talk/secret-contract-api.ts"},{"output":"setup-entry.js","source":"extensions/nextcloud-talk/setup-entry.ts"}],"chunks":[{"output":".setup/api-BvrRSilb.mjs","sha256":"b25f39344c117b809520b3961b58f661adee93617654525cf980397c3567f61c","facadeSource":"extensions/nextcloud-talk/api.ts","sources":[]},{"output":".setup/channel-BA1-OoqO.mjs","sha256":"7332d213f8ca1e37bfa7a913f295bbef288630ddb9739c5f4032aa558c2e4057","facadeSource":null,"sources":["extensions/nextcloud-talk/src/accounts.ts","extensions/nextcloud-talk/src/api-credentials.ts","extensions/nextcloud-talk/src/bot-preflight.ts","extensions/nextcloud-talk/src/channel.ts","extensions/nextcloud-talk/src/config-schema.ts","extensions/nextcloud-talk/src/doctor.ts","extensions/nextcloud-talk/src/guarded-response.ts","extensions/nextcloud-talk/src/inbound-media.ts","extensions/nextcloud-talk/src/inbound.ts","extensions/nextcloud-talk/src/message-actions.ts","extensions/nextcloud-talk/src/monitor.ts","extensions/nextcloud-talk/src/normalize.ts","extensions/nextcloud-talk/src/policy.ts","extensions/nextcloud-talk/src/replay-migration-contract.ts","extensions/nextcloud-talk/src/room-info.ts","extensions/nextcloud-talk/src/send.ts","extensions/nextcloud-talk/src/setup-core.ts","extensions/nextcloud-talk/src/setup-surface.ts","extensions/nextcloud-talk/src/signature.ts","extensions/nextcloud-talk/src/voice-media.ts","extensions/nextcloud-talk/src/webdav.ts","extensions/nextcloud-talk/src/webhook-route.ts","extensions/nextcloud-talk/src/webhook-spool-state.ts","extensions/nextcloud-talk/src/webhook-spool.ts","packages/normalization-core/src/string-coerce.ts","src/gateway/gateway-http-route-contracts.ts","src/gateway/security-path.ts","src/gateway/server/plugins-http/path-context.ts","src/plugins/http-path-prefix.ts"]},{"output":".setup/doctor-contract-CkWQa5uZ.mjs","sha256":"b580887eb445ab10c67ee1a057982cd3be79d68e2c3440b3f2a46f2a8852c55b","facadeSource":null,"sources":["extensions/nextcloud-talk/src/doctor-contract.ts","packages/normalization-core/src/record-coerce.ts","src/config/channel-config-normalization.ts","src/plugin-sdk/legacy-webhook-listener-migration.ts"]},{"output":".setup/outbound-media-CpFe1Xgz.mjs","sha256":"bef81da85203f92dc6478aa3f00d11112e3f8aad10191dbf0a0678c07049ab61","facadeSource":"extensions/nextcloud-talk/src/outbound-media.ts","sources":["extensions/nextcloud-talk/src/outbound-media.ts"]},{"output":".setup/reply-BEkv387l.mjs","sha256":"e2c5093c05fcdbbe57a1693ea81de165c8280573ad3706f244dbd152dcd895ca","facadeSource":"extensions/nextcloud-talk/src/reply.ts","sources":["extensions/nextcloud-talk/src/reply.ts"]},{"output":".setup/runtime-api-CGy_KpdV.mjs","sha256":"344accb3739f831215489e33d0ca4dbaa5062fad8a0c98b7e356ee2bd0bb8228","facadeSource":null,"sources":["extensions/nextcloud-talk/src/runtime.ts"]},{"output":".setup/secret-contract-api-QMihLdr1.mjs","sha256":"0a2531895db3b16212c29ea87314c04021173a1bde49b58fbfd29fed181b4f15","facadeSource":"extensions/nextcloud-talk/secret-contract-api.ts","sources":[]},{"output":".setup/secret-contract-yjCLewtg.mjs","sha256":"183e7de729d242a63a7b607f3d353a5712f19eaea4ca24525cd96cc93bb63ffc","facadeSource":null,"sources":["extensions/nextcloud-talk/src/secret-contract.ts"]},{"output":"api.js","sha256":"e6a136ec30af9d685b3b1724ac335bc48534867c9c553e6a04f47d1ae22444d8","facadeSource":"extensions/nextcloud-talk/api.ts","sources":[]},{"output":"channel-plugin-api.js","sha256":"e6a136ec30af9d685b3b1724ac335bc48534867c9c553e6a04f47d1ae22444d8","facadeSource":"extensions/nextcloud-talk/channel-plugin-api.ts","sources":[]},{"output":"configured-state.js","sha256":"a45a34efe4339d78b7fcc92b8d09f8ad60d19c4a4e3a9754104c7f658be278d0","facadeSource":"extensions/nextcloud-talk/configured-state.ts","sources":["extensions/nextcloud-talk/configured-state.ts"]},{"output":"doctor-contract-api.js","sha256":"71237fb5c510be1302851b9fb7b264dd4e0d0095be206e50ffce4b5890ace54f","facadeSource":"extensions/nextcloud-talk/doctor-contract-api.ts","sources":[]},{"output":"index.js","sha256":"16bcc875626f7dd3bc4c1195210f856deaa9c3757abe5cea2a1d90cb2877cd22","facadeSource":"extensions/nextcloud-talk/index.ts","sources":["extensions/nextcloud-talk/index.ts"]},{"output":"runtime-api.js","sha256":"9306402515a553c1fe195fc8be8d6436a41abca338ae6cd4254434422e6f4cb3","facadeSource":"extensions/nextcloud-talk/runtime-api.ts","sources":[]},{"output":"secret-contract-api.js","sha256":"34c4d2c917c364f14b73bb8f51db22a8f24d047246358f543ab3aa0abfa78202","facadeSource":"extensions/nextcloud-talk/secret-contract-api.ts","sources":[]},{"output":"setup-entry.js","sha256":"7dba8b8fb26185b57bcabe7aab548d7e956deb37c46142110413ff4cab7cf80a","facadeSource":"extensions/nextcloud-talk/setup-entry.ts","sources":["extensions/nextcloud-talk/setup-entry.ts"]}],"unrenderedSources":["extensions/nextcloud-talk/api.ts","extensions/nextcloud-talk/channel-plugin-api.ts","extensions/nextcloud-talk/config-doctor-api.ts","extensions/nextcloud-talk/doctor-contract-api.ts","extensions/nextcloud-talk/runtime-api.ts","extensions/nextcloud-talk/secret-contract-api.ts"]}
package/dist/api.js CHANGED
@@ -1 +1 @@
1
- export { t as nextcloudTalkPlugin } from "./.setup/channel-D9tHRtkv.mjs";
1
+ export { t as nextcloudTalkPlugin } from "./.setup/channel-BA1-OoqO.mjs";
@@ -1 +1 @@
1
- export { t as nextcloudTalkPlugin } from "./.setup/channel-D9tHRtkv.mjs";
1
+ export { t as nextcloudTalkPlugin } from "./.setup/channel-BA1-OoqO.mjs";
@@ -3,10 +3,7 @@ import { DEFAULT_ACCOUNT_ID, createAccountListHelpers, hasConfiguredAccountValue
3
3
  const { listAccountIds: listNextcloudTalkAccountIds, resolveDefaultAccountId: resolveDefaultNextcloudTalkAccountId, resolveAccountConfig: mergeNextcloudTalkAccountConfig } = createAccountListHelpers("nextcloud-talk", {
4
4
  normalizeAccountId,
5
5
  omitKeys: ["defaultAccount"],
6
- hasImplicitDefaultAccount: (cfg) => {
7
- const channel = cfg.channels?.["nextcloud-talk"];
8
- return Boolean(channel?.baseUrl?.trim() && (hasConfiguredAccountValue(channel.botSecret) || channel.botSecretFile?.trim() || process.env.NEXTCLOUD_TALK_BOT_SECRET?.trim()));
9
- }
6
+ hasImplicitDefaultAccount: (cfg) => hasConfiguredNextcloudAccount(cfg.channels?.["nextcloud-talk"], process.env)
10
7
  });
11
8
  function hasConfiguredNextcloudAccount(account, env) {
12
9
  return Boolean(account?.baseUrl?.trim() && (hasConfiguredAccountValue(account.botSecret) || hasConfiguredAccountValue(account.botSecretFile) || hasConfiguredAccountValue(env.NEXTCLOUD_TALK_BOT_SECRET)));
@@ -20,4 +17,4 @@ function hasConfiguredNextcloudTalkChannelState(params) {
20
17
  }
21
18
  return Object.entries(channel?.accounts ?? {}).some(([accountId, account]) => accountId !== DEFAULT_ACCOUNT_ID && account.enabled !== false && hasConfiguredNextcloudAccount(mergeNextcloudTalkAccountConfig(params.cfg, accountId), {}));
22
19
  }
23
- export { hasConfiguredNextcloudTalkChannelState, listNextcloudTalkAccountIds, mergeNextcloudTalkAccountConfig, resolveDefaultNextcloudTalkAccountId };
20
+ export { hasConfiguredNextcloudAccount, hasConfiguredNextcloudTalkChannelState, listNextcloudTalkAccountIds, mergeNextcloudTalkAccountConfig, resolveDefaultNextcloudTalkAccountId };
@@ -1 +1 @@
1
- export { t as GROUP_POLICY_BLOCKED_LABEL, n as createChannelPairingController, r as deliverFormattedTextWithAttachments, i as fetchWithSsrFGuard, a as logInboundDrop, o as resolveAllowlistProviderRuntimeGroupPolicy, s as resolveDefaultGroupPolicy, d as setNextcloudTalkRuntime, c as warnMissingProviderGroupPolicyFallbackOnce } from "./.setup/runtime-api-DSz4xBAm.mjs";
1
+ export { t as GROUP_POLICY_BLOCKED_LABEL, n as createChannelPairingController, r as fetchWithSsrFGuard, i as logInboundDrop, a as resolveAllowlistProviderRuntimeGroupPolicy, o as resolveDefaultGroupPolicy, u as setNextcloudTalkRuntime, s as warnMissingProviderGroupPolicyFallbackOnce } from "./.setup/runtime-api-CGy_KpdV.mjs";
@@ -1 +1 @@
1
- export { t as channelSecrets, n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./.setup/secret-contract-BHyPrmz3.mjs";
1
+ export { t as channelSecrets, n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./.setup/secret-contract-yjCLewtg.mjs";
@@ -4,11 +4,11 @@ import { fileURLToPath } from "node:url";
4
4
  var setup_entry_default = defineBundledChannelSetupEntry({
5
5
  importMetaUrl: import.meta.url,
6
6
  plugin: {
7
- specifier: fileURLToPath(new URL(".setup/api-BgnUYkO3.mjs", import.meta.url).href),
7
+ specifier: fileURLToPath(new URL(".setup/api-BvrRSilb.mjs", import.meta.url).href),
8
8
  exportName: "nextcloudTalkPlugin"
9
9
  },
10
10
  secrets: {
11
- specifier: fileURLToPath(new URL(".setup/secret-contract-api-CKCDZ3m8.mjs", import.meta.url).href),
11
+ specifier: fileURLToPath(new URL(".setup/secret-contract-api-QMihLdr1.mjs", import.meta.url).href),
12
12
  exportName: "channelSecrets"
13
13
  }
14
14
  });