openclaw-quiubo 0.2.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.
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/src/api.d.ts +118 -0
- package/dist/src/api.d.ts.map +1 -0
- package/dist/src/api.js +144 -0
- package/dist/src/api.js.map +1 -0
- package/dist/src/channel.d.ts +70 -0
- package/dist/src/channel.d.ts.map +1 -0
- package/dist/src/channel.js +114 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/types.d.ts +86 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/webhook-handler.d.ts +20 -0
- package/dist/src/webhook-handler.d.ts.map +1 -0
- package/dist/src/webhook-handler.js +84 -0
- package/dist/src/webhook-handler.js.map +1 -0
- package/openclaw.plugin.json +10 -0
- package/package.json +38 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiubo OpenClaw Extension — Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Default export is a function that OpenClaw calls with `api`.
|
|
5
|
+
* We register the channel plugin and optionally start the webhook server.
|
|
6
|
+
*/
|
|
7
|
+
import { quiuboPlugin } from './src/channel.js';
|
|
8
|
+
export { QuiuboApiClient } from './src/api.js';
|
|
9
|
+
export { quiuboPlugin, getQuiuboClient } from './src/channel.js';
|
|
10
|
+
export { startWebhookServer } from './src/webhook-handler.js';
|
|
11
|
+
export type { QuiuboAccountConfig, QuiuboGroup, QuiuboMessage, QuiuboIdentity, QuiuboJoinToken, WebhookPayload, WebhookMessageData, WebhookJoinTokenRedeemedData, } from './src/types.js';
|
|
12
|
+
/**
|
|
13
|
+
* OpenClaw plugin entry point.
|
|
14
|
+
*
|
|
15
|
+
* Called by OpenClaw when it loads the extension:
|
|
16
|
+
* import plugin from './index.ts';
|
|
17
|
+
* plugin(api);
|
|
18
|
+
*/
|
|
19
|
+
export default function register(api: {
|
|
20
|
+
registerChannel: (opts: {
|
|
21
|
+
plugin: typeof quiuboPlugin;
|
|
22
|
+
}) => void;
|
|
23
|
+
}): void;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE;IACpC,eAAe,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,YAAY,CAAA;KAAE,KAAK,IAAI,CAAC;CAClE,QAEA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiubo OpenClaw Extension — Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Default export is a function that OpenClaw calls with `api`.
|
|
5
|
+
* We register the channel plugin and optionally start the webhook server.
|
|
6
|
+
*/
|
|
7
|
+
import { quiuboPlugin } from './src/channel.js';
|
|
8
|
+
// Re-export for consumers
|
|
9
|
+
export { QuiuboApiClient } from './src/api.js';
|
|
10
|
+
export { quiuboPlugin, getQuiuboClient } from './src/channel.js';
|
|
11
|
+
export { startWebhookServer } from './src/webhook-handler.js';
|
|
12
|
+
/**
|
|
13
|
+
* OpenClaw plugin entry point.
|
|
14
|
+
*
|
|
15
|
+
* Called by OpenClaw when it loads the extension:
|
|
16
|
+
* import plugin from './index.ts';
|
|
17
|
+
* plugin(api);
|
|
18
|
+
*/
|
|
19
|
+
export default function register(api) {
|
|
20
|
+
api.registerChannel({ plugin: quiuboPlugin });
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,0BAA0B;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAY9D;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAEhC;IACC,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiubo REST API Client
|
|
3
|
+
*
|
|
4
|
+
* SDK client for interacting with the Quiubo backend API.
|
|
5
|
+
* Used by the OpenClaw extension to send/receive messages and manage groups.
|
|
6
|
+
*/
|
|
7
|
+
import type { QuiuboGroup, QuiuboMessage, QuiuboAuthResponse, QuiuboIdentity, QuiuboJoinToken } from './types.js';
|
|
8
|
+
export declare class QuiuboApiClient {
|
|
9
|
+
private baseUrl;
|
|
10
|
+
private apiKey;
|
|
11
|
+
constructor(baseUrl: string, apiKey: string);
|
|
12
|
+
private request;
|
|
13
|
+
/**
|
|
14
|
+
* Authenticate and verify API key
|
|
15
|
+
*/
|
|
16
|
+
authenticate(): Promise<QuiuboAuthResponse>;
|
|
17
|
+
/**
|
|
18
|
+
* Send a plaintext message to an SDK group
|
|
19
|
+
*/
|
|
20
|
+
sendMessage(groupId: string, opts: {
|
|
21
|
+
senderIdentityId: string;
|
|
22
|
+
plaintext: string;
|
|
23
|
+
clientMessageId?: string;
|
|
24
|
+
}): Promise<QuiuboMessage>;
|
|
25
|
+
/**
|
|
26
|
+
* List messages from an SDK group with cursor-based pagination
|
|
27
|
+
*/
|
|
28
|
+
listMessages(groupId: string, afterMessageId?: string, limit?: number): Promise<{
|
|
29
|
+
messages: QuiuboMessage[];
|
|
30
|
+
hasMore: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Create a new SDK-managed group
|
|
34
|
+
*/
|
|
35
|
+
createGroup(opts: {
|
|
36
|
+
externalGroupId: string;
|
|
37
|
+
name: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
}): Promise<QuiuboGroup>;
|
|
40
|
+
/**
|
|
41
|
+
* Add members to an SDK group
|
|
42
|
+
*/
|
|
43
|
+
addMembers(groupId: string, identityIds: string[]): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Remove members from an SDK group
|
|
46
|
+
*/
|
|
47
|
+
removeMembers(groupId: string, identityIds: string[]): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* List all SDK-managed groups
|
|
50
|
+
*/
|
|
51
|
+
listGroups(): Promise<{
|
|
52
|
+
groups: QuiuboGroup[];
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Get a specific SDK-managed group
|
|
56
|
+
*/
|
|
57
|
+
getGroup(groupId: string): Promise<QuiuboGroup>;
|
|
58
|
+
/**
|
|
59
|
+
* Configure webhook for the SDK app
|
|
60
|
+
*/
|
|
61
|
+
configureWebhook(opts: {
|
|
62
|
+
webhookUrl?: string;
|
|
63
|
+
webhookSecret?: string;
|
|
64
|
+
webhookEnabled?: boolean;
|
|
65
|
+
}): Promise<{
|
|
66
|
+
webhookUrl: string | null;
|
|
67
|
+
webhookEnabled: boolean;
|
|
68
|
+
hasSecret: boolean;
|
|
69
|
+
lastFailureAt: string | null;
|
|
70
|
+
lastFailureReason: string | null;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Create a service identity owned by this SDK app
|
|
74
|
+
*/
|
|
75
|
+
createIdentity(opts: {
|
|
76
|
+
username: string;
|
|
77
|
+
displayName: string;
|
|
78
|
+
avatarUrl?: string;
|
|
79
|
+
}): Promise<QuiuboIdentity>;
|
|
80
|
+
/**
|
|
81
|
+
* List service identities owned by this SDK app
|
|
82
|
+
*/
|
|
83
|
+
listIdentities(): Promise<{
|
|
84
|
+
identities: QuiuboIdentity[];
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Delete (soft-delete) a service identity
|
|
88
|
+
*/
|
|
89
|
+
deleteIdentity(identityId: string): Promise<{
|
|
90
|
+
success: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Create a join token for self-service user onboarding
|
|
94
|
+
*/
|
|
95
|
+
createJoinToken(opts: {
|
|
96
|
+
botIdentityId: string;
|
|
97
|
+
groupName: string;
|
|
98
|
+
groupDescription?: string;
|
|
99
|
+
externalGroupPrefix?: string;
|
|
100
|
+
isReusable?: boolean;
|
|
101
|
+
maxUses?: number;
|
|
102
|
+
expiresInSeconds?: number;
|
|
103
|
+
metadata?: Record<string, unknown>;
|
|
104
|
+
}): Promise<QuiuboJoinToken>;
|
|
105
|
+
/**
|
|
106
|
+
* List join tokens for this SDK app
|
|
107
|
+
*/
|
|
108
|
+
listJoinTokens(): Promise<{
|
|
109
|
+
tokens: QuiuboJoinToken[];
|
|
110
|
+
}>;
|
|
111
|
+
/**
|
|
112
|
+
* Revoke a join token
|
|
113
|
+
*/
|
|
114
|
+
deleteJoinToken(tokenId: string): Promise<{
|
|
115
|
+
success: boolean;
|
|
116
|
+
}>;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/src/api.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiubo REST API Client
|
|
3
|
+
*
|
|
4
|
+
* SDK client for interacting with the Quiubo backend API.
|
|
5
|
+
* Used by the OpenClaw extension to send/receive messages and manage groups.
|
|
6
|
+
*/
|
|
7
|
+
import { randomUUID } from 'crypto';
|
|
8
|
+
export class QuiuboApiClient {
|
|
9
|
+
baseUrl;
|
|
10
|
+
apiKey;
|
|
11
|
+
constructor(baseUrl, apiKey) {
|
|
12
|
+
// Remove trailing slash
|
|
13
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
14
|
+
this.apiKey = apiKey;
|
|
15
|
+
}
|
|
16
|
+
async request(method, path, body) {
|
|
17
|
+
const url = `${this.baseUrl}/v1/sdk${path}`;
|
|
18
|
+
const headers = {
|
|
19
|
+
'X-SDK-API-Key': this.apiKey,
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
};
|
|
22
|
+
const response = await fetch(url, {
|
|
23
|
+
method,
|
|
24
|
+
headers,
|
|
25
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const errorBody = await response.text();
|
|
29
|
+
throw new Error(`Quiubo API error: ${response.status} ${response.statusText} - ${errorBody}`);
|
|
30
|
+
}
|
|
31
|
+
return response.json();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Authenticate and verify API key
|
|
35
|
+
*/
|
|
36
|
+
async authenticate() {
|
|
37
|
+
return this.request('POST', '/auth');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Send a plaintext message to an SDK group
|
|
41
|
+
*/
|
|
42
|
+
async sendMessage(groupId, opts) {
|
|
43
|
+
return this.request('POST', `/groups/${groupId}/messages`, {
|
|
44
|
+
senderIdentityId: opts.senderIdentityId,
|
|
45
|
+
plaintext: opts.plaintext,
|
|
46
|
+
clientMessageId: opts.clientMessageId ?? randomUUID(),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* List messages from an SDK group with cursor-based pagination
|
|
51
|
+
*/
|
|
52
|
+
async listMessages(groupId, afterMessageId, limit = 50) {
|
|
53
|
+
const params = new URLSearchParams({ limit: String(limit) });
|
|
54
|
+
if (afterMessageId) {
|
|
55
|
+
params.set('after_message_id', afterMessageId);
|
|
56
|
+
}
|
|
57
|
+
return this.request('GET', `/groups/${groupId}/messages?${params.toString()}`);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create a new SDK-managed group
|
|
61
|
+
*/
|
|
62
|
+
async createGroup(opts) {
|
|
63
|
+
return this.request('POST', '/groups', opts);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Add members to an SDK group
|
|
67
|
+
*/
|
|
68
|
+
async addMembers(groupId, identityIds) {
|
|
69
|
+
await this.request('POST', `/groups/${groupId}/members`, {
|
|
70
|
+
identityIds,
|
|
71
|
+
action: 'add',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Remove members from an SDK group
|
|
76
|
+
*/
|
|
77
|
+
async removeMembers(groupId, identityIds) {
|
|
78
|
+
await this.request('POST', `/groups/${groupId}/members`, {
|
|
79
|
+
identityIds,
|
|
80
|
+
action: 'remove',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* List all SDK-managed groups
|
|
85
|
+
*/
|
|
86
|
+
async listGroups() {
|
|
87
|
+
return this.request('GET', '/groups');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get a specific SDK-managed group
|
|
91
|
+
*/
|
|
92
|
+
async getGroup(groupId) {
|
|
93
|
+
return this.request('GET', `/groups/${groupId}`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Configure webhook for the SDK app
|
|
97
|
+
*/
|
|
98
|
+
async configureWebhook(opts) {
|
|
99
|
+
return this.request('PATCH', '/webhook', opts);
|
|
100
|
+
}
|
|
101
|
+
// ========================================================================
|
|
102
|
+
// Identity Management
|
|
103
|
+
// ========================================================================
|
|
104
|
+
/**
|
|
105
|
+
* Create a service identity owned by this SDK app
|
|
106
|
+
*/
|
|
107
|
+
async createIdentity(opts) {
|
|
108
|
+
return this.request('POST', '/identities', opts);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* List service identities owned by this SDK app
|
|
112
|
+
*/
|
|
113
|
+
async listIdentities() {
|
|
114
|
+
return this.request('GET', '/identities');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Delete (soft-delete) a service identity
|
|
118
|
+
*/
|
|
119
|
+
async deleteIdentity(identityId) {
|
|
120
|
+
return this.request('DELETE', `/identities/${identityId}`);
|
|
121
|
+
}
|
|
122
|
+
// ========================================================================
|
|
123
|
+
// Join Token Management
|
|
124
|
+
// ========================================================================
|
|
125
|
+
/**
|
|
126
|
+
* Create a join token for self-service user onboarding
|
|
127
|
+
*/
|
|
128
|
+
async createJoinToken(opts) {
|
|
129
|
+
return this.request('POST', '/join-tokens', opts);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* List join tokens for this SDK app
|
|
133
|
+
*/
|
|
134
|
+
async listJoinTokens() {
|
|
135
|
+
return this.request('GET', '/join-tokens');
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Revoke a join token
|
|
139
|
+
*/
|
|
140
|
+
async deleteJoinToken(tokenId) {
|
|
141
|
+
return this.request('DELETE', `/join-tokens/${tokenId}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAMpC,MAAM,OAAO,eAAe;IAClB,OAAO,CAAS;IAChB,MAAM,CAAS;IAEvB,YAAY,OAAe,EAAE,MAAc;QACzC,wBAAwB;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,MAAc,EACd,IAAY,EACZ,IAAc;QAEd,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,UAAU,IAAI,EAAE,CAAC;QAC5C,MAAM,OAAO,GAA2B;YACtC,eAAe,EAAE,IAAI,CAAC,MAAM;YAC5B,cAAc,EAAE,kBAAkB;SACnC,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM;YACN,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9C,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,SAAS,EAAE,CAAC,CAAC;QAChG,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,OAAO,IAAI,CAAC,OAAO,CAAqB,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CACf,OAAe,EACf,IAIC;QAED,OAAO,IAAI,CAAC,OAAO,CAAgB,MAAM,EAAE,WAAW,OAAO,WAAW,EAAE;YACxE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,eAAe,EAAE,IAAI,CAAC,eAAe,IAAI,UAAU,EAAE;SACtD,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAChB,OAAe,EACf,cAAuB,EACvB,KAAK,GAAG,EAAE;QAEV,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7D,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,OAAO,aAAa,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,IAIjB;QACC,OAAO,IAAI,CAAC,OAAO,CAAc,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,OAAe,EAAE,WAAqB;QACrD,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,UAAU,EAAE;YACvD,WAAW;YACX,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,OAAe,EAAE,WAAqB;QACxD,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,UAAU,EAAE;YACvD,WAAW;YACX,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,OAAe;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAc,KAAK,EAAE,WAAW,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,IAItB;QAOC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,2EAA2E;IAC3E,sBAAsB;IACtB,2EAA2E;IAE3E;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,IAIpB;QACC,OAAO,IAAI,CAAC,OAAO,CAAiB,MAAM,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC;IACnE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe,UAAU,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,2EAA2E;IAC3E,wBAAwB;IACxB,2EAA2E;IAE3E;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,IASrB;QACC,OAAO,IAAI,CAAC,OAAO,CAAkB,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,OAAe;QACnC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,gBAAgB,OAAO,EAAE,CAAC,CAAC;IAC3D,CAAC;CACF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiubo Channel Plugin
|
|
3
|
+
*
|
|
4
|
+
* Flat plugin object matching OpenClaw's ChannelPlugin interface.
|
|
5
|
+
*
|
|
6
|
+
* Shape:
|
|
7
|
+
* id, meta, capabilities, config, outbound
|
|
8
|
+
*
|
|
9
|
+
* The gateway (webhook listener) lifecycle is managed outside the plugin
|
|
10
|
+
* object — see index.ts where we wire up the webhook server after
|
|
11
|
+
* the plugin is registered.
|
|
12
|
+
*/
|
|
13
|
+
import { QuiuboApiClient } from './api.js';
|
|
14
|
+
import type { QuiuboAccountConfig } from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* The plugin object passed to api.registerChannel({ plugin }).
|
|
17
|
+
*
|
|
18
|
+
* OpenClaw discovers accounts via config.listAccountIds / resolveAccount,
|
|
19
|
+
* then calls outbound.sendText when the agent needs to respond.
|
|
20
|
+
*/
|
|
21
|
+
export declare const quiuboPlugin: {
|
|
22
|
+
id: "quiubo";
|
|
23
|
+
meta: {
|
|
24
|
+
id: string;
|
|
25
|
+
label: string;
|
|
26
|
+
selectionLabel: string;
|
|
27
|
+
blurb: string;
|
|
28
|
+
aliases: string[];
|
|
29
|
+
};
|
|
30
|
+
capabilities: {
|
|
31
|
+
chatTypes: readonly ["group"];
|
|
32
|
+
};
|
|
33
|
+
config: {
|
|
34
|
+
/**
|
|
35
|
+
* Return the list of account IDs from the user's OpenClaw config.
|
|
36
|
+
* Config lives at: channels.quiubo.accounts.<accountId>
|
|
37
|
+
*/
|
|
38
|
+
listAccountIds(cfg: Record<string, unknown>): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Resolve an account config into the shape our plugin needs.
|
|
41
|
+
* Returns the raw account object (apiUrl, apiKey, botIdentityId, etc.)
|
|
42
|
+
*/
|
|
43
|
+
resolveAccount(cfg: Record<string, unknown>, accountId?: string): QuiuboAccountConfig;
|
|
44
|
+
};
|
|
45
|
+
outbound: {
|
|
46
|
+
deliveryMode: "direct";
|
|
47
|
+
/**
|
|
48
|
+
* Send a text message to the current Quiubo group.
|
|
49
|
+
*
|
|
50
|
+
* OpenClaw calls this with { text, target, ... }.
|
|
51
|
+
* `target` carries routing info — we expect target.groupId to know
|
|
52
|
+
* which Quiubo group to send to.
|
|
53
|
+
*/
|
|
54
|
+
sendText({ text, target }: {
|
|
55
|
+
text: string;
|
|
56
|
+
target?: {
|
|
57
|
+
groupId?: string;
|
|
58
|
+
[key: string]: unknown;
|
|
59
|
+
};
|
|
60
|
+
}): Promise<{
|
|
61
|
+
ok: boolean;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Get the current API client (for webhook handler and other plumbing).
|
|
67
|
+
* Returns null if no account has been resolved yet.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getQuiuboClient(): QuiuboApiClient | null;
|
|
70
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAatD;;;;;GAKG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;QAerB;;;WAGG;4BACiB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE;QAOtD;;;WAGG;4BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,cAChB,MAAM,GACjB,mBAAmB;;;;QAwBtB;;;;;;WAMG;mCAC8B;YAC/B,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,CAAC,EAAE;gBAAE,OAAO,CAAC,EAAE,MAAM,CAAC;gBAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;aAAE,CAAC;SACvD,GAAG,OAAO,CAAC;YAAE,EAAE,EAAE,OAAO,CAAA;SAAE,CAAC;;CA2B/B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,IAAI,eAAe,GAAG,IAAI,CAExD"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiubo Channel Plugin
|
|
3
|
+
*
|
|
4
|
+
* Flat plugin object matching OpenClaw's ChannelPlugin interface.
|
|
5
|
+
*
|
|
6
|
+
* Shape:
|
|
7
|
+
* id, meta, capabilities, config, outbound
|
|
8
|
+
*
|
|
9
|
+
* The gateway (webhook listener) lifecycle is managed outside the plugin
|
|
10
|
+
* object — see index.ts where we wire up the webhook server after
|
|
11
|
+
* the plugin is registered.
|
|
12
|
+
*/
|
|
13
|
+
import { QuiuboApiClient } from './api.js';
|
|
14
|
+
// Module-level client, initialised lazily per-account
|
|
15
|
+
let _client = null;
|
|
16
|
+
let _account = null;
|
|
17
|
+
function getClient() {
|
|
18
|
+
if (!_client || !_account) {
|
|
19
|
+
throw new Error('Quiubo plugin: no account resolved — call resolveAccount first');
|
|
20
|
+
}
|
|
21
|
+
return _client;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The plugin object passed to api.registerChannel({ plugin }).
|
|
25
|
+
*
|
|
26
|
+
* OpenClaw discovers accounts via config.listAccountIds / resolveAccount,
|
|
27
|
+
* then calls outbound.sendText when the agent needs to respond.
|
|
28
|
+
*/
|
|
29
|
+
export const quiuboPlugin = {
|
|
30
|
+
id: 'quiubo',
|
|
31
|
+
meta: {
|
|
32
|
+
id: 'quiubo',
|
|
33
|
+
label: 'Quiubo',
|
|
34
|
+
selectionLabel: 'Quiubo (API)',
|
|
35
|
+
blurb: 'Send and receive messages through Quiubo.',
|
|
36
|
+
aliases: ['qb'],
|
|
37
|
+
},
|
|
38
|
+
capabilities: { chatTypes: ['group'] },
|
|
39
|
+
// ── config adapter ──────────────────────────────────────────────
|
|
40
|
+
config: {
|
|
41
|
+
/**
|
|
42
|
+
* Return the list of account IDs from the user's OpenClaw config.
|
|
43
|
+
* Config lives at: channels.quiubo.accounts.<accountId>
|
|
44
|
+
*/
|
|
45
|
+
listAccountIds(cfg) {
|
|
46
|
+
const channels = cfg.channels;
|
|
47
|
+
const quiubo = channels?.quiubo;
|
|
48
|
+
const accounts = quiubo?.accounts;
|
|
49
|
+
return Object.keys(accounts ?? {});
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* Resolve an account config into the shape our plugin needs.
|
|
53
|
+
* Returns the raw account object (apiUrl, apiKey, botIdentityId, etc.)
|
|
54
|
+
*/
|
|
55
|
+
resolveAccount(cfg, accountId) {
|
|
56
|
+
const channels = cfg.channels;
|
|
57
|
+
const quiubo = channels?.quiubo;
|
|
58
|
+
const accounts = quiubo?.accounts;
|
|
59
|
+
const id = accountId ?? 'default';
|
|
60
|
+
const account = accounts?.[id];
|
|
61
|
+
if (!account) {
|
|
62
|
+
return { accountId: id };
|
|
63
|
+
}
|
|
64
|
+
// Initialise the API client for this account
|
|
65
|
+
const apiUrl = account.apiUrl ?? 'https://api.quiubo.io';
|
|
66
|
+
_client = new QuiuboApiClient(apiUrl, account.apiKey);
|
|
67
|
+
_account = { ...account, accountId: id };
|
|
68
|
+
return _account;
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
// ── outbound adapter ────────────────────────────────────────────
|
|
72
|
+
outbound: {
|
|
73
|
+
deliveryMode: 'direct',
|
|
74
|
+
/**
|
|
75
|
+
* Send a text message to the current Quiubo group.
|
|
76
|
+
*
|
|
77
|
+
* OpenClaw calls this with { text, target, ... }.
|
|
78
|
+
* `target` carries routing info — we expect target.groupId to know
|
|
79
|
+
* which Quiubo group to send to.
|
|
80
|
+
*/
|
|
81
|
+
async sendText({ text, target }) {
|
|
82
|
+
const client = getClient();
|
|
83
|
+
const groupId = target?.groupId;
|
|
84
|
+
if (!groupId) {
|
|
85
|
+
console.error('[Quiubo] sendText called without target.groupId');
|
|
86
|
+
return { ok: false };
|
|
87
|
+
}
|
|
88
|
+
const senderId = _account?.botIdentityId;
|
|
89
|
+
if (!senderId) {
|
|
90
|
+
console.error('[Quiubo] sendText called without botIdentityId configured');
|
|
91
|
+
return { ok: false };
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
await client.sendMessage(groupId, {
|
|
95
|
+
senderIdentityId: senderId,
|
|
96
|
+
plaintext: text,
|
|
97
|
+
});
|
|
98
|
+
return { ok: true };
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error('[Quiubo] sendText failed:', error);
|
|
102
|
+
return { ok: false };
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Get the current API client (for webhook handler and other plumbing).
|
|
109
|
+
* Returns null if no account has been resolved yet.
|
|
110
|
+
*/
|
|
111
|
+
export function getQuiuboClient() {
|
|
112
|
+
return _client;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the Quiubo OpenClaw extension
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Account config as stored in OpenClaw config:
|
|
6
|
+
* channels.quiubo.accounts.<accountId>
|
|
7
|
+
*/
|
|
8
|
+
export interface QuiuboAccountConfig {
|
|
9
|
+
accountId: string;
|
|
10
|
+
apiUrl: string;
|
|
11
|
+
apiKey: string;
|
|
12
|
+
botIdentityId: string;
|
|
13
|
+
webhookSecret?: string;
|
|
14
|
+
webhookPort?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface QuiuboGroup {
|
|
17
|
+
id: string;
|
|
18
|
+
externalGroupId: string;
|
|
19
|
+
name: string;
|
|
20
|
+
description: string | null;
|
|
21
|
+
retentionDays: number;
|
|
22
|
+
visibility: 'native+sdk' | 'sdk-only';
|
|
23
|
+
memberCount: number;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
}
|
|
26
|
+
export interface QuiuboMessage {
|
|
27
|
+
id: string;
|
|
28
|
+
groupId: string;
|
|
29
|
+
senderIdentityId: string;
|
|
30
|
+
clientMessageId: string;
|
|
31
|
+
ciphertext: string | null;
|
|
32
|
+
plaintext: string | null;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
}
|
|
35
|
+
export interface QuiuboAuthResponse {
|
|
36
|
+
appId: string;
|
|
37
|
+
appName: string;
|
|
38
|
+
authenticated: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface QuiuboIdentity {
|
|
41
|
+
identityId: string;
|
|
42
|
+
username: string;
|
|
43
|
+
displayName: string;
|
|
44
|
+
avatarUrl: string | null;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
}
|
|
47
|
+
export interface QuiuboJoinToken {
|
|
48
|
+
tokenId: string;
|
|
49
|
+
token: string;
|
|
50
|
+
joinUrl: string;
|
|
51
|
+
qrCodeData: string;
|
|
52
|
+
botIdentityId: string;
|
|
53
|
+
groupName: string;
|
|
54
|
+
isReusable: boolean;
|
|
55
|
+
maxUses: number | null;
|
|
56
|
+
useCount: number;
|
|
57
|
+
expiresAt: string | null;
|
|
58
|
+
isActive: boolean;
|
|
59
|
+
createdAt: string;
|
|
60
|
+
}
|
|
61
|
+
export interface WebhookPayload {
|
|
62
|
+
event: string;
|
|
63
|
+
timestamp: string;
|
|
64
|
+
data: WebhookMessageData | WebhookJoinTokenRedeemedData;
|
|
65
|
+
}
|
|
66
|
+
export interface WebhookMessageData {
|
|
67
|
+
messageId: string;
|
|
68
|
+
groupId: string;
|
|
69
|
+
externalGroupId: string;
|
|
70
|
+
senderIdentityId: string;
|
|
71
|
+
senderUsername: string;
|
|
72
|
+
plaintext: string;
|
|
73
|
+
clientMessageId: string;
|
|
74
|
+
createdAt: string;
|
|
75
|
+
}
|
|
76
|
+
export interface WebhookJoinTokenRedeemedData {
|
|
77
|
+
tokenId: string;
|
|
78
|
+
groupId: string;
|
|
79
|
+
externalGroupId: string;
|
|
80
|
+
groupName: string;
|
|
81
|
+
userIdentityId: string;
|
|
82
|
+
botIdentityId: string;
|
|
83
|
+
isNew: boolean;
|
|
84
|
+
redeemedAt: string;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,YAAY,GAAG,UAAU,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,kBAAkB,GAAG,4BAA4B,CAAC;CACzD;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook Handler
|
|
3
|
+
*
|
|
4
|
+
* Receives inbound webhook events from Quiubo backend.
|
|
5
|
+
* Verifies HMAC-SHA256 signature and routes messages to the OpenClaw agent.
|
|
6
|
+
*/
|
|
7
|
+
import { type Server } from 'http';
|
|
8
|
+
import type { WebhookPayload } from './types.js';
|
|
9
|
+
export interface WebhookHandlerOptions {
|
|
10
|
+
port: number;
|
|
11
|
+
webhookSecret?: string;
|
|
12
|
+
botIdentityId: string;
|
|
13
|
+
onMessage: (payload: WebhookPayload) => void | Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Start a webhook HTTP server.
|
|
17
|
+
* Returns the server instance for lifecycle management.
|
|
18
|
+
*/
|
|
19
|
+
export declare function startWebhookServer(opts: WebhookHandlerOptions): Promise<Server>;
|
|
20
|
+
//# sourceMappingURL=webhook-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-handler.d.ts","sourceRoot":"","sources":["../../src/webhook-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAgB,KAAK,MAAM,EAA6C,MAAM,MAAM,CAAC;AAC5F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AA0BD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwDrF"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook Handler
|
|
3
|
+
*
|
|
4
|
+
* Receives inbound webhook events from Quiubo backend.
|
|
5
|
+
* Verifies HMAC-SHA256 signature and routes messages to the OpenClaw agent.
|
|
6
|
+
*/
|
|
7
|
+
import { createHmac, timingSafeEqual } from 'crypto';
|
|
8
|
+
import { createServer } from 'http';
|
|
9
|
+
/**
|
|
10
|
+
* Verify HMAC-SHA256 signature
|
|
11
|
+
*/
|
|
12
|
+
function verifySignature(body, signature, secret) {
|
|
13
|
+
const expected = createHmac('sha256', secret).update(body).digest('hex');
|
|
14
|
+
try {
|
|
15
|
+
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read the full request body
|
|
23
|
+
*/
|
|
24
|
+
function readBody(req) {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const chunks = [];
|
|
27
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
28
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
29
|
+
req.on('error', reject);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Start a webhook HTTP server.
|
|
34
|
+
* Returns the server instance for lifecycle management.
|
|
35
|
+
*/
|
|
36
|
+
export async function startWebhookServer(opts) {
|
|
37
|
+
const { port, webhookSecret, botIdentityId, onMessage } = opts;
|
|
38
|
+
const server = createServer(async (req, res) => {
|
|
39
|
+
// Only accept POST /webhooks/quiubo
|
|
40
|
+
if (req.method !== 'POST' || req.url !== '/webhooks/quiubo') {
|
|
41
|
+
res.writeHead(404);
|
|
42
|
+
res.end('Not found');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const body = await readBody(req);
|
|
47
|
+
// Verify signature if secret is configured
|
|
48
|
+
if (webhookSecret) {
|
|
49
|
+
const signature = req.headers['x-quiubo-signature'];
|
|
50
|
+
if (!signature || !verifySignature(body, signature, webhookSecret)) {
|
|
51
|
+
console.error('[Webhook] Invalid signature');
|
|
52
|
+
res.writeHead(401);
|
|
53
|
+
res.end('Invalid signature');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const payload = JSON.parse(body);
|
|
58
|
+
// Skip messages from bot itself (only applies to message events)
|
|
59
|
+
if (payload.event === 'group_message.created' &&
|
|
60
|
+
'senderIdentityId' in payload.data &&
|
|
61
|
+
payload.data.senderIdentityId === botIdentityId) {
|
|
62
|
+
res.writeHead(200);
|
|
63
|
+
res.end('OK (skipped self)');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Route to handler
|
|
67
|
+
await onMessage(payload);
|
|
68
|
+
res.writeHead(200);
|
|
69
|
+
res.end('OK');
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('[Webhook] Handler error:', error);
|
|
73
|
+
res.writeHead(500);
|
|
74
|
+
res.end('Internal error');
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return new Promise((resolve) => {
|
|
78
|
+
server.listen(port, () => {
|
|
79
|
+
console.log(`[Quiubo] Webhook server listening on port ${port}`);
|
|
80
|
+
resolve(server);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=webhook-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-handler.js","sourceRoot":"","sources":["../../src/webhook-handler.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openclaw-quiubo",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "OpenClaw Quiubo channel plugin — chat with AI assistants through Quiubo",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"openclaw.plugin.json"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"openclaw",
|
|
25
|
+
"quiubo",
|
|
26
|
+
"channel",
|
|
27
|
+
"plugin",
|
|
28
|
+
"messaging"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.10.1",
|
|
33
|
+
"typescript": "^5.7.2"
|
|
34
|
+
},
|
|
35
|
+
"openclaw": {
|
|
36
|
+
"extensions": ["./dist/index.js"]
|
|
37
|
+
}
|
|
38
|
+
}
|