@ikatec/digisac-api-sdk 4.11.0 → 4.13.0

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.
Files changed (142) hide show
  1. package/dist/apis/absence/AbsenceApi.cjs +46 -2
  2. package/dist/apis/absence/AbsenceApi.cjs.map +1 -1
  3. package/dist/apis/absence/AbsenceApi.d.ts +38 -4
  4. package/dist/apis/absence/AbsenceApi.d.ts.map +1 -1
  5. package/dist/apis/absence/AbsenceApi.mjs +46 -2
  6. package/dist/apis/absence/AbsenceApi.mjs.map +1 -1
  7. package/dist/apis/absence/types.d.ts +51 -2
  8. package/dist/apis/absence/types.d.ts.map +1 -1
  9. package/dist/apis/activityLog/ActivityLogApi.cjs +10 -1
  10. package/dist/apis/activityLog/ActivityLogApi.cjs.map +1 -1
  11. package/dist/apis/activityLog/ActivityLogApi.d.ts +10 -3
  12. package/dist/apis/activityLog/ActivityLogApi.d.ts.map +1 -1
  13. package/dist/apis/activityLog/ActivityLogApi.mjs +10 -1
  14. package/dist/apis/activityLog/ActivityLogApi.mjs.map +1 -1
  15. package/dist/apis/activityLog/types.d.ts +48 -8
  16. package/dist/apis/activityLog/types.d.ts.map +1 -1
  17. package/dist/apis/categories/types.d.ts +1 -0
  18. package/dist/apis/categories/types.d.ts.map +1 -1
  19. package/dist/apis/creditMovements/CreditMovementsApi.cjs +31 -2
  20. package/dist/apis/creditMovements/CreditMovementsApi.cjs.map +1 -1
  21. package/dist/apis/creditMovements/CreditMovementsApi.d.ts +21 -3
  22. package/dist/apis/creditMovements/CreditMovementsApi.d.ts.map +1 -1
  23. package/dist/apis/creditMovements/CreditMovementsApi.mjs +31 -2
  24. package/dist/apis/creditMovements/CreditMovementsApi.mjs.map +1 -1
  25. package/dist/apis/creditMovements/types.d.ts +73 -2
  26. package/dist/apis/creditMovements/types.d.ts.map +1 -1
  27. package/dist/apis/interactiveMessages/InteractiveMessagesApi.cjs +15 -0
  28. package/dist/apis/interactiveMessages/InteractiveMessagesApi.cjs.map +1 -1
  29. package/dist/apis/interactiveMessages/InteractiveMessagesApi.d.ts +13 -0
  30. package/dist/apis/interactiveMessages/InteractiveMessagesApi.d.ts.map +1 -1
  31. package/dist/apis/interactiveMessages/InteractiveMessagesApi.mjs +15 -0
  32. package/dist/apis/interactiveMessages/InteractiveMessagesApi.mjs.map +1 -1
  33. package/dist/apis/interactiveMessages/types.d.ts +8 -2
  34. package/dist/apis/interactiveMessages/types.d.ts.map +1 -1
  35. package/dist/apis/knowledgeBase/KnowledgeBaseApi.cjs +27 -0
  36. package/dist/apis/knowledgeBase/KnowledgeBaseApi.cjs.map +1 -1
  37. package/dist/apis/knowledgeBase/KnowledgeBaseApi.d.ts +22 -1
  38. package/dist/apis/knowledgeBase/KnowledgeBaseApi.d.ts.map +1 -1
  39. package/dist/apis/knowledgeBase/KnowledgeBaseApi.mjs +27 -0
  40. package/dist/apis/knowledgeBase/KnowledgeBaseApi.mjs.map +1 -1
  41. package/dist/apis/knowledgeBase/types.d.ts +56 -2
  42. package/dist/apis/knowledgeBase/types.d.ts.map +1 -1
  43. package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.cjs +26 -0
  44. package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.cjs.map +1 -1
  45. package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.d.ts +24 -0
  46. package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.d.ts.map +1 -1
  47. package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.mjs +26 -0
  48. package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.mjs.map +1 -1
  49. package/dist/apis/knowledgeBaseItem/types.d.ts +23 -6
  50. package/dist/apis/knowledgeBaseItem/types.d.ts.map +1 -1
  51. package/dist/apis/me/MeApi.cjs +36 -29
  52. package/dist/apis/me/MeApi.cjs.map +1 -1
  53. package/dist/apis/me/MeApi.d.ts +33 -22
  54. package/dist/apis/me/MeApi.d.ts.map +1 -1
  55. package/dist/apis/me/MeApi.mjs +36 -29
  56. package/dist/apis/me/MeApi.mjs.map +1 -1
  57. package/dist/apis/me/types.d.ts +67 -4
  58. package/dist/apis/me/types.d.ts.map +1 -1
  59. package/dist/apis/notifications/NotificationsApi.cjs +50 -2
  60. package/dist/apis/notifications/NotificationsApi.cjs.map +1 -1
  61. package/dist/apis/notifications/NotificationsApi.d.ts +41 -3
  62. package/dist/apis/notifications/NotificationsApi.d.ts.map +1 -1
  63. package/dist/apis/notifications/NotificationsApi.mjs +50 -2
  64. package/dist/apis/notifications/NotificationsApi.mjs.map +1 -1
  65. package/dist/apis/notifications/types.d.ts +54 -8
  66. package/dist/apis/notifications/types.d.ts.map +1 -1
  67. package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.cjs.map +1 -1
  68. package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.d.ts +4 -1
  69. package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.d.ts.map +1 -1
  70. package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.mjs.map +1 -1
  71. package/dist/apis/serviceAccessManagement/types.d.ts +3 -0
  72. package/dist/apis/serviceAccessManagement/types.d.ts.map +1 -1
  73. package/dist/apis/stickerUsers/StickerUsersApi.cjs.map +1 -1
  74. package/dist/apis/stickerUsers/StickerUsersApi.d.ts +3 -1
  75. package/dist/apis/stickerUsers/StickerUsersApi.d.ts.map +1 -1
  76. package/dist/apis/stickerUsers/StickerUsersApi.mjs.map +1 -1
  77. package/dist/apis/stickerUsers/types.d.ts +4 -0
  78. package/dist/apis/stickerUsers/types.d.ts.map +1 -1
  79. package/dist/apis/stickers/StickersApi.cjs +27 -3
  80. package/dist/apis/stickers/StickersApi.cjs.map +1 -1
  81. package/dist/apis/stickers/StickersApi.d.ts +24 -4
  82. package/dist/apis/stickers/StickersApi.d.ts.map +1 -1
  83. package/dist/apis/stickers/StickersApi.mjs +27 -3
  84. package/dist/apis/stickers/StickersApi.mjs.map +1 -1
  85. package/dist/apis/stickers/types.d.ts +28 -4
  86. package/dist/apis/stickers/types.d.ts.map +1 -1
  87. package/dist/apis/transcripts/TranscriptsApi.cjs +12 -2
  88. package/dist/apis/transcripts/TranscriptsApi.cjs.map +1 -1
  89. package/dist/apis/transcripts/TranscriptsApi.d.ts +11 -5
  90. package/dist/apis/transcripts/TranscriptsApi.d.ts.map +1 -1
  91. package/dist/apis/transcripts/TranscriptsApi.mjs +12 -2
  92. package/dist/apis/transcripts/TranscriptsApi.mjs.map +1 -1
  93. package/dist/apis/transcripts/types.d.ts +4 -0
  94. package/dist/apis/transcripts/types.d.ts.map +1 -1
  95. package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.cjs +51 -0
  96. package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.cjs.map +1 -1
  97. package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.d.ts +44 -2
  98. package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.d.ts.map +1 -1
  99. package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.mjs +51 -0
  100. package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.mjs.map +1 -1
  101. package/dist/apis/whatsappBusinessTemplates/types.d.ts +34 -1
  102. package/dist/apis/whatsappBusinessTemplates/types.d.ts.map +1 -1
  103. package/package.json +1 -1
  104. package/src/apis/absence/AbsenceApi.test.ts +65 -0
  105. package/src/apis/absence/AbsenceApi.ts +77 -4
  106. package/src/apis/absence/types.ts +53 -2
  107. package/src/apis/activityLog/ActivityLogApi.test.ts +44 -0
  108. package/src/apis/activityLog/ActivityLogApi.ts +22 -3
  109. package/src/apis/activityLog/types.ts +47 -8
  110. package/src/apis/categories/types.ts +1 -0
  111. package/src/apis/creditMovements/CreditMovementsApi.test.ts +88 -0
  112. package/src/apis/creditMovements/CreditMovementsApi.ts +73 -2
  113. package/src/apis/creditMovements/types.ts +74 -2
  114. package/src/apis/interactiveMessages/InteractiveMessagesApi.test.ts +59 -0
  115. package/src/apis/interactiveMessages/InteractiveMessagesApi.ts +26 -0
  116. package/src/apis/interactiveMessages/types.ts +8 -2
  117. package/src/apis/knowledgeBase/KnowledgeBaseApi.test.ts +54 -0
  118. package/src/apis/knowledgeBase/KnowledgeBaseApi.ts +61 -1
  119. package/src/apis/knowledgeBase/types.ts +62 -2
  120. package/src/apis/knowledgeBaseItem/KnowledgeBaseItemApi.test.ts +57 -0
  121. package/src/apis/knowledgeBaseItem/KnowledgeBaseItemApi.ts +45 -0
  122. package/src/apis/knowledgeBaseItem/types.ts +23 -6
  123. package/src/apis/me/MeApi.test.ts +45 -1
  124. package/src/apis/me/MeApi.ts +83 -28
  125. package/src/apis/me/types.ts +75 -4
  126. package/src/apis/notifications/NotificationsApi.test.ts +74 -0
  127. package/src/apis/notifications/NotificationsApi.ts +88 -3
  128. package/src/apis/notifications/types.ts +65 -7
  129. package/src/apis/payloads.test-d.ts +82 -2
  130. package/src/apis/serviceAccessManagement/ServiceAccessManagementApi.ts +4 -1
  131. package/src/apis/serviceAccessManagement/types.ts +3 -0
  132. package/src/apis/stickerUsers/StickerUsersApi.ts +3 -1
  133. package/src/apis/stickerUsers/types.ts +4 -0
  134. package/src/apis/stickers/StickersApi.test.ts +58 -0
  135. package/src/apis/stickers/StickersApi.ts +46 -4
  136. package/src/apis/stickers/types.ts +29 -4
  137. package/src/apis/transcripts/TranscriptsApi.test.ts +14 -21
  138. package/src/apis/transcripts/TranscriptsApi.ts +15 -6
  139. package/src/apis/transcripts/types.ts +4 -0
  140. package/src/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.test.ts +86 -0
  141. package/src/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.ts +74 -1
  142. package/src/apis/whatsappBusinessTemplates/types.ts +38 -1
@@ -18,6 +18,10 @@ import type {
18
18
  import { CardsApi } from './cards/CardsApi'
19
19
  import { ContactsApi } from './contacts/ContactsApi'
20
20
  import { InteractiveMessagesApi } from './interactiveMessages/InteractiveMessagesApi'
21
+ import { MeApi } from './me/MeApi'
22
+ import type { AccountAmounts, MeStatusResponse } from './me/types'
23
+ import { TranscriptsApi } from './transcripts/TranscriptsApi'
24
+ import { WhatsappBusinessTemplatesApi } from './whatsappBusinessTemplates/WhatsappBusinessTemplatesApi'
21
25
  import type {
22
26
  ChannelRedirect,
23
27
  CtaUrlInteractiveMessageContent,
@@ -67,10 +71,18 @@ import { KnowledgeBaseApi } from './knowledgeBase/KnowledgeBaseApi'
67
71
  import { KnowledgeBaseItemApi } from './knowledgeBaseItem/KnowledgeBaseItemApi'
68
72
  import { MessagesApi } from './messages/MessagesApi'
69
73
  import { NotificationsApi } from './notifications/NotificationsApi'
74
+ import type { NotificationCountsResponse } from './notifications/types'
75
+ import { AbsenceApi } from './absence/AbsenceApi'
76
+ import type { AbsenceReportItem, UnlockAbsenceResponse } from './absence/types'
77
+ import { ActivityLogApi } from './activityLog/ActivityLogApi'
78
+ import { CreditMovementsApi } from './creditMovements/CreditMovementsApi'
79
+ import type { CreditBalances, CreditTotalServices } from './creditMovements/types'
80
+ import { StickersApi } from './stickers/StickersApi'
81
+ import type { Sticker } from './stickers/types'
70
82
  import { OrganizationsApi } from './organizations/OrganizationsApi'
71
83
  import { PeopleApi } from './people/PeopleApi'
72
84
  import { ServicesApi } from './services/ServicesApi'
73
- import type { UpdateUserPayload } from './users/types'
85
+ import type { UpdateUserPayload, User } from './users/types'
74
86
  import { WebhooksApi } from './webhooks/WebhooksApi'
75
87
 
76
88
  declare const client: ApiClient
@@ -210,7 +222,10 @@ expectError(
210
222
  )
211
223
 
212
224
  declare const interactiveMessage: InteractiveMessage
213
- expectType<'list' | 'button' | 'cta_url' | 'request_contact_info'>(interactiveMessage.type)
225
+ // `type` is not a field of the backend (deprecated, optional): the type is `interactive.type`.
226
+ expectType<'list' | 'button' | 'cta_url' | 'request_contact_info' | undefined>(
227
+ interactiveMessage.type,
228
+ )
214
229
  if (interactiveMessage.interactive.type === 'cta_url') {
215
230
  expectType<CtaUrlInteractiveMessageContent>(interactiveMessage.interactive)
216
231
  expectType<string>(interactiveMessage.interactive.action.parameters.url)
@@ -548,6 +563,33 @@ expectType<Promise<boolean>>(new RolesApi(client).deleteById('r-1'))
548
563
  expectType<Promise<void>>(new AcceptanceTermsApi(client).deleteById('t-1'))
549
564
  expectType<Promise<void>>(new DistributionApi(client).deleteById('d-1'))
550
565
 
566
+ // ── QARC-1009: /me, transcripts, interactive messages, templates ─────
567
+
568
+ expectType<Promise<'OK'>>(new MeApi(client).activateOtpAuth({ 'x-digisac-otp': '123456' }))
569
+ expectType<Promise<MeStatusResponse>>(
570
+ new MeApi(client).updateStatus({ status: 'offline', client: 'web' }),
571
+ )
572
+ expectType<Promise<AccountAmounts>>(
573
+ new MeApi(client).getAccountAmounts({ filter: ['users.amounts'] }),
574
+ )
575
+ expectType<Promise<User>>(new MeApi(client).getMe({ include: ['account'] }))
576
+ expectError(new MeApi(client).updateStatus({ status: 'offline', client: 'desktop' }))
577
+ expectType<Promise<void>>(new TranscriptsApi(client).transcribe('m-1'))
578
+ expectType<Promise<{ count: number }>>(new InteractiveMessagesApi(client).count())
579
+ expectType<Promise<{ count: number }>>(new WhatsappBusinessTemplatesApi(client).count())
580
+ expectType<Promise<'OK'>>(new WhatsappBusinessTemplatesApi(client).refreshTemplates())
581
+ expectError(
582
+ new WhatsappBusinessTemplatesApi(client).create({
583
+ name: 'qa',
584
+ internalName: 'QA',
585
+ components: [],
586
+ serviceId: 's-1',
587
+ messageType: 'text_only',
588
+ language: 'pt_BR',
589
+ category: 'UTILITY',
590
+ }),
591
+ )
592
+
551
593
  // ── create/updateById: what each route really answers (QARC-1008) ─────
552
594
 
553
595
  expectType<Promise<Distribution | undefined>>(
@@ -669,3 +711,41 @@ expectAssignable<ApiClient>({
669
711
  patch: async <T>() => undefined as T,
670
712
  delete: async <T>() => undefined as T,
671
713
  })
714
+
715
+ // ── QARC-1010: notifications, absence, log, knowledge base, credits, stickers ─────
716
+
717
+ expectType<Promise<NotificationCountsResponse>>(new NotificationsApi(client).count())
718
+ expectType<Promise<string>>(new NotificationsApi(client).count().then(({ count }) => count.total))
719
+ expectError(new NotificationsApi(client).sendAll({ to: 'admin' }))
720
+ expectType<Promise<void>>(new NotificationsApi(client).readMany(['n-1']))
721
+ expectType<Promise<Paginated<AbsenceReportItem>>>(
722
+ new AbsenceApi(client).report({ filters: { reason: 'x' }, order: 'ASC' }),
723
+ )
724
+ expectType<Promise<UnlockAbsenceResponse>>(new AbsenceApi(client).unlock({}))
725
+ expectError(new AbsenceApi(client).report({ sort: 'name' }))
726
+ expectType<Promise<string>>(
727
+ new ActivityLogApi(client).exportCsv({ filters: { from: 'a', to: 'b' } }),
728
+ )
729
+ expectAssignable<Parameters<ActivityLogApi['create']>[0]>({
730
+ resourceType: 'contact',
731
+ event: 'update',
732
+ })
733
+ expectType<Promise<true>>(new KnowledgeBaseItemApi(client).deleteMany(['i-1']))
734
+ expectError(
735
+ new KnowledgeBaseApi(client).saveWithItems({ name: 'qa', items: [{ name: 'x', type: 'pdf' }] }),
736
+ )
737
+ expectType<Promise<CreditBalances>>(new CreditMovementsApi(client).balances())
738
+ expectType<Promise<number>>(new CreditMovementsApi(client).balance('sms-wavy'))
739
+ expectType<Promise<CreditTotalServices | undefined>>(
740
+ new CreditMovementsApi(client).totalServices({
741
+ filters: { from: 'a', to: 'b', serviceType: 'summary' },
742
+ page: 1,
743
+ }),
744
+ )
745
+ expectType<Promise<ArrayBuffer>>(
746
+ new CreditMovementsApi(client).exportXlsx({ from: 'a', to: 'b', where: { $and: [] } }),
747
+ )
748
+ expectType<Promise<Sticker>>(new StickersApi(client).create({ base64: 'iVBOR', name: 'qa' }))
749
+ expectError(new StickersApi(client).create({ type: 'created' }))
750
+ expectType<Promise<'OK' | false>>(new StickersApi(client).remove('s-1'))
751
+ expectAssignable<Parameters<StickersApi['getMany']>[0]>({ include: ['file'] })
@@ -6,7 +6,10 @@ export class ServiceAccessManagementApi
6
6
  extends BaseApi
7
7
  implements HasGetMany<ServiceAccessManagement>
8
8
  {
9
- /** Returns a paginated list of which users have access to which services. */
9
+ /**
10
+ * The connections denied to each user (one row per user × connection, written by
11
+ * `POST /services/:id/access-management`), raw. Filter by the `serviceId` or `userId` you want.
12
+ */
10
13
  getMany(
11
14
  query: ListQuery<ServiceAccessManagement> & { paginate: false },
12
15
  headers?: Record<string, string>,
@@ -6,8 +6,11 @@ export type ServiceAccessManagement = {
6
6
  serviceId: string
7
7
  createdAt: string
8
8
  // relationships
9
+ /** @deprecated Not served: the backend drops every include of this route. */
9
10
  user?: User
11
+ /** @deprecated Not served: the backend drops every include of this route. */
10
12
  service?: Service
11
13
  }
12
14
 
15
+ /** None is served: the backend drops every include of this route. */
13
16
  export type ServiceAccessManagementRelationships = 'user' | 'service'
@@ -4,7 +4,9 @@ import type { StickerUser } from './types'
4
4
 
5
5
  export class StickerUsersApi extends BaseApi implements HasGetMany<StickerUser> {
6
6
  /**
7
- * Returns a paginated list of sticker-user associations with their related file.
7
+ * The stickers the current user sent recently (`lastSendAt`), paginated; only the `file` include is
8
+ * served. A row is written when the user sends a message of type `sticker` (in the background, after the
9
+ * send).
8
10
  * @permissions stickers.send
9
11
  */
10
12
  getMany(
@@ -10,9 +10,13 @@ export type StickerUser = {
10
10
  createdAt: string
11
11
  updatedAt: string
12
12
  // relationships
13
+ /** @deprecated Not served: the backend only serves the `file` include. */
13
14
  sticker?: Sticker
15
+ /** @deprecated Not served: the backend only serves the `file` include. */
14
16
  user?: User
17
+ /** The image of the sticker. */
15
18
  file?: File
16
19
  }
17
20
 
21
+ /** The backend serves only `file` (`sticker` and `user` are dropped). */
18
22
  export type StickerUserRelationships = 'sticker' | 'user' | 'file'
@@ -0,0 +1,58 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { StickersApi } from './StickersApi'
3
+ import type { ApiClient } from '../../core/ApiClient'
4
+
5
+ // ── Mock client factory ──────────────────────────────────────────────
6
+
7
+ function createMockClient(): ApiClient {
8
+ return {
9
+ setAccessToken: vi.fn().mockReturnThis(),
10
+ request: vi.fn(),
11
+ requestRaw: vi.fn(),
12
+ get: vi.fn(),
13
+ post: vi.fn(),
14
+ put: vi.fn(),
15
+ patch: vi.fn(),
16
+ delete: vi.fn(),
17
+ }
18
+ }
19
+
20
+ // ── Tests ────────────────────────────────────────────────────────────
21
+
22
+ describe('StickersApi', () => {
23
+ let client: ReturnType<typeof createMockClient>
24
+ let api: StickersApi
25
+
26
+ beforeEach(() => {
27
+ client = createMockClient()
28
+ api = new StickersApi(client)
29
+ })
30
+
31
+ it('create posts the image to /stickers', async () => {
32
+ await api.create({ base64: 'iVBOR', name: 'qa' })
33
+ expect(client.post).toHaveBeenCalledWith(
34
+ '/stickers',
35
+ { base64: 'iVBOR', name: 'qa' },
36
+ undefined,
37
+ )
38
+ })
39
+
40
+ it('exist serializes the message and the checksum', async () => {
41
+ vi.mocked(client.get).mockResolvedValue({})
42
+ await expect(api.exist({ messageId: 'm-1', fileChecksum: 'abc' })).resolves.toEqual({})
43
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
44
+ expect(url).toMatch(/^\/stickers\/exist\?/)
45
+ expect(decodeURIComponent(url)).toContain('"fileChecksum":"abc"')
46
+ })
47
+
48
+ it('add posts the message to /stickers/add', async () => {
49
+ await api.add('m-1')
50
+ expect(client.post).toHaveBeenCalledWith('/stickers/add', { messageId: 'm-1' }, undefined)
51
+ })
52
+
53
+ it('remove deletes /stickers/remove/:stickerId', async () => {
54
+ vi.mocked(client.delete).mockResolvedValue('OK')
55
+ await expect(api.remove('s-1')).resolves.toBe('OK')
56
+ expect(client.delete).toHaveBeenCalledWith('/stickers/remove/s-1', undefined)
57
+ })
58
+ })
@@ -1,12 +1,18 @@
1
1
  import type { ApiClient } from '../../core/ApiClient'
2
2
  import { BaseCrudApi } from '../../core/BaseCrudApi'
3
3
  import type { GetByIdQuery } from '../../core/types'
4
- import type { Sticker, CreateStickerPayload, UpdateStickerPayload } from './types'
4
+ import type {
5
+ Sticker,
6
+ CreateStickerPayload,
7
+ UpdateStickerPayload,
8
+ StickerExistQuery,
9
+ } from './types'
5
10
 
6
11
  /**
7
- * Stickers of the account. The backend serves `GET /stickers` and `POST /stickers` (plus
8
- * `GET /stickers/exist`, `POST /stickers/add` and `DELETE /stickers/remove/:stickerId`); there is
9
- * no read by id, update nor `DELETE /stickers/:id`.
12
+ * Stickers of the account: every user of the account sees them. The backend serves `GET /stickers`,
13
+ * `POST /stickers`, `GET /stickers/exist`, `POST /stickers/add` and `DELETE /stickers/remove/:stickerId`;
14
+ * there is no read by id, update nor `DELETE /stickers/:id`. The list accepts only the `file` include.
15
+ * @permissions stickers.send (list) · stickers.management (create, exist, add, remove)
10
16
  */
11
17
  export class StickersApi extends BaseCrudApi<Sticker, CreateStickerPayload, UpdateStickerPayload> {
12
18
  constructor(client: ApiClient) {
@@ -38,4 +44,40 @@ export class StickersApi extends BaseCrudApi<Sticker, CreateStickerPayload, Upda
38
44
  override deleteById(id: string, headers?: Record<string, string>): Promise<Sticker> {
39
45
  return super.deleteById(id, headers)
40
46
  }
47
+
48
+ /**
49
+ * Finds the sticker of the account that came from the message, or from the file of `fileChecksum` or
50
+ * `filehash`. Resolves `{ stickerId }`, or `{}` when there is none; without `messageId` it answers 500
51
+ * `Invalid message ID`.
52
+ */
53
+ exist(
54
+ query: StickerExistQuery,
55
+ headers?: Record<string, string>,
56
+ ): Promise<{ stickerId?: string }> {
57
+ return this.client.get<{ stickerId?: string }>(
58
+ `${this.basePath}/exist${this.toQueryString(query)}`,
59
+ headers,
60
+ )
61
+ }
62
+
63
+ /**
64
+ * Turns the file of a message of the account into a sticker (`type: 'added'`). Idempotent: a sticker that
65
+ * already came from the message (or its file) is answered as is, and a removed one is restored. A message
66
+ * without file answers 500 `Message or file not found`.
67
+ */
68
+ add(messageId: string, headers?: Record<string, string>): Promise<Sticker> {
69
+ return this.client.post<Sticker, { messageId: string }>(
70
+ `${this.basePath}/add`,
71
+ { messageId },
72
+ headers,
73
+ )
74
+ }
75
+
76
+ /**
77
+ * Removes a sticker of the account (soft delete; its file stays in the storage) and clears it from the
78
+ * recent stickers of every user. Resolves the text `'OK'`, or `false` when there is no such sticker.
79
+ */
80
+ remove(stickerId: string, headers?: Record<string, string>): Promise<'OK' | false> {
81
+ return this.client.delete<'OK' | false>(`${this.basePath}/remove/${stickerId}`, headers)
82
+ }
41
83
  }
@@ -1,8 +1,11 @@
1
+ import type { File } from '../files/types'
1
2
  import type { User } from '../users/types'
2
3
 
4
+ /** A sticker of the account (every user of the account sees it). */
3
5
  export type Sticker = {
4
6
  id: string
5
- type: string
7
+ /** `'created'` (uploaded with `create`) or `'added'` (taken from a message with `add`). */
8
+ type: 'created' | 'added' | (string & {})
6
9
  originFileChecksum: string | null
7
10
  originFilehash: string | null
8
11
  originMessageId: string | null
@@ -10,20 +13,42 @@ export type Sticker = {
10
13
  accountId: string
11
14
  createdAt: string
12
15
  updatedAt: string
13
- deletedAt: string | null
16
+ deletedAt?: string | null
14
17
  // relationships
18
+ /** @deprecated Not served: the backend only serves the `file` include. */
15
19
  user?: User
20
+ /** The image (webp) of the sticker. */
21
+ file?: File
16
22
  }
17
23
 
18
- export type StickerRelationships = 'user'
24
+ /** The backend serves only `file` (`user` is dropped). */
25
+ export type StickerRelationships = 'user' | 'file'
19
26
 
27
+ /**
28
+ * Uploads an image as a sticker: the backend converts it to a 512x512 webp (413 when it ends up too large:
29
+ * 100KB static, 500KB animated). `base64` without the `data:...;base64,` prefix.
30
+ */
20
31
  export type CreateStickerPayload = {
21
- type: string
32
+ base64: string
33
+ /** The name of the file (`<name>.webp`). */
34
+ name: string
35
+ /** @deprecated Ignored by the backend: a created sticker is always `'created'`. */
36
+ type?: string
37
+ /** @deprecated Ignored by the backend: use `add` to take a sticker from a message. */
22
38
  originMessageId?: string
39
+ /** @deprecated Ignored by the backend. */
23
40
  originFileChecksum?: string
41
+ /** @deprecated Ignored by the backend. */
24
42
  originFilehash?: string
25
43
  }
26
44
 
27
45
  export type UpdateStickerPayload = {
28
46
  type?: string
29
47
  }
48
+
49
+ /** Query of `exist`: finds a sticker of the account by the message or by the file it came from. */
50
+ export type StickerExistQuery = {
51
+ messageId: string
52
+ fileChecksum?: string
53
+ filehash?: string
54
+ }
@@ -1,7 +1,6 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
  import { TranscriptsApi } from './TranscriptsApi'
3
3
  import type { ApiClient } from '../../core/ApiClient'
4
- import type { TranscriptResponse } from './types'
5
4
 
6
5
  // ── Mock client factory ──────────────────────────────────────────────
7
6
 
@@ -28,36 +27,30 @@ describe('TranscriptsApi', () => {
28
27
  api = new TranscriptsApi(client)
29
28
  })
30
29
 
31
- // ── getById ──────────────────────────────────────────────────────
32
-
33
- describe('getById', () => {
34
- it('calls client.get with /transcripts/:id', async () => {
35
- const response: TranscriptResponse = {
36
- id: 'msg-1',
37
- isTranscribing: true,
38
- transcribeError: false,
39
- }
40
- vi.mocked(client.get).mockResolvedValue(response)
41
- const result = await api.getById('msg-1')
30
+ describe('transcribe', () => {
31
+ it('calls client.get with /transcripts/:messageId and resolves the empty answer', async () => {
32
+ vi.mocked(client.get).mockResolvedValue(undefined)
33
+ await expect(api.transcribe('msg-1')).resolves.toBeUndefined()
42
34
  expect(client.get).toHaveBeenCalledWith('/transcripts/msg-1', undefined)
43
- expect(result).toEqual(response)
44
35
  })
45
36
 
46
37
  it('forwards custom headers', async () => {
47
- const response: TranscriptResponse = {
48
- id: 'msg-2',
49
- isTranscribing: false,
50
- transcribeError: true,
51
- }
52
- vi.mocked(client.get).mockResolvedValue(response)
53
38
  const headers = { 'X-Custom': 'h' }
54
- await api.getById('msg-2', headers)
39
+ await api.transcribe('msg-2', headers)
55
40
  expect(client.get).toHaveBeenCalledWith('/transcripts/msg-2', headers)
56
41
  })
57
42
 
58
43
  it('propagates errors from client.get', async () => {
59
44
  vi.mocked(client.get).mockRejectedValue(new Error('Not found'))
60
- await expect(api.getById('missing')).rejects.toThrow('Not found')
45
+ await expect(api.transcribe('missing')).rejects.toThrow('Not found')
46
+ })
47
+ })
48
+
49
+ describe('getById (deprecated)', () => {
50
+ it('starts the transcription through the same route', async () => {
51
+ vi.mocked(client.get).mockResolvedValue(undefined)
52
+ await expect(api.getById('msg-3')).resolves.toBeUndefined()
53
+ expect(client.get).toHaveBeenCalledWith('/transcripts/msg-3', undefined)
61
54
  })
62
55
  })
63
56
  })
@@ -1,12 +1,21 @@
1
1
  import { BaseApi } from '../../core/BaseApi'
2
- import type { HasGetById } from '../../core/types'
3
- import type { TranscriptResponse } from './types'
4
2
 
5
- export class TranscriptsApi extends BaseApi implements HasGetById<TranscriptResponse> {
3
+ export class TranscriptsApi extends BaseApi {
6
4
  private readonly basePath = '/transcripts'
7
5
 
8
- /** Triggers audio transcription for a message by dispatching an async job, and marks it as transcribing. */
9
- getById(id: string, headers?: Record<string, string>): Promise<TranscriptResponse> {
10
- return this.client.get<TranscriptResponse>(`${this.basePath}/${id}`, headers)
6
+ /**
7
+ * Starts the transcription of the audio of a message: marks the message as transcribing and dispatches an async
8
+ * job, which calls the transcription service (AI) and debits the AI credits of the account. Resolves with no body;
9
+ * the result shows on the message. An unknown message answers 500.
10
+ */
11
+ transcribe(messageId: string, headers?: Record<string, string>): Promise<void> {
12
+ return this.client.get<void>(`${this.basePath}/${messageId}`, headers)
13
+ }
14
+
15
+ /**
16
+ * @deprecated Not a read: it starts the transcription of the message. Use {@link transcribe}.
17
+ */
18
+ getById(id: string, headers?: Record<string, string>): Promise<void> {
19
+ return this.transcribe(id, headers)
11
20
  }
12
21
  }
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @deprecated The route answers no body: `TranscriptsApi.transcribe` (and `getById`) resolve `undefined`. The
3
+ * transcription status shows on the message (`isTranscribing`, `transcribeError`).
4
+ */
1
5
  export type TranscriptResponse = {
2
6
  id: string
3
7
  isTranscribing: boolean
@@ -0,0 +1,86 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { WhatsappBusinessTemplatesApi } from './WhatsappBusinessTemplatesApi'
3
+ import type { ApiClient } from '../../core/ApiClient'
4
+
5
+ // ── Mock client factory ──────────────────────────────────────────────
6
+
7
+ function createMockClient(): ApiClient {
8
+ return {
9
+ setAccessToken: vi.fn().mockReturnThis(),
10
+ request: vi.fn(),
11
+ get: vi.fn(),
12
+ post: vi.fn(),
13
+ put: vi.fn(),
14
+ patch: vi.fn(),
15
+ delete: vi.fn(),
16
+ }
17
+ }
18
+
19
+ // ── Tests ────────────────────────────────────────────────────────────
20
+
21
+ describe('WhatsappBusinessTemplatesApi', () => {
22
+ let client: ReturnType<typeof createMockClient>
23
+ let api: WhatsappBusinessTemplatesApi
24
+
25
+ beforeEach(() => {
26
+ client = createMockClient()
27
+ api = new WhatsappBusinessTemplatesApi(client)
28
+ })
29
+
30
+ it('count calls client.get with /whatsapp-business-templates/count', async () => {
31
+ vi.mocked(client.get).mockResolvedValue({ count: 2 })
32
+ await expect(api.count()).resolves.toEqual({ count: 2 })
33
+ expect(client.get).toHaveBeenCalledWith('/whatsapp-business-templates/count', undefined)
34
+ })
35
+
36
+ it('getHsmLimit calls client.get with /whatsapp-business-templates/:accountId/hsmLimit', async () => {
37
+ const limit = { hsmLimit: 10, hsmUsedLimit: 3, hasLimit: 7 }
38
+ vi.mocked(client.get).mockResolvedValue(limit)
39
+ await expect(api.getHsmLimit('acc-1')).resolves.toEqual(limit)
40
+ expect(client.get).toHaveBeenCalledWith(
41
+ '/whatsapp-business-templates/acc-1/hsmLimit',
42
+ undefined,
43
+ )
44
+ })
45
+
46
+ it('sendToReview posts to /whatsapp-business-templates/:id/send-to-review', async () => {
47
+ await api.sendToReview('t-1')
48
+ expect(client.post).toHaveBeenCalledWith(
49
+ '/whatsapp-business-templates/t-1/send-to-review',
50
+ undefined,
51
+ undefined,
52
+ )
53
+ })
54
+
55
+ it('refreshTemplates posts to /whatsapp-business-templates/refresh-templates and resolves OK', async () => {
56
+ vi.mocked(client.post).mockResolvedValue('OK')
57
+ await expect(api.refreshTemplates()).resolves.toBe('OK')
58
+ expect(client.post).toHaveBeenCalledWith(
59
+ '/whatsapp-business-templates/refresh-templates',
60
+ undefined,
61
+ undefined,
62
+ )
63
+ })
64
+
65
+ it('resume calls client.get with /whatsapp-business-templates/resume', async () => {
66
+ vi.mocked(client.get).mockResolvedValue([])
67
+ await expect(api.resume()).resolves.toEqual([])
68
+ expect(client.get).toHaveBeenCalledWith('/whatsapp-business-templates/resume', undefined)
69
+ })
70
+
71
+ it('create posts the draft with status and namespace', async () => {
72
+ const body = {
73
+ name: 'qa_template',
74
+ internalName: 'QA',
75
+ status: '',
76
+ namespace: '',
77
+ components: [{ type: 'BODY' as const, text: 'Olá' }],
78
+ serviceId: 's-1',
79
+ messageType: 'text_only' as const,
80
+ language: 'pt_BR' as const,
81
+ category: 'UTILITY' as const,
82
+ }
83
+ await api.create(body)
84
+ expect(client.post).toHaveBeenCalledWith('/whatsapp-business-templates', body, undefined)
85
+ })
86
+ })
@@ -1,17 +1,90 @@
1
1
  import type { ApiClient } from '../../core/ApiClient'
2
+ import type { ListQuery } from '../../core/types'
2
3
  import { BaseCrudApi } from '../../core/BaseCrudApi'
3
4
  import type {
4
5
  WhatsappBusinessTemplate,
5
6
  CreateWhatsappBusinessTemplatePayload,
6
7
  UpdateWhatsappBusinessTemplatePayload,
8
+ WhatsappBusinessTemplateHsmLimit,
7
9
  } from './types'
8
10
 
11
+ /**
12
+ * WhatsApp Business templates. Create, update, reads and count are local; `sendToReview`, `refreshTemplates`,
13
+ * `resume` and the delete of a template of a `whatsapp-business` connection call the provider (Meta, 360Dialog).
14
+ * `getById` answers `null` for an unknown id.
15
+ */
9
16
  export class WhatsappBusinessTemplatesApi extends BaseCrudApi<
10
17
  WhatsappBusinessTemplate,
11
18
  CreateWhatsappBusinessTemplatePayload,
12
- UpdateWhatsappBusinessTemplatePayload
19
+ UpdateWhatsappBusinessTemplatePayload,
20
+ ListQuery<WhatsappBusinessTemplate>,
21
+ unknown
13
22
  > {
14
23
  constructor(client: ApiClient) {
15
24
  super(client, '/whatsapp-business-templates')
16
25
  }
26
+
27
+ /**
28
+ * Counts the templates matching the query.
29
+ * @permissions hsm.view
30
+ */
31
+ count(
32
+ query?: ListQuery<WhatsappBusinessTemplate>,
33
+ headers?: Record<string, string>,
34
+ ): Promise<{ count: number }> {
35
+ return this.client.get<{ count: number }>(
36
+ `${this.basePath}/count${this.toQueryString(query)}`,
37
+ headers,
38
+ )
39
+ }
40
+
41
+ /**
42
+ * Reads the template limit of the plan of the account. Send the `accountId` of the current user: the route is
43
+ * outside the error handler of the backend, so an unknown id gets no answer (the request waits for the timeout).
44
+ * @permissions hsm.view
45
+ */
46
+ getHsmLimit(
47
+ accountId: string,
48
+ headers?: Record<string, string>,
49
+ ): Promise<WhatsappBusinessTemplateHsmLimit> {
50
+ return this.client.get<WhatsappBusinessTemplateHsmLimit>(
51
+ `${this.basePath}/${accountId}/hsmLimit`,
52
+ headers,
53
+ )
54
+ }
55
+
56
+ /**
57
+ * Deletes a template. On a `whatsapp-business` connection it goes to the provider (and answers what it answers);
58
+ * a draft of another connection type is deleted locally (answers the stored template). An unknown id answers 500.
59
+ * @permissions hsm.view OR hsm.destroy
60
+ */
61
+ override deleteById(id: string, headers?: Record<string, string>): Promise<unknown> {
62
+ return super.deleteById(id, headers)
63
+ }
64
+
65
+ /**
66
+ * SENDS the template to Meta for approval (through the provider of the connection). An unknown or archived
67
+ * template answers 500 before anything is sent.
68
+ * @permissions hsm.view OR hsm.send OR hsm.send.before.expire
69
+ */
70
+ sendToReview(id: string, headers?: Record<string, string>): Promise<unknown> {
71
+ return this.client.post<unknown>(`${this.basePath}/${id}/send-to-review`, undefined, headers)
72
+ }
73
+
74
+ /**
75
+ * Reads the templates of the connected `whatsapp-business` connections from the provider and syncs them (it may
76
+ * archive the local templates the provider no longer has). Resolves the text `'OK'`.
77
+ * @permissions hsm.view
78
+ */
79
+ refreshTemplates(headers?: Record<string, string>): Promise<'OK'> {
80
+ return this.client.post<'OK'>(`${this.basePath}/refresh-templates`, undefined, headers)
81
+ }
82
+
83
+ /**
84
+ * Reads the template balance from 360Dialog (an external call, when there is a 360Dialog connection).
85
+ * @permissions hsm.view
86
+ */
87
+ resume(headers?: Record<string, string>): Promise<Record<string, unknown>[]> {
88
+ return this.client.get<Record<string, unknown>[]>(`${this.basePath}/resume`, headers)
89
+ }
17
90
  }