@whitewall/blip-sdk 0.0.136 → 0.0.138
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/cjs/client.js +1 -1
- package/dist/cjs/client.js.map +1 -1
- package/dist/esm/client.js +1 -1
- package/dist/esm/client.js.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +117 -0
- package/src/index.ts +6 -0
- package/src/namespaces/account.ts +729 -0
- package/src/namespaces/activecampaign.ts +285 -0
- package/src/namespaces/analytics.ts +230 -0
- package/src/namespaces/billing.ts +17 -0
- package/src/namespaces/builder.ts +52 -0
- package/src/namespaces/configurations.ts +19 -0
- package/src/namespaces/context.ts +67 -0
- package/src/namespaces/desk.ts +679 -0
- package/src/namespaces/media.ts +39 -0
- package/src/namespaces/namespace.ts +125 -0
- package/src/namespaces/plugins.ts +223 -0
- package/src/namespaces/portal.ts +402 -0
- package/src/namespaces/scheduler.ts +88 -0
- package/src/namespaces/whatsapp.ts +383 -0
- package/src/sender/bliperror.ts +42 -0
- package/src/sender/enveloperesolver.ts +148 -0
- package/src/sender/gateway/customgatewaysender.ts +43 -0
- package/src/sender/http/httpsender.ts +94 -0
- package/src/sender/index.ts +7 -0
- package/src/sender/plugin/communication.ts +72 -0
- package/src/sender/plugin/pluginsender.ts +75 -0
- package/src/sender/security.ts +33 -0
- package/src/sender/sender.ts +145 -0
- package/src/sender/sessionnegotiator.ts +175 -0
- package/src/sender/tcp/tcpsender.ts +252 -0
- package/src/sender/throttler.ts +36 -0
- package/src/sender/websocket/websocketsender.ts +175 -0
- package/src/types/account.ts +84 -0
- package/src/types/analytics.ts +18 -0
- package/src/types/billing.ts +15 -0
- package/src/types/command.ts +47 -0
- package/src/types/commons.ts +16 -0
- package/src/types/desk.ts +51 -0
- package/src/types/envelope.ts +9 -0
- package/src/types/flow.ts +327 -0
- package/src/types/index.ts +13 -0
- package/src/types/message.ts +116 -0
- package/src/types/node.ts +86 -0
- package/src/types/notification.ts +18 -0
- package/src/types/plugins.ts +51 -0
- package/src/types/portal.ts +39 -0
- package/src/types/reason.ts +22 -0
- package/src/types/session.ts +22 -0
- package/src/types/whatsapp.ts +84 -0
- package/src/utils/odata.ts +114 -0
- package/src/utils/random.ts +3 -0
- package/src/utils/uri.ts +46 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import type { BlipClient } from '../client.ts'
|
|
2
|
+
import { type Identity, Node } from '../types/node.ts'
|
|
3
|
+
import { uri } from '../utils/uri.ts'
|
|
4
|
+
import { type ConsumeOptions, Namespace, type SendCommandOptions } from './namespace.ts'
|
|
5
|
+
|
|
6
|
+
type AudienceSummary = {
|
|
7
|
+
id: string
|
|
8
|
+
name: string
|
|
9
|
+
campaignStatus: string
|
|
10
|
+
failed: number
|
|
11
|
+
processed: number
|
|
12
|
+
read: number
|
|
13
|
+
received: number
|
|
14
|
+
total: number
|
|
15
|
+
scheduled?: string
|
|
16
|
+
created: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class ActiveCampaignNamespace extends Namespace {
|
|
20
|
+
constructor(blipClient: BlipClient, defaultOptions?: SendCommandOptions) {
|
|
21
|
+
super(blipClient, 'activecampaign', defaultOptions)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public createAndDispatchBatchCampaign(
|
|
25
|
+
campaign: {
|
|
26
|
+
name: string
|
|
27
|
+
flowId: string
|
|
28
|
+
stateId: string
|
|
29
|
+
campaignSender: string
|
|
30
|
+
subbotIdentity?: Identity
|
|
31
|
+
agentEmail?: string
|
|
32
|
+
scheduled?: string
|
|
33
|
+
tags?: Array<string>
|
|
34
|
+
},
|
|
35
|
+
audiences: Array<{
|
|
36
|
+
recipient: string
|
|
37
|
+
buttonVariable?: string
|
|
38
|
+
mediaVariable?: string
|
|
39
|
+
bodyVariables: Array<string>
|
|
40
|
+
additionalContactExtras?: Record<string, string | null>
|
|
41
|
+
}>,
|
|
42
|
+
message: {
|
|
43
|
+
template: string
|
|
44
|
+
language: string
|
|
45
|
+
},
|
|
46
|
+
opts?: ConsumeOptions,
|
|
47
|
+
): Promise<{
|
|
48
|
+
id: string
|
|
49
|
+
status: string
|
|
50
|
+
created: string
|
|
51
|
+
}> {
|
|
52
|
+
const messageVariables = [
|
|
53
|
+
audiences[0].mediaVariable ? 'urllink' : undefined,
|
|
54
|
+
audiences[0].buttonVariable ? 'button' : undefined,
|
|
55
|
+
...audiences[0].bodyVariables.map((_, i) => `variable${i + 1}`),
|
|
56
|
+
].filter((v) => v)
|
|
57
|
+
return this.sendCommand(
|
|
58
|
+
{
|
|
59
|
+
method: 'set',
|
|
60
|
+
uri: uri`/campaign/full`,
|
|
61
|
+
type: 'application/vnd.iris.activecampaign.full-campaign+json',
|
|
62
|
+
resource: {
|
|
63
|
+
campaign: {
|
|
64
|
+
name: campaign.name,
|
|
65
|
+
campaignType: 'BATCH',
|
|
66
|
+
flowId: campaign.flowId,
|
|
67
|
+
stateId: campaign.stateId,
|
|
68
|
+
campaignSender: campaign.campaignSender,
|
|
69
|
+
masterstate: campaign.subbotIdentity,
|
|
70
|
+
attendanceRedirect: campaign.agentEmail ? new Node(campaign.agentEmail, 'blip.ai') : undefined,
|
|
71
|
+
scheduled: campaign.scheduled,
|
|
72
|
+
tags: campaign.tags,
|
|
73
|
+
},
|
|
74
|
+
audiences: audiences.map((audience) => {
|
|
75
|
+
return {
|
|
76
|
+
recipient: audience.recipient,
|
|
77
|
+
messageParams: {
|
|
78
|
+
urllink: audience.mediaVariable,
|
|
79
|
+
button: audience.buttonVariable,
|
|
80
|
+
...Object.fromEntries(audience.bodyVariables.map((v, i) => [`variable${i + 1}`, v])),
|
|
81
|
+
...audience.additionalContactExtras,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}),
|
|
85
|
+
message: {
|
|
86
|
+
messageTemplate: message.template,
|
|
87
|
+
messageTemplateLanguage: message.language,
|
|
88
|
+
// Needed because of a bug where the API interprets empty array as a single empty variable
|
|
89
|
+
// E.g. "messageParams": [""]
|
|
90
|
+
messageParams: messageVariables.length > 0 ? messageVariables : undefined,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
opts,
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public async cancelCampaign(campaign: string, opts?: ConsumeOptions) {
|
|
99
|
+
return await this.sendCommand(
|
|
100
|
+
{
|
|
101
|
+
method: 'delete',
|
|
102
|
+
uri: uri`/campaigns/${campaign}`,
|
|
103
|
+
},
|
|
104
|
+
opts,
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public async getCampaigns(opts?: ConsumeOptions) {
|
|
109
|
+
// This is needed because this route throws an error if passed an $skip or $take query parameter
|
|
110
|
+
const resource = await this.sendCommand<'get', { items: Array<{ id: string; name: string }> }>(
|
|
111
|
+
{
|
|
112
|
+
method: 'get',
|
|
113
|
+
uri: uri`/campaigns`,
|
|
114
|
+
},
|
|
115
|
+
opts,
|
|
116
|
+
)
|
|
117
|
+
return resource.items
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public getCampaign(
|
|
121
|
+
campaign: string,
|
|
122
|
+
opts?: ConsumeOptions,
|
|
123
|
+
): Promise<{
|
|
124
|
+
id: string
|
|
125
|
+
name: string
|
|
126
|
+
campaignType: 'BATCH' | 'INDIVIDUAL'
|
|
127
|
+
masterState: Identity
|
|
128
|
+
flowId: string
|
|
129
|
+
stateId: string
|
|
130
|
+
campaignSender: Identity
|
|
131
|
+
status: string
|
|
132
|
+
created: string
|
|
133
|
+
}> {
|
|
134
|
+
return this.sendCommand(
|
|
135
|
+
{
|
|
136
|
+
method: 'get',
|
|
137
|
+
uri: uri`/campaigns/${campaign}`,
|
|
138
|
+
},
|
|
139
|
+
opts,
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public async getCampaignMessage(campaign: string, opts?: ConsumeOptions) {
|
|
144
|
+
const [message] = await this.sendCommand<
|
|
145
|
+
'get',
|
|
146
|
+
Array<{
|
|
147
|
+
channelType: 'WHATSAPP'
|
|
148
|
+
messageTemplate: string
|
|
149
|
+
messageTemplateLanguage: string
|
|
150
|
+
messageParams: Array<string>
|
|
151
|
+
}>
|
|
152
|
+
>(
|
|
153
|
+
{
|
|
154
|
+
method: 'get',
|
|
155
|
+
uri: uri`/messages/${campaign}`,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
collection: true,
|
|
159
|
+
...opts,
|
|
160
|
+
},
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return message
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public getAudienceSummaries(
|
|
167
|
+
filter?: {
|
|
168
|
+
scheduled?: boolean
|
|
169
|
+
campaignName?: string
|
|
170
|
+
},
|
|
171
|
+
opts?: ConsumeOptions,
|
|
172
|
+
): Promise<Array<AudienceSummary>> {
|
|
173
|
+
return this.sendCommand(
|
|
174
|
+
{
|
|
175
|
+
method: 'get',
|
|
176
|
+
uri: uri`/audience-summary?${filter}`,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
collection: true,
|
|
180
|
+
...opts,
|
|
181
|
+
},
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public async getAudienceSummary(campaign: string, opts?: ConsumeOptions) {
|
|
186
|
+
const [summary] = await this.sendCommand<'get', Array<AudienceSummary>>(
|
|
187
|
+
{
|
|
188
|
+
method: 'get',
|
|
189
|
+
uri: uri`/audience-summary/${campaign}`,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
collection: true,
|
|
193
|
+
...opts,
|
|
194
|
+
},
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
return summary
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public getAudience(
|
|
201
|
+
campaign: string,
|
|
202
|
+
opts?: ConsumeOptions,
|
|
203
|
+
): Promise<
|
|
204
|
+
Array<{
|
|
205
|
+
OwnerIdentity: Identity
|
|
206
|
+
CampaignId: string
|
|
207
|
+
recipient: string
|
|
208
|
+
recipientType: 'PhoneNumber'
|
|
209
|
+
channelType: 'WHATSAPP'
|
|
210
|
+
messageParams: Record<string, string>
|
|
211
|
+
status: string
|
|
212
|
+
validatedAccount: Identity
|
|
213
|
+
// These strings are actually timestamps
|
|
214
|
+
// Can be used to infer the message's state
|
|
215
|
+
processed?: string
|
|
216
|
+
received?: string
|
|
217
|
+
read?: string
|
|
218
|
+
failed?: string
|
|
219
|
+
reasonCode?: number
|
|
220
|
+
reasonDescription?: string
|
|
221
|
+
}>
|
|
222
|
+
> {
|
|
223
|
+
return this.sendCommand(
|
|
224
|
+
{
|
|
225
|
+
method: 'get',
|
|
226
|
+
uri: uri`/audiences/${campaign}`,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
collection: true,
|
|
230
|
+
take: 1000,
|
|
231
|
+
...opts,
|
|
232
|
+
},
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public getCampaignsSummaries(
|
|
237
|
+
filters: {
|
|
238
|
+
createdDate: string | Date
|
|
239
|
+
source?: 'Portal' | 'Desk' | 'API'
|
|
240
|
+
campaignSender?: string
|
|
241
|
+
},
|
|
242
|
+
opts?: ConsumeOptions,
|
|
243
|
+
): Promise<
|
|
244
|
+
Array<{
|
|
245
|
+
id: string
|
|
246
|
+
name: string
|
|
247
|
+
messageTemplate: string
|
|
248
|
+
masterState: Identity
|
|
249
|
+
flowId: string
|
|
250
|
+
stateId: string
|
|
251
|
+
attendanceRedirect: Identity
|
|
252
|
+
campaignSender: Identity
|
|
253
|
+
sendDate: string
|
|
254
|
+
statusAudience: Array<{
|
|
255
|
+
recipientIdentity: Identity
|
|
256
|
+
status: 'NOT_PROCESSED' | 'PROCESSED' | 'RECEIVED' | 'READ' | 'FAILED'
|
|
257
|
+
processed?: string
|
|
258
|
+
received?: string
|
|
259
|
+
read?: string
|
|
260
|
+
failed?: string
|
|
261
|
+
reasonCode?: number
|
|
262
|
+
reasonDescription?: string
|
|
263
|
+
numberStatus: string
|
|
264
|
+
}>
|
|
265
|
+
}>
|
|
266
|
+
> {
|
|
267
|
+
return this.sendCommand(
|
|
268
|
+
{
|
|
269
|
+
method: 'get',
|
|
270
|
+
uri: uri`/campaigns/summaries?${{
|
|
271
|
+
created:
|
|
272
|
+
typeof filters.createdDate === 'string'
|
|
273
|
+
? filters.createdDate
|
|
274
|
+
: filters.createdDate.toISOString(),
|
|
275
|
+
SourceApplication: filters.source,
|
|
276
|
+
CampaignSender: filters.campaignSender,
|
|
277
|
+
}}`,
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
collection: true,
|
|
281
|
+
...opts,
|
|
282
|
+
},
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type { BlipClient } from '../client.ts'
|
|
2
|
+
import type { EventTrack, NonNullableEventTracking } from '../types/analytics.ts'
|
|
3
|
+
import type { Identity } from '../types/node.ts'
|
|
4
|
+
import { uri } from '../utils/uri.ts'
|
|
5
|
+
import { type ConsumeOptions, Namespace, type SendCommandOptions } from './namespace.ts'
|
|
6
|
+
|
|
7
|
+
export class AnalyticsNamespace extends Namespace {
|
|
8
|
+
constructor(blipClient: BlipClient, defaultOptions?: SendCommandOptions) {
|
|
9
|
+
super(blipClient, 'analytics', defaultOptions)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public async track(
|
|
13
|
+
contact: Identity | undefined,
|
|
14
|
+
category: string,
|
|
15
|
+
action: string,
|
|
16
|
+
extras: Record<string, string | undefined> = {},
|
|
17
|
+
opts?: ConsumeOptions,
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
return await this.sendCommand(
|
|
20
|
+
{
|
|
21
|
+
method: 'observe',
|
|
22
|
+
uri: uri`/event-track`,
|
|
23
|
+
type: 'application/vnd.iris.eventTrack+json',
|
|
24
|
+
resource: {
|
|
25
|
+
category,
|
|
26
|
+
action,
|
|
27
|
+
contact: contact
|
|
28
|
+
? {
|
|
29
|
+
identity: contact,
|
|
30
|
+
}
|
|
31
|
+
: undefined,
|
|
32
|
+
extras: {
|
|
33
|
+
...(contact ? { contactIdentity: contact } : {}),
|
|
34
|
+
...extras,
|
|
35
|
+
},
|
|
36
|
+
} satisfies EventTrack,
|
|
37
|
+
},
|
|
38
|
+
opts,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async getCategories(
|
|
43
|
+
filter?: string,
|
|
44
|
+
opts?: ConsumeOptions,
|
|
45
|
+
): Promise<Array<Pick<NonNullableEventTracking, 'category'>>> {
|
|
46
|
+
return await this.sendCommand(
|
|
47
|
+
{
|
|
48
|
+
method: 'get',
|
|
49
|
+
uri: uri`/event-track?${{ categoryFilter: filter }}`,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
collection: true,
|
|
53
|
+
...opts,
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** @returns Quantity of actions in the category between the start and end date */
|
|
59
|
+
public async getCategoryCount(
|
|
60
|
+
category: string,
|
|
61
|
+
startDate: Date,
|
|
62
|
+
endDate: Date,
|
|
63
|
+
opts?: ConsumeOptions,
|
|
64
|
+
): Promise<number> {
|
|
65
|
+
const { count } = await this.sendCommand<'get', { count: number }>(
|
|
66
|
+
{
|
|
67
|
+
method: 'get',
|
|
68
|
+
uri: uri`/event-track-count/${category}?${{ startDate, endDate }}`,
|
|
69
|
+
},
|
|
70
|
+
opts,
|
|
71
|
+
)
|
|
72
|
+
return count
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** @returns Counts of each action in the category grouped by day between the start and end date */
|
|
76
|
+
public async getCategoryActions(
|
|
77
|
+
category: string,
|
|
78
|
+
startDate: Date,
|
|
79
|
+
endDate: Date,
|
|
80
|
+
opts?: ConsumeOptions,
|
|
81
|
+
): Promise<Array<Pick<NonNullableEventTracking, 'storageDate' | 'category' | 'action' | 'count'>>> {
|
|
82
|
+
return await this.sendCommand(
|
|
83
|
+
{
|
|
84
|
+
method: 'get',
|
|
85
|
+
uri: uri`/event-track/${category}?${{ startDate, endDate }}`,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
collection: true,
|
|
89
|
+
...opts,
|
|
90
|
+
},
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public async getTrackings(category: string, action: string, startDate: Date, endDate: Date, opts?: ConsumeOptions) {
|
|
95
|
+
const trackings = await this.sendCommand<
|
|
96
|
+
'get',
|
|
97
|
+
Array<
|
|
98
|
+
Pick<EventTrack, 'ownerIdentity' | 'storageDate' | 'category' | 'action' | 'extras' | 'contact'> & {
|
|
99
|
+
contact: {
|
|
100
|
+
// This is a workaround, sometimes Blip returns it on pascal case
|
|
101
|
+
Identity: Identity
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
>
|
|
105
|
+
>(
|
|
106
|
+
{
|
|
107
|
+
method: 'get',
|
|
108
|
+
uri: uri`/event-track/${category}/${action}?${{ startDate, endDate }}`,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
collection: true,
|
|
112
|
+
...opts,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return trackings.map((tracking) => ({
|
|
117
|
+
...tracking,
|
|
118
|
+
contact: {
|
|
119
|
+
identity: tracking.contact?.Identity ?? tracking.contact?.identity ?? tracking.extras.contactIdentity,
|
|
120
|
+
},
|
|
121
|
+
}))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public async hasWebhook(url: string, opts?: ConsumeOptions) {
|
|
125
|
+
const webhooks = await this.getWebhooks(opts)
|
|
126
|
+
return webhooks.some((webhook) => webhook.url === url)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public async getWebhooks(opts?: ConsumeOptions) {
|
|
130
|
+
const configurations = await this.blipClient.account.getConfigurations({
|
|
131
|
+
...opts,
|
|
132
|
+
ownerIdentity: this.identity,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const webhookUrls = configurations['Webhook.Url']?.split(';') ?? []
|
|
136
|
+
const advancedWebhookSettings = JSON.parse(configurations['Webhook.AdvancedSettings'] ?? '[]')
|
|
137
|
+
|
|
138
|
+
type Settings = {
|
|
139
|
+
settings: {
|
|
140
|
+
dispatchTypes: Array<'contacts' | 'messages' | 'eventtrackings'>
|
|
141
|
+
customHeaders: Record<string, string>
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return webhookUrls
|
|
146
|
+
.filter((url) => url)
|
|
147
|
+
.map((url) => {
|
|
148
|
+
const settings = advancedWebhookSettings.find(
|
|
149
|
+
(webhookSettings: Record<string, Settings>) => webhookSettings[url]?.settings,
|
|
150
|
+
)?.[url]?.settings
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
url,
|
|
154
|
+
settings: (settings ?? {
|
|
155
|
+
dispatchTypes: ['contacts', 'messages', 'eventtrackings'],
|
|
156
|
+
customHeaders: {},
|
|
157
|
+
}) as Settings['settings'],
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* It will add the url as an active webhook if it doesn't exist yet
|
|
164
|
+
* If the url already exists, it will update the settings
|
|
165
|
+
* @param url The url to set
|
|
166
|
+
* @param settings.listeners Default: ['contacts', 'messages', 'eventtrackings']
|
|
167
|
+
*/
|
|
168
|
+
public async setWebhook(
|
|
169
|
+
url: string,
|
|
170
|
+
settings?: {
|
|
171
|
+
listeners?: Array<'contacts' | 'messages' | 'eventtrackings'>
|
|
172
|
+
headers?: Record<string, string>
|
|
173
|
+
},
|
|
174
|
+
opts?: ConsumeOptions,
|
|
175
|
+
) {
|
|
176
|
+
const configurations = await this.blipClient.account.getConfigurations({
|
|
177
|
+
...opts,
|
|
178
|
+
ownerIdentity: this.identity,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
let webhookUrls = configurations['Webhook.Url']?.split(';') ?? []
|
|
182
|
+
if (!webhookUrls.includes(url)) {
|
|
183
|
+
webhookUrls = [...webhookUrls, url]
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const webhookSettings = {
|
|
187
|
+
dispatchTypes: settings?.listeners ?? ['contacts', 'messages', 'eventtrackings'],
|
|
188
|
+
customHeaders: settings?.headers ?? {},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const advancedWebhookSettings = JSON.parse(configurations['Webhook.AdvancedSettings'] ?? '[]').filter(
|
|
192
|
+
(urls: Record<string, never>) => !urls[url],
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
await this.blipClient.account.setConfigurations(
|
|
196
|
+
{
|
|
197
|
+
'Webhook.Url': webhookUrls.join(';'),
|
|
198
|
+
'Webhook.IsValid': 'True',
|
|
199
|
+
'Webhook.AdvancedSettings': JSON.stringify([
|
|
200
|
+
...advancedWebhookSettings,
|
|
201
|
+
{
|
|
202
|
+
[url]: {
|
|
203
|
+
settings: webhookSettings,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
]),
|
|
207
|
+
},
|
|
208
|
+
{ ...opts, ownerIdentity: this.identity },
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
public async deleteWebhook(url: string, opts?: ConsumeOptions) {
|
|
213
|
+
const configurations = await this.blipClient.account.getConfigurations({
|
|
214
|
+
...opts,
|
|
215
|
+
ownerIdentity: this.identity,
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
const currentWebhookUrls = configurations['Webhook.Url']?.split(';') ?? []
|
|
219
|
+
const advancedWebhookSettings = JSON.parse(configurations['Webhook.AdvancedSettings'] ?? '[]')
|
|
220
|
+
await this.blipClient.account.setConfigurations(
|
|
221
|
+
{
|
|
222
|
+
'Webhook.Url': currentWebhookUrls.filter((u) => u !== url).join(';'),
|
|
223
|
+
'Webhook.AdvancedSettings': JSON.stringify(
|
|
224
|
+
advancedWebhookSettings.filter((urls: Record<string, never>) => !urls[url]),
|
|
225
|
+
),
|
|
226
|
+
},
|
|
227
|
+
{ ...opts, ownerIdentity: this.identity },
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BlipClient } from '../client.ts'
|
|
2
|
+
import type { Plan } from '../types/billing.ts'
|
|
3
|
+
import { uri } from '../utils/uri.ts'
|
|
4
|
+
import { Namespace, type SendCommandOptions } from './namespace.ts'
|
|
5
|
+
|
|
6
|
+
export class BillingNamespace extends Namespace {
|
|
7
|
+
constructor(blipClient: BlipClient, defaultOptions?: SendCommandOptions) {
|
|
8
|
+
super(blipClient, 'billing', { ...defaultOptions, domain: 'blip.ai' })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async getPlan(tenantId: string): Promise<Plan> {
|
|
12
|
+
return await this.sendCommand({
|
|
13
|
+
method: 'get',
|
|
14
|
+
uri: uri`/tenants/${tenantId}/subscription/plan`,
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { BlipClient } from '../client.ts'
|
|
2
|
+
import { BlipError } from '../sender/bliperror.ts'
|
|
3
|
+
import { uri } from '../utils/uri.ts'
|
|
4
|
+
import { type ConsumeOptions, Namespace, type SendCommandOptions } from './namespace.ts'
|
|
5
|
+
|
|
6
|
+
export class BuilderNamespace extends Namespace {
|
|
7
|
+
constructor(blipClient: BlipClient, defaultOptions?: SendCommandOptions) {
|
|
8
|
+
super(blipClient, 'builder', defaultOptions)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async getFlowId(botIdentifier?: string, opts?: ConsumeOptions): Promise<string | undefined> {
|
|
12
|
+
try {
|
|
13
|
+
return await this.sendCommand(
|
|
14
|
+
{
|
|
15
|
+
method: 'get',
|
|
16
|
+
uri: uri`/flow-id?${{ shortName: botIdentifier }}`,
|
|
17
|
+
},
|
|
18
|
+
opts,
|
|
19
|
+
)
|
|
20
|
+
} catch (err) {
|
|
21
|
+
if (err instanceof BlipError && err.code === 67) {
|
|
22
|
+
return undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
throw err
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public async getFlowStates(
|
|
30
|
+
botIdentifier?: string,
|
|
31
|
+
opts?: ConsumeOptions,
|
|
32
|
+
): Promise<Array<{ id: string; name: string }>> {
|
|
33
|
+
try {
|
|
34
|
+
return await this.sendCommand(
|
|
35
|
+
{
|
|
36
|
+
method: 'get',
|
|
37
|
+
uri: uri`/flow/states?${{ shortName: botIdentifier }}`,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
collection: true,
|
|
41
|
+
...opts,
|
|
42
|
+
},
|
|
43
|
+
)
|
|
44
|
+
} catch (err) {
|
|
45
|
+
if (err instanceof BlipError && err.code === 67) {
|
|
46
|
+
return []
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
throw err
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BlipClient } from '../client.ts'
|
|
2
|
+
import { uri } from '../utils/uri.ts'
|
|
3
|
+
import { Namespace, type SendCommandOptions } from './namespace.ts'
|
|
4
|
+
|
|
5
|
+
export class ConfigurationsNamespace extends Namespace {
|
|
6
|
+
constructor(blipClient: BlipClient, defaultOptions?: SendCommandOptions) {
|
|
7
|
+
super(blipClient, 'configurations', defaultOptions)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public getConfigurations(opts?: SendCommandOptions): Promise<Record<string, string>> {
|
|
11
|
+
return this.sendCommand(
|
|
12
|
+
{
|
|
13
|
+
method: 'get',
|
|
14
|
+
uri: uri`/configuration`,
|
|
15
|
+
},
|
|
16
|
+
opts,
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { BlipClient, Ticket } from '../index.ts'
|
|
2
|
+
import { PluginSender } from '../sender/plugin/pluginsender.ts'
|
|
3
|
+
import type { Account, BlipLanguage } from '../types/account.ts'
|
|
4
|
+
import { Namespace, type SendCommandOptions } from './namespace.ts'
|
|
5
|
+
|
|
6
|
+
export class ContextNamespace extends Namespace {
|
|
7
|
+
constructor(blipClient: BlipClient, defaultOptions?: SendCommandOptions) {
|
|
8
|
+
super(blipClient, '', defaultOptions)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async getCurrentTicket(): Promise<Ticket> {
|
|
12
|
+
const sender = this.checkSenderRealm('desk')
|
|
13
|
+
const { item } = await sender.channel.post<{ item: Ticket }>('currentTicket', null)
|
|
14
|
+
return item
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public getUser(): Promise<Account> {
|
|
18
|
+
const sender = this.checkSenderRealm('portal')
|
|
19
|
+
return sender.channel.post('getUserContext', { command: 'getCurrentUser' })
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public getLanguage(): Promise<BlipLanguage> {
|
|
23
|
+
const sender = this.checkSenderRealm()
|
|
24
|
+
return sender.channel.post('getCurrentLanguage', null)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public toast(type: 'success' | 'warning' | 'danger', message: string): void {
|
|
28
|
+
const sender = this.checkSenderRealm()
|
|
29
|
+
const fixedType = this.isOnBlipDesk() && type === 'danger' ? 'error' : type
|
|
30
|
+
sender.channel.post('toast', { type: fixedType, message }, { fireAndForget: true })
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public changeHeight(height: number): void {
|
|
34
|
+
const sender = this.checkSenderRealm('portal')
|
|
35
|
+
sender.channel.post('heightChange', height, { fireAndForget: true })
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public loading(show: boolean): void {
|
|
39
|
+
const sender = this.checkSenderRealm()
|
|
40
|
+
if (show) {
|
|
41
|
+
sender.channel.post('startLoading', {}, { fireAndForget: true })
|
|
42
|
+
} else {
|
|
43
|
+
sender.channel.post('stopLoading', {}, { fireAndForget: true })
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public getUserToken(): Promise<string> {
|
|
48
|
+
const sender = this.checkSenderRealm('portal')
|
|
49
|
+
return sender.channel.post('getToken', null)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public isOnBlipDesk(): boolean {
|
|
53
|
+
return PluginSender.getRealm(this.blipClient) === 'desk'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public isOnPortal(): boolean {
|
|
57
|
+
return PluginSender.getRealm(this.blipClient) === 'portal'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private checkSenderRealm(realm?: 'portal' | 'desk') {
|
|
61
|
+
if (realm && PluginSender.getRealm(this.blipClient) !== realm) {
|
|
62
|
+
throw new Error(`This command is only allowed for ${realm} realm`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return PluginSender.check(this.blipClient)
|
|
66
|
+
}
|
|
67
|
+
}
|