@igoruehara/canvas-flow 0.1.12 → 0.1.14
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/README.md +15 -0
- package/bin/canvas-flow.js +113 -3
- package/package.json +1 -1
- package/public/assets/index-BUVXJRGV.js +767 -0
- package/public/assets/{index-PCQkqMUe.css → index-D-m2588h.css} +1 -1
- package/public/index.html +2 -2
- package/server/provider-config/provider-config-controller.d.ts +35 -0
- package/server/provider-config/provider-config-controller.js +15 -0
- package/server/provider-config/provider-config-controller.js.map +1 -1
- package/server/provider-config/provider-config-service.d.ts +54 -0
- package/server/provider-config/provider-config-service.js +251 -11
- package/server/provider-config/provider-config-service.js.map +1 -1
- package/server/queue/sqs-transition-service.js +6 -0
- package/server/queue/sqs-transition-service.js.map +1 -1
- package/server/rag/rag-service.d.ts +4 -2
- package/server/rag/rag-service.js +44 -25
- package/server/rag/rag-service.js.map +1 -1
- package/server/runner/runner-controller.d.ts +8 -0
- package/server/runner/runner-service.d.ts +20 -0
- package/server/runner/runner-service.js +295 -13
- package/server/runner/runner-service.js.map +1 -1
- package/templates/config.example.json +11 -0
- package/templates/config.production.example.json +11 -0
- package/public/assets/index-CAYKh0bn.js +0 -767
package/public/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Canvas Flow</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-BUVXJRGV.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-D-m2588h.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
|
@@ -15,6 +15,41 @@ export declare class ProviderConfigController {
|
|
|
15
15
|
settings: any;
|
|
16
16
|
secretStatus: Record<string, boolean>;
|
|
17
17
|
}>;
|
|
18
|
+
completeWhatsappEmbeddedSignup(body: any, agentId?: string, authorization?: string, headerToken?: string, xApiKey?: string): Promise<{
|
|
19
|
+
onboarding: {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
coexistenceEnabled: boolean;
|
|
22
|
+
businessAccountId: string;
|
|
23
|
+
phoneNumberId: string;
|
|
24
|
+
phoneNumber: string;
|
|
25
|
+
tokenExchange: any;
|
|
26
|
+
subscribe: {
|
|
27
|
+
skipped: boolean;
|
|
28
|
+
reason: string;
|
|
29
|
+
ok?: undefined;
|
|
30
|
+
status?: undefined;
|
|
31
|
+
error?: undefined;
|
|
32
|
+
body?: undefined;
|
|
33
|
+
} | {
|
|
34
|
+
ok: boolean;
|
|
35
|
+
status: number;
|
|
36
|
+
error: any;
|
|
37
|
+
body: any;
|
|
38
|
+
skipped?: undefined;
|
|
39
|
+
reason?: undefined;
|
|
40
|
+
} | {
|
|
41
|
+
ok: boolean;
|
|
42
|
+
status: number;
|
|
43
|
+
body: any;
|
|
44
|
+
skipped?: undefined;
|
|
45
|
+
reason?: undefined;
|
|
46
|
+
error?: undefined;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
providerStatus?: Record<import("./provider-config-service").ProviderConfigSection, any>;
|
|
50
|
+
settings: any;
|
|
51
|
+
secretStatus: Record<string, boolean>;
|
|
52
|
+
}>;
|
|
18
53
|
clearConfigSection(section: string, agentId?: string, authorization?: string, headerToken?: string, xApiKey?: string): Promise<{
|
|
19
54
|
providerStatus?: Record<import("./provider-config-service").ProviderConfigSection, any>;
|
|
20
55
|
settings: any;
|
|
@@ -33,6 +33,10 @@ let ProviderConfigController = class ProviderConfigController {
|
|
|
33
33
|
const user = await this.assertAuth(authorization, headerToken, xApiKey);
|
|
34
34
|
return await this.service.updateSettings(body?.settings || body || {}, user?.id, body?.agentId || agentId);
|
|
35
35
|
}
|
|
36
|
+
async completeWhatsappEmbeddedSignup(body, agentId, authorization, headerToken, xApiKey) {
|
|
37
|
+
const user = await this.assertAuth(authorization, headerToken, xApiKey);
|
|
38
|
+
return await this.service.completeWhatsappEmbeddedSignup(body || {}, user?.id, body?.agentId || agentId);
|
|
39
|
+
}
|
|
36
40
|
async clearConfigSection(section, agentId, authorization, headerToken, xApiKey) {
|
|
37
41
|
const user = await this.assertAuth(authorization, headerToken, xApiKey);
|
|
38
42
|
return await this.service.clearSection(section, user?.id, agentId);
|
|
@@ -60,6 +64,17 @@ __decorate([
|
|
|
60
64
|
__metadata("design:paramtypes", [Object, String, String, String, String]),
|
|
61
65
|
__metadata("design:returntype", Promise)
|
|
62
66
|
], ProviderConfigController.prototype, "updateConfig", null);
|
|
67
|
+
__decorate([
|
|
68
|
+
(0, common_1.Post)('whatsapp/embedded-signup'),
|
|
69
|
+
__param(0, (0, common_1.Body)()),
|
|
70
|
+
__param(1, (0, common_1.Query)('agentId')),
|
|
71
|
+
__param(2, (0, common_1.Headers)('authorization')),
|
|
72
|
+
__param(3, (0, common_1.Headers)('x-canvas-flow-token')),
|
|
73
|
+
__param(4, (0, common_1.Headers)('x-api-key')),
|
|
74
|
+
__metadata("design:type", Function),
|
|
75
|
+
__metadata("design:paramtypes", [Object, String, String, String, String]),
|
|
76
|
+
__metadata("design:returntype", Promise)
|
|
77
|
+
], ProviderConfigController.prototype, "completeWhatsappEmbeddedSignup", null);
|
|
63
78
|
__decorate([
|
|
64
79
|
(0, common_1.Delete)(':section'),
|
|
65
80
|
__param(0, (0, common_1.Param)('section')),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-config-controller.js","sourceRoot":"","sources":["../../src/provider-config/provider-config-controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"provider-config-controller.js","sourceRoot":"","sources":["../../src/provider-config/provider-config-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -104,12 +104,23 @@ export interface ProviderSettings {
|
|
|
104
104
|
whatsapp: {
|
|
105
105
|
provider: 'meta' | 'blip' | 'sinch';
|
|
106
106
|
deliveryMode: 'provider' | 'apiResponse';
|
|
107
|
+
onboardingMode: 'manual' | 'embeddedSignup' | 'coexistence';
|
|
107
108
|
autoReply: boolean;
|
|
108
109
|
verifyToken: string;
|
|
109
110
|
businessAccountId: string;
|
|
110
111
|
phoneNumberId: string;
|
|
111
112
|
accessToken: string;
|
|
112
113
|
graphApiVersion: string;
|
|
114
|
+
coexistenceEnabled: boolean;
|
|
115
|
+
syncMessageEchoes: boolean;
|
|
116
|
+
syncHistory: boolean;
|
|
117
|
+
embeddedSignupAppId: string;
|
|
118
|
+
embeddedSignupConfigId: string;
|
|
119
|
+
embeddedSignupAppSecret: string;
|
|
120
|
+
embeddedSignupSolutionId: string;
|
|
121
|
+
embeddedSignupFeatureType: string;
|
|
122
|
+
embeddedSignupSessionInfoVersion: string;
|
|
123
|
+
embeddedSignupVersion: string;
|
|
113
124
|
blipContractId: string;
|
|
114
125
|
blipAuthorizationKey: string;
|
|
115
126
|
sinchProjectId: string;
|
|
@@ -152,6 +163,8 @@ export declare class ProviderConfigService {
|
|
|
152
163
|
private hasClaudeConfig;
|
|
153
164
|
private hasGrokConfig;
|
|
154
165
|
private hasBedrockConfig;
|
|
166
|
+
private hasMeaningfulOverride;
|
|
167
|
+
private hasSectionOverride;
|
|
155
168
|
private hasSectionConfig;
|
|
156
169
|
private buildProviderStatus;
|
|
157
170
|
private hasEnvWebWidgetConfig;
|
|
@@ -164,6 +177,47 @@ export declare class ProviderConfigService {
|
|
|
164
177
|
settings: any;
|
|
165
178
|
secretStatus: Record<string, boolean>;
|
|
166
179
|
}>;
|
|
180
|
+
private normalizeWhatsappGraphApiVersion;
|
|
181
|
+
private parseGraphResponse;
|
|
182
|
+
private exchangeWhatsappEmbeddedSignupCode;
|
|
183
|
+
private getWhatsappPhoneNumber;
|
|
184
|
+
private findWhatsappPhoneNumber;
|
|
185
|
+
private subscribeWhatsappWaba;
|
|
186
|
+
completeWhatsappEmbeddedSignup(body: any, updatedBy?: string, agentId?: string): Promise<{
|
|
187
|
+
onboarding: {
|
|
188
|
+
ok: boolean;
|
|
189
|
+
coexistenceEnabled: boolean;
|
|
190
|
+
businessAccountId: string;
|
|
191
|
+
phoneNumberId: string;
|
|
192
|
+
phoneNumber: string;
|
|
193
|
+
tokenExchange: any;
|
|
194
|
+
subscribe: {
|
|
195
|
+
skipped: boolean;
|
|
196
|
+
reason: string;
|
|
197
|
+
ok?: undefined;
|
|
198
|
+
status?: undefined;
|
|
199
|
+
error?: undefined;
|
|
200
|
+
body?: undefined;
|
|
201
|
+
} | {
|
|
202
|
+
ok: boolean;
|
|
203
|
+
status: number;
|
|
204
|
+
error: any;
|
|
205
|
+
body: any;
|
|
206
|
+
skipped?: undefined;
|
|
207
|
+
reason?: undefined;
|
|
208
|
+
} | {
|
|
209
|
+
ok: boolean;
|
|
210
|
+
status: number;
|
|
211
|
+
body: any;
|
|
212
|
+
skipped?: undefined;
|
|
213
|
+
reason?: undefined;
|
|
214
|
+
error?: undefined;
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
providerStatus?: Record<ProviderConfigSection, any>;
|
|
218
|
+
settings: any;
|
|
219
|
+
secretStatus: Record<string, boolean>;
|
|
220
|
+
}>;
|
|
167
221
|
updateSettings(patch: any, updatedBy?: string, agentId?: string): Promise<{
|
|
168
222
|
providerStatus?: Record<ProviderConfigSection, any>;
|
|
169
223
|
settings: any;
|
|
@@ -31,10 +31,17 @@ const SECRET_PATHS = new Set([
|
|
|
31
31
|
'azureSearch.apiKey',
|
|
32
32
|
'mongodb.connectionString',
|
|
33
33
|
'whatsapp.accessToken',
|
|
34
|
+
'whatsapp.embeddedSignupAppSecret',
|
|
34
35
|
'whatsapp.blipAuthorizationKey',
|
|
35
36
|
'whatsapp.sinchAccessToken',
|
|
36
37
|
'whatsapp.sinchServiceToken',
|
|
37
38
|
]);
|
|
39
|
+
const SINERGY_WHATSAPP_COEXISTENCE_PRESET = {
|
|
40
|
+
embeddedSignupAppId: '617497366521622',
|
|
41
|
+
embeddedSignupConfigId: '1952866105586018',
|
|
42
|
+
embeddedSignupSessionInfoVersion: '3',
|
|
43
|
+
embeddedSignupVersion: 'v3',
|
|
44
|
+
};
|
|
38
45
|
let ProviderConfigService = class ProviderConfigService {
|
|
39
46
|
constructor(model, configService) {
|
|
40
47
|
this.model = model;
|
|
@@ -174,6 +181,7 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
174
181
|
whatsapp: {
|
|
175
182
|
provider: this.configService.get('WHATSAPP_PROVIDER') || 'meta',
|
|
176
183
|
deliveryMode: this.configService.get('WHATSAPP_DELIVERY_MODE') || 'provider',
|
|
184
|
+
onboardingMode: this.configService.get('WHATSAPP_ONBOARDING_MODE') || 'manual',
|
|
177
185
|
autoReply: this.configService.get('WHATSAPP_AUTO_REPLY') === undefined
|
|
178
186
|
? true
|
|
179
187
|
: this.envFlag(this.configService.get('WHATSAPP_AUTO_REPLY')),
|
|
@@ -182,6 +190,18 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
182
190
|
phoneNumberId: this.configService.get('WHATSAPP_PHONE_NUMBER_ID') || '',
|
|
183
191
|
accessToken: this.configService.get('WHATSAPP_ACCESS_TOKEN') || '',
|
|
184
192
|
graphApiVersion: this.configService.get('WHATSAPP_GRAPH_API_VERSION') || 'v20.0',
|
|
193
|
+
coexistenceEnabled: this.envFlag(this.configService.get('WHATSAPP_COEXISTENCE_ENABLED')),
|
|
194
|
+
syncMessageEchoes: this.configService.get('WHATSAPP_SYNC_MESSAGE_ECHOES') === undefined
|
|
195
|
+
? true
|
|
196
|
+
: this.envFlag(this.configService.get('WHATSAPP_SYNC_MESSAGE_ECHOES')),
|
|
197
|
+
syncHistory: this.envFlag(this.configService.get('WHATSAPP_SYNC_HISTORY')),
|
|
198
|
+
embeddedSignupAppId: this.configService.get('WHATSAPP_EMBEDDED_SIGNUP_APP_ID') || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupAppId,
|
|
199
|
+
embeddedSignupConfigId: this.configService.get('WHATSAPP_EMBEDDED_SIGNUP_CONFIG_ID') || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupConfigId,
|
|
200
|
+
embeddedSignupAppSecret: this.configService.get('WHATSAPP_EMBEDDED_SIGNUP_APP_SECRET') || '',
|
|
201
|
+
embeddedSignupSolutionId: this.configService.get('WHATSAPP_EMBEDDED_SIGNUP_SOLUTION_ID') || '',
|
|
202
|
+
embeddedSignupFeatureType: this.configService.get('WHATSAPP_EMBEDDED_SIGNUP_FEATURE_TYPE') || '',
|
|
203
|
+
embeddedSignupSessionInfoVersion: this.configService.get('WHATSAPP_EMBEDDED_SIGNUP_SESSION_INFO_VERSION') || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupSessionInfoVersion,
|
|
204
|
+
embeddedSignupVersion: this.configService.get('WHATSAPP_EMBEDDED_SIGNUP_VERSION') || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupVersion,
|
|
185
205
|
blipContractId: this.configService.get('BLIP_CONTRACT_ID') || '',
|
|
186
206
|
blipAuthorizationKey: this.configService.get('BLIP_AUTHORIZATION_KEY') || '',
|
|
187
207
|
sinchProjectId: this.configService.get('SINCH_PROJECT_ID') || '',
|
|
@@ -274,6 +294,9 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
274
294
|
if (clean.whatsapp?.deliveryMode && !['provider', 'apiResponse'].includes(clean.whatsapp.deliveryMode)) {
|
|
275
295
|
throw new common_1.BadRequestException('whatsapp.deliveryMode invalido.');
|
|
276
296
|
}
|
|
297
|
+
if (clean.whatsapp?.onboardingMode && !['manual', 'embeddedSignup', 'coexistence'].includes(clean.whatsapp.onboardingMode)) {
|
|
298
|
+
throw new common_1.BadRequestException('whatsapp.onboardingMode invalido.');
|
|
299
|
+
}
|
|
277
300
|
if (clean.whatsapp?.sinchApiMode && !['conversation', 'relay'].includes(clean.whatsapp.sinchApiMode)) {
|
|
278
301
|
throw new common_1.BadRequestException('whatsapp.sinchApiMode invalido.');
|
|
279
302
|
}
|
|
@@ -327,6 +350,23 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
327
350
|
hasBedrockConfig(settings) {
|
|
328
351
|
return Boolean(String(settings.bedrock?.apiKey || '').trim() && String(settings.bedrock?.baseUrl || '').trim());
|
|
329
352
|
}
|
|
353
|
+
hasMeaningfulOverride(value) {
|
|
354
|
+
if (value === undefined || value === null || value === '')
|
|
355
|
+
return false;
|
|
356
|
+
if (Array.isArray(value))
|
|
357
|
+
return value.some((item) => this.hasMeaningfulOverride(item));
|
|
358
|
+
if (typeof value === 'object') {
|
|
359
|
+
return Object.values(value).some((item) => this.hasMeaningfulOverride(item));
|
|
360
|
+
}
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
hasSectionOverride(section, settings) {
|
|
364
|
+
if (!settings || typeof settings !== 'object')
|
|
365
|
+
return false;
|
|
366
|
+
if (!Object.prototype.hasOwnProperty.call(settings, section))
|
|
367
|
+
return false;
|
|
368
|
+
return this.hasMeaningfulOverride(settings[section]);
|
|
369
|
+
}
|
|
330
370
|
hasSectionConfig(section, settings) {
|
|
331
371
|
if (!settings || typeof settings !== 'object')
|
|
332
372
|
return false;
|
|
@@ -385,24 +425,34 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
385
425
|
buildProviderStatus(params) {
|
|
386
426
|
const sections = ['openai', 'azureOpenai', 'gemini', 'claude', 'grok', 'bedrock', 'milvus', 'azureBlob', 'azureSearch', 'mongodb', 'webWidget', 'whatsapp'];
|
|
387
427
|
const envSettings = params.envSettings || this.getEnvSettings();
|
|
428
|
+
const globalStored = params.globalStored || {};
|
|
429
|
+
const scopedStored = params.scopedStored || {};
|
|
430
|
+
const globalEffective = this.deepMergeFallback(envSettings, globalStored);
|
|
431
|
+
const scopedEffective = this.deepMergeFallback(globalEffective, scopedStored);
|
|
388
432
|
const status = {};
|
|
389
433
|
const scoped = String(params.agentId || '').trim();
|
|
390
434
|
sections.forEach((section) => {
|
|
391
|
-
const
|
|
392
|
-
const
|
|
435
|
+
const agentOverride = scoped ? this.hasSectionOverride(section, scopedStored) : false;
|
|
436
|
+
const globalOverride = this.hasSectionOverride(section, globalStored);
|
|
393
437
|
const envConfigured = section === 'webWidget' ? this.hasEnvWebWidgetConfig() : this.hasSectionConfig(section, envSettings);
|
|
438
|
+
const effectiveSettings = scoped ? scopedEffective : globalEffective;
|
|
439
|
+
const configured = section === 'webWidget'
|
|
440
|
+
? agentOverride || globalOverride || envConfigured
|
|
441
|
+
: this.hasSectionConfig(section, effectiveSettings);
|
|
394
442
|
let source = 'none';
|
|
395
|
-
if (
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
443
|
+
if (configured) {
|
|
444
|
+
if (agentOverride)
|
|
445
|
+
source = 'agent';
|
|
446
|
+
else if (globalOverride)
|
|
447
|
+
source = 'global';
|
|
448
|
+
else if (envConfigured)
|
|
449
|
+
source = 'env';
|
|
450
|
+
}
|
|
401
451
|
status[section] = {
|
|
402
|
-
configured
|
|
452
|
+
configured,
|
|
403
453
|
source,
|
|
404
|
-
scopeConfigured: scoped ?
|
|
405
|
-
inherited: scoped ? !
|
|
454
|
+
scopeConfigured: scoped ? agentOverride : globalOverride,
|
|
455
|
+
inherited: scoped ? !agentOverride && source !== 'none' : !globalOverride && source === 'env',
|
|
406
456
|
};
|
|
407
457
|
});
|
|
408
458
|
return status;
|
|
@@ -456,6 +506,16 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
456
506
|
else if (bedrockConfigured)
|
|
457
507
|
next.llmProvider = 'bedrock';
|
|
458
508
|
}
|
|
509
|
+
const whatsapp = next.whatsapp || {};
|
|
510
|
+
const onboardingMode = String(whatsapp.onboardingMode || 'manual');
|
|
511
|
+
whatsapp.onboardingMode = ['manual', 'embeddedSignup', 'coexistence'].includes(onboardingMode)
|
|
512
|
+
? onboardingMode
|
|
513
|
+
: 'manual';
|
|
514
|
+
whatsapp.coexistenceEnabled = whatsapp.onboardingMode === 'coexistence' || whatsapp.coexistenceEnabled === true;
|
|
515
|
+
whatsapp.syncMessageEchoes = whatsapp.syncMessageEchoes !== false;
|
|
516
|
+
whatsapp.syncHistory = whatsapp.syncHistory === true;
|
|
517
|
+
whatsapp.embeddedSignupSessionInfoVersion = String(whatsapp.embeddedSignupSessionInfoVersion || '3');
|
|
518
|
+
next.whatsapp = whatsapp;
|
|
459
519
|
return next;
|
|
460
520
|
}
|
|
461
521
|
blankSection(section) {
|
|
@@ -537,12 +597,23 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
537
597
|
whatsapp: {
|
|
538
598
|
provider: 'meta',
|
|
539
599
|
deliveryMode: 'provider',
|
|
600
|
+
onboardingMode: 'manual',
|
|
540
601
|
autoReply: true,
|
|
541
602
|
verifyToken: '',
|
|
542
603
|
businessAccountId: '',
|
|
543
604
|
phoneNumberId: '',
|
|
544
605
|
accessToken: '',
|
|
545
606
|
graphApiVersion: defaults.whatsapp.graphApiVersion || 'v20.0',
|
|
607
|
+
coexistenceEnabled: false,
|
|
608
|
+
syncMessageEchoes: true,
|
|
609
|
+
syncHistory: false,
|
|
610
|
+
embeddedSignupAppId: defaults.whatsapp.embeddedSignupAppId || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupAppId,
|
|
611
|
+
embeddedSignupConfigId: defaults.whatsapp.embeddedSignupConfigId || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupConfigId,
|
|
612
|
+
embeddedSignupAppSecret: '',
|
|
613
|
+
embeddedSignupSolutionId: defaults.whatsapp.embeddedSignupSolutionId || '',
|
|
614
|
+
embeddedSignupFeatureType: defaults.whatsapp.embeddedSignupFeatureType || '',
|
|
615
|
+
embeddedSignupSessionInfoVersion: defaults.whatsapp.embeddedSignupSessionInfoVersion || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupSessionInfoVersion,
|
|
616
|
+
embeddedSignupVersion: defaults.whatsapp.embeddedSignupVersion || SINERGY_WHATSAPP_COEXISTENCE_PRESET.embeddedSignupVersion,
|
|
546
617
|
blipContractId: '',
|
|
547
618
|
blipAuthorizationKey: '',
|
|
548
619
|
sinchProjectId: '',
|
|
@@ -600,6 +671,175 @@ let ProviderConfigService = class ProviderConfigService {
|
|
|
600
671
|
}
|
|
601
672
|
return this.maskSafe(await this.getEffectiveSettings(agentId), this.buildProviderStatus({ agentId, globalStored, scopedStored, envSettings: this.getEnvSettings() }));
|
|
602
673
|
}
|
|
674
|
+
normalizeWhatsappGraphApiVersion(value) {
|
|
675
|
+
const raw = String(value || 'v20.0').trim() || 'v20.0';
|
|
676
|
+
return raw.startsWith('v') ? raw : `v${raw}`;
|
|
677
|
+
}
|
|
678
|
+
async parseGraphResponse(response) {
|
|
679
|
+
const body = await response.json().catch(() => ({}));
|
|
680
|
+
if (response.ok)
|
|
681
|
+
return body;
|
|
682
|
+
const message = body?.error?.message || body?.message || `Meta Graph API HTTP ${response.status}`;
|
|
683
|
+
const error = new common_1.BadRequestException(message);
|
|
684
|
+
error.graphBody = body;
|
|
685
|
+
error.graphStatus = response.status;
|
|
686
|
+
throw error;
|
|
687
|
+
}
|
|
688
|
+
async exchangeWhatsappEmbeddedSignupCode(params) {
|
|
689
|
+
const buildUrl = (includeRedirectUri) => {
|
|
690
|
+
const url = new URL(`https://graph.facebook.com/${params.graphApiVersion}/oauth/access_token`);
|
|
691
|
+
url.searchParams.set('client_id', params.appId);
|
|
692
|
+
url.searchParams.set('client_secret', params.appSecret);
|
|
693
|
+
url.searchParams.set('code', params.code);
|
|
694
|
+
if (includeRedirectUri && params.redirectUri)
|
|
695
|
+
url.searchParams.set('redirect_uri', params.redirectUri);
|
|
696
|
+
return url;
|
|
697
|
+
};
|
|
698
|
+
try {
|
|
699
|
+
const response = await fetch(buildUrl(Boolean(params.redirectUri)).toString());
|
|
700
|
+
return await this.parseGraphResponse(response);
|
|
701
|
+
}
|
|
702
|
+
catch (error) {
|
|
703
|
+
if (!params.redirectUri)
|
|
704
|
+
throw error;
|
|
705
|
+
const response = await fetch(buildUrl(false).toString());
|
|
706
|
+
return await this.parseGraphResponse(response);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
async getWhatsappPhoneNumber(phoneNumberId, accessToken, graphApiVersion) {
|
|
710
|
+
if (!phoneNumberId || !accessToken)
|
|
711
|
+
return null;
|
|
712
|
+
const url = new URL(`https://graph.facebook.com/${graphApiVersion}/${encodeURIComponent(phoneNumberId)}`);
|
|
713
|
+
url.searchParams.set('fields', 'id,display_phone_number,verified_name,whatsapp_business_account');
|
|
714
|
+
const response = await fetch(url.toString(), {
|
|
715
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
716
|
+
});
|
|
717
|
+
return await this.parseGraphResponse(response).catch(() => null);
|
|
718
|
+
}
|
|
719
|
+
async findWhatsappPhoneNumber(wabaId, accessToken, graphApiVersion) {
|
|
720
|
+
if (!wabaId || !accessToken)
|
|
721
|
+
return null;
|
|
722
|
+
const url = new URL(`https://graph.facebook.com/${graphApiVersion}/${encodeURIComponent(wabaId)}/phone_numbers`);
|
|
723
|
+
url.searchParams.set('fields', 'id,display_phone_number,verified_name');
|
|
724
|
+
const response = await fetch(url.toString(), {
|
|
725
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
726
|
+
});
|
|
727
|
+
const body = await this.parseGraphResponse(response).catch(() => null);
|
|
728
|
+
return Array.isArray(body?.data) ? body.data[0] || null : null;
|
|
729
|
+
}
|
|
730
|
+
async subscribeWhatsappWaba(wabaId, accessToken, graphApiVersion) {
|
|
731
|
+
if (!wabaId || !accessToken)
|
|
732
|
+
return { skipped: true, reason: 'missing_waba_or_token' };
|
|
733
|
+
const response = await fetch(`https://graph.facebook.com/${graphApiVersion}/${encodeURIComponent(wabaId)}/subscribed_apps`, {
|
|
734
|
+
method: 'POST',
|
|
735
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
736
|
+
});
|
|
737
|
+
const body = await response.json().catch(() => ({}));
|
|
738
|
+
if (!response.ok) {
|
|
739
|
+
return {
|
|
740
|
+
ok: false,
|
|
741
|
+
status: response.status,
|
|
742
|
+
error: body?.error?.message || body?.message || `Meta Graph API HTTP ${response.status}`,
|
|
743
|
+
body,
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
return { ok: true, status: response.status, body };
|
|
747
|
+
}
|
|
748
|
+
async completeWhatsappEmbeddedSignup(body, updatedBy, agentId) {
|
|
749
|
+
if (this.model.db.readyState !== 1) {
|
|
750
|
+
throw new common_1.BadRequestException('MongoDB ainda nao esta conectado para salvar configuracoes.');
|
|
751
|
+
}
|
|
752
|
+
const effective = await this.getEffectiveSettings(agentId);
|
|
753
|
+
const whatsapp = effective.whatsapp || this.getEnvSettings().whatsapp;
|
|
754
|
+
const graphApiVersion = this.normalizeWhatsappGraphApiVersion(body?.graphApiVersion || whatsapp.graphApiVersion);
|
|
755
|
+
const appId = String(body?.appId || whatsapp.embeddedSignupAppId || '').trim();
|
|
756
|
+
const appSecret = String(body?.appSecret || whatsapp.embeddedSignupAppSecret || '').trim();
|
|
757
|
+
const code = String(body?.code || '').trim();
|
|
758
|
+
let accessToken = String(whatsapp.accessToken || '').trim();
|
|
759
|
+
let tokenExchange = { skipped: true, reason: 'missing_code_or_app_secret' };
|
|
760
|
+
if (code && appId && appSecret) {
|
|
761
|
+
const tokenResult = await this.exchangeWhatsappEmbeddedSignupCode({
|
|
762
|
+
appId,
|
|
763
|
+
appSecret,
|
|
764
|
+
code,
|
|
765
|
+
graphApiVersion,
|
|
766
|
+
redirectUri: String(body?.redirectUri || '').trim() || undefined,
|
|
767
|
+
});
|
|
768
|
+
accessToken = String(tokenResult?.access_token || accessToken || '').trim();
|
|
769
|
+
tokenExchange = {
|
|
770
|
+
ok: Boolean(accessToken),
|
|
771
|
+
tokenType: tokenResult?.token_type,
|
|
772
|
+
expiresIn: tokenResult?.expires_in,
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
let businessAccountId = String(body?.wabaId ||
|
|
776
|
+
body?.waba_id ||
|
|
777
|
+
body?.businessAccountId ||
|
|
778
|
+
whatsapp.businessAccountId ||
|
|
779
|
+
'').trim();
|
|
780
|
+
let phoneNumberId = String(body?.phoneNumberId ||
|
|
781
|
+
body?.phone_number_id ||
|
|
782
|
+
whatsapp.phoneNumberId ||
|
|
783
|
+
'').trim();
|
|
784
|
+
let phoneNumber = String(body?.phoneNumber || body?.displayPhoneNumber || '').trim();
|
|
785
|
+
if (phoneNumberId && accessToken) {
|
|
786
|
+
const phoneNumberInfo = await this.getWhatsappPhoneNumber(phoneNumberId, accessToken, graphApiVersion);
|
|
787
|
+
if (!phoneNumber)
|
|
788
|
+
phoneNumber = String(phoneNumberInfo?.display_phone_number || '').trim();
|
|
789
|
+
if (!businessAccountId) {
|
|
790
|
+
businessAccountId = String(phoneNumberInfo?.whatsapp_business_account?.id ||
|
|
791
|
+
phoneNumberInfo?.whatsapp_business_account ||
|
|
792
|
+
'').trim();
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
if (!phoneNumberId && businessAccountId && accessToken) {
|
|
796
|
+
const phoneNumberInfo = await this.findWhatsappPhoneNumber(businessAccountId, accessToken, graphApiVersion);
|
|
797
|
+
phoneNumberId = String(phoneNumberInfo?.id || '').trim();
|
|
798
|
+
phoneNumber = phoneNumber || String(phoneNumberInfo?.display_phone_number || '').trim();
|
|
799
|
+
}
|
|
800
|
+
if (!businessAccountId && !phoneNumberId) {
|
|
801
|
+
throw new common_1.BadRequestException('Embedded Signup nao retornou WABA ID nem Phone Number ID.');
|
|
802
|
+
}
|
|
803
|
+
const coexistenceEnabled = body?.coexistenceEnabled === true || whatsapp.coexistenceEnabled === true || whatsapp.onboardingMode === 'coexistence';
|
|
804
|
+
const subscribe = body?.subscribeWebhooks === false
|
|
805
|
+
? { skipped: true, reason: 'disabled' }
|
|
806
|
+
: await this.subscribeWhatsappWaba(businessAccountId, accessToken, graphApiVersion);
|
|
807
|
+
const settingsPatch = {
|
|
808
|
+
whatsapp: {
|
|
809
|
+
provider: 'meta',
|
|
810
|
+
deliveryMode: whatsapp.deliveryMode || 'provider',
|
|
811
|
+
onboardingMode: coexistenceEnabled ? 'coexistence' : 'embeddedSignup',
|
|
812
|
+
coexistenceEnabled,
|
|
813
|
+
syncMessageEchoes: coexistenceEnabled ? true : whatsapp.syncMessageEchoes !== false,
|
|
814
|
+
syncHistory: whatsapp.syncHistory === true,
|
|
815
|
+
businessAccountId,
|
|
816
|
+
phoneNumberId,
|
|
817
|
+
accessToken,
|
|
818
|
+
graphApiVersion,
|
|
819
|
+
embeddedSignupAppId: appId || whatsapp.embeddedSignupAppId || '',
|
|
820
|
+
embeddedSignupConfigId: String(body?.configId || body?.configurationId || whatsapp.embeddedSignupConfigId || '').trim(),
|
|
821
|
+
embeddedSignupSolutionId: String(body?.solutionId || whatsapp.embeddedSignupSolutionId || '').trim(),
|
|
822
|
+
embeddedSignupFeatureType: String(body?.featureType || whatsapp.embeddedSignupFeatureType || '').trim(),
|
|
823
|
+
embeddedSignupSessionInfoVersion: String(body?.sessionInfoVersion || whatsapp.embeddedSignupSessionInfoVersion || '3').trim(),
|
|
824
|
+
embeddedSignupVersion: String(body?.embeddedSignupVersion || whatsapp.embeddedSignupVersion || '').trim(),
|
|
825
|
+
},
|
|
826
|
+
};
|
|
827
|
+
if (appSecret)
|
|
828
|
+
settingsPatch.whatsapp.embeddedSignupAppSecret = appSecret;
|
|
829
|
+
const safe = await this.updateSettings(settingsPatch, updatedBy, agentId);
|
|
830
|
+
return {
|
|
831
|
+
...safe,
|
|
832
|
+
onboarding: {
|
|
833
|
+
ok: true,
|
|
834
|
+
coexistenceEnabled,
|
|
835
|
+
businessAccountId,
|
|
836
|
+
phoneNumberId,
|
|
837
|
+
phoneNumber,
|
|
838
|
+
tokenExchange,
|
|
839
|
+
subscribe,
|
|
840
|
+
},
|
|
841
|
+
};
|
|
842
|
+
}
|
|
603
843
|
async updateSettings(patch, updatedBy, agentId) {
|
|
604
844
|
if (this.model.db.readyState !== 1) {
|
|
605
845
|
throw new common_1.BadRequestException('MongoDB ainda nao esta conectado para salvar configuracoes.');
|