@wabot-dev/framework 0.9.19 → 0.9.21
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/src/addon/async/in-memory/InMemoryCronJobRepository.js +1 -0
- package/dist/src/addon/async/in-memory/InMemoryJobRepository.js +18 -0
- package/dist/src/addon/async/pg/PgJobRepository.js +17 -0
- package/dist/src/addon/chat-bot/google/GoogleChatAdapter.js +30 -13
- package/dist/src/addon/chat-controller/whatsapp/kapso/@kapso.js +23 -0
- package/dist/src/addon/chat-controller/whatsapp/kapso/KapsoChannel.js +65 -0
- package/dist/src/addon/chat-controller/whatsapp/kapso/KapsoChannelConfig.js +14 -0
- package/dist/src/addon/chat-controller/whatsapp/kapso/KapsoChannelName.js +3 -0
- package/dist/src/addon/chat-controller/whatsapp/kapso/KapsoReceiver.js +36 -0
- package/dist/src/addon/chat-controller/whatsapp/kapso/KapsoSender.js +44 -0
- package/dist/src/addon/chat-controller/whatsapp/kapso/KapsoWebhookController.js +99 -0
- package/dist/src/feature/async/@commandHandler.js +11 -1
- package/dist/src/feature/async/@cronHandler.js +5 -0
- package/dist/src/feature/async/Async.js +31 -5
- package/dist/src/feature/async/AsyncMetadataStore.js +16 -1
- package/dist/src/feature/async/CronScheduler.js +14 -1
- package/dist/src/feature/async/Job.js +3 -0
- package/dist/src/feature/async/JobRepository.js +3 -0
- package/dist/src/feature/async/computeDedupKey.js +21 -0
- package/dist/src/feature/project-runner/ProjectRunner.js +1 -0
- package/dist/src/index.d.ts +159 -6
- package/dist/src/index.js +8 -0
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ import '../../../feature/async/AsyncMetadataStore.js';
|
|
|
8
8
|
import '../../../feature/async/TransactionMetadataStore.js';
|
|
9
9
|
import '../../../feature/async/Async.js';
|
|
10
10
|
import { CronJob } from '../../../feature/async/CronJob.js';
|
|
11
|
+
import 'node:crypto';
|
|
11
12
|
import '../../../core/error/setupErrorHandlers.js';
|
|
12
13
|
import '../../../feature/async/JobRepository.js';
|
|
13
14
|
import '../../../feature/async/JobRunner.js';
|
|
@@ -9,6 +9,7 @@ import '../../../feature/async/TransactionMetadataStore.js';
|
|
|
9
9
|
import '../../../feature/async/Async.js';
|
|
10
10
|
import '../../../_virtual/index.js';
|
|
11
11
|
import { Job } from '../../../feature/async/Job.js';
|
|
12
|
+
import 'node:crypto';
|
|
12
13
|
import '../../../feature/async/JobRepository.js';
|
|
13
14
|
import '../../../feature/async/JobRunner.js';
|
|
14
15
|
import '../../../feature/async/JobScheduler.js';
|
|
@@ -78,6 +79,23 @@ let InMemoryJobRepository = class InMemoryJobRepository {
|
|
|
78
79
|
return j['data'].scheduledAt != null && j['data'].startedAt != null;
|
|
79
80
|
});
|
|
80
81
|
}
|
|
82
|
+
async findActiveByDedupKey(commandName, dedupKey, succeededSinceTimestamp) {
|
|
83
|
+
const candidates = [...this.items.values()]
|
|
84
|
+
.filter((j) => {
|
|
85
|
+
const d = j['data'];
|
|
86
|
+
if (d.commandName !== commandName)
|
|
87
|
+
return false;
|
|
88
|
+
if (d.dedupKey !== dedupKey)
|
|
89
|
+
return false;
|
|
90
|
+
if (d.failedAt != null)
|
|
91
|
+
return false;
|
|
92
|
+
if (d.successAt != null && d.successAt < succeededSinceTimestamp)
|
|
93
|
+
return false;
|
|
94
|
+
return true;
|
|
95
|
+
})
|
|
96
|
+
.sort((a, b) => (b['data'].createdAt ?? 0) - (a['data'].createdAt ?? 0));
|
|
97
|
+
return candidates[0] ?? null;
|
|
98
|
+
}
|
|
81
99
|
async countRunningByCommand(commandName) {
|
|
82
100
|
let count = 0;
|
|
83
101
|
for (const j of this.items.values()) {
|
|
@@ -56,6 +56,23 @@ let PgJobRepository = class PgJobRepository extends PgCrudRepository {
|
|
|
56
56
|
const items = await this.query(sql, []);
|
|
57
57
|
return items;
|
|
58
58
|
}
|
|
59
|
+
async findActiveByDedupKey(commandName, dedupKey, succeededSinceTimestamp) {
|
|
60
|
+
const sql = `
|
|
61
|
+
SELECT ${this.columns}
|
|
62
|
+
FROM ${this.table}
|
|
63
|
+
WHERE data->>'commandName' = $1
|
|
64
|
+
AND data->>'dedupKey' = $2
|
|
65
|
+
AND data->>'failedAt' IS NULL
|
|
66
|
+
AND (
|
|
67
|
+
data->>'successAt' IS NULL
|
|
68
|
+
OR (data->>'successAt')::bigint >= $3
|
|
69
|
+
)
|
|
70
|
+
ORDER BY (data->>'createdAt')::bigint DESC
|
|
71
|
+
LIMIT 1
|
|
72
|
+
`;
|
|
73
|
+
const items = await this.query(sql, [commandName, dedupKey, succeededSinceTimestamp]);
|
|
74
|
+
return items[0] ?? null;
|
|
75
|
+
}
|
|
59
76
|
async countRunningByCommand(commandName) {
|
|
60
77
|
const sql = `
|
|
61
78
|
SELECT COUNT(*)::int AS count
|
|
@@ -49,14 +49,7 @@ let GoogleChatAdapter = class GoogleChatAdapter {
|
|
|
49
49
|
let lastError;
|
|
50
50
|
for (const ref of req.models) {
|
|
51
51
|
try {
|
|
52
|
-
const response = await this.
|
|
53
|
-
model: ref.model,
|
|
54
|
-
contents,
|
|
55
|
-
config: {
|
|
56
|
-
tools: [{ functionDeclarations }],
|
|
57
|
-
...(hasUnsignedFunctionCall ? { thinkingConfig: { thinkingBudget: 0 } } : {}),
|
|
58
|
-
},
|
|
59
|
-
});
|
|
52
|
+
const response = await this.callGenerate(ref.model, contents, functionDeclarations, hasUnsignedFunctionCall);
|
|
60
53
|
return this.mapResponse(response, ref.model);
|
|
61
54
|
}
|
|
62
55
|
catch (err) {
|
|
@@ -68,6 +61,25 @@ let GoogleChatAdapter = class GoogleChatAdapter {
|
|
|
68
61
|
}
|
|
69
62
|
throw lastError ?? new Error('No Google model could handle the request');
|
|
70
63
|
}
|
|
64
|
+
async callGenerate(model, contents, functionDeclarations, hasUnsignedFunctionCall) {
|
|
65
|
+
const baseConfig = { tools: [{ functionDeclarations }] };
|
|
66
|
+
if (!hasUnsignedFunctionCall) {
|
|
67
|
+
return this.ai.models.generateContent({ model, contents, config: baseConfig });
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
return await this.ai.models.generateContent({
|
|
71
|
+
model,
|
|
72
|
+
contents,
|
|
73
|
+
config: { ...baseConfig, thinkingConfig: { thinkingBudget: 0 } },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
if (!isThinkingModeRequiredError(err))
|
|
78
|
+
throw err;
|
|
79
|
+
this.logger.warn(`Google model '${model}' requires thinking mode; retrying without thinkingBudget override`);
|
|
80
|
+
return this.ai.models.generateContent({ model, contents, config: baseConfig });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
71
83
|
async mapChatItems(chatItems) {
|
|
72
84
|
const contents = [];
|
|
73
85
|
for (const chatItem of chatItems) {
|
|
@@ -179,9 +191,7 @@ let GoogleChatAdapter = class GoogleChatAdapter {
|
|
|
179
191
|
if (!response.candidates || !response.candidates.length) {
|
|
180
192
|
throw new Error('No candidates in response');
|
|
181
193
|
}
|
|
182
|
-
if (!response.usageMetadata
|
|
183
|
-
!response.usageMetadata.promptTokenCount ||
|
|
184
|
-
!response.usageMetadata.candidatesTokenCount) {
|
|
194
|
+
if (!response.usageMetadata) {
|
|
185
195
|
throw new Error('Not usage metadata');
|
|
186
196
|
}
|
|
187
197
|
const content = response.candidates.find((x) => x.content)?.content;
|
|
@@ -210,9 +220,10 @@ let GoogleChatAdapter = class GoogleChatAdapter {
|
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
222
|
const cachedTokens = response.usageMetadata.cachedContentTokenCount ?? 0;
|
|
223
|
+
const thoughtsTokens = response.usageMetadata.thoughtsTokenCount ?? 0;
|
|
213
224
|
let usage = {
|
|
214
|
-
inputTokens: response.usageMetadata.promptTokenCount,
|
|
215
|
-
outputTokens: response.usageMetadata.candidatesTokenCount,
|
|
225
|
+
inputTokens: response.usageMetadata.promptTokenCount ?? 0,
|
|
226
|
+
outputTokens: (response.usageMetadata.candidatesTokenCount ?? 0) + thoughtsTokens,
|
|
216
227
|
cacheReadTokens: cachedTokens || undefined,
|
|
217
228
|
provider: 'google',
|
|
218
229
|
model: response.modelVersion ?? modelName,
|
|
@@ -225,6 +236,12 @@ GoogleChatAdapter = __decorate([
|
|
|
225
236
|
singleton(),
|
|
226
237
|
__metadata("design:paramtypes", [Env])
|
|
227
238
|
], GoogleChatAdapter);
|
|
239
|
+
function isThinkingModeRequiredError(err) {
|
|
240
|
+
if (!err || typeof err !== 'object')
|
|
241
|
+
return false;
|
|
242
|
+
const message = err.message;
|
|
243
|
+
return typeof message === 'string' && /only works in thinking mode/i.test(message);
|
|
244
|
+
}
|
|
228
245
|
function stripDataUrlPrefix(dataUrl) {
|
|
229
246
|
const commaIndex = dataUrl.indexOf(',');
|
|
230
247
|
return commaIndex >= 0 && dataUrl.startsWith('data:') ? dataUrl.slice(commaIndex + 1) : dataUrl;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { container } from '../../../../core/injection/index.js';
|
|
2
|
+
import { resolveConfigReferences } from '../../../../core/config/resolver.js';
|
|
3
|
+
import { ControllerMetadataStore } from '../../../../feature/chat-controller/metadata/ControllerMetadataStore.js';
|
|
4
|
+
import '../../../../feature/chat-controller/ChatResolver.js';
|
|
5
|
+
import '../../../../feature/chat-controller/runChatControllers.js';
|
|
6
|
+
import { KapsoChannel } from './KapsoChannel.js';
|
|
7
|
+
import { KapsoChannelConfig } from './KapsoChannelConfig.js';
|
|
8
|
+
|
|
9
|
+
function kapso(config) {
|
|
10
|
+
return function (target, propertyKey) {
|
|
11
|
+
const cfg = config ?? {};
|
|
12
|
+
const resolvedConfig = resolveConfigReferences(cfg);
|
|
13
|
+
const store = container.resolve(ControllerMetadataStore);
|
|
14
|
+
store.saveChannelMetadata({
|
|
15
|
+
channelConstructor: KapsoChannel,
|
|
16
|
+
functionName: propertyKey.toString(),
|
|
17
|
+
controllerConstructor: target.constructor,
|
|
18
|
+
channelConfig: new KapsoChannelConfig(resolvedConfig),
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { kapso };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { injectable } from '../../../../core/injection/index.js';
|
|
3
|
+
import { Env } from '../../../../core/env/Env.js';
|
|
4
|
+
import { Logger } from '../../../../core/logger/Logger.js';
|
|
5
|
+
import { KapsoChannelConfig } from './KapsoChannelConfig.js';
|
|
6
|
+
import { KapsoReceiver } from './KapsoReceiver.js';
|
|
7
|
+
import { KapsoSender } from './KapsoSender.js';
|
|
8
|
+
import { kapsoChannelName } from './KapsoChannelName.js';
|
|
9
|
+
|
|
10
|
+
var KapsoChannel_1;
|
|
11
|
+
let KapsoChannel = class KapsoChannel {
|
|
12
|
+
static { KapsoChannel_1 = this; }
|
|
13
|
+
logger = new Logger('wabot:whatsapp-by-kapso-channel');
|
|
14
|
+
sender;
|
|
15
|
+
receiver;
|
|
16
|
+
phoneNumberId;
|
|
17
|
+
static channelName = kapsoChannelName;
|
|
18
|
+
constructor(config, env) {
|
|
19
|
+
const apiKey = config.apiKey ?? env.requireString('KAPSO_API_KEY');
|
|
20
|
+
const webhookSecret = config.webhookSecret ?? process.env.KAPSO_WEBHOOK_SECRET;
|
|
21
|
+
this.phoneNumberId = config.phoneNumberId ?? env.requireString('KAPSO_PHONE_NUMBER_ID');
|
|
22
|
+
this.sender = new KapsoSender(apiKey, this.phoneNumberId);
|
|
23
|
+
this.receiver = new KapsoReceiver({
|
|
24
|
+
webhookSecret,
|
|
25
|
+
webhookPath: config.webhookPath,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
listen(callback) {
|
|
29
|
+
this.receiver.listenMessage(async (message, from) => {
|
|
30
|
+
try {
|
|
31
|
+
await callback({
|
|
32
|
+
channel: kapsoChannelName,
|
|
33
|
+
chatConnection: {
|
|
34
|
+
chatType: 'PRIVATE',
|
|
35
|
+
channelName: KapsoChannel_1.channelName,
|
|
36
|
+
id: from,
|
|
37
|
+
},
|
|
38
|
+
message,
|
|
39
|
+
reply: async (replyMessage) => {
|
|
40
|
+
await this.sender.sendMessage({
|
|
41
|
+
from: this.phoneNumberId,
|
|
42
|
+
to: from,
|
|
43
|
+
message: replyMessage,
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
this.logger.error('Failed to handle WhatsApp message', err);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
connect() {
|
|
54
|
+
this.receiver.connect();
|
|
55
|
+
}
|
|
56
|
+
disconnect() {
|
|
57
|
+
this.receiver.disconnect();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
KapsoChannel = KapsoChannel_1 = __decorate([
|
|
61
|
+
injectable(),
|
|
62
|
+
__metadata("design:paramtypes", [KapsoChannelConfig, Env])
|
|
63
|
+
], KapsoChannel);
|
|
64
|
+
|
|
65
|
+
export { KapsoChannel };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class KapsoChannelConfig {
|
|
2
|
+
apiKey;
|
|
3
|
+
webhookSecret;
|
|
4
|
+
phoneNumberId;
|
|
5
|
+
webhookPath;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.apiKey = config.apiKey;
|
|
8
|
+
this.webhookSecret = config.webhookSecret;
|
|
9
|
+
this.phoneNumberId = config.phoneNumberId;
|
|
10
|
+
this.webhookPath = config.webhookPath ?? '/kapso/hook';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { KapsoChannelConfig };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import '../../../../core/injection/index.js';
|
|
3
|
+
import '../../../../feature/rest-controller/metadata/RestControllerMetadataStore.js';
|
|
4
|
+
import { restController } from '../../../../feature/rest-controller/metadata/@restController.js';
|
|
5
|
+
import { runRestControllers } from '../../../../feature/rest-controller/runRestControllers.js';
|
|
6
|
+
import { KapsoWebhookController } from './KapsoWebhookController.js';
|
|
7
|
+
|
|
8
|
+
class KapsoReceiver {
|
|
9
|
+
config;
|
|
10
|
+
listener = null;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
}
|
|
14
|
+
listenMessage(listener) {
|
|
15
|
+
this.listener = listener;
|
|
16
|
+
}
|
|
17
|
+
connect() {
|
|
18
|
+
const webhookSecret = this.config.webhookSecret;
|
|
19
|
+
const listener = this.listener;
|
|
20
|
+
let UniqueController = class UniqueController extends KapsoWebhookController {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(webhookSecret, listener);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
UniqueController = __decorate([
|
|
26
|
+
restController(this.config.webhookPath),
|
|
27
|
+
__metadata("design:paramtypes", [])
|
|
28
|
+
], UniqueController);
|
|
29
|
+
runRestControllers([UniqueController]);
|
|
30
|
+
}
|
|
31
|
+
disconnect() {
|
|
32
|
+
// Nothing to disconnect
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { KapsoReceiver };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Logger } from '../../../../core/logger/Logger.js';
|
|
2
|
+
|
|
3
|
+
class KapsoSender {
|
|
4
|
+
apiKey;
|
|
5
|
+
phoneNumberId;
|
|
6
|
+
logger = new Logger('wabot:whatsapp-sender-by-kapso');
|
|
7
|
+
baseUrl = 'https://api.kapso.ai/meta/whatsapp/v24.0';
|
|
8
|
+
constructor(apiKey, phoneNumberId) {
|
|
9
|
+
this.apiKey = apiKey;
|
|
10
|
+
this.phoneNumberId = phoneNumberId;
|
|
11
|
+
}
|
|
12
|
+
async sendMessage(request) {
|
|
13
|
+
const url = `${this.baseUrl}/${this.phoneNumberId}/messages`;
|
|
14
|
+
const payload = {
|
|
15
|
+
messaging_product: 'whatsapp',
|
|
16
|
+
recipient_type: 'individual',
|
|
17
|
+
to: request.to.replace(/\D+/g, ''),
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: {
|
|
20
|
+
preview_url: false,
|
|
21
|
+
body: request.message.text ?? '',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
const response = await fetch(url, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: {
|
|
27
|
+
'X-API-Key': this.apiKey,
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify(payload),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
const errorBody = await response.text();
|
|
34
|
+
this.logger.error(`Failed to send message from '${request.from}' to '${request.to}': ${response.status} ${errorBody}`);
|
|
35
|
+
throw new Error(`Kapso send message failed: ${response.status} ${errorBody}`);
|
|
36
|
+
}
|
|
37
|
+
this.logger.trace(`message sent from '${request.from}' to '${request.to}'`);
|
|
38
|
+
}
|
|
39
|
+
async sendTemplate(_request) {
|
|
40
|
+
throw new Error('Method not implemented.');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { KapsoSender };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
3
|
+
import { IncomingMessage } from 'node:http';
|
|
4
|
+
import { Logger } from '../../../../core/logger/Logger.js';
|
|
5
|
+
import '../../../../core/injection/index.js';
|
|
6
|
+
import '../../../../feature/rest-controller/metadata/RestControllerMetadataStore.js';
|
|
7
|
+
import { onPost } from '../../../../feature/rest-controller/metadata/@onPost.js';
|
|
8
|
+
|
|
9
|
+
class KapsoWebhookController {
|
|
10
|
+
webhookSecret;
|
|
11
|
+
listener;
|
|
12
|
+
logger = new Logger('wabot:kapso-webhook');
|
|
13
|
+
constructor(webhookSecret, listener) {
|
|
14
|
+
this.webhookSecret = webhookSecret;
|
|
15
|
+
this.listener = listener;
|
|
16
|
+
}
|
|
17
|
+
async handleWebhook(req) {
|
|
18
|
+
const rawBody = await this.getRawBody(req);
|
|
19
|
+
if (!this.verifySignature(req, rawBody)) {
|
|
20
|
+
this.logger.warn('rejected webhook with invalid signature');
|
|
21
|
+
throw new Error('Invalid webhook signature');
|
|
22
|
+
}
|
|
23
|
+
let event;
|
|
24
|
+
try {
|
|
25
|
+
event = JSON.parse(rawBody);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
this.logger.error('Failed to parse webhook payload', err);
|
|
29
|
+
throw new Error('Invalid webhook payload');
|
|
30
|
+
}
|
|
31
|
+
this.logger.trace(`received event ${event.event}`);
|
|
32
|
+
switch (event.event) {
|
|
33
|
+
case 'whatsapp.message.received':
|
|
34
|
+
await this.handleMessageReceived(event);
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
this.logger.trace(`unhandled event type ${event.event}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async handleMessageReceived(event) {
|
|
41
|
+
const message = event.message;
|
|
42
|
+
if (message.type !== 'text' || !message.text) {
|
|
43
|
+
this.logger.warn(`message type '${message.type}' is not supported yet`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const rawNumber = message.from ?? event.conversation?.phone_number ?? '';
|
|
47
|
+
if (!rawNumber) {
|
|
48
|
+
this.logger.warn('received message without a sender number');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const from = rawNumber.startsWith('+') ? rawNumber : `+${rawNumber}`;
|
|
52
|
+
const senderName = event.conversation?.kapso?.contact_name ?? message.username ?? from;
|
|
53
|
+
this.logger.trace(`new message from '${from}'`);
|
|
54
|
+
await this.listener({
|
|
55
|
+
text: message.text.body,
|
|
56
|
+
senderName,
|
|
57
|
+
senderId: from,
|
|
58
|
+
metadata: {
|
|
59
|
+
whatsAppNumber: from,
|
|
60
|
+
},
|
|
61
|
+
}, from);
|
|
62
|
+
}
|
|
63
|
+
verifySignature(req, rawBody) {
|
|
64
|
+
if (!this.webhookSecret) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
const headerValue = req.headers['x-webhook-signature'];
|
|
68
|
+
const provided = Array.isArray(headerValue) ? headerValue[0] : headerValue;
|
|
69
|
+
if (!provided) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const expected = createHmac('sha256', this.webhookSecret).update(rawBody).digest('hex');
|
|
73
|
+
const providedHex = provided.startsWith('sha256=') ? provided.slice('sha256='.length) : provided;
|
|
74
|
+
const expectedBuf = Buffer.from(expected, 'hex');
|
|
75
|
+
const providedBuf = Buffer.from(providedHex, 'hex');
|
|
76
|
+
if (expectedBuf.length !== providedBuf.length) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return timingSafeEqual(expectedBuf, providedBuf);
|
|
80
|
+
}
|
|
81
|
+
getRawBody(req) {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
let data = '';
|
|
84
|
+
req.on('data', (chunk) => {
|
|
85
|
+
data += chunk;
|
|
86
|
+
});
|
|
87
|
+
req.on('end', () => resolve(data));
|
|
88
|
+
req.on('error', (err) => reject(err));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
__decorate([
|
|
93
|
+
onPost({ disableJsonParser: true, disableUrlEncodedParser: true }),
|
|
94
|
+
__metadata("design:type", Function),
|
|
95
|
+
__metadata("design:paramtypes", [IncomingMessage]),
|
|
96
|
+
__metadata("design:returntype", Promise)
|
|
97
|
+
], KapsoWebhookController.prototype, "handleWebhook", null);
|
|
98
|
+
|
|
99
|
+
export { KapsoWebhookController };
|
|
@@ -4,7 +4,17 @@ import { container, injectable } from '../../core/injection/index.js';
|
|
|
4
4
|
function commandHandler(config) {
|
|
5
5
|
return function (target) {
|
|
6
6
|
const metadataStore = container.resolve(AsyncMetadataStore);
|
|
7
|
-
|
|
7
|
+
const isCtor = typeof config === 'function';
|
|
8
|
+
const command = isCtor ? config : config.command;
|
|
9
|
+
const options = isCtor
|
|
10
|
+
? {}
|
|
11
|
+
: {
|
|
12
|
+
reintentsDelaysInSeconds: config.reintentsDelaysInSeconds,
|
|
13
|
+
aceptableRunningTimeSeconds: config.aceptableRunningTimeSeconds,
|
|
14
|
+
stuckRetryAttempts: config.stuckRetryAttempts,
|
|
15
|
+
};
|
|
16
|
+
const dedup = isCtor ? undefined : config.dedup;
|
|
17
|
+
metadataStore.registerCommandHandler(command, target, options, dedup);
|
|
8
18
|
injectable()(target);
|
|
9
19
|
};
|
|
10
20
|
}
|
|
@@ -9,6 +9,11 @@ function cronHandler(config) {
|
|
|
9
9
|
commandName: `cron:${config.name}`,
|
|
10
10
|
cron: config.cron,
|
|
11
11
|
enabled: !config.disabled,
|
|
12
|
+
maxRunningJobs: config.maxRunningJobs,
|
|
13
|
+
misfirePolicy: config.misfirePolicy,
|
|
14
|
+
reintentsDelaysInSeconds: config.reintentsDelaysInSeconds,
|
|
15
|
+
aceptableRunningTimeSeconds: config.aceptableRunningTimeSeconds,
|
|
16
|
+
stuckRetryAttempts: config.stuckRetryAttempts,
|
|
12
17
|
});
|
|
13
18
|
singleton()(target);
|
|
14
19
|
};
|
|
@@ -8,15 +8,19 @@ import { JobRepository } from './JobRepository.js';
|
|
|
8
8
|
import { JobScheduler } from './JobScheduler.js';
|
|
9
9
|
import '../../core/validation/metadata/ValidationMetadataStore.js';
|
|
10
10
|
import { validateAndTransform } from '../../core/validation/validateAndTransform.js';
|
|
11
|
+
import { Locker } from '../../core/lock/Locker.js';
|
|
12
|
+
import { computeDedupKey } from './computeDedupKey.js';
|
|
11
13
|
|
|
12
14
|
let Async = class Async {
|
|
13
15
|
jobRepository;
|
|
14
16
|
metadataStore;
|
|
15
17
|
jobScheduler;
|
|
16
|
-
|
|
18
|
+
locker;
|
|
19
|
+
constructor(jobRepository, metadataStore, jobScheduler, locker) {
|
|
17
20
|
this.jobRepository = jobRepository;
|
|
18
21
|
this.metadataStore = metadataStore;
|
|
19
22
|
this.jobScheduler = jobScheduler;
|
|
23
|
+
this.locker = locker;
|
|
20
24
|
}
|
|
21
25
|
async runCommand(ctor, data) {
|
|
22
26
|
const job = await this.scheduleCommand(ctor, data, new Date());
|
|
@@ -36,13 +40,34 @@ let Async = class Async {
|
|
|
36
40
|
});
|
|
37
41
|
}
|
|
38
42
|
const scheduledDate = this.resolveScheduledDate(scheduledAt);
|
|
39
|
-
const
|
|
43
|
+
const options = this.metadataStore.getJobOptionsForCommandName(commandName);
|
|
44
|
+
const dedupConfig = this.metadataStore.getDedupConfigForCommandName(commandName);
|
|
45
|
+
const buildJob = (dedupKey) => new Job({
|
|
40
46
|
commandName,
|
|
41
47
|
commandData,
|
|
42
48
|
scheduledAt: scheduledDate.getTime(),
|
|
49
|
+
reintentsDelaysInSeconds: options.reintentsDelaysInSeconds,
|
|
50
|
+
aceptableRunningTimeSeconds: options.aceptableRunningTimeSeconds,
|
|
51
|
+
stuckRetryAttempts: options.stuckRetryAttempts,
|
|
52
|
+
dedupKey,
|
|
53
|
+
});
|
|
54
|
+
if (!dedupConfig) {
|
|
55
|
+
const job = buildJob();
|
|
56
|
+
await this.jobRepository.create(job);
|
|
57
|
+
return job;
|
|
58
|
+
}
|
|
59
|
+
const dedupKey = computeDedupKey(commandData);
|
|
60
|
+
const succeededSinceTimestamp = dedupConfig === 'forever' ? 0 : Date.now() - dedupConfig.windowSeconds * 1000;
|
|
61
|
+
return await this.locker
|
|
62
|
+
.withKey(`wabot-async-dedup-${commandName}-${dedupKey}`)
|
|
63
|
+
.run(async () => {
|
|
64
|
+
const existing = await this.jobRepository.findActiveByDedupKey(commandName, dedupKey, succeededSinceTimestamp);
|
|
65
|
+
if (existing)
|
|
66
|
+
return existing;
|
|
67
|
+
const job = buildJob(dedupKey);
|
|
68
|
+
await this.jobRepository.create(job);
|
|
69
|
+
return job;
|
|
43
70
|
});
|
|
44
|
-
await this.jobRepository.create(job);
|
|
45
|
-
return job;
|
|
46
71
|
}
|
|
47
72
|
resolveScheduledDate(scheduledAt) {
|
|
48
73
|
if (scheduledAt instanceof Date) {
|
|
@@ -68,7 +93,8 @@ Async = __decorate([
|
|
|
68
93
|
singleton(),
|
|
69
94
|
__metadata("design:paramtypes", [JobRepository,
|
|
70
95
|
AsyncMetadataStore,
|
|
71
|
-
JobScheduler
|
|
96
|
+
JobScheduler,
|
|
97
|
+
Locker])
|
|
72
98
|
], Async);
|
|
73
99
|
|
|
74
100
|
export { Async };
|
|
@@ -6,6 +6,8 @@ let AsyncMetadataStore = class AsyncMetadataStore {
|
|
|
6
6
|
handlersInverseMap = new Map();
|
|
7
7
|
commandsMap = new Map();
|
|
8
8
|
commandsInverseMap = new Map();
|
|
9
|
+
handlerOptionsMap = new Map();
|
|
10
|
+
dedupConfigMap = new Map();
|
|
9
11
|
cronsMap = new Map();
|
|
10
12
|
registerCron(cron, config) {
|
|
11
13
|
let ctorCrons = this.cronsMap.get(cron);
|
|
@@ -26,13 +28,20 @@ let AsyncMetadataStore = class AsyncMetadataStore {
|
|
|
26
28
|
this.commandsMap.set(commandName, command);
|
|
27
29
|
this.commandsInverseMap.set(command, commandName);
|
|
28
30
|
}
|
|
29
|
-
registerCommandHandler(command, handlerConstructor) {
|
|
31
|
+
registerCommandHandler(command, handlerConstructor, options = {}, dedup) {
|
|
30
32
|
let commandName = this.commandsInverseMap.get(command);
|
|
31
33
|
if (!commandName) {
|
|
32
34
|
throw new Error(`Should use @command decorator on command class ${command.name}`);
|
|
33
35
|
}
|
|
34
36
|
this.handlersMap.set(commandName, handlerConstructor);
|
|
35
37
|
this.handlersInverseMap.set(handlerConstructor, commandName);
|
|
38
|
+
this.handlerOptionsMap.set(commandName, options);
|
|
39
|
+
if (dedup !== undefined) {
|
|
40
|
+
this.dedupConfigMap.set(commandName, dedup);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
this.dedupConfigMap.delete(commandName);
|
|
44
|
+
}
|
|
36
45
|
}
|
|
37
46
|
getHandlerForCommandName(commandName) {
|
|
38
47
|
return this.handlersMap.get(commandName) ?? null;
|
|
@@ -52,6 +61,12 @@ let AsyncMetadataStore = class AsyncMetadataStore {
|
|
|
52
61
|
getCommandForCommandName(commandName) {
|
|
53
62
|
return this.commandsMap.get(commandName) ?? null;
|
|
54
63
|
}
|
|
64
|
+
getJobOptionsForCommandName(commandName) {
|
|
65
|
+
return this.handlerOptionsMap.get(commandName) ?? {};
|
|
66
|
+
}
|
|
67
|
+
getDedupConfigForCommandName(commandName) {
|
|
68
|
+
return this.dedupConfigMap.get(commandName);
|
|
69
|
+
}
|
|
55
70
|
getAllCommandHandlers() {
|
|
56
71
|
return Array.from(this.handlersInverseMap.keys());
|
|
57
72
|
}
|
|
@@ -136,7 +136,15 @@ let CronScheduler = class CronScheduler {
|
|
|
136
136
|
let cronJob = await this.cronRepo.findByName(config.name);
|
|
137
137
|
if (cronJob) {
|
|
138
138
|
this.logger.debug(`found cron job for name='${config.name}'`);
|
|
139
|
-
cronJob.update({
|
|
139
|
+
cronJob.update({
|
|
140
|
+
cron: config.cron,
|
|
141
|
+
enabled: config.enabled,
|
|
142
|
+
maxRunningJobs: config.maxRunningJobs,
|
|
143
|
+
misfirePolicy: config.misfirePolicy,
|
|
144
|
+
reintentsDelaysInSeconds: config.reintentsDelaysInSeconds,
|
|
145
|
+
aceptableRunningTimeSeconds: config.aceptableRunningTimeSeconds,
|
|
146
|
+
stuckRetryAttempts: config.stuckRetryAttempts,
|
|
147
|
+
});
|
|
140
148
|
await this.cronRepo.update(cronJob);
|
|
141
149
|
this.logger.debug(`cron job for name='${config.name}' updated`);
|
|
142
150
|
}
|
|
@@ -146,6 +154,11 @@ let CronScheduler = class CronScheduler {
|
|
|
146
154
|
cron: config.cron,
|
|
147
155
|
commandName: config.commandName,
|
|
148
156
|
enabled: config.enabled,
|
|
157
|
+
maxRunningJobs: config.maxRunningJobs,
|
|
158
|
+
misfirePolicy: config.misfirePolicy,
|
|
159
|
+
reintentsDelaysInSeconds: config.reintentsDelaysInSeconds,
|
|
160
|
+
aceptableRunningTimeSeconds: config.aceptableRunningTimeSeconds,
|
|
161
|
+
stuckRetryAttempts: config.stuckRetryAttempts,
|
|
149
162
|
});
|
|
150
163
|
await this.cronRepo.create(cronJob);
|
|
151
164
|
}
|
|
@@ -32,6 +32,9 @@ let JobRepository = class JobRepository {
|
|
|
32
32
|
countRunningByCommand(commandName) {
|
|
33
33
|
throw new Error('Method not implemented.');
|
|
34
34
|
}
|
|
35
|
+
findActiveByDedupKey(commandName, dedupKey, succeededSinceTimestamp) {
|
|
36
|
+
throw new Error('Method not implemented.');
|
|
37
|
+
}
|
|
35
38
|
};
|
|
36
39
|
JobRepository = __decorate([
|
|
37
40
|
singleton()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
function canonicalize(value) {
|
|
4
|
+
if (value === undefined || value === null)
|
|
5
|
+
return 'null';
|
|
6
|
+
if (typeof value === 'number')
|
|
7
|
+
return Number.isFinite(value) ? JSON.stringify(value) : 'null';
|
|
8
|
+
if (typeof value !== 'object')
|
|
9
|
+
return JSON.stringify(value);
|
|
10
|
+
if (Array.isArray(value))
|
|
11
|
+
return '[' + value.map(canonicalize).join(',') + ']';
|
|
12
|
+
const keys = Object.keys(value)
|
|
13
|
+
.filter((k) => value[k] !== undefined)
|
|
14
|
+
.sort();
|
|
15
|
+
return ('{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalize(value[k])).join(',') + '}');
|
|
16
|
+
}
|
|
17
|
+
function computeDedupKey(commandData) {
|
|
18
|
+
return createHash('sha256').update(canonicalize(commandData)).digest('hex');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { computeDedupKey };
|
|
@@ -22,6 +22,7 @@ import { TransactionMetadataStore } from '../async/TransactionMetadataStore.js';
|
|
|
22
22
|
import '../async/Async.js';
|
|
23
23
|
import '../../_virtual/index.js';
|
|
24
24
|
import { CronJobRepository } from '../async/CronJobRepository.js';
|
|
25
|
+
import 'node:crypto';
|
|
25
26
|
import { JobRepository } from '../async/JobRepository.js';
|
|
26
27
|
import '../async/JobRunner.js';
|
|
27
28
|
import { runCommandHandlers } from '../async/runCommandHandlers.js';
|
package/dist/src/index.d.ts
CHANGED
|
@@ -464,8 +464,19 @@ interface ICommandHandler<C extends object> {
|
|
|
464
464
|
handle(command: C): void | Promise<void>;
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
-
interface
|
|
467
|
+
interface IJobOptions {
|
|
468
|
+
reintentsDelaysInSeconds?: number[];
|
|
469
|
+
aceptableRunningTimeSeconds?: number;
|
|
470
|
+
stuckRetryAttempts?: number;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
type IDedupConfig = {
|
|
474
|
+
windowSeconds: number;
|
|
475
|
+
} | 'forever';
|
|
476
|
+
|
|
477
|
+
interface ICommandHandlerConfig<C extends object> extends IJobOptions {
|
|
468
478
|
command: IConstructor<IStorableData<C>>;
|
|
479
|
+
dedup?: IDedupConfig;
|
|
469
480
|
}
|
|
470
481
|
declare function commandHandler<C extends object>(config: ICommandHandlerConfig<C> | IConstructor<IStorableData<C>>): (target: IConstructor<ICommandHandler<C>>) => void;
|
|
471
482
|
|
|
@@ -474,20 +485,24 @@ interface ICronHandler {
|
|
|
474
485
|
handleError?(e: any): void | Promise<void>;
|
|
475
486
|
}
|
|
476
487
|
|
|
477
|
-
interface ICronConfig {
|
|
488
|
+
interface ICronConfig extends IJobOptions {
|
|
478
489
|
name: string;
|
|
479
490
|
cron: string;
|
|
480
491
|
disabled?: boolean;
|
|
492
|
+
maxRunningJobs?: number;
|
|
493
|
+
misfirePolicy?: 'RUN_ONCE' | 'RUN_ALL' | 'SKIP';
|
|
481
494
|
}
|
|
482
495
|
declare function cronHandler(config: ICronConfig): (target: IConstructor<ICronHandler>) => void;
|
|
483
496
|
|
|
484
497
|
declare function transaction(dbNames?: readonly string[]): <This, A extends unknown[], R>(_target: object, _propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<(this: This, ...args: A) => Promise<R>>) => TypedPropertyDescriptor<(this: This, ...args: A) => Promise<R>>;
|
|
485
498
|
|
|
486
|
-
interface ICronJobScheduleConfig {
|
|
499
|
+
interface ICronJobScheduleConfig extends IJobOptions {
|
|
487
500
|
name: string;
|
|
488
501
|
commandName: string;
|
|
489
502
|
cron: string;
|
|
490
503
|
enabled: boolean;
|
|
504
|
+
maxRunningJobs?: number;
|
|
505
|
+
misfirePolicy?: 'RUN_ONCE' | 'RUN_ALL' | 'SKIP';
|
|
491
506
|
}
|
|
492
507
|
|
|
493
508
|
interface ICronMetadata {
|
|
@@ -500,16 +515,20 @@ declare class AsyncMetadataStore {
|
|
|
500
515
|
private handlersInverseMap;
|
|
501
516
|
private commandsMap;
|
|
502
517
|
private commandsInverseMap;
|
|
518
|
+
private handlerOptionsMap;
|
|
519
|
+
private dedupConfigMap;
|
|
503
520
|
private cronsMap;
|
|
504
521
|
registerCron(cron: IConstructor<ICronHandler>, config: ICronJobScheduleConfig): void;
|
|
505
522
|
requireCronMetadata(cron: IConstructor<ICronHandler>): ICronMetadata[];
|
|
506
523
|
registerCommand(command: IConstructor<any>, commandName: string): void;
|
|
507
|
-
registerCommandHandler<C extends object>(command: IConstructor<IStorableData<C>>, handlerConstructor: IConstructor<ICommandHandler<C
|
|
524
|
+
registerCommandHandler<C extends object>(command: IConstructor<IStorableData<C>>, handlerConstructor: IConstructor<ICommandHandler<C>>, options?: IJobOptions, dedup?: IDedupConfig): void;
|
|
508
525
|
getHandlerForCommandName(commandName: string): IConstructor<ICommandHandler<any>> | null;
|
|
509
526
|
getCommandNameForHandler(handlerConstructor: IConstructor<ICommandHandler<any>>): string | null;
|
|
510
527
|
requireCommandNameForHandler(handlerConstructor: IConstructor<ICommandHandler<any>>): string;
|
|
511
528
|
getCommandName(command: IConstructor<any>): string | null;
|
|
512
529
|
getCommandForCommandName(commandName: string): IConstructor<any> | null;
|
|
530
|
+
getJobOptionsForCommandName(commandName: string): IJobOptions;
|
|
531
|
+
getDedupConfigForCommandName(commandName: string): IDedupConfig | undefined;
|
|
513
532
|
getAllCommandHandlers(): IConstructor<ICommandHandler<any>>[];
|
|
514
533
|
getAllCronHandlers(): IConstructor<ICronHandler>[];
|
|
515
534
|
}
|
|
@@ -532,6 +551,7 @@ interface IJobData extends IEntityData {
|
|
|
532
551
|
};
|
|
533
552
|
aceptableRunningTimeSeconds?: number;
|
|
534
553
|
stuckRetryAttempts?: number;
|
|
554
|
+
dedupKey?: string;
|
|
535
555
|
}
|
|
536
556
|
declare class Job extends Entity<IJobData> {
|
|
537
557
|
get commandName(): string;
|
|
@@ -539,6 +559,7 @@ declare class Job extends Entity<IJobData> {
|
|
|
539
559
|
get reintentsDelaysInSeconds(): number[] | undefined;
|
|
540
560
|
get aceptableRunningTimeSeconds(): number | undefined;
|
|
541
561
|
get stuckRetryAttempts(): number | undefined;
|
|
562
|
+
get dedupKey(): string | undefined;
|
|
542
563
|
get runningSeconds(): number;
|
|
543
564
|
get successAt(): Date | undefined;
|
|
544
565
|
get failedAt(): Date | undefined;
|
|
@@ -560,6 +581,7 @@ interface IJobRepository extends ICrudRepository<Job> {
|
|
|
560
581
|
findPendingForRunFrom(date: Date, limit: number): Promise<Job[]>;
|
|
561
582
|
findRunningJobs(): Promise<Job[]>;
|
|
562
583
|
countRunningByCommand(commandName: string): Promise<number>;
|
|
584
|
+
findActiveByDedupKey(commandName: string, dedupKey: string, succeededSinceTimestamp: number): Promise<Job | null>;
|
|
563
585
|
}
|
|
564
586
|
|
|
565
587
|
declare class JobRepository implements IJobRepository {
|
|
@@ -573,6 +595,7 @@ declare class JobRepository implements IJobRepository {
|
|
|
573
595
|
update(item: Job): Promise<void>;
|
|
574
596
|
delete(item: Job): Promise<void>;
|
|
575
597
|
countRunningByCommand(commandName: string): Promise<number>;
|
|
598
|
+
findActiveByDedupKey(commandName: string, dedupKey: string, succeededSinceTimestamp: number): Promise<Job | null>;
|
|
576
599
|
}
|
|
577
600
|
|
|
578
601
|
declare class JobRunner {
|
|
@@ -627,7 +650,8 @@ declare class Async {
|
|
|
627
650
|
private jobRepository;
|
|
628
651
|
private metadataStore;
|
|
629
652
|
private jobScheduler;
|
|
630
|
-
|
|
653
|
+
private locker;
|
|
654
|
+
constructor(jobRepository: JobRepository, metadataStore: AsyncMetadataStore, jobScheduler: JobScheduler, locker: Locker);
|
|
631
655
|
runCommand<T>(ctor: IConstructor<T>, data: IValidateInputShape<T>): Promise<Job>;
|
|
632
656
|
scheduleCommand<T>(ctor: IConstructor<T>, data: IValidateInputShape<T>, scheduledAt: IScheduleAt): Promise<Job>;
|
|
633
657
|
private resolveScheduledDate;
|
|
@@ -679,6 +703,8 @@ declare class CronJobRepository implements ICronJobRepository {
|
|
|
679
703
|
findOrThrow(id: string): Promise<CronJob>;
|
|
680
704
|
}
|
|
681
705
|
|
|
706
|
+
declare function computeDedupKey(commandData: unknown): string;
|
|
707
|
+
|
|
682
708
|
interface ITransactionAdapter {
|
|
683
709
|
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
684
710
|
}
|
|
@@ -1659,6 +1685,7 @@ declare class PgJobRepository extends PgCrudRepository<Job> implements IJobRepos
|
|
|
1659
1685
|
constructor(pool: Pool);
|
|
1660
1686
|
findPendingForRunFrom(date: Date, limit: number): Promise<Job[]>;
|
|
1661
1687
|
findRunningJobs(): Promise<Job[]>;
|
|
1688
|
+
findActiveByDedupKey(commandName: string, dedupKey: string, succeededSinceTimestamp: number): Promise<Job | null>;
|
|
1662
1689
|
countRunningByCommand(commandName: string): Promise<number>;
|
|
1663
1690
|
}
|
|
1664
1691
|
|
|
@@ -1680,6 +1707,7 @@ declare class InMemoryJobRepository implements IJobRepository {
|
|
|
1680
1707
|
delete(item: Job): Promise<void>;
|
|
1681
1708
|
findPendingForRunFrom(date: Date, limit: number): Promise<Job[]>;
|
|
1682
1709
|
findRunningJobs(): Promise<Job[]>;
|
|
1710
|
+
findActiveByDedupKey(commandName: string, dedupKey: string, succeededSinceTimestamp: number): Promise<Job | null>;
|
|
1683
1711
|
countRunningByCommand(commandName: string): Promise<number>;
|
|
1684
1712
|
private touch;
|
|
1685
1713
|
private enforceLimit;
|
|
@@ -1934,6 +1962,7 @@ declare class GoogleChatAdapter implements IChatAdapter {
|
|
|
1934
1962
|
private readonly logger;
|
|
1935
1963
|
constructor(env: Env);
|
|
1936
1964
|
nextItems(req: IChatAdapterNextItemsReq): Promise<IChatAdapterNextItemsRes>;
|
|
1965
|
+
private callGenerate;
|
|
1937
1966
|
private mapChatItems;
|
|
1938
1967
|
private mapHumanMessage;
|
|
1939
1968
|
private toGoogleFilePart;
|
|
@@ -2355,6 +2384,130 @@ declare class WhatsAppApiSender implements IWhatsAppSender {
|
|
|
2355
2384
|
sendTemplate(request: ISendWhatsAppTemplateReq): Promise<void>;
|
|
2356
2385
|
}
|
|
2357
2386
|
|
|
2387
|
+
interface IKapsoChannelConfig {
|
|
2388
|
+
apiKey?: string | ConfigReference<string>;
|
|
2389
|
+
webhookSecret?: string | ConfigReference<string>;
|
|
2390
|
+
phoneNumberId?: string | ConfigReference<string>;
|
|
2391
|
+
webhookPath?: string;
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
declare function kapso(config?: IKapsoChannelConfig): (target: object, propertyKey: string | symbol) => void;
|
|
2395
|
+
|
|
2396
|
+
interface IKapsoChatMessage extends IChatMessage {
|
|
2397
|
+
metadata: {
|
|
2398
|
+
whatsAppNumber: string;
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
declare const kapsoChannelName: "WhatsAppByKapsoChannel";
|
|
2403
|
+
|
|
2404
|
+
interface IKapsoReceivedMessage extends IReceivedMessage {
|
|
2405
|
+
channel: typeof kapsoChannelName;
|
|
2406
|
+
message: IKapsoChatMessage;
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
interface IKapsoChannelMessage extends IKapsoReceivedMessage {
|
|
2410
|
+
chatConnection: IChatConnection;
|
|
2411
|
+
injectInstances?: [any, any][];
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
type IKapsoEvent = IKapsoMessageReceivedEvent | IKapsoUnknownEvent;
|
|
2415
|
+
interface IKapsoUnknownEvent {
|
|
2416
|
+
event: string;
|
|
2417
|
+
[key: string]: unknown;
|
|
2418
|
+
}
|
|
2419
|
+
interface IKapsoMessageReceivedEvent {
|
|
2420
|
+
event: 'whatsapp.message.received';
|
|
2421
|
+
message: IKapsoIncomingMessage;
|
|
2422
|
+
conversation: IKapsoConversation;
|
|
2423
|
+
is_new_conversation?: boolean;
|
|
2424
|
+
phone_number_id?: string;
|
|
2425
|
+
}
|
|
2426
|
+
interface IKapsoIncomingMessage {
|
|
2427
|
+
id: string;
|
|
2428
|
+
timestamp: string;
|
|
2429
|
+
type: string;
|
|
2430
|
+
from: string;
|
|
2431
|
+
from_user_id?: string;
|
|
2432
|
+
from_parent_user_id?: string;
|
|
2433
|
+
username?: string;
|
|
2434
|
+
text?: {
|
|
2435
|
+
body: string;
|
|
2436
|
+
};
|
|
2437
|
+
}
|
|
2438
|
+
interface IKapsoConversation {
|
|
2439
|
+
id: string;
|
|
2440
|
+
phone_number?: string;
|
|
2441
|
+
business_scoped_user_id?: string;
|
|
2442
|
+
parent_business_scoped_user_id?: string;
|
|
2443
|
+
username?: string;
|
|
2444
|
+
status?: string;
|
|
2445
|
+
phone_number_id?: string;
|
|
2446
|
+
kapso?: {
|
|
2447
|
+
contact_name?: string;
|
|
2448
|
+
[key: string]: unknown;
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
declare class KapsoChannelConfig {
|
|
2453
|
+
readonly apiKey?: string;
|
|
2454
|
+
readonly webhookSecret?: string;
|
|
2455
|
+
readonly phoneNumberId?: string;
|
|
2456
|
+
readonly webhookPath: string;
|
|
2457
|
+
constructor(config: {
|
|
2458
|
+
apiKey?: string;
|
|
2459
|
+
webhookSecret?: string;
|
|
2460
|
+
phoneNumberId?: string;
|
|
2461
|
+
webhookPath?: string;
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
declare class KapsoChannel implements IChatChannel {
|
|
2466
|
+
private logger;
|
|
2467
|
+
private sender;
|
|
2468
|
+
private receiver;
|
|
2469
|
+
private phoneNumberId;
|
|
2470
|
+
static channelName: "WhatsAppByKapsoChannel";
|
|
2471
|
+
constructor(config: KapsoChannelConfig, env: Env);
|
|
2472
|
+
listen(callback: (message: IKapsoChannelMessage) => Promise<void>): void;
|
|
2473
|
+
connect(): void;
|
|
2474
|
+
disconnect(): void;
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
type IKapsoChannelMessageListener = (message: IKapsoChatMessage, from: string) => Promise<void>;
|
|
2478
|
+
declare class KapsoWebhookController {
|
|
2479
|
+
private webhookSecret;
|
|
2480
|
+
private listener;
|
|
2481
|
+
private logger;
|
|
2482
|
+
constructor(webhookSecret: string | undefined, listener: IKapsoChannelMessageListener);
|
|
2483
|
+
handleWebhook(req: IncomingMessage): Promise<void>;
|
|
2484
|
+
private handleMessageReceived;
|
|
2485
|
+
private verifySignature;
|
|
2486
|
+
private getRawBody;
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
declare class KapsoReceiver {
|
|
2490
|
+
private config;
|
|
2491
|
+
private listener;
|
|
2492
|
+
constructor(config: {
|
|
2493
|
+
webhookSecret?: string;
|
|
2494
|
+
webhookPath: string;
|
|
2495
|
+
});
|
|
2496
|
+
listenMessage(listener: IKapsoChannelMessageListener): void;
|
|
2497
|
+
connect(): void;
|
|
2498
|
+
disconnect(): void;
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
declare class KapsoSender implements IWhatsAppSender {
|
|
2502
|
+
private apiKey;
|
|
2503
|
+
private phoneNumberId;
|
|
2504
|
+
private logger;
|
|
2505
|
+
private baseUrl;
|
|
2506
|
+
constructor(apiKey: string, phoneNumberId: string);
|
|
2507
|
+
sendMessage(request: ISendWhatsAppMessageReq): Promise<void>;
|
|
2508
|
+
sendTemplate(_request: ISendWhatsAppTemplateReq): Promise<void>;
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2358
2511
|
interface IWasenderChannelConfig {
|
|
2359
2512
|
apiKey?: string | ConfigReference<string>;
|
|
2360
2513
|
webhookSecret?: string | ConfigReference<string>;
|
|
@@ -2524,4 +2677,4 @@ declare function HtmlModule(options: IHtmlModuleOptions): {
|
|
|
2524
2677
|
new (): {};
|
|
2525
2678
|
};
|
|
2526
2679
|
|
|
2527
|
-
export { AnthropicChatAdapter, ApiKey, ApiKeyGuardMiddleware, ApiKeyHandshakeGuardMiddleware, ApiKeyRepository, Async, AsyncMetadataStore, Auth, Chat, ChatAdapter, ChatAdapterMetadataStore, ChatAdapterRegistry, ChatBot, ChatBotMetadataStore, ChatItem, ChatMemory, ChatOperator, ChatRepository, ChatResolver, type ClientMap, CmdChannel, CmdChannelConfig, CmdChannelServer, type CmdClientMessage, type CmdServerMessage, type ConfigReference, type ConfigReferenceType, ConfigResolver, Container, ControllerMetadataStore, CronJob, CronJobRepository, CrudRepository, CustomError, DeepSeekChatAdapter, DescriptionMetadataStore, EXPRESS_REQ, EXPRESS_RES, Entity, Env, type ErrorSeverity, ExpressProvider, GoogleChatAdapter, type GoogleChatAdapterV2Options, HtmlModule, HttpServerProvider, type IApiKeyData, type IApiKeyRepository, type IArrayValidationError, type IArrayValidationResult, type IBotMessageItem, type IBuiltQuery, type IChannelMessage, type IChannelMetadata, type IChatAdapter, type IChatAdapterDecoratorConfig, type IChatAdapterMetadata, type IChatAdapterNextItemsReq, type IChatAdapterNextItemsRes, type IChatAssociation, type IChatBot, type IChatBotMetadata, type IChatChannel, type IChatConnection, type IChatControllerMetadata, type IChatData, type IChatItem, type IChatItemData, type IChatItemType, type IChatMemory, type IChatMessage, type IChatMessageDocument, type IChatMessageFile, type IChatMessageImage, type IChatMessagesPrivateFile, type IChatMessagesPublicFile, type IChatRepository, type IChatType, type ICmdChannelEntry, type ICmdChannelHandlers, type ICmdChannelMessage, type ICmdReceivedMessage, type ICommandConfig, type ICommandHandler, type ICommandHandlerConfig, type IConstructor, type ICronConfig, type ICronHandler, type ICronJobData, type ICronJobRepository, type ICrudRepository, type ICustomErrorData, type IDescriptionMetadata, type IEndPointConfig, type IEndPointMetadata, type IEntityData, type IEnvType, type IErrorHandlersConfig, type IErrorMonitor, type IErrorMonitorContext, type IExtractChatMessageTextOptions, type IFunctionCall, type IFunctionCallItem, type IGenerateApiKeyReq, type IGenerateApiKeyRes, type IHandshakeMiddleware, type IHandshakeMiddlewareMetadata, type IHtmlModuleOptions, type IHumanMessageItem, type IJobData, type IJobRepository, type IJwtRefreshTokenData, type IJwtRefreshTokenRepository, type ILanguageModelUsage, type ILockKey, type ILocker, type ILockerKey, type IMemoryRepositoryAdapterOptions, type IMessageContext, type IMiddleware, type IMiddlewareMetadata, type IMindset, type IMindsetConfig, type IMindsetIdentity, type IMindsetLlm, type IMindsetMetadata, type IMindsetModelKind, type IMindsetModelRef, type IMindsetModels, type IMindsetModuleConfig, type IMindsetModuleMetadata, type IMindsetParameterSchema, type IMindsetTool, type IMindsetToolParameter, type IModelValidationError, type IModelValidationResult, type IModelValidatorsInfo, type IMoneyData, type IPersistentData, type IPgRepositoryConfig, type IProjectRunnerConfig, type IPropertyValidatorInfo, type IQueryAst, type IQueryCondition, type IQueryMethodMetadata, type IQueryOrderBy, type IReceivedMessage, type IRemoteApiKeyFetcher, type IRepositoryAdapter, type IRepositoryConfig, type IRepositoryRuntime, type IRestControllerConfig, type IRestControllerMetadata, type IScanProjectFilesOptions, type IScheduleAt, type IScheduleDelay, type ISendWhatsAppMessageReq, type ISendWhatsAppTemplateReq, type ISocketChannelConfig, type ISocketChannelMessage, type ISocketChannelReceivedMessage, type ISocketControllerConfig, type ISocketControllerMetadata, type ISocketEventConfig, type ISocketEventMetadata, type ISocketReceivedMessage, type IStorableData, type ITelegramChannelConfig, type ITelegramChannelMessage, type ITelegramReceivedMessage, type ITransactionAdapter, type IValidateArrayOptions, type IValidateArrayOptionsWithItemsValidators, type IValidateInputShape, type IValidateIsInOptions, type IValidateIsRecordOptions, type IValidateMaxOptions, type IValidateMinOptions, type IValidationError, type IValidationResult, type IValidator, type IValidatorMetadata, type IWasenderChannelConfig, type IWasenderChannelMessageListener, type IWasenderDeviceListMetadata, type IWasenderEvent, type IWasenderMessageContent, type IWasenderMessageContextInfo, type IWasenderMessageKey, type IWasenderMessageReceivedData, type IWasenderMessageReceivedEvent, type IWasenderQrUpdatedEvent, type IWasenderReceivedMessage, type IWhatsAppCloudContact, type IWhatsAppCloudMessage, type IWhatsAppCloudMessageMetadata, type IWhatsAppCloudTemplate, type IWhatsAppCloudTemplateComponent, type IWhatsAppCloudTemplateResponse, type IWhatsAppCloudWebhookPayload, type IWhatsAppSender, type IWhatsAppTemplateData, type IWhatsAppTemplateParameter, type IchatControllerConfig, InMemoryChatMemory, InMemoryChatRepository, InMemoryCronJobRepository, InMemoryJobRepository, InMemoryLockKey, InMemoryLocker, Job, JobRepository, JobRunner, Jwt, JwtAccessAndRefreshTokenDto, JwtConfig, JwtGuardMiddleware, JwtHandshakeGuardMiddleware, JwtRefreshToken, JwtRefreshTokenRepository, JwtSigner, JwtTokenDto, Lifecycle, Locker, Logger, MEMORY_ADAPTER_ID, Mapper, MemoryRepositoryAdapter, MemoryRepositoryExtension, Mindset, MindsetMetadataStore, MindsetOperator, Money, MoneyDto, OpenRouterChatAdapter, OpenaiChatAdapter, PG_ADAPTER_ID, Password, type PasswordHashOptions, Persistent, PgApiKeyRepository, PgChatMemory, PgChatRepository, PgCronJobRepository, PgCrudRepository, PgJobRepository, PgJsonRepositoryAdapter, PgJwtRefreshTokenRepository, PgLockKey, PgLocker, PgRepositoryBase, PgRepositoryBase as PgRepositoryExtension, PgTransactionAdapter, ProjectRunner, type QueryConnector, type QueryOperator, type QueryPrefix, Random, RemoteApiKeyRepository, RepositoryAdapterRegistry, RepositoryMetadataStore, type ResolvedConfig, RestControllerMetadataStore, RestRequest, SocketChannel, SocketChannelConfig, SocketChannelMessageFile, SocketChannelReceivedMessage, SocketControllerMetadataStore, SocketServerConfig, SocketServerProvider, Storable, TelegramChannel, TelegramChannelConfig, TransactionMetadataStore, UnionChatAdapter, ValidationMetadataStore, WabotChatAdapter, WasenderChannel, WasenderChannelConfig, WasenderReceiver, WasenderSender, WasenderWebhookController, WhatsAppApiSender, WhatsAppReceiverByCloudApi, WhatsAppSender, apiKeyGuard, apiKeyHandshakeGuard, bool, boolArr, buildQuerySql, chatAdapter, chatBot, chatController, chatItemTypeOptions, cmd, cmdChannelName, cmdChannelSocketPath, command, commandHandler, container, cronHandler, description, errorToPlainObject, evaluateQueryAst, extractChatMessageText, extractNumberFromWasenderMessageKey, getClientMap, getPgClient, handshakeMiddlewares, inject, injectable, isArray, isBoolean, isChatMessageEmpty, isDate, isIn, isModel, isNotEmpty, isNumber, isOptional, isPresent, isRecord, isRetryableError, isString, jwtGuard, jwtHandshakeGuard, markdownToTelegramHtml, max, memExtension, middleware, min, mindset, mindsetModule, modelInfo, num, numArr, obj, onDelete, onGet, onPost, onPut, onSocketEvent, parseQueryMethodName, pgExtension, pgStorage, query, queryExtension, readJsonFromFile, repository, resolveConfigReferences, restController, run, runChatAdapters, runChatControllers, runCmdClient, runCommandHandlers, runCronHandlers, runRestControllers, runSocketControllers, safeJsonParse, scanProjectFiles, scoped, setupErrorHandlers, singleton, socket, socketChannelName, socketController, stopCommandHandlers, stopCronHandlers, str, strArr, telegram, telegramChannelName, transaction, validateAndTransform, validateArray, validateIsBoolean, validateIsDate, validateIsIn, validateIsNotEmpty, validateIsNumber, validateIsPresent, validateIsRecord, validateIsString, validateMax, validateMin, validateModel, wasender, wasenderChannelName, withPgClient, withPgTransaction, writeJsonToFile };
|
|
2680
|
+
export { AnthropicChatAdapter, ApiKey, ApiKeyGuardMiddleware, ApiKeyHandshakeGuardMiddleware, ApiKeyRepository, Async, AsyncMetadataStore, Auth, Chat, ChatAdapter, ChatAdapterMetadataStore, ChatAdapterRegistry, ChatBot, ChatBotMetadataStore, ChatItem, ChatMemory, ChatOperator, ChatRepository, ChatResolver, type ClientMap, CmdChannel, CmdChannelConfig, CmdChannelServer, type CmdClientMessage, type CmdServerMessage, type ConfigReference, type ConfigReferenceType, ConfigResolver, Container, ControllerMetadataStore, CronJob, CronJobRepository, CrudRepository, CustomError, DeepSeekChatAdapter, DescriptionMetadataStore, EXPRESS_REQ, EXPRESS_RES, Entity, Env, type ErrorSeverity, ExpressProvider, GoogleChatAdapter, type GoogleChatAdapterV2Options, HtmlModule, HttpServerProvider, type IApiKeyData, type IApiKeyRepository, type IArrayValidationError, type IArrayValidationResult, type IBotMessageItem, type IBuiltQuery, type IChannelMessage, type IChannelMetadata, type IChatAdapter, type IChatAdapterDecoratorConfig, type IChatAdapterMetadata, type IChatAdapterNextItemsReq, type IChatAdapterNextItemsRes, type IChatAssociation, type IChatBot, type IChatBotMetadata, type IChatChannel, type IChatConnection, type IChatControllerMetadata, type IChatData, type IChatItem, type IChatItemData, type IChatItemType, type IChatMemory, type IChatMessage, type IChatMessageDocument, type IChatMessageFile, type IChatMessageImage, type IChatMessagesPrivateFile, type IChatMessagesPublicFile, type IChatRepository, type IChatType, type ICmdChannelEntry, type ICmdChannelHandlers, type ICmdChannelMessage, type ICmdReceivedMessage, type ICommandConfig, type ICommandHandler, type ICommandHandlerConfig, type IConstructor, type ICronConfig, type ICronHandler, type ICronJobData, type ICronJobRepository, type ICrudRepository, type ICustomErrorData, type IDedupConfig, type IDescriptionMetadata, type IEndPointConfig, type IEndPointMetadata, type IEntityData, type IEnvType, type IErrorHandlersConfig, type IErrorMonitor, type IErrorMonitorContext, type IExtractChatMessageTextOptions, type IFunctionCall, type IFunctionCallItem, type IGenerateApiKeyReq, type IGenerateApiKeyRes, type IHandshakeMiddleware, type IHandshakeMiddlewareMetadata, type IHtmlModuleOptions, type IHumanMessageItem, type IJobData, type IJobOptions, type IJobRepository, type IJwtRefreshTokenData, type IJwtRefreshTokenRepository, type IKapsoChannelConfig, type IKapsoChannelMessage, type IKapsoChannelMessageListener, type IKapsoChatMessage, type IKapsoConversation, type IKapsoEvent, type IKapsoIncomingMessage, type IKapsoMessageReceivedEvent, type IKapsoReceivedMessage, type IKapsoUnknownEvent, type ILanguageModelUsage, type ILockKey, type ILocker, type ILockerKey, type IMemoryRepositoryAdapterOptions, type IMessageContext, type IMiddleware, type IMiddlewareMetadata, type IMindset, type IMindsetConfig, type IMindsetIdentity, type IMindsetLlm, type IMindsetMetadata, type IMindsetModelKind, type IMindsetModelRef, type IMindsetModels, type IMindsetModuleConfig, type IMindsetModuleMetadata, type IMindsetParameterSchema, type IMindsetTool, type IMindsetToolParameter, type IModelValidationError, type IModelValidationResult, type IModelValidatorsInfo, type IMoneyData, type IPersistentData, type IPgRepositoryConfig, type IProjectRunnerConfig, type IPropertyValidatorInfo, type IQueryAst, type IQueryCondition, type IQueryMethodMetadata, type IQueryOrderBy, type IReceivedMessage, type IRemoteApiKeyFetcher, type IRepositoryAdapter, type IRepositoryConfig, type IRepositoryRuntime, type IRestControllerConfig, type IRestControllerMetadata, type IScanProjectFilesOptions, type IScheduleAt, type IScheduleDelay, type ISendWhatsAppMessageReq, type ISendWhatsAppTemplateReq, type ISocketChannelConfig, type ISocketChannelMessage, type ISocketChannelReceivedMessage, type ISocketControllerConfig, type ISocketControllerMetadata, type ISocketEventConfig, type ISocketEventMetadata, type ISocketReceivedMessage, type IStorableData, type ITelegramChannelConfig, type ITelegramChannelMessage, type ITelegramReceivedMessage, type ITransactionAdapter, type IValidateArrayOptions, type IValidateArrayOptionsWithItemsValidators, type IValidateInputShape, type IValidateIsInOptions, type IValidateIsRecordOptions, type IValidateMaxOptions, type IValidateMinOptions, type IValidationError, type IValidationResult, type IValidator, type IValidatorMetadata, type IWasenderChannelConfig, type IWasenderChannelMessageListener, type IWasenderDeviceListMetadata, type IWasenderEvent, type IWasenderMessageContent, type IWasenderMessageContextInfo, type IWasenderMessageKey, type IWasenderMessageReceivedData, type IWasenderMessageReceivedEvent, type IWasenderQrUpdatedEvent, type IWasenderReceivedMessage, type IWhatsAppCloudContact, type IWhatsAppCloudMessage, type IWhatsAppCloudMessageMetadata, type IWhatsAppCloudTemplate, type IWhatsAppCloudTemplateComponent, type IWhatsAppCloudTemplateResponse, type IWhatsAppCloudWebhookPayload, type IWhatsAppSender, type IWhatsAppTemplateData, type IWhatsAppTemplateParameter, type IchatControllerConfig, InMemoryChatMemory, InMemoryChatRepository, InMemoryCronJobRepository, InMemoryJobRepository, InMemoryLockKey, InMemoryLocker, Job, JobRepository, JobRunner, Jwt, JwtAccessAndRefreshTokenDto, JwtConfig, JwtGuardMiddleware, JwtHandshakeGuardMiddleware, JwtRefreshToken, JwtRefreshTokenRepository, JwtSigner, JwtTokenDto, KapsoChannel, KapsoChannelConfig, KapsoReceiver, KapsoSender, KapsoWebhookController, Lifecycle, Locker, Logger, MEMORY_ADAPTER_ID, Mapper, MemoryRepositoryAdapter, MemoryRepositoryExtension, Mindset, MindsetMetadataStore, MindsetOperator, Money, MoneyDto, OpenRouterChatAdapter, OpenaiChatAdapter, PG_ADAPTER_ID, Password, type PasswordHashOptions, Persistent, PgApiKeyRepository, PgChatMemory, PgChatRepository, PgCronJobRepository, PgCrudRepository, PgJobRepository, PgJsonRepositoryAdapter, PgJwtRefreshTokenRepository, PgLockKey, PgLocker, PgRepositoryBase, PgRepositoryBase as PgRepositoryExtension, PgTransactionAdapter, ProjectRunner, type QueryConnector, type QueryOperator, type QueryPrefix, Random, RemoteApiKeyRepository, RepositoryAdapterRegistry, RepositoryMetadataStore, type ResolvedConfig, RestControllerMetadataStore, RestRequest, SocketChannel, SocketChannelConfig, SocketChannelMessageFile, SocketChannelReceivedMessage, SocketControllerMetadataStore, SocketServerConfig, SocketServerProvider, Storable, TelegramChannel, TelegramChannelConfig, TransactionMetadataStore, UnionChatAdapter, ValidationMetadataStore, WabotChatAdapter, WasenderChannel, WasenderChannelConfig, WasenderReceiver, WasenderSender, WasenderWebhookController, WhatsAppApiSender, WhatsAppReceiverByCloudApi, WhatsAppSender, apiKeyGuard, apiKeyHandshakeGuard, bool, boolArr, buildQuerySql, chatAdapter, chatBot, chatController, chatItemTypeOptions, cmd, cmdChannelName, cmdChannelSocketPath, command, commandHandler, computeDedupKey, container, cronHandler, description, errorToPlainObject, evaluateQueryAst, extractChatMessageText, extractNumberFromWasenderMessageKey, getClientMap, getPgClient, handshakeMiddlewares, inject, injectable, isArray, isBoolean, isChatMessageEmpty, isDate, isIn, isModel, isNotEmpty, isNumber, isOptional, isPresent, isRecord, isRetryableError, isString, jwtGuard, jwtHandshakeGuard, kapso, kapsoChannelName, markdownToTelegramHtml, max, memExtension, middleware, min, mindset, mindsetModule, modelInfo, num, numArr, obj, onDelete, onGet, onPost, onPut, onSocketEvent, parseQueryMethodName, pgExtension, pgStorage, query, queryExtension, readJsonFromFile, repository, resolveConfigReferences, restController, run, runChatAdapters, runChatControllers, runCmdClient, runCommandHandlers, runCronHandlers, runRestControllers, runSocketControllers, safeJsonParse, scanProjectFiles, scoped, setupErrorHandlers, singleton, socket, socketChannelName, socketController, stopCommandHandlers, stopCronHandlers, str, strArr, telegram, telegramChannelName, transaction, validateAndTransform, validateArray, validateIsBoolean, validateIsDate, validateIsIn, validateIsNotEmpty, validateIsNumber, validateIsPresent, validateIsRecord, validateIsString, validateMax, validateMin, validateModel, wasender, wasenderChannelName, withPgClient, withPgTransaction, writeJsonToFile };
|
package/dist/src/index.js
CHANGED
|
@@ -51,6 +51,7 @@ export { Async } from './feature/async/Async.js';
|
|
|
51
51
|
export { AsyncMetadataStore } from './feature/async/AsyncMetadataStore.js';
|
|
52
52
|
export { CronJob } from './feature/async/CronJob.js';
|
|
53
53
|
export { CronJobRepository } from './feature/async/CronJobRepository.js';
|
|
54
|
+
export { computeDedupKey } from './feature/async/computeDedupKey.js';
|
|
54
55
|
export { Job } from './feature/async/Job.js';
|
|
55
56
|
export { JobRepository } from './feature/async/JobRepository.js';
|
|
56
57
|
export { JobRunner } from './feature/async/JobRunner.js';
|
|
@@ -180,6 +181,13 @@ export { telegramChannelName } from './addon/chat-controller/telegram/telegramCh
|
|
|
180
181
|
export { markdownToTelegramHtml } from './addon/chat-controller/telegram/markdownToTelegramHtml.js';
|
|
181
182
|
export { WhatsAppReceiverByCloudApi } from './addon/chat-controller/whatsapp/cloud-api/WhatsAppReceiverByCloudApi.js';
|
|
182
183
|
export { WhatsAppApiSender } from './addon/chat-controller/whatsapp/cloud-api/WhatsAppApiSender.js';
|
|
184
|
+
export { kapso } from './addon/chat-controller/whatsapp/kapso/@kapso.js';
|
|
185
|
+
export { KapsoChannel } from './addon/chat-controller/whatsapp/kapso/KapsoChannel.js';
|
|
186
|
+
export { KapsoChannelConfig } from './addon/chat-controller/whatsapp/kapso/KapsoChannelConfig.js';
|
|
187
|
+
export { kapsoChannelName } from './addon/chat-controller/whatsapp/kapso/KapsoChannelName.js';
|
|
188
|
+
export { KapsoReceiver } from './addon/chat-controller/whatsapp/kapso/KapsoReceiver.js';
|
|
189
|
+
export { KapsoSender } from './addon/chat-controller/whatsapp/kapso/KapsoSender.js';
|
|
190
|
+
export { KapsoWebhookController } from './addon/chat-controller/whatsapp/kapso/KapsoWebhookController.js';
|
|
183
191
|
export { wasender } from './addon/chat-controller/whatsapp/wasender/@wasender.js';
|
|
184
192
|
export { WasenderChannel } from './addon/chat-controller/whatsapp/wasender/WasenderChannel.js';
|
|
185
193
|
export { WasenderChannelConfig } from './addon/chat-controller/whatsapp/wasender/WasenderChannelConfig.js';
|