openclaw-ringcentral 2026.1.29-beta1

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.
@@ -0,0 +1,68 @@
1
+ declare module "openclaw/plugin-sdk" {
2
+ import { z } from "zod";
3
+
4
+ // Types
5
+ export type OpenClawConfig = {
6
+ channels?: Record<string, unknown>;
7
+ [key: string]: unknown;
8
+ };
9
+
10
+ export type OpenClawPluginApi = {
11
+ runtime: PluginRuntime;
12
+ registerChannel(opts: { plugin: ChannelPlugin; dock: ChannelDock }): void;
13
+ [key: string]: unknown;
14
+ };
15
+
16
+ export type PluginRuntime = {
17
+ log: {
18
+ info(msg: string, ...args: unknown[]): void;
19
+ warn(msg: string, ...args: unknown[]): void;
20
+ error(msg: string, ...args: unknown[]): void;
21
+ debug(msg: string, ...args: unknown[]): void;
22
+ };
23
+ [key: string]: unknown;
24
+ };
25
+
26
+ export type ChannelPlugin = {
27
+ id: string;
28
+ [key: string]: unknown;
29
+ };
30
+
31
+ export type ChannelDock = {
32
+ id: string;
33
+ [key: string]: unknown;
34
+ };
35
+
36
+ export type DmPolicy = "open" | "allowlist" | "disabled";
37
+ export type GroupPolicy = "open" | "allowlist" | "disabled";
38
+ export type MarkdownConfig = {
39
+ enabled?: boolean;
40
+ [key: string]: unknown;
41
+ };
42
+
43
+ // Constants
44
+ export const DEFAULT_ACCOUNT_ID: string;
45
+
46
+ // Functions
47
+ export function normalizeAccountId(accountId: string | undefined): string;
48
+ export function emptyPluginConfigSchema(): z.ZodObject<Record<string, never>>;
49
+ export function resolveMentionGatingWithBypass(opts: unknown): unknown;
50
+ export function requireOpenAllowFrom(opts: unknown): void;
51
+ export function applyAccountNameToChannelSection(opts: unknown): unknown;
52
+ export function buildChannelConfigSchema(opts: unknown): unknown;
53
+ export function deleteAccountFromConfigSection(opts: unknown): unknown;
54
+ export function formatPairingApproveHint(opts: unknown): string;
55
+ export function migrateBaseNameToDefaultAccount(opts: unknown): unknown;
56
+ export function missingTargetError(opts: unknown): Error;
57
+ export function setAccountEnabledInConfigSection(opts: unknown): unknown;
58
+ export function resolveChannelMediaMaxBytes(opts: unknown): number;
59
+
60
+ // Constants for messages
61
+ export const PAIRING_APPROVED_MESSAGE: string;
62
+
63
+ // Zod Schemas
64
+ export const BlockStreamingCoalesceSchema: z.ZodType<unknown>;
65
+ export const DmPolicySchema: z.ZodType<DmPolicy>;
66
+ export const GroupPolicySchema: z.ZodType<GroupPolicy>;
67
+ export const MarkdownConfigSchema: z.ZodType<MarkdownConfig>;
68
+ }
package/src/runtime.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { PluginRuntime } from "openclaw/plugin-sdk";
2
+
3
+ let runtime: PluginRuntime | null = null;
4
+
5
+ export function setRingCentralRuntime(next: PluginRuntime) {
6
+ runtime = next;
7
+ }
8
+
9
+ export function getRingCentralRuntime(): PluginRuntime {
10
+ if (!runtime) {
11
+ throw new Error("RingCentral runtime not initialized");
12
+ }
13
+ return runtime;
14
+ }
@@ -0,0 +1,118 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ normalizeRingCentralTarget,
4
+ isRingCentralChatTarget,
5
+ isRingCentralUserTarget,
6
+ formatRingCentralChatTarget,
7
+ formatRingCentralUserTarget,
8
+ parseRingCentralTarget,
9
+ } from "./targets.js";
10
+
11
+ describe("normalizeRingCentralTarget", () => {
12
+ it("returns null for empty string", () => {
13
+ expect(normalizeRingCentralTarget("")).toBeNull();
14
+ expect(normalizeRingCentralTarget(" ")).toBeNull();
15
+ });
16
+
17
+ it("removes ringcentral: prefix", () => {
18
+ expect(normalizeRingCentralTarget("ringcentral:12345")).toBe("12345");
19
+ expect(normalizeRingCentralTarget("RINGCENTRAL:12345")).toBe("12345");
20
+ });
21
+
22
+ it("removes rc: prefix", () => {
23
+ expect(normalizeRingCentralTarget("rc:12345")).toBe("12345");
24
+ expect(normalizeRingCentralTarget("RC:12345")).toBe("12345");
25
+ });
26
+
27
+ it("removes chat: prefix", () => {
28
+ expect(normalizeRingCentralTarget("chat:12345")).toBe("12345");
29
+ });
30
+
31
+ it("removes user: prefix", () => {
32
+ expect(normalizeRingCentralTarget("user:12345")).toBe("12345");
33
+ });
34
+
35
+ it("removes combined prefixes", () => {
36
+ expect(normalizeRingCentralTarget("rc:chat:12345")).toBe("12345");
37
+ expect(normalizeRingCentralTarget("ringcentral:user:12345")).toBe("12345");
38
+ });
39
+
40
+ it("trims whitespace", () => {
41
+ expect(normalizeRingCentralTarget(" 12345 ")).toBe("12345");
42
+ });
43
+
44
+ it("returns plain ID as-is", () => {
45
+ expect(normalizeRingCentralTarget("12345")).toBe("12345");
46
+ });
47
+ });
48
+
49
+ describe("isRingCentralChatTarget", () => {
50
+ it("returns true for numeric IDs", () => {
51
+ expect(isRingCentralChatTarget("12345")).toBe(true);
52
+ expect(isRingCentralChatTarget("rc:12345")).toBe(true);
53
+ expect(isRingCentralChatTarget("chat:12345")).toBe(true);
54
+ });
55
+
56
+ it("returns false for non-numeric IDs", () => {
57
+ expect(isRingCentralChatTarget("abc")).toBe(false);
58
+ expect(isRingCentralChatTarget("12345abc")).toBe(false);
59
+ });
60
+
61
+ it("returns false for empty string", () => {
62
+ expect(isRingCentralChatTarget("")).toBe(false);
63
+ });
64
+ });
65
+
66
+ describe("isRingCentralUserTarget", () => {
67
+ it("returns true for numeric IDs", () => {
68
+ expect(isRingCentralUserTarget("12345")).toBe(true);
69
+ expect(isRingCentralUserTarget("rc:12345")).toBe(true);
70
+ });
71
+
72
+ it("returns false for empty string", () => {
73
+ expect(isRingCentralUserTarget("")).toBe(false);
74
+ });
75
+ });
76
+
77
+ describe("formatRingCentralChatTarget", () => {
78
+ it("formats chat ID with rc:chat: prefix", () => {
79
+ expect(formatRingCentralChatTarget("12345")).toBe("rc:chat:12345");
80
+ });
81
+ });
82
+
83
+ describe("formatRingCentralUserTarget", () => {
84
+ it("formats user ID with rc:user: prefix", () => {
85
+ expect(formatRingCentralUserTarget("12345")).toBe("rc:user:12345");
86
+ });
87
+ });
88
+
89
+ describe("parseRingCentralTarget", () => {
90
+ it("parses chat: prefix", () => {
91
+ expect(parseRingCentralTarget("chat:12345")).toEqual({ type: "chat", id: "12345" });
92
+ expect(parseRingCentralTarget("rc:chat:12345")).toEqual({ type: "chat", id: "12345" });
93
+ expect(parseRingCentralTarget("ringcentral:chat:12345")).toEqual({ type: "chat", id: "12345" });
94
+ });
95
+
96
+ it("parses user: prefix", () => {
97
+ expect(parseRingCentralTarget("user:12345")).toEqual({ type: "user", id: "12345" });
98
+ expect(parseRingCentralTarget("rc:user:12345")).toEqual({ type: "user", id: "12345" });
99
+ });
100
+
101
+ it("parses group: prefix as chat", () => {
102
+ expect(parseRingCentralTarget("group:12345")).toEqual({ type: "chat", id: "12345" });
103
+ expect(parseRingCentralTarget("team:12345")).toEqual({ type: "chat", id: "12345" });
104
+ });
105
+
106
+ it("defaults numeric IDs to chat type", () => {
107
+ expect(parseRingCentralTarget("12345")).toEqual({ type: "chat", id: "12345" });
108
+ expect(parseRingCentralTarget("rc:12345")).toEqual({ type: "chat", id: "12345" });
109
+ });
110
+
111
+ it("returns unknown for non-numeric IDs without type prefix", () => {
112
+ expect(parseRingCentralTarget("abc")).toEqual({ type: "unknown", id: "abc" });
113
+ });
114
+
115
+ it("trims whitespace", () => {
116
+ expect(parseRingCentralTarget(" chat:12345 ")).toEqual({ type: "chat", id: "12345" });
117
+ });
118
+ });
package/src/targets.ts ADDED
@@ -0,0 +1,70 @@
1
+ // Target ID normalization and resolution for RingCentral
2
+
3
+ export function normalizeRingCentralTarget(raw: string): string | null {
4
+ const trimmed = raw.trim();
5
+ if (!trimmed) return null;
6
+
7
+ // Remove common prefixes
8
+ let normalized = trimmed
9
+ .replace(/^(ringcentral|rc):/i, "")
10
+ .replace(/^(chat|user|group|team):/i, "")
11
+ .trim();
12
+
13
+ if (!normalized) return null;
14
+ return normalized;
15
+ }
16
+
17
+ export function isRingCentralChatTarget(target: string): boolean {
18
+ const normalized = normalizeRingCentralTarget(target);
19
+ if (!normalized) return false;
20
+ // RingCentral chat IDs are typically numeric strings
21
+ return /^\d+$/.test(normalized);
22
+ }
23
+
24
+ export function isRingCentralUserTarget(target: string): boolean {
25
+ const normalized = normalizeRingCentralTarget(target);
26
+ if (!normalized) return false;
27
+ // User IDs can be numeric or prefixed
28
+ return /^\d+$/.test(normalized) || normalized.toLowerCase().startsWith("user:");
29
+ }
30
+
31
+ export function formatRingCentralChatTarget(chatId: string): string {
32
+ return `rc:chat:${chatId}`;
33
+ }
34
+
35
+ export function formatRingCentralUserTarget(userId: string): string {
36
+ return `rc:user:${userId}`;
37
+ }
38
+
39
+ export function parseRingCentralTarget(target: string): {
40
+ type: "chat" | "user" | "unknown";
41
+ id: string;
42
+ } {
43
+ const trimmed = target.trim();
44
+
45
+ // Check for explicit type prefixes
46
+ const chatMatch = trimmed.match(/^(?:ringcentral|rc)?:?chat:(.+)$/i);
47
+ if (chatMatch) {
48
+ return { type: "chat", id: chatMatch[1].trim() };
49
+ }
50
+
51
+ const userMatch = trimmed.match(/^(?:ringcentral|rc)?:?user:(.+)$/i);
52
+ if (userMatch) {
53
+ return { type: "user", id: userMatch[1].trim() };
54
+ }
55
+
56
+ const groupMatch = trimmed.match(/^(?:ringcentral|rc)?:?(?:group|team):(.+)$/i);
57
+ if (groupMatch) {
58
+ return { type: "chat", id: groupMatch[1].trim() };
59
+ }
60
+
61
+ // Remove any remaining prefix
62
+ const cleaned = trimmed.replace(/^(?:ringcentral|rc):/i, "").trim();
63
+
64
+ // Default to chat for numeric IDs
65
+ if (/^\d+$/.test(cleaned)) {
66
+ return { type: "chat", id: cleaned };
67
+ }
68
+
69
+ return { type: "unknown", id: cleaned };
70
+ }
package/src/types.ts ADDED
@@ -0,0 +1,174 @@
1
+ import type { DmPolicy, GroupPolicy, MarkdownConfig } from "openclaw/plugin-sdk";
2
+
3
+ // RingCentral Team Messaging API types
4
+
5
+ export type RingCentralUser = {
6
+ id?: string;
7
+ firstName?: string;
8
+ lastName?: string;
9
+ email?: string;
10
+ };
11
+
12
+ export type RingCentralChat = {
13
+ id?: string;
14
+ name?: string;
15
+ description?: string;
16
+ type?: "Everyone" | "Team" | "Group" | "Personal" | "Direct" | "PersonalChat";
17
+ status?: "Active" | "Archived";
18
+ members?: string[];
19
+ isPublic?: boolean;
20
+ creationTime?: string;
21
+ lastModifiedTime?: string;
22
+ };
23
+
24
+ export type RingCentralPost = {
25
+ id?: string;
26
+ groupId?: string;
27
+ type?: "TextMessage" | "PersonJoined" | "PersonsAdded";
28
+ text?: string;
29
+ creatorId?: string;
30
+ addedPersonIds?: string[];
31
+ creationTime?: string;
32
+ lastModifiedTime?: string;
33
+ attachments?: RingCentralAttachment[];
34
+ activity?: string;
35
+ title?: string;
36
+ iconUri?: string;
37
+ iconEmoji?: string;
38
+ mentions?: RingCentralMention[];
39
+ };
40
+
41
+ export type RingCentralAttachment = {
42
+ id?: string;
43
+ type?: string;
44
+ name?: string;
45
+ contentUri?: string;
46
+ contentType?: string;
47
+ size?: number;
48
+ };
49
+
50
+ export type RingCentralMention = {
51
+ id?: string;
52
+ type?: "Person" | "Team" | "File" | "Link" | "Event" | "Task" | "Note" | "Card";
53
+ name?: string;
54
+ };
55
+
56
+ // Adaptive Cards types (Microsoft Adaptive Card schema v1.3)
57
+ export type RingCentralAdaptiveCardElement = {
58
+ type: string;
59
+ text?: string;
60
+ size?: "Small" | "Default" | "Medium" | "Large" | "ExtraLarge";
61
+ weight?: "Lighter" | "Default" | "Bolder";
62
+ color?: "Default" | "Dark" | "Light" | "Accent" | "Good" | "Warning" | "Attention";
63
+ wrap?: boolean;
64
+ url?: string;
65
+ altText?: string;
66
+ columns?: RingCentralAdaptiveCardElement[];
67
+ items?: RingCentralAdaptiveCardElement[];
68
+ width?: string | number;
69
+ style?: string;
70
+ isVisible?: boolean;
71
+ id?: string;
72
+ // Input elements
73
+ label?: string;
74
+ placeholder?: string;
75
+ value?: string;
76
+ isRequired?: boolean;
77
+ // Action elements
78
+ title?: string;
79
+ data?: Record<string, unknown>;
80
+ [key: string]: unknown;
81
+ };
82
+
83
+ export type RingCentralAdaptiveCardAction = {
84
+ type: "Action.Submit" | "Action.OpenUrl" | "Action.ShowCard" | "Action.ToggleVisibility";
85
+ title?: string;
86
+ url?: string;
87
+ data?: Record<string, unknown>;
88
+ card?: RingCentralAdaptiveCard;
89
+ targetElements?: Array<string | { elementId: string; isVisible?: boolean }>;
90
+ };
91
+
92
+ export type RingCentralAdaptiveCard = {
93
+ type?: "AdaptiveCard";
94
+ $schema?: string;
95
+ version?: string;
96
+ body?: RingCentralAdaptiveCardElement[];
97
+ actions?: RingCentralAdaptiveCardAction[];
98
+ fallbackText?: string;
99
+ speak?: string;
100
+ lang?: string;
101
+ verticalContentAlignment?: "Top" | "Center" | "Bottom";
102
+ backgroundImage?: string | { url: string; fillMode?: string };
103
+ minHeight?: string;
104
+ };
105
+
106
+ export type RingCentralWebhookEvent = {
107
+ uuid?: string;
108
+ event?: string;
109
+ timestamp?: string;
110
+ subscriptionId?: string;
111
+ ownerId?: string;
112
+ body?: RingCentralEventBody;
113
+ };
114
+
115
+ export type RingCentralEventBody = {
116
+ id?: string;
117
+ groupId?: string;
118
+ type?: string;
119
+ text?: string;
120
+ creatorId?: string;
121
+ eventType?: "PostAdded" | "PostChanged" | "PostRemoved" | "GroupJoined" | "GroupLeft" | "GroupChanged";
122
+ creationTime?: string;
123
+ lastModifiedTime?: string;
124
+ attachments?: RingCentralAttachment[];
125
+ mentions?: RingCentralMention[];
126
+ name?: string;
127
+ members?: string[];
128
+ status?: string;
129
+ };
130
+
131
+ // Config types
132
+
133
+ export type RingCentralGroupConfig = {
134
+ requireMention?: boolean;
135
+ enabled?: boolean;
136
+ users?: Array<string | number>;
137
+ systemPrompt?: string;
138
+ };
139
+
140
+ export type RingCentralCredentials = {
141
+ clientId?: string;
142
+ clientSecret?: string;
143
+ jwt?: string;
144
+ server?: string;
145
+ };
146
+
147
+ export type RingCentralAccountConfig = {
148
+ enabled?: boolean;
149
+ name?: string;
150
+ credentials?: RingCentralCredentials;
151
+ markdown?: MarkdownConfig;
152
+ dmPolicy?: DmPolicy;
153
+ allowFrom?: Array<string | number>;
154
+ dm?: { policy?: DmPolicy; allowFrom?: Array<string | number>; enabled?: boolean };
155
+ groupPolicy?: GroupPolicy;
156
+ groups?: Record<string, RingCentralGroupConfig>;
157
+ groupAllowFrom?: Array<string | number>;
158
+ requireMention?: boolean;
159
+ mediaMaxMb?: number;
160
+ textChunkLimit?: number;
161
+ chunkMode?: "length" | "newline";
162
+ blockStreaming?: boolean;
163
+ blockStreamingCoalesce?: { minChars?: number; idleMs?: number };
164
+ allowBots?: boolean;
165
+ botExtensionId?: string;
166
+ replyToMode?: "off" | "all";
167
+ selfOnly?: boolean; // JWT mode: only accept messages from the JWT user in Personal chat (default: true)
168
+ useAdaptiveCards?: boolean; // Use Adaptive Cards for messages with code blocks (default: false)
169
+ };
170
+
171
+ export type RingCentralConfig = RingCentralAccountConfig & {
172
+ accounts?: Record<string, RingCentralAccountConfig>;
173
+ defaultAccount?: string;
174
+ };