@openclaw/nextcloud-talk 2026.5.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
@@ -0,0 +1,2 @@
1
+ import { t as nextcloudTalkPlugin } from "./channel-BVVRsVr5.js";
2
+ export { nextcloudTalkPlugin };
@@ -0,0 +1,2 @@
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-bczDw2-2.js";
2
+ export { collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -0,0 +1,7 @@
1
+ import { createLegacyPrivateNetworkDoctorContract } from "openclaw/plugin-sdk/ssrf-runtime";
2
+ //#region extensions/nextcloud-talk/src/doctor-contract.ts
3
+ const contract = createLegacyPrivateNetworkDoctorContract({ channelKey: "nextcloud-talk" });
4
+ const legacyConfigRules = contract.legacyConfigRules;
5
+ const normalizeCompatibilityConfig = contract.normalizeCompatibilityConfig;
6
+ //#endregion
7
+ export { normalizeCompatibilityConfig as n, legacyConfigRules as t };
@@ -0,0 +1,2 @@
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-CYlB-4Bf.js";
2
+ export { legacyConfigRules, normalizeCompatibilityConfig };
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
+ //#region extensions/nextcloud-talk/index.ts
3
+ var nextcloud_talk_default = defineBundledChannelEntry({
4
+ id: "nextcloud-talk",
5
+ name: "Nextcloud Talk",
6
+ description: "Nextcloud Talk channel plugin",
7
+ importMetaUrl: import.meta.url,
8
+ plugin: {
9
+ specifier: "./channel-plugin-api.js",
10
+ exportName: "nextcloudTalkPlugin"
11
+ },
12
+ secrets: {
13
+ specifier: "./secret-contract-api.js",
14
+ exportName: "channelSecrets"
15
+ },
16
+ runtime: {
17
+ specifier: "./runtime-api.js",
18
+ exportName: "setNextcloudTalkRuntime"
19
+ }
20
+ });
21
+ //#endregion
22
+ export { nextcloud_talk_default as default };
@@ -0,0 +1,15 @@
1
+ import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
2
+ import { readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithCommandGate } from "openclaw/plugin-sdk/channel-policy";
3
+ import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
4
+ import { logInboundDrop } from "openclaw/plugin-sdk/channel-logging";
5
+ import { GROUP_POLICY_BLOCKED_LABEL, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
6
+ import { dispatchInboundReplyWithBase } from "openclaw/plugin-sdk/inbound-reply-dispatch";
7
+ import { deliverFormattedTextWithAttachments } from "openclaw/plugin-sdk/reply-payload";
8
+ import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
9
+ //#region extensions/nextcloud-talk/src/runtime.ts
10
+ const { setRuntime: setNextcloudTalkRuntime, getRuntime: getNextcloudTalkRuntime } = createPluginRuntimeStore({
11
+ pluginId: "nextcloud-talk",
12
+ errorMessage: "Nextcloud Talk runtime not initialized"
13
+ });
14
+ //#endregion
15
+ export { fetchWithSsrFGuard as a, resolveAllowlistProviderRuntimeGroupPolicy as c, warnMissingProviderGroupPolicyFallbackOnce as d, getNextcloudTalkRuntime as f, dispatchInboundReplyWithBase as i, resolveDefaultGroupPolicy as l, createChannelPairingController as n, logInboundDrop as o, setNextcloudTalkRuntime as p, deliverFormattedTextWithAttachments as r, readStoreAllowFromForDmPolicy as s, GROUP_POLICY_BLOCKED_LABEL as t, resolveDmGroupAccessWithCommandGate as u };
@@ -0,0 +1,2 @@
1
+ import { a as fetchWithSsrFGuard, c as resolveAllowlistProviderRuntimeGroupPolicy, d as warnMissingProviderGroupPolicyFallbackOnce, i as dispatchInboundReplyWithBase, l as resolveDefaultGroupPolicy, n as createChannelPairingController, o as logInboundDrop, p as setNextcloudTalkRuntime, r as deliverFormattedTextWithAttachments, s as readStoreAllowFromForDmPolicy, t as GROUP_POLICY_BLOCKED_LABEL, u as resolveDmGroupAccessWithCommandGate } from "./runtime-api-BcCzeRN9.js";
2
+ export { GROUP_POLICY_BLOCKED_LABEL, createChannelPairingController, deliverFormattedTextWithAttachments, dispatchInboundReplyWithBase, fetchWithSsrFGuard, logInboundDrop, readStoreAllowFromForDmPolicy, resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, resolveDmGroupAccessWithCommandGate, setNextcloudTalkRuntime, warnMissingProviderGroupPolicyFallbackOnce };
@@ -0,0 +1,2 @@
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-bczDw2-2.js";
2
+ export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -0,0 +1,86 @@
1
+ import { collectConditionalChannelFieldAssignments, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
+ //#region extensions/nextcloud-talk/src/secret-contract.ts
3
+ const secretTargetRegistryEntries = [
4
+ {
5
+ id: "channels.nextcloud-talk.accounts.*.apiPassword",
6
+ targetType: "channels.nextcloud-talk.accounts.*.apiPassword",
7
+ configFile: "openclaw.json",
8
+ pathPattern: "channels.nextcloud-talk.accounts.*.apiPassword",
9
+ secretShape: "secret_input",
10
+ expectedResolvedValue: "string",
11
+ includeInPlan: true,
12
+ includeInConfigure: true,
13
+ includeInAudit: true
14
+ },
15
+ {
16
+ id: "channels.nextcloud-talk.accounts.*.botSecret",
17
+ targetType: "channels.nextcloud-talk.accounts.*.botSecret",
18
+ configFile: "openclaw.json",
19
+ pathPattern: "channels.nextcloud-talk.accounts.*.botSecret",
20
+ secretShape: "secret_input",
21
+ expectedResolvedValue: "string",
22
+ includeInPlan: true,
23
+ includeInConfigure: true,
24
+ includeInAudit: true
25
+ },
26
+ {
27
+ id: "channels.nextcloud-talk.apiPassword",
28
+ targetType: "channels.nextcloud-talk.apiPassword",
29
+ configFile: "openclaw.json",
30
+ pathPattern: "channels.nextcloud-talk.apiPassword",
31
+ secretShape: "secret_input",
32
+ expectedResolvedValue: "string",
33
+ includeInPlan: true,
34
+ includeInConfigure: true,
35
+ includeInAudit: true
36
+ },
37
+ {
38
+ id: "channels.nextcloud-talk.botSecret",
39
+ targetType: "channels.nextcloud-talk.botSecret",
40
+ configFile: "openclaw.json",
41
+ pathPattern: "channels.nextcloud-talk.botSecret",
42
+ secretShape: "secret_input",
43
+ expectedResolvedValue: "string",
44
+ includeInPlan: true,
45
+ includeInConfigure: true,
46
+ includeInAudit: true
47
+ }
48
+ ];
49
+ function collectRuntimeConfigAssignments(params) {
50
+ const resolved = getChannelSurface(params.config, "nextcloud-talk");
51
+ if (!resolved) return;
52
+ const { channel: nextcloudTalk, surface } = resolved;
53
+ const inheritsField = (field) => ({ account, enabled }) => enabled && !hasOwnProperty(account, field);
54
+ collectConditionalChannelFieldAssignments({
55
+ channelKey: "nextcloud-talk",
56
+ field: "botSecret",
57
+ channel: nextcloudTalk,
58
+ surface,
59
+ defaults: params.defaults,
60
+ context: params.context,
61
+ topLevelActiveWithoutAccounts: true,
62
+ topLevelInheritedAccountActive: inheritsField("botSecret"),
63
+ accountActive: ({ enabled }) => enabled,
64
+ topInactiveReason: "no enabled Nextcloud Talk surface inherits this top-level botSecret.",
65
+ accountInactiveReason: "Nextcloud Talk account is disabled."
66
+ });
67
+ collectConditionalChannelFieldAssignments({
68
+ channelKey: "nextcloud-talk",
69
+ field: "apiPassword",
70
+ channel: nextcloudTalk,
71
+ surface,
72
+ defaults: params.defaults,
73
+ context: params.context,
74
+ topLevelActiveWithoutAccounts: true,
75
+ topLevelInheritedAccountActive: inheritsField("apiPassword"),
76
+ accountActive: ({ enabled }) => enabled,
77
+ topInactiveReason: "no enabled Nextcloud Talk surface inherits this top-level apiPassword.",
78
+ accountInactiveReason: "Nextcloud Talk account is disabled."
79
+ });
80
+ }
81
+ const channelSecrets = {
82
+ secretTargetRegistryEntries,
83
+ collectRuntimeConfigAssignments
84
+ };
85
+ //#endregion
86
+ export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
@@ -0,0 +1,15 @@
1
+ import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
+ //#region extensions/nextcloud-talk/setup-entry.ts
3
+ var setup_entry_default = defineBundledChannelSetupEntry({
4
+ importMetaUrl: import.meta.url,
5
+ plugin: {
6
+ specifier: "./api.js",
7
+ exportName: "nextcloudTalkPlugin"
8
+ },
9
+ secrets: {
10
+ specifier: "./secret-contract-api.js",
11
+ exportName: "channelSecrets"
12
+ }
13
+ });
14
+ //#endregion
15
+ export { setup_entry_default as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/nextcloud-talk",
3
- "version": "2026.5.2",
3
+ "version": "2026.5.3-beta.1",
4
4
  "description": "OpenClaw Nextcloud Talk channel plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,7 +15,7 @@
15
15
  "openclaw": "workspace:*"
16
16
  },
17
17
  "peerDependencies": {
18
- "openclaw": ">=2026.5.2"
18
+ "openclaw": ">=2026.5.3-beta.1"
19
19
  },
20
20
  "peerDependenciesMeta": {
21
21
  "openclaw": {
@@ -47,14 +47,22 @@
47
47
  "minHostVersion": ">=2026.4.10"
48
48
  },
49
49
  "compat": {
50
- "pluginApi": ">=2026.5.2"
50
+ "pluginApi": ">=2026.5.3-beta.1"
51
51
  },
52
52
  "build": {
53
- "openclawVersion": "2026.5.2"
53
+ "openclawVersion": "2026.5.3-beta.1"
54
54
  },
55
55
  "release": {
56
56
  "publishToClawHub": true,
57
57
  "publishToNpm": true
58
- }
59
- }
58
+ },
59
+ "runtimeExtensions": [
60
+ "./dist/index.js"
61
+ ],
62
+ "runtimeSetupEntry": "./dist/setup-entry.js"
63
+ },
64
+ "files": [
65
+ "dist/**",
66
+ "openclaw.plugin.json"
67
+ ]
60
68
  }
package/api.ts DELETED
@@ -1 +0,0 @@
1
- export { nextcloudTalkPlugin } from "./src/channel.js";
@@ -1 +0,0 @@
1
- export { nextcloudTalkPlugin } from "./src/channel.js";
package/contract-api.ts DELETED
@@ -1,4 +0,0 @@
1
- export {
2
- collectRuntimeConfigAssignments,
3
- secretTargetRegistryEntries,
4
- } from "./src/secret-contract.js";
@@ -1 +0,0 @@
1
- export { normalizeCompatibilityConfig, legacyConfigRules } from "./src/doctor-contract.js";
package/index.ts DELETED
@@ -1,20 +0,0 @@
1
- import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
-
3
- export default defineBundledChannelEntry({
4
- id: "nextcloud-talk",
5
- name: "Nextcloud Talk",
6
- description: "Nextcloud Talk channel plugin",
7
- importMetaUrl: import.meta.url,
8
- plugin: {
9
- specifier: "./channel-plugin-api.js",
10
- exportName: "nextcloudTalkPlugin",
11
- },
12
- secrets: {
13
- specifier: "./secret-contract-api.js",
14
- exportName: "channelSecrets",
15
- },
16
- runtime: {
17
- specifier: "./runtime-api.js",
18
- exportName: "setNextcloudTalkRuntime",
19
- },
20
- });
package/runtime-api.ts DELETED
@@ -1,33 +0,0 @@
1
- // Private runtime barrel for the bundled Nextcloud Talk extension.
2
- // Keep this barrel thin and aligned with the local extension surface.
3
-
4
- export type { AllowlistMatch } from "openclaw/plugin-sdk/allow-from";
5
- export type { ChannelGroupContext } from "openclaw/plugin-sdk/channel-contract";
6
- export { logInboundDrop } from "openclaw/plugin-sdk/channel-logging";
7
- export { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
8
- export {
9
- readStoreAllowFromForDmPolicy,
10
- resolveDmGroupAccessWithCommandGate,
11
- } from "openclaw/plugin-sdk/channel-policy";
12
- export type {
13
- BlockStreamingCoalesceConfig,
14
- DmConfig,
15
- DmPolicy,
16
- GroupPolicy,
17
- GroupToolPolicyConfig,
18
- OpenClawConfig,
19
- } from "openclaw/plugin-sdk/config-types";
20
- export {
21
- GROUP_POLICY_BLOCKED_LABEL,
22
- resolveAllowlistProviderRuntimeGroupPolicy,
23
- resolveDefaultGroupPolicy,
24
- warnMissingProviderGroupPolicyFallbackOnce,
25
- } from "openclaw/plugin-sdk/runtime-group-policy";
26
- export { dispatchInboundReplyWithBase } from "openclaw/plugin-sdk/inbound-reply-dispatch";
27
- export type { OutboundReplyPayload } from "openclaw/plugin-sdk/reply-payload";
28
- export { deliverFormattedTextWithAttachments } from "openclaw/plugin-sdk/reply-payload";
29
- export type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";
30
- export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
31
- export type { SecretInput } from "openclaw/plugin-sdk/secret-input";
32
- export { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
33
- export { setNextcloudTalkRuntime } from "./src/runtime.js";
@@ -1,5 +0,0 @@
1
- export {
2
- channelSecrets,
3
- collectRuntimeConfigAssignments,
4
- secretTargetRegistryEntries,
5
- } from "./src/secret-contract.js";
package/setup-entry.ts DELETED
@@ -1,13 +0,0 @@
1
- import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
-
3
- export default defineBundledChannelSetupEntry({
4
- importMetaUrl: import.meta.url,
5
- plugin: {
6
- specifier: "./api.js",
7
- exportName: "nextcloudTalkPlugin",
8
- },
9
- secrets: {
10
- specifier: "./secret-contract-api.js",
11
- exportName: "channelSecrets",
12
- },
13
- });
package/src/accounts.ts DELETED
@@ -1,139 +0,0 @@
1
- import {
2
- createAccountListHelpers,
3
- DEFAULT_ACCOUNT_ID,
4
- normalizeAccountId,
5
- resolveAccountWithDefaultFallback,
6
- resolveMergedAccountConfig,
7
- } from "openclaw/plugin-sdk/account-core";
8
- import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
9
- import {
10
- normalizeLowercaseStringOrEmpty,
11
- normalizeOptionalString,
12
- } from "openclaw/plugin-sdk/text-runtime";
13
- import { normalizeResolvedSecretInputString } from "./secret-input.js";
14
- import type { CoreConfig, NextcloudTalkAccountConfig } from "./types.js";
15
-
16
- function isTruthyEnvValue(value?: string): boolean {
17
- const normalized = normalizeLowercaseStringOrEmpty(value);
18
- return normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on";
19
- }
20
-
21
- const debugAccounts = (...args: unknown[]) => {
22
- if (isTruthyEnvValue(process.env.OPENCLAW_DEBUG_NEXTCLOUD_TALK_ACCOUNTS)) {
23
- console.warn("[nextcloud-talk:accounts]", ...args);
24
- }
25
- };
26
-
27
- export type ResolvedNextcloudTalkAccount = {
28
- accountId: string;
29
- enabled: boolean;
30
- name?: string;
31
- baseUrl: string;
32
- secret: string;
33
- secretSource: "env" | "secretFile" | "config" | "none";
34
- config: NextcloudTalkAccountConfig;
35
- };
36
-
37
- const {
38
- listAccountIds: listNextcloudTalkAccountIdsInternal,
39
- resolveDefaultAccountId: resolveDefaultNextcloudTalkAccountId,
40
- } = createAccountListHelpers("nextcloud-talk", {
41
- normalizeAccountId,
42
- });
43
- export { resolveDefaultNextcloudTalkAccountId };
44
-
45
- export function listNextcloudTalkAccountIds(cfg: CoreConfig): string[] {
46
- const ids = listNextcloudTalkAccountIdsInternal(cfg);
47
- debugAccounts("listNextcloudTalkAccountIds", ids);
48
- return ids;
49
- }
50
-
51
- function mergeNextcloudTalkAccountConfig(
52
- cfg: CoreConfig,
53
- accountId: string,
54
- ): NextcloudTalkAccountConfig {
55
- return resolveMergedAccountConfig<NextcloudTalkAccountConfig>({
56
- channelConfig: cfg.channels?.["nextcloud-talk"] as NextcloudTalkAccountConfig | undefined,
57
- accounts: cfg.channels?.["nextcloud-talk"]?.accounts as
58
- | Record<string, Partial<NextcloudTalkAccountConfig>>
59
- | undefined,
60
- accountId,
61
- omitKeys: ["defaultAccount"],
62
- normalizeAccountId,
63
- });
64
- }
65
-
66
- function resolveNextcloudTalkSecret(
67
- cfg: CoreConfig,
68
- opts: { accountId?: string },
69
- ): { secret: string; source: ResolvedNextcloudTalkAccount["secretSource"] } {
70
- const resolvedAccountId = opts.accountId ?? resolveDefaultNextcloudTalkAccountId(cfg);
71
- const merged = mergeNextcloudTalkAccountConfig(cfg, resolvedAccountId);
72
-
73
- const envSecret = normalizeOptionalString(process.env.NEXTCLOUD_TALK_BOT_SECRET);
74
- if (envSecret && resolvedAccountId === DEFAULT_ACCOUNT_ID) {
75
- return { secret: envSecret, source: "env" };
76
- }
77
-
78
- if (merged.botSecretFile) {
79
- const fileSecret = tryReadSecretFileSync(
80
- merged.botSecretFile,
81
- "Nextcloud Talk bot secret file",
82
- { rejectSymlink: true },
83
- );
84
- if (fileSecret) {
85
- return { secret: fileSecret, source: "secretFile" };
86
- }
87
- }
88
-
89
- const inlineSecret = normalizeResolvedSecretInputString({
90
- value: merged.botSecret,
91
- path: `channels.nextcloud-talk.accounts.${resolvedAccountId}.botSecret`,
92
- });
93
- if (inlineSecret) {
94
- return { secret: inlineSecret, source: "config" };
95
- }
96
-
97
- return { secret: "", source: "none" };
98
- }
99
-
100
- export function resolveNextcloudTalkAccount(params: {
101
- cfg: CoreConfig;
102
- accountId?: string | null;
103
- }): ResolvedNextcloudTalkAccount {
104
- const baseEnabled = params.cfg.channels?.["nextcloud-talk"]?.enabled !== false;
105
- const resolvedAccountId = params.accountId ?? resolveDefaultNextcloudTalkAccountId(params.cfg);
106
-
107
- const resolve = (accountId: string) => {
108
- const merged = mergeNextcloudTalkAccountConfig(params.cfg, accountId);
109
- const accountEnabled = merged.enabled !== false;
110
- const enabled = baseEnabled && accountEnabled;
111
- const secretResolution = resolveNextcloudTalkSecret(params.cfg, { accountId });
112
- const baseUrl = merged.baseUrl?.trim()?.replace(/\/$/, "") ?? "";
113
-
114
- debugAccounts("resolve", {
115
- accountId,
116
- enabled,
117
- secretSource: secretResolution.source,
118
- baseUrl: baseUrl ? "[set]" : "[missing]",
119
- });
120
-
121
- return {
122
- accountId,
123
- enabled,
124
- name: normalizeOptionalString(merged.name),
125
- baseUrl,
126
- secret: secretResolution.secret,
127
- secretSource: secretResolution.source,
128
- config: merged,
129
- } satisfies ResolvedNextcloudTalkAccount;
130
- };
131
-
132
- return resolveAccountWithDefaultFallback({
133
- accountId: resolvedAccountId,
134
- normalizeAccountId,
135
- resolvePrimary: resolve,
136
- hasCredential: (account) => account.secretSource !== "none",
137
- resolveDefaultAccountId: () => resolveDefaultNextcloudTalkAccountId(params.cfg),
138
- });
139
- }
@@ -1,17 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { nextcloudTalkApprovalAuth } from "./approval-auth.js";
3
-
4
- describe("nextcloudTalkApprovalAuth", () => {
5
- it("matches Nextcloud Talk actor ids case-insensitively", () => {
6
- const cfg = { channels: { "nextcloud-talk": { allowFrom: ["Owner"] } } };
7
-
8
- expect(
9
- nextcloudTalkApprovalAuth.authorizeActorAction({
10
- cfg,
11
- senderId: "owner",
12
- action: "approve",
13
- approvalKind: "exec",
14
- }),
15
- ).toEqual({ authorized: true });
16
- });
17
- });
@@ -1,27 +0,0 @@
1
- import {
2
- createResolvedApproverActionAuthAdapter,
3
- resolveApprovalApprovers,
4
- } from "openclaw/plugin-sdk/approval-auth-runtime";
5
- import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
6
- import { resolveNextcloudTalkAccount } from "./accounts.js";
7
- import type { CoreConfig } from "./types.js";
8
-
9
- function normalizeNextcloudTalkApproverId(value: string | number): string | undefined {
10
- return normalizeOptionalLowercaseString(
11
- String(value)
12
- .trim()
13
- .replace(/^(nextcloud-talk|nc-talk|nc):/i, ""),
14
- );
15
- }
16
-
17
- export const nextcloudTalkApprovalAuth = createResolvedApproverActionAuthAdapter({
18
- channelLabel: "Nextcloud Talk",
19
- resolveApprovers: ({ cfg, accountId }) => {
20
- const account = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
21
- return resolveApprovalApprovers({
22
- allowFrom: account.config.allowFrom,
23
- normalizeApprover: normalizeNextcloudTalkApproverId,
24
- });
25
- },
26
- normalizeSenderId: (value) => normalizeNextcloudTalkApproverId(value),
27
- });
@@ -1,5 +0,0 @@
1
- export type { ChannelPlugin } from "openclaw/plugin-sdk/channel-plugin-common";
2
- export type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
3
- export { clearAccountEntryFields } from "openclaw/plugin-sdk/channel-plugin-common";
4
- export { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
5
- export { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
@@ -1,52 +0,0 @@
1
- import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
2
- import {
3
- adaptScopedAccountAccessor,
4
- createScopedChannelConfigAdapter,
5
- createScopedDmSecurityResolver,
6
- } from "openclaw/plugin-sdk/channel-config-helpers";
7
- import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
8
- import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
9
- import {
10
- listNextcloudTalkAccountIds,
11
- resolveDefaultNextcloudTalkAccountId,
12
- resolveNextcloudTalkAccount,
13
- type ResolvedNextcloudTalkAccount,
14
- } from "./accounts.js";
15
- import type { CoreConfig } from "./types.js";
16
-
17
- export const nextcloudTalkConfigAdapter = createScopedChannelConfigAdapter<
18
- ResolvedNextcloudTalkAccount,
19
- ResolvedNextcloudTalkAccount,
20
- CoreConfig
21
- >({
22
- sectionKey: "nextcloud-talk",
23
- listAccountIds: listNextcloudTalkAccountIds,
24
- resolveAccount: adaptScopedAccountAccessor(resolveNextcloudTalkAccount),
25
- defaultAccountId: resolveDefaultNextcloudTalkAccountId,
26
- clearBaseFields: ["botSecret", "botSecretFile", "baseUrl", "name"],
27
- resolveAllowFrom: (account) => account.config.allowFrom,
28
- formatAllowFrom: (allowFrom) =>
29
- formatAllowFromLowercase({
30
- allowFrom,
31
- stripPrefixRe: /^(nextcloud-talk|nc-talk|nc):/i,
32
- }),
33
- });
34
-
35
- export const nextcloudTalkSecurityAdapter = {
36
- resolveDmPolicy: createScopedDmSecurityResolver<ResolvedNextcloudTalkAccount>({
37
- channelKey: "nextcloud-talk",
38
- resolvePolicy: (account) => account.config.dmPolicy,
39
- resolveAllowFrom: (account) => account.config.allowFrom,
40
- policyPathSuffix: "dmPolicy",
41
- normalizeEntry: (raw) =>
42
- normalizeLowercaseStringOrEmpty(raw.trim().replace(/^(nextcloud-talk|nc-talk|nc):/i, "")),
43
- }),
44
- };
45
-
46
- export const nextcloudTalkPairingTextAdapter = {
47
- idLabel: "nextcloudUserId",
48
- message: "OpenClaw: your access has been approved.",
49
- normalizeAllowEntry: createPairingPrefixStripper(/^(nextcloud-talk|nc-talk|nc):/i, (entry) =>
50
- normalizeLowercaseStringOrEmpty(entry),
51
- ),
52
- };
@@ -1,75 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- nextcloudTalkConfigAdapter,
4
- nextcloudTalkPairingTextAdapter,
5
- nextcloudTalkSecurityAdapter,
6
- } from "./channel.adapters.js";
7
- import { NextcloudTalkConfigSchema } from "./config-schema.js";
8
- import type { CoreConfig } from "./types.js";
9
-
10
- describe("nextcloud talk channel core", () => {
11
- it("accepts SecretRef botSecret and apiPassword at top-level", () => {
12
- const result = NextcloudTalkConfigSchema.safeParse({
13
- baseUrl: "https://cloud.example.com",
14
- botSecret: { source: "env", provider: "default", id: "NEXTCLOUD_TALK_BOT_SECRET" },
15
- apiUser: "bot",
16
- apiPassword: { source: "env", provider: "default", id: "NEXTCLOUD_TALK_API_PASSWORD" },
17
- });
18
- expect(result.success).toBe(true);
19
- });
20
-
21
- it("accepts SecretRef botSecret and apiPassword on account", () => {
22
- const result = NextcloudTalkConfigSchema.safeParse({
23
- accounts: {
24
- main: {
25
- baseUrl: "https://cloud.example.com",
26
- botSecret: {
27
- source: "env",
28
- provider: "default",
29
- id: "NEXTCLOUD_TALK_MAIN_BOT_SECRET",
30
- },
31
- apiUser: "bot",
32
- apiPassword: {
33
- source: "env",
34
- provider: "default",
35
- id: "NEXTCLOUD_TALK_MAIN_API_PASSWORD",
36
- },
37
- },
38
- },
39
- });
40
- expect(result.success).toBe(true);
41
- });
42
-
43
- it("normalizes trimmed DM allowlist prefixes to lowercase ids", () => {
44
- const resolveDmPolicy = nextcloudTalkSecurityAdapter.resolveDmPolicy;
45
- if (!resolveDmPolicy) {
46
- throw new Error("resolveDmPolicy unavailable");
47
- }
48
-
49
- const cfg = {
50
- channels: {
51
- "nextcloud-talk": {
52
- baseUrl: "https://cloud.example.com",
53
- botSecret: "secret",
54
- dmPolicy: "allowlist",
55
- allowFrom: [" nc:User-Id "],
56
- },
57
- },
58
- } as CoreConfig;
59
-
60
- const result = resolveDmPolicy({
61
- cfg,
62
- account: nextcloudTalkConfigAdapter.resolveAccount(cfg, "default"),
63
- });
64
- if (!result) {
65
- throw new Error("nextcloud-talk resolveDmPolicy returned null");
66
- }
67
-
68
- expect(result.policy).toBe("allowlist");
69
- expect(result.allowFrom).toEqual([" nc:User-Id "]);
70
- expect(result.normalizeEntry?.(" nc:User-Id ")).toBe("user-id");
71
- expect(nextcloudTalkPairingTextAdapter.normalizeAllowEntry(" nextcloud-talk:User-Id ")).toBe(
72
- "user-id",
73
- );
74
- });
75
- });