@openclaw/nextcloud-talk 2026.5.2-beta.2 → 2026.5.3-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/api.js +2 -0
  2. package/dist/channel-BVVRsVr5.js +1788 -0
  3. package/dist/channel-plugin-api.js +2 -0
  4. package/dist/contract-api.js +2 -0
  5. package/dist/doctor-contract-CYlB-4Bf.js +7 -0
  6. package/dist/doctor-contract-api.js +2 -0
  7. package/dist/index.js +22 -0
  8. package/dist/runtime-api-BcCzeRN9.js +15 -0
  9. package/dist/runtime-api.js +2 -0
  10. package/dist/secret-contract-api.js +2 -0
  11. package/dist/secret-contract-bczDw2-2.js +86 -0
  12. package/dist/setup-entry.js +15 -0
  13. package/package.json +14 -6
  14. package/api.ts +0 -1
  15. package/channel-plugin-api.ts +0 -1
  16. package/contract-api.ts +0 -4
  17. package/doctor-contract-api.ts +0 -1
  18. package/index.ts +0 -20
  19. package/runtime-api.ts +0 -33
  20. package/secret-contract-api.ts +0 -5
  21. package/setup-entry.ts +0 -13
  22. package/src/accounts.ts +0 -139
  23. package/src/approval-auth.test.ts +0 -17
  24. package/src/approval-auth.ts +0 -27
  25. package/src/channel-api.ts +0 -5
  26. package/src/channel.adapters.ts +0 -52
  27. package/src/channel.core.test.ts +0 -75
  28. package/src/channel.lifecycle.test.ts +0 -81
  29. package/src/channel.ts +0 -195
  30. package/src/config-schema.ts +0 -79
  31. package/src/core.test.ts +0 -397
  32. package/src/doctor-contract.ts +0 -9
  33. package/src/doctor.test.ts +0 -40
  34. package/src/doctor.ts +0 -10
  35. package/src/gateway.ts +0 -109
  36. package/src/inbound.authz.test.ts +0 -149
  37. package/src/inbound.behavior.test.ts +0 -202
  38. package/src/inbound.ts +0 -320
  39. package/src/monitor-runtime.ts +0 -138
  40. package/src/monitor.replay.test.ts +0 -279
  41. package/src/monitor.test-fixtures.ts +0 -30
  42. package/src/monitor.test-harness.ts +0 -59
  43. package/src/monitor.ts +0 -385
  44. package/src/normalize.ts +0 -44
  45. package/src/policy.ts +0 -180
  46. package/src/replay-guard.ts +0 -128
  47. package/src/room-info.test.ts +0 -116
  48. package/src/room-info.ts +0 -148
  49. package/src/runtime.ts +0 -9
  50. package/src/secret-contract.ts +0 -103
  51. package/src/secret-input.ts +0 -4
  52. package/src/send.cfg-threading.test.ts +0 -153
  53. package/src/send.runtime.ts +0 -8
  54. package/src/send.ts +0 -236
  55. package/src/session-route.ts +0 -40
  56. package/src/setup-core.ts +0 -248
  57. package/src/setup-surface.ts +0 -190
  58. package/src/setup.test.ts +0 -422
  59. package/src/signature.ts +0 -82
  60. package/src/types.ts +0 -193
  61. package/tsconfig.json +0 -16
@@ -1,81 +0,0 @@
1
- import { createStartAccountContext } from "openclaw/plugin-sdk/channel-test-helpers";
2
- import {
3
- expectStopPendingUntilAbort,
4
- startAccountAndTrackLifecycle,
5
- waitForStartedMocks,
6
- } from "openclaw/plugin-sdk/channel-test-helpers";
7
- import { afterEach, describe, expect, it, vi } from "vitest";
8
- import type { ResolvedNextcloudTalkAccount } from "./accounts.js";
9
-
10
- const hoisted = vi.hoisted(() => ({
11
- monitorNextcloudTalkProvider: vi.fn(),
12
- }));
13
-
14
- vi.mock("./monitor-runtime.js", () => ({
15
- monitorNextcloudTalkProvider: hoisted.monitorNextcloudTalkProvider,
16
- }));
17
-
18
- const { nextcloudTalkGatewayAdapter } = await import("./gateway.js");
19
-
20
- function buildAccount(): ResolvedNextcloudTalkAccount {
21
- return {
22
- accountId: "default",
23
- enabled: true,
24
- baseUrl: "https://nextcloud.example.com",
25
- secret: "secret", // pragma: allowlist secret
26
- secretSource: "config", // pragma: allowlist secret
27
- config: {
28
- baseUrl: "https://nextcloud.example.com",
29
- botSecret: "secret", // pragma: allowlist secret
30
- webhookPath: "/nextcloud-talk-webhook",
31
- webhookPort: 8788,
32
- },
33
- };
34
- }
35
-
36
- function mockStartedMonitor() {
37
- const stop = vi.fn();
38
- hoisted.monitorNextcloudTalkProvider.mockResolvedValue({ stop });
39
- return stop;
40
- }
41
-
42
- function startNextcloudAccount(abortSignal?: AbortSignal) {
43
- return nextcloudTalkGatewayAdapter.startAccount!(
44
- createStartAccountContext({
45
- account: buildAccount(),
46
- abortSignal,
47
- }),
48
- );
49
- }
50
-
51
- describe("nextcloud-talk startAccount lifecycle", () => {
52
- afterEach(() => {
53
- vi.clearAllMocks();
54
- });
55
-
56
- it("keeps startAccount pending until abort, then stops the monitor", async () => {
57
- const stop = mockStartedMonitor();
58
- const { abort, task, isSettled } = startAccountAndTrackLifecycle({
59
- startAccount: nextcloudTalkGatewayAdapter.startAccount!,
60
- account: buildAccount(),
61
- });
62
- await expectStopPendingUntilAbort({
63
- waitForStarted: waitForStartedMocks(hoisted.monitorNextcloudTalkProvider),
64
- isSettled,
65
- abort,
66
- task,
67
- stop,
68
- });
69
- });
70
-
71
- it("stops immediately when startAccount receives an already-aborted signal", async () => {
72
- const stop = mockStartedMonitor();
73
- const abort = new AbortController();
74
- abort.abort();
75
-
76
- await startNextcloudAccount(abort.signal);
77
-
78
- expect(hoisted.monitorNextcloudTalkProvider).toHaveBeenCalledOnce();
79
- expect(stop).toHaveBeenCalledOnce();
80
- });
81
- });
package/src/channel.ts DELETED
@@ -1,195 +0,0 @@
1
- import { describeWebhookAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
2
- import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
3
- import { createLoggedPairingApprovalNotifier } from "openclaw/plugin-sdk/channel-pairing";
4
- import { createAllowlistProviderRouteAllowlistWarningCollector } from "openclaw/plugin-sdk/channel-policy";
5
- import {
6
- buildWebhookChannelStatusSummary,
7
- createComputedAccountStatusAdapter,
8
- createDefaultChannelRuntimeState,
9
- } from "openclaw/plugin-sdk/status-helpers";
10
- import { resolveNextcloudTalkAccount, type ResolvedNextcloudTalkAccount } from "./accounts.js";
11
- import { nextcloudTalkApprovalAuth } from "./approval-auth.js";
12
- import { buildChannelConfigSchema, DEFAULT_ACCOUNT_ID, type ChannelPlugin } from "./channel-api.js";
13
- import {
14
- nextcloudTalkConfigAdapter,
15
- nextcloudTalkPairingTextAdapter,
16
- nextcloudTalkSecurityAdapter,
17
- } from "./channel.adapters.js";
18
- import { NextcloudTalkConfigSchema } from "./config-schema.js";
19
- import { nextcloudTalkDoctor } from "./doctor.js";
20
- import { nextcloudTalkGatewayAdapter } from "./gateway.js";
21
- import {
22
- looksLikeNextcloudTalkTargetId,
23
- normalizeNextcloudTalkMessagingTarget,
24
- } from "./normalize.js";
25
- import { resolveNextcloudTalkGroupToolPolicy } from "./policy.js";
26
- import { getNextcloudTalkRuntime } from "./runtime.js";
27
- import { collectRuntimeConfigAssignments, secretTargetRegistryEntries } from "./secret-contract.js";
28
- import { sendMessageNextcloudTalk } from "./send.js";
29
- import { resolveNextcloudTalkOutboundSessionRoute } from "./session-route.js";
30
- import { nextcloudTalkSetupAdapter } from "./setup-core.js";
31
- import { nextcloudTalkSetupWizard } from "./setup-surface.js";
32
- import type { CoreConfig } from "./types.js";
33
-
34
- const meta = {
35
- id: "nextcloud-talk",
36
- label: "Nextcloud Talk",
37
- selectionLabel: "Nextcloud Talk (self-hosted)",
38
- docsPath: "/channels/nextcloud-talk",
39
- docsLabel: "nextcloud-talk",
40
- blurb: "Self-hosted chat via Nextcloud Talk webhook bots.",
41
- aliases: ["nc-talk", "nc"],
42
- order: 65,
43
- quickstartAllowFrom: true,
44
- };
45
-
46
- const collectNextcloudTalkSecurityWarnings =
47
- createAllowlistProviderRouteAllowlistWarningCollector<ResolvedNextcloudTalkAccount>({
48
- providerConfigPresent: (cfg) =>
49
- (cfg.channels as Record<string, unknown> | undefined)?.["nextcloud-talk"] !== undefined,
50
- resolveGroupPolicy: (account) => account.config.groupPolicy,
51
- resolveRouteAllowlistConfigured: (account) =>
52
- Boolean(account.config.rooms) && Object.keys(account.config.rooms ?? {}).length > 0,
53
- restrictSenders: {
54
- surface: "Nextcloud Talk rooms",
55
- openScope: "any member in allowed rooms",
56
- groupPolicyPath: "channels.nextcloud-talk.groupPolicy",
57
- groupAllowFromPath: "channels.nextcloud-talk.groupAllowFrom",
58
- },
59
- noRouteAllowlist: {
60
- surface: "Nextcloud Talk rooms",
61
- routeAllowlistPath: "channels.nextcloud-talk.rooms",
62
- routeScope: "room",
63
- groupPolicyPath: "channels.nextcloud-talk.groupPolicy",
64
- groupAllowFromPath: "channels.nextcloud-talk.groupAllowFrom",
65
- },
66
- });
67
-
68
- export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
69
- createChatChannelPlugin({
70
- base: {
71
- id: "nextcloud-talk",
72
- meta,
73
- setupWizard: nextcloudTalkSetupWizard,
74
- capabilities: {
75
- chatTypes: ["direct", "group"],
76
- reactions: true,
77
- threads: false,
78
- media: true,
79
- nativeCommands: false,
80
- blockStreaming: true,
81
- },
82
- reload: { configPrefixes: ["channels.nextcloud-talk"] },
83
- configSchema: buildChannelConfigSchema(NextcloudTalkConfigSchema),
84
- config: {
85
- ...nextcloudTalkConfigAdapter,
86
- isConfigured: (account) => Boolean(account.secret?.trim() && account.baseUrl?.trim()),
87
- describeAccount: (account) =>
88
- describeWebhookAccountSnapshot({
89
- account,
90
- configured: Boolean(account.secret?.trim() && account.baseUrl?.trim()),
91
- extra: {
92
- secretSource: account.secretSource,
93
- baseUrl: account.baseUrl ? "[set]" : "[missing]",
94
- },
95
- }),
96
- },
97
- approvalCapability: nextcloudTalkApprovalAuth,
98
- doctor: nextcloudTalkDoctor,
99
- groups: {
100
- resolveRequireMention: ({ cfg, accountId, groupId }) => {
101
- const account = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
102
- const rooms = account.config.rooms;
103
- if (!rooms || !groupId) {
104
- return true;
105
- }
106
-
107
- const roomConfig = rooms[groupId];
108
- if (roomConfig?.requireMention !== undefined) {
109
- return roomConfig.requireMention;
110
- }
111
-
112
- const wildcardConfig = rooms["*"];
113
- if (wildcardConfig?.requireMention !== undefined) {
114
- return wildcardConfig.requireMention;
115
- }
116
-
117
- return true;
118
- },
119
- resolveToolPolicy: resolveNextcloudTalkGroupToolPolicy,
120
- },
121
- messaging: {
122
- targetPrefixes: ["nextcloud-talk", "nc-talk", "nc"],
123
- normalizeTarget: normalizeNextcloudTalkMessagingTarget,
124
- resolveOutboundSessionRoute: (params) => resolveNextcloudTalkOutboundSessionRoute(params),
125
- targetResolver: {
126
- looksLikeId: looksLikeNextcloudTalkTargetId,
127
- hint: "<roomToken>",
128
- },
129
- },
130
- secrets: {
131
- secretTargetRegistryEntries,
132
- collectRuntimeConfigAssignments,
133
- },
134
- setup: nextcloudTalkSetupAdapter,
135
- status: createComputedAccountStatusAdapter<ResolvedNextcloudTalkAccount>({
136
- defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
137
- buildChannelSummary: ({ snapshot }) =>
138
- buildWebhookChannelStatusSummary(snapshot, {
139
- secretSource: snapshot.secretSource ?? "none",
140
- }),
141
- resolveAccountSnapshot: ({ account }) => ({
142
- accountId: account.accountId,
143
- name: account.name,
144
- enabled: account.enabled,
145
- configured: Boolean(account.secret?.trim() && account.baseUrl?.trim()),
146
- extra: {
147
- secretSource: account.secretSource,
148
- baseUrl: account.baseUrl ? "[set]" : "[missing]",
149
- mode: "webhook",
150
- },
151
- }),
152
- }),
153
- gateway: nextcloudTalkGatewayAdapter,
154
- },
155
- pairing: {
156
- text: {
157
- ...nextcloudTalkPairingTextAdapter,
158
- notify: createLoggedPairingApprovalNotifier(
159
- ({ id }) => `[nextcloud-talk] User ${id} approved for pairing`,
160
- ),
161
- },
162
- },
163
- security: {
164
- ...nextcloudTalkSecurityAdapter,
165
- collectWarnings: collectNextcloudTalkSecurityWarnings,
166
- },
167
- outbound: {
168
- base: {
169
- deliveryMode: "direct",
170
- chunker: (text, limit) =>
171
- getNextcloudTalkRuntime().channel.text.chunkMarkdownText(text, limit),
172
- chunkerMode: "markdown",
173
- textChunkLimit: 4000,
174
- },
175
- attachedResults: {
176
- channel: "nextcloud-talk",
177
- sendText: async ({ cfg, to, text, accountId, replyToId }) =>
178
- await sendMessageNextcloudTalk(to, text, {
179
- accountId: accountId ?? undefined,
180
- replyTo: replyToId ?? undefined,
181
- cfg: cfg as CoreConfig,
182
- }),
183
- sendMedia: async ({ cfg, to, text, mediaUrl, accountId, replyToId }) =>
184
- await sendMessageNextcloudTalk(
185
- to,
186
- mediaUrl ? `${text}\n\nAttachment: ${mediaUrl}` : text,
187
- {
188
- accountId: accountId ?? undefined,
189
- replyTo: replyToId ?? undefined,
190
- cfg: cfg as CoreConfig,
191
- },
192
- ),
193
- },
194
- },
195
- });
@@ -1,79 +0,0 @@
1
- import {
2
- DmPolicySchema,
3
- GroupPolicySchema,
4
- MarkdownConfigSchema,
5
- ReplyRuntimeConfigSchemaShape,
6
- ToolPolicySchema,
7
- requireOpenAllowFrom,
8
- } from "openclaw/plugin-sdk/channel-config-schema";
9
- import { requireChannelOpenAllowFrom } from "openclaw/plugin-sdk/extension-shared";
10
- import { z } from "openclaw/plugin-sdk/zod";
11
- import { buildSecretInputSchema } from "./secret-input.js";
12
-
13
- const NextcloudTalkRoomSchema = z
14
- .object({
15
- requireMention: z.boolean().optional(),
16
- tools: ToolPolicySchema,
17
- skills: z.array(z.string()).optional(),
18
- enabled: z.boolean().optional(),
19
- allowFrom: z.array(z.string()).optional(),
20
- systemPrompt: z.string().optional(),
21
- })
22
- .strict();
23
-
24
- const NextcloudTalkNetworkSchema = z
25
- .object({
26
- /** Dangerous opt-in for self-hosted Nextcloud Talk on trusted private/internal hosts. */
27
- dangerouslyAllowPrivateNetwork: z.boolean().optional(),
28
- })
29
- .strict()
30
- .optional();
31
-
32
- const NextcloudTalkAccountSchemaBase = z
33
- .object({
34
- name: z.string().optional(),
35
- enabled: z.boolean().optional(),
36
- markdown: MarkdownConfigSchema,
37
- baseUrl: z.string().optional(),
38
- botSecret: buildSecretInputSchema().optional(),
39
- botSecretFile: z.string().optional(),
40
- apiUser: z.string().optional(),
41
- apiPassword: buildSecretInputSchema().optional(),
42
- apiPasswordFile: z.string().optional(),
43
- dmPolicy: DmPolicySchema.optional().default("pairing"),
44
- webhookPort: z.number().int().positive().optional(),
45
- webhookHost: z.string().optional(),
46
- webhookPath: z.string().optional(),
47
- webhookPublicUrl: z.string().optional(),
48
- allowFrom: z.array(z.string()).optional(),
49
- groupAllowFrom: z.array(z.string()).optional(),
50
- groupPolicy: GroupPolicySchema.optional().default("allowlist"),
51
- rooms: z.record(z.string(), NextcloudTalkRoomSchema.optional()).optional(),
52
- /** Network policy overrides for self-hosted Nextcloud Talk on trusted private/internal hosts. */
53
- network: NextcloudTalkNetworkSchema,
54
- ...ReplyRuntimeConfigSchemaShape,
55
- })
56
- .strict();
57
-
58
- const NextcloudTalkAccountSchema = NextcloudTalkAccountSchemaBase.superRefine((value, ctx) => {
59
- requireChannelOpenAllowFrom({
60
- channel: "nextcloud-talk",
61
- policy: value.dmPolicy,
62
- allowFrom: value.allowFrom,
63
- ctx,
64
- requireOpenAllowFrom,
65
- });
66
- });
67
-
68
- export const NextcloudTalkConfigSchema = NextcloudTalkAccountSchemaBase.extend({
69
- accounts: z.record(z.string(), NextcloudTalkAccountSchema.optional()).optional(),
70
- defaultAccount: z.string().optional(),
71
- }).superRefine((value, ctx) => {
72
- requireChannelOpenAllowFrom({
73
- channel: "nextcloud-talk",
74
- policy: value.dmPolicy,
75
- allowFrom: value.allowFrom,
76
- ctx,
77
- requireOpenAllowFrom,
78
- });
79
- });