@digisglobal/omnivox-sdk 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +539 -1
- package/dist/index.d.cts +693 -1
- package/dist/index.d.ts +693 -1
- package/dist/index.js +534 -1
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -26,6 +26,11 @@ async function parseResponse(res) {
|
|
|
26
26
|
}
|
|
27
27
|
return text ? JSON.parse(text) : void 0;
|
|
28
28
|
}
|
|
29
|
+
async function parseEnvelopedResponse(res) {
|
|
30
|
+
if (NO_BODY_STATUSES.includes(res.status)) return void 0;
|
|
31
|
+
const envelope = await parseResponse(res);
|
|
32
|
+
return envelope.data;
|
|
33
|
+
}
|
|
29
34
|
|
|
30
35
|
// src/auth/auth-me.ts
|
|
31
36
|
function createAuthMeModule(options) {
|
|
@@ -125,6 +130,9 @@ var getConversationsControllerListLobbyUrl = (params) => {
|
|
|
125
130
|
var getConversationsControllerPickupLobbyEntryUrl = (entryId) => {
|
|
126
131
|
return `/api/v1/conversations/lobby/${entryId}/pickup`;
|
|
127
132
|
};
|
|
133
|
+
var getConversationsControllerGetWhatsAppRecoveryOptionsUrl = (id) => {
|
|
134
|
+
return `/api/v1/conversations/${id}/whatsapp-recovery-options`;
|
|
135
|
+
};
|
|
128
136
|
var getConversationsControllerFindOneUrl = (id) => {
|
|
129
137
|
return `/api/v1/conversations/${id}`;
|
|
130
138
|
};
|
|
@@ -141,6 +149,9 @@ var getMessagesControllerListUrl = (params) => {
|
|
|
141
149
|
const stringifiedParams = normalizedParams.toString();
|
|
142
150
|
return stringifiedParams.length > 0 ? `/api/v1/messages?${stringifiedParams}` : `/api/v1/messages`;
|
|
143
151
|
};
|
|
152
|
+
var getMessagesControllerSendTemplateUrl = () => {
|
|
153
|
+
return `/api/v1/messages/send-template`;
|
|
154
|
+
};
|
|
144
155
|
var getMessagesControllerGetByIdUrl = (id, params) => {
|
|
145
156
|
const normalizedParams = new URLSearchParams();
|
|
146
157
|
Object.entries(params || {}).forEach(([key, value]) => {
|
|
@@ -169,6 +180,12 @@ var getChannelsControllerUpdateUrl = (id, channelId) => {
|
|
|
169
180
|
var getChannelsControllerVerifyUrl = (id, channelId) => {
|
|
170
181
|
return `/api/v1/tenants/${id}/channels/${channelId}/verify`;
|
|
171
182
|
};
|
|
183
|
+
var getWhatsAppBusinessAccountsControllerListUrl = (id) => {
|
|
184
|
+
return `/api/v1/tenants/${id}/whatsapp-business-accounts`;
|
|
185
|
+
};
|
|
186
|
+
var getWhatsAppBusinessAccountsControllerFindOneUrl = (id, wabaRowId) => {
|
|
187
|
+
return `/api/v1/tenants/${id}/whatsapp-business-accounts/${wabaRowId}`;
|
|
188
|
+
};
|
|
172
189
|
var getAgentsControllerCreateUrl = () => {
|
|
173
190
|
return `/api/v1/agents`;
|
|
174
191
|
};
|
|
@@ -185,6 +202,68 @@ var getAgentsControllerListUrl = (params) => {
|
|
|
185
202
|
var getAgentsControllerFindOneUrl = (id) => {
|
|
186
203
|
return `/api/v1/agents/${id}`;
|
|
187
204
|
};
|
|
205
|
+
var getTemplatesControllerAuthorDraftUrl = (id, wabaId) => {
|
|
206
|
+
return `/api/v1/tenants/${id}/whatsapp-business-accounts/${wabaId}/templates`;
|
|
207
|
+
};
|
|
208
|
+
var getTemplatesControllerImportApprovedUrl = (id, wabaId) => {
|
|
209
|
+
return `/api/v1/tenants/${id}/whatsapp-business-accounts/${wabaId}/templates/import`;
|
|
210
|
+
};
|
|
211
|
+
var getTemplatesControllerForkDraftUrl = (id, wabaId, templateId) => {
|
|
212
|
+
return `/api/v1/tenants/${id}/whatsapp-business-accounts/${wabaId}/templates/${templateId}`;
|
|
213
|
+
};
|
|
214
|
+
var getTemplatesControllerGetHistoryUrl = (id, wabaId, templateId) => {
|
|
215
|
+
return `/api/v1/tenants/${id}/whatsapp-business-accounts/${wabaId}/templates/${templateId}/history`;
|
|
216
|
+
};
|
|
217
|
+
var getTemplatesControllerSubmitUrl = (id, wabaId, templateId) => {
|
|
218
|
+
return `/api/v1/tenants/${id}/whatsapp-business-accounts/${wabaId}/templates/${templateId}/submit`;
|
|
219
|
+
};
|
|
220
|
+
var getEmailTemplatesControllerCreateUrl = () => {
|
|
221
|
+
return `/api/v1/templates/email`;
|
|
222
|
+
};
|
|
223
|
+
var getEmailTemplatesControllerListUrl = (params) => {
|
|
224
|
+
const normalizedParams = new URLSearchParams();
|
|
225
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
226
|
+
if (value !== void 0) {
|
|
227
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const stringifiedParams = normalizedParams.toString();
|
|
231
|
+
return stringifiedParams.length > 0 ? `/api/v1/templates/email?${stringifiedParams}` : `/api/v1/templates/email`;
|
|
232
|
+
};
|
|
233
|
+
var getEmailTemplatesControllerGetByIdUrl = (id) => {
|
|
234
|
+
return `/api/v1/templates/email/${id}`;
|
|
235
|
+
};
|
|
236
|
+
var getEmailTemplatesControllerPatchUrl = (id) => {
|
|
237
|
+
return `/api/v1/templates/email/${id}`;
|
|
238
|
+
};
|
|
239
|
+
var getEmailTemplatesControllerDeleteUrl = (id) => {
|
|
240
|
+
return `/api/v1/templates/email/${id}`;
|
|
241
|
+
};
|
|
242
|
+
var getCannedResponsesControllerCreateUrl = () => {
|
|
243
|
+
return `/api/v1/canned-responses`;
|
|
244
|
+
};
|
|
245
|
+
var getCannedResponsesControllerListUrl = (params) => {
|
|
246
|
+
const normalizedParams = new URLSearchParams();
|
|
247
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
248
|
+
if (value !== void 0) {
|
|
249
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
const stringifiedParams = normalizedParams.toString();
|
|
253
|
+
return stringifiedParams.length > 0 ? `/api/v1/canned-responses?${stringifiedParams}` : `/api/v1/canned-responses`;
|
|
254
|
+
};
|
|
255
|
+
var getCannedResponsesControllerPatchUrl = (id) => {
|
|
256
|
+
return `/api/v1/canned-responses/${id}`;
|
|
257
|
+
};
|
|
258
|
+
var getCannedResponsesControllerDeleteUrl = (id) => {
|
|
259
|
+
return `/api/v1/canned-responses/${id}`;
|
|
260
|
+
};
|
|
261
|
+
var getAttachmentsControllerUploadUrl = () => {
|
|
262
|
+
return `/api/v1/attachments`;
|
|
263
|
+
};
|
|
264
|
+
var getAttachmentsControllerGetDownloadUrlUrl = (id) => {
|
|
265
|
+
return `/api/v1/attachments/${id}/url`;
|
|
266
|
+
};
|
|
188
267
|
|
|
189
268
|
// src/pagination/pagination.ts
|
|
190
269
|
var MAX_PAGE_SIZE = 100;
|
|
@@ -585,6 +664,18 @@ function createConversationsModule(options) {
|
|
|
585
664
|
const url = `${baseUrl}${path}`;
|
|
586
665
|
const res = await fetch(url, buildInit("POST", input));
|
|
587
666
|
return parseResponse(res);
|
|
667
|
+
},
|
|
668
|
+
/**
|
|
669
|
+
* List APPROVED + SENDABLE WhatsApp templates eligible to re-open an
|
|
670
|
+
* expired 24-hour customer-service window for the given conversation.
|
|
671
|
+
* Returns an empty array when the channel is not WhatsApp or has no linked WABA.
|
|
672
|
+
* Calls GET /api/v1/conversations/:id/whatsapp-recovery-options.
|
|
673
|
+
*/
|
|
674
|
+
async whatsappRecoveryOptions(id) {
|
|
675
|
+
const path = getConversationsControllerGetWhatsAppRecoveryOptionsUrl(id);
|
|
676
|
+
const url = `${baseUrl}${path}`;
|
|
677
|
+
const res = await fetch(url, buildInit("GET"));
|
|
678
|
+
return parseResponse(res);
|
|
588
679
|
}
|
|
589
680
|
};
|
|
590
681
|
}
|
|
@@ -651,6 +742,415 @@ function createMessagesModule(options) {
|
|
|
651
742
|
const url = `${baseUrl}${path}`;
|
|
652
743
|
const res = await fetch(url, buildInit("DELETE"));
|
|
653
744
|
await parseResponse(res);
|
|
745
|
+
},
|
|
746
|
+
/**
|
|
747
|
+
* Send a template message in a conversation (WhatsApp or Email).
|
|
748
|
+
* Branches on the conversation channel type — WhatsApp uses positional
|
|
749
|
+
* `variables`; Email uses named `emailVariables`.
|
|
750
|
+
* Calls POST /api/v1/messages/send-template.
|
|
751
|
+
*/
|
|
752
|
+
async sendTemplate(input) {
|
|
753
|
+
const path = getMessagesControllerSendTemplateUrl();
|
|
754
|
+
const url = `${baseUrl}${path}`;
|
|
755
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
756
|
+
return parseResponse(res);
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/templates/templates.ts
|
|
762
|
+
function createTemplatesModule(options) {
|
|
763
|
+
const baseUrl = options.baseUrl;
|
|
764
|
+
function buildInit(method, body) {
|
|
765
|
+
return {
|
|
766
|
+
method,
|
|
767
|
+
credentials: options.getCredentials(),
|
|
768
|
+
headers: {
|
|
769
|
+
"Content-Type": "application/json",
|
|
770
|
+
...options.getHeaders()
|
|
771
|
+
},
|
|
772
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
/**
|
|
777
|
+
* WhatsApp template submodule — WABA-scoped operations.
|
|
778
|
+
*/
|
|
779
|
+
whatsapp: {
|
|
780
|
+
/**
|
|
781
|
+
* Author a new DRAFT template (version 1) under a WhatsApp Business Account.
|
|
782
|
+
* Calls POST /api/v1/tenants/:id/whatsapp-business-accounts/:wabaId/templates.
|
|
783
|
+
*/
|
|
784
|
+
async authorDraft(tenantId, wabaId, input) {
|
|
785
|
+
const path = getTemplatesControllerAuthorDraftUrl(tenantId, wabaId);
|
|
786
|
+
const url = `${baseUrl}${path}`;
|
|
787
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
788
|
+
return parseEnvelopedResponse(res);
|
|
789
|
+
},
|
|
790
|
+
/**
|
|
791
|
+
* Import all APPROVED templates from the WABA into the system (immediately sendable).
|
|
792
|
+
* Calls POST /api/v1/tenants/:id/whatsapp-business-accounts/:wabaId/templates/import.
|
|
793
|
+
*/
|
|
794
|
+
async importApproved(tenantId, wabaId) {
|
|
795
|
+
const path = getTemplatesControllerImportApprovedUrl(tenantId, wabaId);
|
|
796
|
+
const url = `${baseUrl}${path}`;
|
|
797
|
+
const res = await fetch(url, buildInit("POST"));
|
|
798
|
+
return parseEnvelopedResponse(res);
|
|
799
|
+
},
|
|
800
|
+
/**
|
|
801
|
+
* Fork a new DRAFT version from the latest version of a template (update).
|
|
802
|
+
* Calls PATCH /api/v1/tenants/:id/whatsapp-business-accounts/:wabaId/templates/:templateId.
|
|
803
|
+
*/
|
|
804
|
+
async update(tenantId, wabaId, templateId, input) {
|
|
805
|
+
const path = getTemplatesControllerForkDraftUrl(
|
|
806
|
+
tenantId,
|
|
807
|
+
wabaId,
|
|
808
|
+
templateId
|
|
809
|
+
);
|
|
810
|
+
const url = `${baseUrl}${path}`;
|
|
811
|
+
const res = await fetch(url, buildInit("PATCH", input));
|
|
812
|
+
return parseEnvelopedResponse(res);
|
|
813
|
+
},
|
|
814
|
+
/**
|
|
815
|
+
* List all versions and status events for a template in chronological order.
|
|
816
|
+
* Calls GET /api/v1/tenants/:id/whatsapp-business-accounts/:wabaId/templates/:templateId/history.
|
|
817
|
+
*/
|
|
818
|
+
async history(tenantId, wabaId, templateId) {
|
|
819
|
+
const path = getTemplatesControllerGetHistoryUrl(
|
|
820
|
+
tenantId,
|
|
821
|
+
wabaId,
|
|
822
|
+
templateId
|
|
823
|
+
);
|
|
824
|
+
const url = `${baseUrl}${path}`;
|
|
825
|
+
const res = await fetch(url, buildInit("GET"));
|
|
826
|
+
return parseEnvelopedResponse(res);
|
|
827
|
+
},
|
|
828
|
+
/**
|
|
829
|
+
* Submit a DRAFT template version to Meta for review and approval (DRAFT → PENDING_APPROVAL).
|
|
830
|
+
* Calls POST /api/v1/tenants/:id/whatsapp-business-accounts/:wabaId/templates/:templateId/submit.
|
|
831
|
+
*/
|
|
832
|
+
async submit(tenantId, wabaId, templateId) {
|
|
833
|
+
const path = getTemplatesControllerSubmitUrl(
|
|
834
|
+
tenantId,
|
|
835
|
+
wabaId,
|
|
836
|
+
templateId
|
|
837
|
+
);
|
|
838
|
+
const url = `${baseUrl}${path}`;
|
|
839
|
+
const res = await fetch(url, buildInit("POST"));
|
|
840
|
+
return parseEnvelopedResponse(res);
|
|
841
|
+
}
|
|
842
|
+
},
|
|
843
|
+
/**
|
|
844
|
+
* Email template submodule — tenant-scoped operations.
|
|
845
|
+
*/
|
|
846
|
+
email: {
|
|
847
|
+
/**
|
|
848
|
+
* Create an Email template for the authenticated tenant.
|
|
849
|
+
* Calls POST /api/v1/templates/email.
|
|
850
|
+
*/
|
|
851
|
+
async create(input) {
|
|
852
|
+
const path = getEmailTemplatesControllerCreateUrl();
|
|
853
|
+
const url = `${baseUrl}${path}`;
|
|
854
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
855
|
+
return parseEnvelopedResponse(res);
|
|
856
|
+
},
|
|
857
|
+
/**
|
|
858
|
+
* List Email templates for the authenticated tenant (paginated).
|
|
859
|
+
* Calls GET /api/v1/templates/email.
|
|
860
|
+
*/
|
|
861
|
+
async list(opts) {
|
|
862
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
863
|
+
const path = getEmailTemplatesControllerListUrl({ page, pageSize });
|
|
864
|
+
const url = `${baseUrl}${path}`;
|
|
865
|
+
const res = await fetch(url, buildInit("GET"));
|
|
866
|
+
return parseResponse(res);
|
|
867
|
+
},
|
|
868
|
+
/**
|
|
869
|
+
* Get an Email template by id.
|
|
870
|
+
* Calls GET /api/v1/templates/email/:id.
|
|
871
|
+
*/
|
|
872
|
+
async getById(id) {
|
|
873
|
+
const path = getEmailTemplatesControllerGetByIdUrl(id);
|
|
874
|
+
const url = `${baseUrl}${path}`;
|
|
875
|
+
const res = await fetch(url, buildInit("GET"));
|
|
876
|
+
return parseEnvelopedResponse(res);
|
|
877
|
+
},
|
|
878
|
+
/**
|
|
879
|
+
* Partially update an Email template — name, subject, htmlBody, textBody, and/or variableSchema; omitted fields unchanged.
|
|
880
|
+
* Calls PATCH /api/v1/templates/email/:id.
|
|
881
|
+
*/
|
|
882
|
+
async patch(id, input) {
|
|
883
|
+
const path = getEmailTemplatesControllerPatchUrl(id);
|
|
884
|
+
const url = `${baseUrl}${path}`;
|
|
885
|
+
const res = await fetch(url, buildInit("PATCH", input));
|
|
886
|
+
return parseEnvelopedResponse(res);
|
|
887
|
+
},
|
|
888
|
+
/**
|
|
889
|
+
* Delete an Email template.
|
|
890
|
+
* Calls DELETE /api/v1/templates/email/:id.
|
|
891
|
+
*/
|
|
892
|
+
async delete(id) {
|
|
893
|
+
const path = getEmailTemplatesControllerDeleteUrl(id);
|
|
894
|
+
const url = `${baseUrl}${path}`;
|
|
895
|
+
const res = await fetch(url, buildInit("DELETE"));
|
|
896
|
+
if (!res.ok) {
|
|
897
|
+
return parseResponse(res);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// src/canned-responses/canned-responses.ts
|
|
905
|
+
function createCannedResponsesModule(options) {
|
|
906
|
+
const baseUrl = options.baseUrl;
|
|
907
|
+
function buildInit(method, body) {
|
|
908
|
+
return {
|
|
909
|
+
method,
|
|
910
|
+
credentials: options.getCredentials(),
|
|
911
|
+
headers: {
|
|
912
|
+
"Content-Type": "application/json",
|
|
913
|
+
...options.getHeaders()
|
|
914
|
+
},
|
|
915
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
return {
|
|
919
|
+
/**
|
|
920
|
+
* List canned responses (paginated, no search filter).
|
|
921
|
+
* pageSize is clamped to 100 per the API contract.
|
|
922
|
+
* Calls GET /api/v1/canned-responses.
|
|
923
|
+
*/
|
|
924
|
+
async list(opts) {
|
|
925
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
926
|
+
const path = getCannedResponsesControllerListUrl({ page, pageSize });
|
|
927
|
+
const url = `${baseUrl}${path}`;
|
|
928
|
+
const res = await fetch(url, buildInit("GET"));
|
|
929
|
+
return parseResponse(res);
|
|
930
|
+
},
|
|
931
|
+
/**
|
|
932
|
+
* Search canned responses by title substring or keyword prefix.
|
|
933
|
+
* pageSize is clamped to 100 per the API contract.
|
|
934
|
+
* Calls GET /api/v1/canned-responses?q=<term>.
|
|
935
|
+
*/
|
|
936
|
+
async search(opts) {
|
|
937
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
938
|
+
const path = getCannedResponsesControllerListUrl({
|
|
939
|
+
page,
|
|
940
|
+
pageSize,
|
|
941
|
+
q: opts.q
|
|
942
|
+
});
|
|
943
|
+
const url = `${baseUrl}${path}`;
|
|
944
|
+
const res = await fetch(url, buildInit("GET"));
|
|
945
|
+
return parseResponse(res);
|
|
946
|
+
},
|
|
947
|
+
/**
|
|
948
|
+
* Create a canned response.
|
|
949
|
+
* Calls POST /api/v1/canned-responses.
|
|
950
|
+
*/
|
|
951
|
+
async create(input) {
|
|
952
|
+
const path = getCannedResponsesControllerCreateUrl();
|
|
953
|
+
const url = `${baseUrl}${path}`;
|
|
954
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
955
|
+
return parseResponse(res);
|
|
956
|
+
},
|
|
957
|
+
/**
|
|
958
|
+
* Partially update a canned response — title, body, and/or keywords.
|
|
959
|
+
* Calls PATCH /api/v1/canned-responses/:id.
|
|
960
|
+
*/
|
|
961
|
+
async update(id, input) {
|
|
962
|
+
const path = getCannedResponsesControllerPatchUrl(id);
|
|
963
|
+
const url = `${baseUrl}${path}`;
|
|
964
|
+
const res = await fetch(url, buildInit("PATCH", input));
|
|
965
|
+
return parseResponse(res);
|
|
966
|
+
},
|
|
967
|
+
/**
|
|
968
|
+
* Delete a canned response by id.
|
|
969
|
+
* Calls DELETE /api/v1/canned-responses/:id.
|
|
970
|
+
*/
|
|
971
|
+
async delete(id) {
|
|
972
|
+
const path = getCannedResponsesControllerDeleteUrl(id);
|
|
973
|
+
const url = `${baseUrl}${path}`;
|
|
974
|
+
const res = await fetch(url, buildInit("DELETE"));
|
|
975
|
+
if (!res.ok) {
|
|
976
|
+
return parseResponse(res);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// src/attachments/attachments.ts
|
|
983
|
+
function createAttachmentsModule(options) {
|
|
984
|
+
const baseUrl = options.baseUrl;
|
|
985
|
+
return {
|
|
986
|
+
/**
|
|
987
|
+
* Upload a file as a draft attachment.
|
|
988
|
+
*
|
|
989
|
+
* Accepts a Blob or File (browser) or a Uint8Array wrapped in a Blob (Node 22+).
|
|
990
|
+
* Content-Type is intentionally omitted from headers so that fetch (both
|
|
991
|
+
* Node 22 built-in and browser) can set the multipart/form-data boundary.
|
|
992
|
+
*
|
|
993
|
+
* Calls POST /api/v1/attachments.
|
|
994
|
+
*/
|
|
995
|
+
async upload(file, _opts) {
|
|
996
|
+
const form = new FormData();
|
|
997
|
+
const blob = file instanceof Uint8Array ? new Blob([file]) : file;
|
|
998
|
+
form.append("file", blob);
|
|
999
|
+
const path = getAttachmentsControllerUploadUrl();
|
|
1000
|
+
const url = `${baseUrl}${path}`;
|
|
1001
|
+
const res = await fetch(url, {
|
|
1002
|
+
method: "POST",
|
|
1003
|
+
credentials: options.getCredentials(),
|
|
1004
|
+
headers: {
|
|
1005
|
+
// No Content-Type — let fetch set multipart boundary.
|
|
1006
|
+
...options.getHeaders()
|
|
1007
|
+
},
|
|
1008
|
+
body: form
|
|
1009
|
+
});
|
|
1010
|
+
return parseResponse(res);
|
|
1011
|
+
},
|
|
1012
|
+
/**
|
|
1013
|
+
* Get a short-lived presigned download URL for a stored attachment.
|
|
1014
|
+
* The URL is valid for ≤ 15 minutes (NF-09).
|
|
1015
|
+
*
|
|
1016
|
+
* Calls GET /api/v1/attachments/:id/url.
|
|
1017
|
+
*/
|
|
1018
|
+
async url(id) {
|
|
1019
|
+
const path = getAttachmentsControllerGetDownloadUrlUrl(id);
|
|
1020
|
+
const fullUrl = `${baseUrl}${path}`;
|
|
1021
|
+
const res = await fetch(fullUrl, {
|
|
1022
|
+
method: "GET",
|
|
1023
|
+
credentials: options.getCredentials(),
|
|
1024
|
+
headers: {
|
|
1025
|
+
...options.getHeaders()
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
return parseResponse(res);
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// src/whatsapp-business-accounts/whatsapp-business-accounts.ts
|
|
1034
|
+
function createWhatsAppBusinessAccountsModule(options) {
|
|
1035
|
+
const baseUrl = options.baseUrl;
|
|
1036
|
+
function buildInit(method) {
|
|
1037
|
+
return {
|
|
1038
|
+
method,
|
|
1039
|
+
credentials: options.getCredentials(),
|
|
1040
|
+
headers: {
|
|
1041
|
+
"Content-Type": "application/json",
|
|
1042
|
+
...options.getHeaders()
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
return {
|
|
1047
|
+
/**
|
|
1048
|
+
* List all WhatsApp Business Accounts for the tenant.
|
|
1049
|
+
* Returns a non-secret view — no secretRef is exposed.
|
|
1050
|
+
* Calls GET /api/v1/tenants/:id/whatsapp-business-accounts.
|
|
1051
|
+
*
|
|
1052
|
+
* @example
|
|
1053
|
+
* const wabas = await sdk.whatsappBusinessAccounts.list('ten_acmecorp')
|
|
1054
|
+
* // pick wabas[0].id as the wabaId for sdk.templates.whatsapp.*
|
|
1055
|
+
*/
|
|
1056
|
+
async list(tenantId) {
|
|
1057
|
+
const path = getWhatsAppBusinessAccountsControllerListUrl(tenantId);
|
|
1058
|
+
const url = `${baseUrl}${path}`;
|
|
1059
|
+
const res = await fetch(url, buildInit("GET"));
|
|
1060
|
+
return parseEnvelopedResponse(res);
|
|
1061
|
+
},
|
|
1062
|
+
/**
|
|
1063
|
+
* Get a single WhatsApp Business Account by its row id.
|
|
1064
|
+
* Returns a non-secret view — no secretRef is exposed.
|
|
1065
|
+
* Calls GET /api/v1/tenants/:id/whatsapp-business-accounts/:wabaRowId.
|
|
1066
|
+
*
|
|
1067
|
+
* @example
|
|
1068
|
+
* const waba = await sdk.whatsappBusinessAccounts.get('ten_acmecorp', 'waba_row_001')
|
|
1069
|
+
*/
|
|
1070
|
+
async get(tenantId, wabaRowId) {
|
|
1071
|
+
const path = getWhatsAppBusinessAccountsControllerFindOneUrl(
|
|
1072
|
+
tenantId,
|
|
1073
|
+
wabaRowId
|
|
1074
|
+
);
|
|
1075
|
+
const url = `${baseUrl}${path}`;
|
|
1076
|
+
const res = await fetch(url, buildInit("GET"));
|
|
1077
|
+
return parseEnvelopedResponse(res);
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// src/ws/ws-client.ts
|
|
1083
|
+
import { io } from "socket.io-client";
|
|
1084
|
+
function createWsClient(options) {
|
|
1085
|
+
const handshakeAuth = options.auth === void 0 ? void 0 : "apiKey" in options.auth ? { apiKey: options.auth.apiKey } : { token: options.auth.token };
|
|
1086
|
+
const ioOptions = {
|
|
1087
|
+
reconnection: true,
|
|
1088
|
+
reconnectionAttempts: Infinity,
|
|
1089
|
+
reconnectionDelay: 1e3,
|
|
1090
|
+
reconnectionDelayMax: 3e4,
|
|
1091
|
+
randomizationFactor: 0.5,
|
|
1092
|
+
withCredentials: options.withCredentials ?? false
|
|
1093
|
+
};
|
|
1094
|
+
if (handshakeAuth !== void 0) {
|
|
1095
|
+
ioOptions.auth = handshakeAuth;
|
|
1096
|
+
}
|
|
1097
|
+
const socket = io(`${options.baseUrl}/ws/chat`, ioOptions);
|
|
1098
|
+
let currentState = "connecting";
|
|
1099
|
+
const stateListeners = /* @__PURE__ */ new Set();
|
|
1100
|
+
function setState(next) {
|
|
1101
|
+
if (next === currentState) return;
|
|
1102
|
+
currentState = next;
|
|
1103
|
+
for (const listener of stateListeners) {
|
|
1104
|
+
listener(next);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
socket.on("connect", () => {
|
|
1108
|
+
setState("connected");
|
|
1109
|
+
});
|
|
1110
|
+
socket.on("disconnect", () => {
|
|
1111
|
+
setState("disconnected");
|
|
1112
|
+
});
|
|
1113
|
+
socket.on("reconnect_attempt", () => {
|
|
1114
|
+
setState("reconnecting");
|
|
1115
|
+
});
|
|
1116
|
+
socket.on("reconnect", () => {
|
|
1117
|
+
setState("connected");
|
|
1118
|
+
});
|
|
1119
|
+
return {
|
|
1120
|
+
get state() {
|
|
1121
|
+
return currentState;
|
|
1122
|
+
},
|
|
1123
|
+
onStateChange(listener) {
|
|
1124
|
+
stateListeners.add(listener);
|
|
1125
|
+
return () => {
|
|
1126
|
+
stateListeners.delete(listener);
|
|
1127
|
+
};
|
|
1128
|
+
},
|
|
1129
|
+
on(event, handler) {
|
|
1130
|
+
const rawHandler = handler;
|
|
1131
|
+
socket.on(event, rawHandler);
|
|
1132
|
+
return () => {
|
|
1133
|
+
;
|
|
1134
|
+
socket.off(event, rawHandler);
|
|
1135
|
+
};
|
|
1136
|
+
},
|
|
1137
|
+
joinConversation(conversationId) {
|
|
1138
|
+
socket.emit("conversation:join", { conversationId });
|
|
1139
|
+
},
|
|
1140
|
+
leaveConversation(conversationId) {
|
|
1141
|
+
socket.emit("conversation:leave", { conversationId });
|
|
1142
|
+
},
|
|
1143
|
+
typingStart(conversationId) {
|
|
1144
|
+
socket.emit("typing:start", { conversationId });
|
|
1145
|
+
},
|
|
1146
|
+
typingStop(conversationId) {
|
|
1147
|
+
socket.emit("typing:stop", { conversationId });
|
|
1148
|
+
},
|
|
1149
|
+
markRead(conversationId, lastReadMessageId) {
|
|
1150
|
+
socket.emit("message:read", { conversationId, lastReadMessageId });
|
|
1151
|
+
},
|
|
1152
|
+
disconnect() {
|
|
1153
|
+
socket.disconnect();
|
|
654
1154
|
}
|
|
655
1155
|
};
|
|
656
1156
|
}
|
|
@@ -669,7 +1169,35 @@ function createOmnivoxClient(options) {
|
|
|
669
1169
|
channels: createChannelsModule(moduleOptions),
|
|
670
1170
|
contacts: createContactsModule(moduleOptions),
|
|
671
1171
|
conversations: createConversationsModule(moduleOptions),
|
|
672
|
-
messages: createMessagesModule(moduleOptions)
|
|
1172
|
+
messages: createMessagesModule(moduleOptions),
|
|
1173
|
+
templates: createTemplatesModule(moduleOptions),
|
|
1174
|
+
cannedResponses: createCannedResponsesModule(moduleOptions),
|
|
1175
|
+
attachments: createAttachmentsModule(moduleOptions),
|
|
1176
|
+
whatsappBusinessAccounts: createWhatsAppBusinessAccountsModule(moduleOptions),
|
|
1177
|
+
/**
|
|
1178
|
+
* Creates a WebSocket client connected to the `/ws/chat` namespace.
|
|
1179
|
+
*
|
|
1180
|
+
* Call this factory once and reuse the returned client. Reconnection with
|
|
1181
|
+
* exponential backoff + jitter (cap 30 s) is fully automatic.
|
|
1182
|
+
*
|
|
1183
|
+
* For API-key or token auth, pass the credential explicitly:
|
|
1184
|
+
* @example
|
|
1185
|
+
* const ws = client.connect({ apiKey: 'ovx_live_abc' })
|
|
1186
|
+
* ws.on('message:new', (msg) => console.log(msg))
|
|
1187
|
+
* ws.joinConversation('conv_001')
|
|
1188
|
+
*
|
|
1189
|
+
* For session/cookie auth (Console), call with no argument — the token
|
|
1190
|
+
* provider's `getCredentials() === 'include'` signals cookie mode and
|
|
1191
|
+
* `withCredentials` is set automatically:
|
|
1192
|
+
* @example
|
|
1193
|
+
* const ws = client.connect()
|
|
1194
|
+
* ws.on('message:new', (msg) => console.log(msg))
|
|
1195
|
+
*/
|
|
1196
|
+
connect: (auth) => createWsClient({
|
|
1197
|
+
baseUrl: options.baseUrl,
|
|
1198
|
+
...auth !== void 0 ? { auth } : {},
|
|
1199
|
+
withCredentials: options.tokenProvider.getCredentials() === "include"
|
|
1200
|
+
})
|
|
673
1201
|
};
|
|
674
1202
|
}
|
|
675
1203
|
|
|
@@ -699,13 +1227,18 @@ export {
|
|
|
699
1227
|
buildPageParams,
|
|
700
1228
|
createAgentsModule,
|
|
701
1229
|
createApiKeyTokenProvider,
|
|
1230
|
+
createAttachmentsModule,
|
|
702
1231
|
createAuthMeModule,
|
|
1232
|
+
createCannedResponsesModule,
|
|
703
1233
|
createChannelsModule,
|
|
704
1234
|
createContactsModule,
|
|
705
1235
|
createConversationsModule,
|
|
706
1236
|
createMessagesModule,
|
|
707
1237
|
createOmnivoxClient,
|
|
708
1238
|
createSessionTokenProvider,
|
|
1239
|
+
createTemplatesModule,
|
|
709
1240
|
createTenantsModule,
|
|
1241
|
+
createWhatsAppBusinessAccountsModule,
|
|
1242
|
+
createWsClient,
|
|
710
1243
|
iteratePages
|
|
711
1244
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digisglobal/omnivox-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^25.9.1",
|
|
27
|
+
"dependency-cruiser": "^17.4.0",
|
|
27
28
|
"happy-dom": "^20.9.0",
|
|
28
29
|
"orval": "^8.15.0",
|
|
29
30
|
"tsup": "latest",
|
|
@@ -31,11 +32,15 @@
|
|
|
31
32
|
"vitest": "latest",
|
|
32
33
|
"@omnivox/tsconfig": "0.0.0"
|
|
33
34
|
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"socket.io-client": "^4.8.3"
|
|
37
|
+
},
|
|
34
38
|
"scripts": {
|
|
35
39
|
"codegen": "orval --config orval.config.ts && prettier --write src/_generated",
|
|
36
40
|
"build": "tsup",
|
|
37
41
|
"typecheck": "tsc --noEmit",
|
|
38
42
|
"test": "vitest run",
|
|
39
|
-
"lint": "eslint ."
|
|
43
|
+
"lint": "eslint .",
|
|
44
|
+
"depcruise": "depcruise src --config .dependency-cruiser.cjs"
|
|
40
45
|
}
|
|
41
46
|
}
|