@openclaw/nextcloud-talk 2026.5.2 → 2026.5.3-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 +2 -0
- package/dist/channel-BVVRsVr5.js +1788 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/contract-api.js +2 -0
- package/dist/doctor-contract-CYlB-4Bf.js +7 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/index.js +22 -0
- package/dist/runtime-api-BcCzeRN9.js +15 -0
- package/dist/runtime-api.js +2 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/secret-contract-bczDw2-2.js +86 -0
- package/dist/setup-entry.js +15 -0
- package/package.json +14 -6
- package/api.ts +0 -1
- package/channel-plugin-api.ts +0 -1
- package/contract-api.ts +0 -4
- package/doctor-contract-api.ts +0 -1
- package/index.ts +0 -20
- package/runtime-api.ts +0 -33
- package/secret-contract-api.ts +0 -5
- package/setup-entry.ts +0 -13
- package/src/accounts.ts +0 -139
- package/src/approval-auth.test.ts +0 -17
- package/src/approval-auth.ts +0 -27
- package/src/channel-api.ts +0 -5
- package/src/channel.adapters.ts +0 -52
- package/src/channel.core.test.ts +0 -75
- package/src/channel.lifecycle.test.ts +0 -81
- package/src/channel.ts +0 -195
- package/src/config-schema.ts +0 -79
- package/src/core.test.ts +0 -397
- package/src/doctor-contract.ts +0 -9
- package/src/doctor.test.ts +0 -40
- package/src/doctor.ts +0 -10
- package/src/gateway.ts +0 -109
- package/src/inbound.authz.test.ts +0 -149
- package/src/inbound.behavior.test.ts +0 -202
- package/src/inbound.ts +0 -320
- package/src/monitor-runtime.ts +0 -138
- package/src/monitor.replay.test.ts +0 -279
- package/src/monitor.test-fixtures.ts +0 -30
- package/src/monitor.test-harness.ts +0 -59
- package/src/monitor.ts +0 -385
- package/src/normalize.ts +0 -44
- package/src/policy.ts +0 -180
- package/src/replay-guard.ts +0 -128
- package/src/room-info.test.ts +0 -116
- package/src/room-info.ts +0 -148
- package/src/runtime.ts +0 -9
- package/src/secret-contract.ts +0 -103
- package/src/secret-input.ts +0 -4
- package/src/send.cfg-threading.test.ts +0 -153
- package/src/send.runtime.ts +0 -8
- package/src/send.ts +0 -236
- package/src/session-route.ts +0 -40
- package/src/setup-core.ts +0 -248
- package/src/setup-surface.ts +0 -190
- package/src/setup.test.ts +0 -422
- package/src/signature.ts +0 -82
- package/src/types.ts +0 -193
- package/tsconfig.json +0 -16
|
@@ -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 };
|
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,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.2",
|
|
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.2"
|
|
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.2"
|
|
51
51
|
},
|
|
52
52
|
"build": {
|
|
53
|
-
"openclawVersion": "2026.5.2"
|
|
53
|
+
"openclawVersion": "2026.5.3-beta.2"
|
|
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";
|
package/channel-plugin-api.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { nextcloudTalkPlugin } from "./src/channel.js";
|
package/contract-api.ts
DELETED
package/doctor-contract-api.ts
DELETED
|
@@ -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";
|
package/secret-contract-api.ts
DELETED
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
|
-
});
|
package/src/approval-auth.ts
DELETED
|
@@ -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
|
-
});
|
package/src/channel-api.ts
DELETED
|
@@ -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";
|
package/src/channel.adapters.ts
DELETED
|
@@ -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
|
-
};
|
package/src/channel.core.test.ts
DELETED
|
@@ -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
|
-
});
|