@ikatec/digisac-api-sdk 4.2.0 → 4.4.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 (66) hide show
  1. package/dist/apis/contacts/ContactsApi.cjs +70 -0
  2. package/dist/apis/contacts/ContactsApi.cjs.map +1 -1
  3. package/dist/apis/contacts/ContactsApi.d.ts +51 -1
  4. package/dist/apis/contacts/ContactsApi.d.ts.map +1 -1
  5. package/dist/apis/contacts/ContactsApi.mjs +70 -0
  6. package/dist/apis/contacts/ContactsApi.mjs.map +1 -1
  7. package/dist/apis/contacts/types.d.ts +141 -1
  8. package/dist/apis/contacts/types.d.ts.map +1 -1
  9. package/dist/apis/dashboard/DashboardApi.cjs +36 -1
  10. package/dist/apis/dashboard/DashboardApi.cjs.map +1 -1
  11. package/dist/apis/dashboard/DashboardApi.d.ts +55 -2
  12. package/dist/apis/dashboard/DashboardApi.d.ts.map +1 -1
  13. package/dist/apis/dashboard/DashboardApi.mjs +36 -1
  14. package/dist/apis/dashboard/DashboardApi.mjs.map +1 -1
  15. package/dist/apis/dashboard/types.d.ts +71 -0
  16. package/dist/apis/dashboard/types.d.ts.map +1 -1
  17. package/dist/apis/services/ServicesApi.cjs +8 -0
  18. package/dist/apis/services/ServicesApi.cjs.map +1 -1
  19. package/dist/apis/services/ServicesApi.d.ts +7 -1
  20. package/dist/apis/services/ServicesApi.d.ts.map +1 -1
  21. package/dist/apis/services/ServicesApi.mjs +8 -0
  22. package/dist/apis/services/ServicesApi.mjs.map +1 -1
  23. package/dist/apis/services/types.d.ts +7 -0
  24. package/dist/apis/services/types.d.ts.map +1 -1
  25. package/dist/apis/tags/TagsApi.cjs +23 -0
  26. package/dist/apis/tags/TagsApi.cjs.map +1 -1
  27. package/dist/apis/tags/TagsApi.d.ts +19 -1
  28. package/dist/apis/tags/TagsApi.d.ts.map +1 -1
  29. package/dist/apis/tags/TagsApi.mjs +23 -0
  30. package/dist/apis/tags/TagsApi.mjs.map +1 -1
  31. package/dist/apis/tags/types.d.ts +8 -0
  32. package/dist/apis/tags/types.d.ts.map +1 -1
  33. package/dist/apis/users/UsersApi.cjs +77 -0
  34. package/dist/apis/users/UsersApi.cjs.map +1 -1
  35. package/dist/apis/users/UsersApi.d.ts +59 -1
  36. package/dist/apis/users/UsersApi.d.ts.map +1 -1
  37. package/dist/apis/users/UsersApi.mjs +77 -0
  38. package/dist/apis/users/UsersApi.mjs.map +1 -1
  39. package/dist/apis/users/types.d.ts +102 -0
  40. package/dist/apis/users/types.d.ts.map +1 -1
  41. package/package.json +1 -1
  42. package/src/apis/acceptanceTerms/AcceptanceTermsApi.test.ts +1 -1
  43. package/src/apis/authHistory/AuthHistoryApi.test.ts +1 -1
  44. package/src/apis/campaigns/CampaignsApi.test.ts +1 -1
  45. package/src/apis/contacts/ContactsApi.test.ts +182 -5
  46. package/src/apis/contacts/ContactsApi.ts +128 -0
  47. package/src/apis/contacts/types.ts +154 -1
  48. package/src/apis/dashboard/DashboardApi.test-d.ts +49 -0
  49. package/src/apis/dashboard/DashboardApi.test.ts +197 -9
  50. package/src/apis/dashboard/DashboardApi.ts +130 -2
  51. package/src/apis/dashboard/types.ts +78 -0
  52. package/src/apis/messages/MessagesApi.test.ts +3 -3
  53. package/src/apis/payloads.test-d.ts +26 -0
  54. package/src/apis/queryFormat.test.ts +91 -3
  55. package/src/apis/serviceAccessManagement/ServiceAccessManagementApi.test.ts +2 -2
  56. package/src/apis/services/ServicesApi.test.ts +49 -0
  57. package/src/apis/services/ServicesApi.ts +10 -1
  58. package/src/apis/services/types.ts +9 -0
  59. package/src/apis/stickerUsers/StickerUsersApi.test.ts +1 -1
  60. package/src/apis/tags/TagsApi.test.ts +79 -0
  61. package/src/apis/tags/TagsApi.ts +57 -1
  62. package/src/apis/tags/types.ts +9 -0
  63. package/src/apis/terms/TermsApi.test.ts +1 -1
  64. package/src/apis/users/UsersApi.test.ts +228 -0
  65. package/src/apis/users/UsersApi.ts +152 -1
  66. package/src/apis/users/types.ts +121 -0
@@ -5,6 +5,83 @@ var UsersApi = class extends ArchivableCrudApi {
5
5
  constructor(client) {
6
6
  super(client, "/users");
7
7
  }
8
+ /**
9
+ * Archives or restores a user through the dedicated route used by the UI, which also
10
+ * sets the user offline and ends its sessions. The route enforces the business rules that
11
+ * {@link archive}/{@link unarchive} (a plain `PUT { archivedAt }`) skip:
12
+ * - archiving refuses (403) a user referenced by a bot or with open tickets;
13
+ * - restoring refuses (402) when the plan has no free user slot.
14
+ * @permissions users.view OR users.archive
15
+ */
16
+ archiveWithValidation(id, body, headers) {
17
+ return this.client.post(`${this.basePath}/${id}/archive`, body, headers);
18
+ }
19
+ /**
20
+ * Previews a bulk archive/unarchive without changing anything.
21
+ * @permissions users.archive
22
+ */
23
+ previewBulkStatus(body, headers) {
24
+ return this.client.post(`${this.basePath}/bulk-status/preview`, body, headers);
25
+ }
26
+ /**
27
+ * Archives or unarchives up to 100 users at once.
28
+ * @permissions users.archive
29
+ */
30
+ bulkStatus(body, headers) {
31
+ return this.client.post(`${this.basePath}/bulk-status`, body, headers);
32
+ }
33
+ /**
34
+ * Exports the users of the account as CSV. Resolves to the CSV text.
35
+ * @permissions users.export
36
+ */
37
+ exportCsv(body, headers) {
38
+ return this.client.post(`${this.basePath}/export`, body, headers);
39
+ }
40
+ /**
41
+ * Validates a CSV file previously uploaded through `FilesApi` before importing it.
42
+ * @permissions users.create
43
+ */
44
+ validateImport(body, headers) {
45
+ return this.client.post(`${this.basePath}/import/validate`, body, headers);
46
+ }
47
+ /**
48
+ * Starts the import of a CSV file previously uploaded through `FilesApi`. The import runs
49
+ * in the background (the route answers `202 Accepted`).
50
+ * @permissions users.create
51
+ */
52
+ startImport(body, headers) {
53
+ return this.client.post(`${this.basePath}/import`, body, headers);
54
+ }
55
+ /**
56
+ * Turns off the two-factor authentication (OTP) of a user.
57
+ * @permissions users.update AND myAccount.update
58
+ */
59
+ disableOtpAuth(id, headers) {
60
+ return this.client.post(`${this.basePath}/${id}/disable-otp-auth`, void 0, headers);
61
+ }
62
+ /**
63
+ * Clears the login throttling of a user blocked by too many failed attempts.
64
+ * @permissions users.update
65
+ */
66
+ enableAccess(id, headers) {
67
+ return this.client.post(`${this.basePath}/${id}/enable-access`, void 0, headers);
68
+ }
69
+ /**
70
+ * Returns the contacts pinned by the logged user.
71
+ * @permissions contacts.pin
72
+ */
73
+ getPinnedContacts(headers) {
74
+ return this.client.get(`${this.basePath}/pin`, headers);
75
+ }
76
+ /**
77
+ * Pins the contact for the logged user, or unpins it when already pinned. A user can pin
78
+ * up to 3 contacts. Resolves to the created link rows when pinning, or to the number of
79
+ * removed links when unpinning.
80
+ * @permissions contacts.pin
81
+ */
82
+ togglePinContact(body, headers) {
83
+ return this.client.patch(`${this.basePath}/pin`, body, headers);
84
+ }
8
85
  };
9
86
 
10
87
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"UsersApi.mjs","names":[],"sources":["../../../src/apis/users/UsersApi.ts"],"sourcesContent":["import type { ApiClient } from '../../core/ApiClient'\nimport { ArchivableCrudApi } from '../../core/ArchivableCrudApi'\nimport type { User, CreateUserPayload, UpdateUserPayload } from './types'\n\nexport class UsersApi extends ArchivableCrudApi<User, CreateUserPayload, UpdateUserPayload> {\n constructor(client: ApiClient) {\n super(client, '/users')\n }\n}\n"],"mappings":";;;AAIA,IAAa,WAAb,cAA8B,kBAA8D;CAC1F,YAAY,QAAmB;AAC7B,QAAM,QAAQ,SAAS"}
1
+ {"version":3,"file":"UsersApi.mjs","names":[],"sources":["../../../src/apis/users/UsersApi.ts"],"sourcesContent":["import type { ApiClient } from '../../core/ApiClient'\nimport { ArchivableCrudApi } from '../../core/ArchivableCrudApi'\nimport type { Contact } from '../contacts/types'\nimport type {\n ArchiveUserPayload,\n BulkUsersStatusPayload,\n BulkUsersStatusPreview,\n BulkUsersStatusResult,\n CreateUserPayload,\n EnableUserAccessResult,\n ExportUsersPayload,\n ImportUsersPayload,\n ImportUsersResult,\n TogglePinContactPayload,\n TogglePinContactResult,\n UpdateUserPayload,\n User,\n ValidateUserImportPayload,\n ValidateUserImportResult,\n} from './types'\n\nexport class UsersApi extends ArchivableCrudApi<User, CreateUserPayload, UpdateUserPayload> {\n constructor(client: ApiClient) {\n super(client, '/users')\n }\n\n /**\n * Archives or restores a user through the dedicated route used by the UI, which also\n * sets the user offline and ends its sessions. The route enforces the business rules that\n * {@link archive}/{@link unarchive} (a plain `PUT { archivedAt }`) skip:\n * - archiving refuses (403) a user referenced by a bot or with open tickets;\n * - restoring refuses (402) when the plan has no free user slot.\n * @permissions users.view OR users.archive\n */\n archiveWithValidation(\n id: string,\n body: ArchiveUserPayload,\n headers?: Record<string, string>,\n ): Promise<User> {\n return this.client.post<User, ArchiveUserPayload>(\n `${this.basePath}/${id}/archive`,\n body,\n headers,\n )\n }\n\n /**\n * Previews a bulk archive/unarchive without changing anything.\n * @permissions users.archive\n */\n previewBulkStatus(\n body: BulkUsersStatusPayload,\n headers?: Record<string, string>,\n ): Promise<BulkUsersStatusPreview> {\n return this.client.post<BulkUsersStatusPreview, BulkUsersStatusPayload>(\n `${this.basePath}/bulk-status/preview`,\n body,\n headers,\n )\n }\n\n /**\n * Archives or unarchives up to 100 users at once.\n * @permissions users.archive\n */\n bulkStatus(\n body: BulkUsersStatusPayload,\n headers?: Record<string, string>,\n ): Promise<BulkUsersStatusResult> {\n return this.client.post<BulkUsersStatusResult, BulkUsersStatusPayload>(\n `${this.basePath}/bulk-status`,\n body,\n headers,\n )\n }\n\n /**\n * Exports the users of the account as CSV. Resolves to the CSV text.\n * @permissions users.export\n */\n exportCsv(body: ExportUsersPayload, headers?: Record<string, string>): Promise<string> {\n return this.client.post<string, ExportUsersPayload>(`${this.basePath}/export`, body, headers)\n }\n\n /**\n * Validates a CSV file previously uploaded through `FilesApi` before importing it.\n * @permissions users.create\n */\n validateImport(\n body: ValidateUserImportPayload,\n headers?: Record<string, string>,\n ): Promise<ValidateUserImportResult> {\n return this.client.post<ValidateUserImportResult, ValidateUserImportPayload>(\n `${this.basePath}/import/validate`,\n body,\n headers,\n )\n }\n\n /**\n * Starts the import of a CSV file previously uploaded through `FilesApi`. The import runs\n * in the background (the route answers `202 Accepted`).\n * @permissions users.create\n */\n startImport(\n body: ImportUsersPayload,\n headers?: Record<string, string>,\n ): Promise<ImportUsersResult> {\n return this.client.post<ImportUsersResult, ImportUsersPayload>(\n `${this.basePath}/import`,\n body,\n headers,\n )\n }\n\n /**\n * Turns off the two-factor authentication (OTP) of a user.\n * @permissions users.update AND myAccount.update\n */\n disableOtpAuth(id: string, headers?: Record<string, string>): Promise<User> {\n return this.client.post<User>(`${this.basePath}/${id}/disable-otp-auth`, undefined, headers)\n }\n\n /**\n * Clears the login throttling of a user blocked by too many failed attempts.\n * @permissions users.update\n */\n enableAccess(id: string, headers?: Record<string, string>): Promise<EnableUserAccessResult> {\n return this.client.post<EnableUserAccessResult>(\n `${this.basePath}/${id}/enable-access`,\n undefined,\n headers,\n )\n }\n\n /**\n * Returns the contacts pinned by the logged user.\n * @permissions contacts.pin\n */\n getPinnedContacts(headers?: Record<string, string>): Promise<Contact[]> {\n return this.client.get<Contact[]>(`${this.basePath}/pin`, headers)\n }\n\n /**\n * Pins the contact for the logged user, or unpins it when already pinned. A user can pin\n * up to 3 contacts. Resolves to the created link rows when pinning, or to the number of\n * removed links when unpinning.\n * @permissions contacts.pin\n */\n togglePinContact(\n body: TogglePinContactPayload,\n headers?: Record<string, string>,\n ): Promise<TogglePinContactResult> {\n return this.client.patch<TogglePinContactResult, TogglePinContactPayload>(\n `${this.basePath}/pin`,\n body,\n headers,\n )\n }\n}\n"],"mappings":";;;AAqBA,IAAa,WAAb,cAA8B,kBAA8D;CAC1F,YAAY,QAAmB;AAC7B,QAAM,QAAQ,SAAS;;;;;;;;;;CAWzB,sBACE,IACA,MACA,SACe;AACf,SAAO,KAAK,OAAO,KACjB,GAAG,KAAK,SAAS,GAAG,GAAG,WACvB,MACA,QACD;;;;;;CAOH,kBACE,MACA,SACiC;AACjC,SAAO,KAAK,OAAO,KACjB,GAAG,KAAK,SAAS,uBACjB,MACA,QACD;;;;;;CAOH,WACE,MACA,SACgC;AAChC,SAAO,KAAK,OAAO,KACjB,GAAG,KAAK,SAAS,eACjB,MACA,QACD;;;;;;CAOH,UAAU,MAA0B,SAAmD;AACrF,SAAO,KAAK,OAAO,KAAiC,GAAG,KAAK,SAAS,UAAU,MAAM,QAAQ;;;;;;CAO/F,eACE,MACA,SACmC;AACnC,SAAO,KAAK,OAAO,KACjB,GAAG,KAAK,SAAS,mBACjB,MACA,QACD;;;;;;;CAQH,YACE,MACA,SAC4B;AAC5B,SAAO,KAAK,OAAO,KACjB,GAAG,KAAK,SAAS,UACjB,MACA,QACD;;;;;;CAOH,eAAe,IAAY,SAAiD;AAC1E,SAAO,KAAK,OAAO,KAAW,GAAG,KAAK,SAAS,GAAG,GAAG,oBAAoB,QAAW,QAAQ;;;;;;CAO9F,aAAa,IAAY,SAAmE;AAC1F,SAAO,KAAK,OAAO,KACjB,GAAG,KAAK,SAAS,GAAG,GAAG,iBACvB,QACA,QACD;;;;;;CAOH,kBAAkB,SAAsD;AACtE,SAAO,KAAK,OAAO,IAAe,GAAG,KAAK,SAAS,OAAO,QAAQ;;;;;;;;CASpE,iBACE,MACA,SACiC;AACjC,SAAO,KAAK,OAAO,MACjB,GAAG,KAAK,SAAS,OACjB,MACA,QACD"}
@@ -62,4 +62,106 @@ export type UpdateUserPayload = {
62
62
  language?: string;
63
63
  archivedAt?: string | null;
64
64
  };
65
+ /** Body for `POST /users/:id/archive`. */
66
+ export type ArchiveUserPayload = {
67
+ /** `true` archives the user; `false` restores it. */
68
+ archive: boolean;
69
+ };
70
+ /** Body for `POST /users/bulk-status` and `POST /users/bulk-status/preview` (1 to 100 IDs). */
71
+ export type BulkUsersStatusPayload = {
72
+ ids: string[];
73
+ archive: boolean;
74
+ };
75
+ export type BulkUsersStatusScenario = 'emptySelection' | 'noneEligible' | 'allEligible' | 'partiallyBlocked' | 'onlySelfBlocked' | 'planLimitExceeded';
76
+ /** Read-only preview of a bulk status change: nothing is written. */
77
+ export type BulkUsersStatusPreview = {
78
+ scenario: BulkUsersStatusScenario;
79
+ totalSelected: number;
80
+ /** Users already in the target status. */
81
+ noop: number;
82
+ eligible: number;
83
+ /** Users that cannot change (e.g. referenced by a bot, or the acting user). */
84
+ blocked: number;
85
+ blockedSelf: boolean;
86
+ /** Free plan slots when unarchiving; `null` when archiving. */
87
+ planSlotsAvailable: number | null;
88
+ };
89
+ export type BulkUsersStatusResult = {
90
+ changed: number;
91
+ noop: number;
92
+ blocked: number;
93
+ failed: number;
94
+ changedIds: string[];
95
+ /** IDs of the batch that no longer exist in the account. */
96
+ missingIds: string[];
97
+ };
98
+ /** Body for `POST /users/export`. */
99
+ export type ExportUsersPayload = {
100
+ filter: 'all' | 'active' | 'archived';
101
+ };
102
+ /** A file previously uploaded through `FilesApi`. */
103
+ export type UserImportFile = {
104
+ id: string;
105
+ name: string;
106
+ mimetype: string;
107
+ url?: string;
108
+ urlToUpload?: string;
109
+ };
110
+ /** Body for `POST /users/import/validate`. */
111
+ export type ValidateUserImportPayload = {
112
+ file: UserImportFile;
113
+ };
114
+ export type UserImportRowsSummary = {
115
+ total: number;
116
+ valid: number;
117
+ invalid: number;
118
+ hasInvalid: boolean;
119
+ };
120
+ export type ValidateUserImportResult = {
121
+ licenses: {
122
+ requestedRows: number;
123
+ available: number;
124
+ exceeded: boolean;
125
+ };
126
+ columns: {
127
+ required: {
128
+ name: string;
129
+ found: boolean;
130
+ }[];
131
+ missingRequired: string[];
132
+ optionalFound: string[];
133
+ };
134
+ rows: UserImportRowsSummary;
135
+ /** Same rows validated with the optional columns applied. */
136
+ rowsWithOptionalColumns: UserImportRowsSummary;
137
+ };
138
+ /** Body for `POST /users/import`. */
139
+ export type ImportUsersPayload = {
140
+ file: UserImportFile;
141
+ useOptionalColumns?: boolean;
142
+ };
143
+ /** The import runs in the background (the route answers `202 Accepted`). */
144
+ export type ImportUsersResult = {
145
+ importId: string;
146
+ };
147
+ export type EnableUserAccessResult = {
148
+ success: boolean;
149
+ message: string;
150
+ };
151
+ /** Body for `PATCH /users/pin`: toggles the pin of a contact for the logged user (max. 3). */
152
+ export type TogglePinContactPayload = {
153
+ contactId: string;
154
+ };
155
+ /** Link row returned by `PATCH /users/pin` when the contact gets pinned. */
156
+ export type UserPinnedContactLink = {
157
+ userId: string;
158
+ contactId: string;
159
+ createdAt: string;
160
+ updatedAt: string;
161
+ };
162
+ /**
163
+ * Result of `PATCH /users/pin`: the created link rows when the contact gets pinned, or the
164
+ * number of removed links when it gets unpinned.
165
+ */
166
+ export type TogglePinContactResult = UserPinnedContactLink[] | number;
65
167
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/apis/users/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/apis/users/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikatec/digisac-api-sdk",
3
- "version": "4.2.0",
3
+ "version": "4.4.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -87,7 +87,7 @@ describe('AcceptanceTermsApi', () => {
87
87
  it('includes the file relationship', async () => {
88
88
  vi.mocked(client.get).mockResolvedValue({ ...term, file: null })
89
89
  const result = await api.getById('at-1', { include: ['file'] })
90
- const url = vi.mocked(client.get).mock.calls[0][0] as string
90
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
91
91
  expect(url).toContain('/acceptance-terms/at-1?')
92
92
  expect(url).toContain('include')
93
93
  expect(result.file).toBeNull()
@@ -66,7 +66,7 @@ describe('AuthHistoryApi', () => {
66
66
  it('serializes query parameters', async () => {
67
67
  vi.mocked(client.get).mockResolvedValue(paginated)
68
68
  await api.getMany({ page: 2, perPage: 5 })
69
- const url = vi.mocked(client.get).mock.calls[0][0] as string
69
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
70
70
  expect(url).toContain('/auth-history?')
71
71
  expect(decodeURIComponent(url)).toContain('"page":2')
72
72
  })
@@ -94,7 +94,7 @@ describe('CampaignsApi', () => {
94
94
  it('serializes query parameters', async () => {
95
95
  vi.mocked(client.get).mockResolvedValue(paginated)
96
96
  await api.getMany({ page: 2, perPage: 5 })
97
- const url = vi.mocked(client.get).mock.calls[0][0] as string
97
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
98
98
  expect(url).toContain('/campaigns?')
99
99
  expect(decodeURIComponent(url)).toContain('"page":2')
100
100
  })
@@ -2,12 +2,20 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
  import { ContactsApi } from './ContactsApi'
3
3
  import type { ApiClient } from '../../core/ApiClient'
4
4
  import type {
5
+ BlockContactPayload,
6
+ BulkTransferTicketsPayload,
7
+ BulkTransferTicketsResult,
5
8
  Contact,
9
+ ContactMediaPage,
10
+ ContactsSelection,
6
11
  CreateContactPayload,
12
+ CreateManyContactsItem,
13
+ ExportCsvPayload,
7
14
  ExportTemplatePayload,
8
15
  CountContactsQuery,
9
16
  ExistsContactsParams,
10
17
  CountMediaResult,
18
+ ImportContactsPayload,
11
19
  } from './types'
12
20
  import type { Paginated } from '../../core/types'
13
21
 
@@ -101,7 +109,7 @@ describe('ContactsApi', () => {
101
109
  it('serializes query parameters', async () => {
102
110
  vi.mocked(client.get).mockResolvedValue(paginated)
103
111
  await api.getMany({ page: 2, perPage: 5 })
104
- const url = vi.mocked(client.get).mock.calls[0][0] as string
112
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
105
113
  expect(url).toContain('/contacts?')
106
114
  expect(decodeURIComponent(url)).toContain('"page":2')
107
115
  })
@@ -225,7 +233,7 @@ describe('ContactsApi', () => {
225
233
  vi.mocked(client.get).mockResolvedValue({ count: 10 })
226
234
  const query: CountContactsQuery = { where: { name: 'Alice' } }
227
235
  await api.count(query)
228
- const url = vi.mocked(client.get).mock.calls[0][0] as string
236
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
229
237
  expect(url).toContain('/contacts/count?')
230
238
  expect(url).toContain('where')
231
239
  })
@@ -270,7 +278,7 @@ describe('ContactsApi', () => {
270
278
  it('serializes query parameters', async () => {
271
279
  vi.mocked(client.get).mockResolvedValue(paginated)
272
280
  await api.forward({ page: 1, perPage: 10 })
273
- const url = vi.mocked(client.get).mock.calls[0][0] as string
281
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
274
282
  expect(url).toContain('/contacts/forward?')
275
283
  })
276
284
 
@@ -289,7 +297,7 @@ describe('ContactsApi', () => {
289
297
  vi.mocked(client.get).mockResolvedValue({ '1234567890': true })
290
298
  const params: ExistsContactsParams = { serviceId: 'svc-1', numbers: ['1234567890'] }
291
299
  const result = await api.exists(params)
292
- const url = vi.mocked(client.get).mock.calls[0][0] as string
300
+ const url = vi.mocked(client.get).mock.calls[0]?.[0] as string
293
301
  expect(url).toContain('/contacts/exists?')
294
302
  expect(url).toContain('serviceId=svc-1')
295
303
  expect(result).toEqual({ '1234567890': true })
@@ -299,7 +307,7 @@ describe('ContactsApi', () => {
299
307
  vi.mocked(client.get).mockResolvedValue({})
300
308
  const headers = { 'X-Custom': 'h' }
301
309
  await api.exists({ serviceId: 'svc-1', numbers: [] }, headers)
302
- expect(vi.mocked(client.get).mock.calls[0][1]).toEqual(headers)
310
+ expect(vi.mocked(client.get).mock.calls[0]?.[1]).toEqual(headers)
303
311
  })
304
312
  })
305
313
 
@@ -365,6 +373,175 @@ describe('ContactsApi', () => {
365
373
  })
366
374
  })
367
375
 
376
+ // ── createMany ───────────────────────────────────────────────────
377
+
378
+ describe('createMany', () => {
379
+ const items: CreateManyContactsItem[] = [
380
+ { serviceId: 'svc-1', name: 'Alice', number: '5511999990001' },
381
+ { serviceId: 'svc-1', name: 'Bob', number: '5511999990002', tagIds: ['t1'] },
382
+ ]
383
+
384
+ it('calls client.post with /contacts/many and the array body', async () => {
385
+ vi.mocked(client.post).mockResolvedValue([contact])
386
+ const result = await api.createMany(items)
387
+ expect(client.post).toHaveBeenCalledWith('/contacts/many', items, undefined)
388
+ expect(result).toEqual([contact])
389
+ })
390
+
391
+ it('serializes the query and forwards custom headers', async () => {
392
+ const headers = { 'X-Custom': 'value' }
393
+ await api.createMany(items, { include: ['tags'] }, headers)
394
+ const [url, body, sentHeaders] = vi.mocked(client.post).mock.calls[0] ?? []
395
+ expect(decodeURIComponent(url as string)).toBe('/contacts/many?query={"include":["tags"]}')
396
+ expect(body).toBe(items)
397
+ expect(sentHeaders).toBe(headers)
398
+ })
399
+ })
400
+
401
+ // ── deleteMany ───────────────────────────────────────────────────
402
+
403
+ describe('deleteMany', () => {
404
+ it('calls client.request with DELETE /contacts/many and the selection', async () => {
405
+ vi.mocked(client.request).mockResolvedValue(true)
406
+ const body: ContactsSelection = { where: { id: { $in: ['c1', 'c2'] } } }
407
+ const result = await api.deleteMany(body)
408
+ expect(client.request).toHaveBeenCalledWith('DELETE', '/contacts/many', body, undefined)
409
+ expect(result).toBe(true)
410
+ })
411
+
412
+ it('forwards custom headers', async () => {
413
+ const headers = { 'X-Custom': 'value' }
414
+ await api.deleteMany({ where: { id: 'c1' } }, headers)
415
+ expect(client.request).toHaveBeenCalledWith(
416
+ 'DELETE',
417
+ '/contacts/many',
418
+ { where: { id: 'c1' } },
419
+ headers,
420
+ )
421
+ })
422
+ })
423
+
424
+ // ── exportCsv ────────────────────────────────────────────────────
425
+
426
+ describe('exportCsv', () => {
427
+ it('calls client.post with /contacts/export/csv and resolves to the CSV text', async () => {
428
+ const csv = 'Nome,DDI,Número\nAlice,55,11999990001\n'
429
+ vi.mocked(client.post).mockResolvedValue(csv)
430
+ const body: ExportCsvPayload = {
431
+ serviceType: 'whatsapp',
432
+ type: 'comma',
433
+ where: { id: 'cnt-1' },
434
+ }
435
+ const result = await api.exportCsv(body)
436
+ expect(client.post).toHaveBeenCalledWith('/contacts/export/csv', body, undefined)
437
+ expect(result).toBe(csv)
438
+ })
439
+ })
440
+
441
+ // ── importCsv ────────────────────────────────────────────────────
442
+
443
+ describe('importCsv', () => {
444
+ it('calls client.post with /contacts/import-contacts and body', async () => {
445
+ const body: ImportContactsPayload = {
446
+ service: { id: 'svc-1', accountId: 'acc-1', type: 'whatsapp' },
447
+ file: { id: 'f1', name: 'contacts.csv', mimetype: 'text/csv', urlToUpload: 'https://s3' },
448
+ csvHeaderLine: ['Nome', 'DDI', 'Número'],
449
+ type: 'comma',
450
+ tagsIds: ['t1'],
451
+ }
452
+ vi.mocked(client.post).mockResolvedValue('OK')
453
+ const headers = { 'X-Custom': 'value' }
454
+ const result = await api.importCsv(body, headers)
455
+ expect(client.post).toHaveBeenCalledWith('/contacts/import-contacts', body, headers)
456
+ expect(result).toBe('OK')
457
+ })
458
+ })
459
+
460
+ // ── sync ─────────────────────────────────────────────────────────
461
+
462
+ describe('sync', () => {
463
+ it('calls client.post with /contacts/:id/sync and an empty body by default', async () => {
464
+ vi.mocked(client.post).mockResolvedValue('OK')
465
+ const result = await api.sync('c1')
466
+ expect(client.post).toHaveBeenCalledWith('/contacts/c1/sync', {}, undefined)
467
+ expect(result).toBe('OK')
468
+ })
469
+
470
+ it('sends forceSync and forwards custom headers', async () => {
471
+ const headers = { 'X-Custom': 'value' }
472
+ await api.sync('c1', { forceSync: true }, headers)
473
+ expect(client.post).toHaveBeenCalledWith('/contacts/c1/sync', { forceSync: true }, headers)
474
+ })
475
+ })
476
+
477
+ // ── block ────────────────────────────────────────────────────────
478
+
479
+ describe('block', () => {
480
+ it('calls client.post with /contacts/:id/block and body', async () => {
481
+ vi.mocked(client.post).mockResolvedValue({ ...contact, block: true })
482
+ const body: BlockContactPayload = { block: true, description: 'spam' }
483
+ const result = await api.block('c1', body)
484
+ expect(client.post).toHaveBeenCalledWith('/contacts/c1/block', body, undefined)
485
+ expect(result.block).toBe(true)
486
+ })
487
+ })
488
+
489
+ // ── markRead ─────────────────────────────────────────────────────
490
+
491
+ describe('markRead', () => {
492
+ it('calls client.post with /contacts/:id/mark-read and no body', async () => {
493
+ vi.mocked(client.post).mockResolvedValue('OK')
494
+ const headers = { 'X-Custom': 'value' }
495
+ const result = await api.markRead('c1', headers)
496
+ expect(client.post).toHaveBeenCalledWith('/contacts/c1/mark-read', undefined, headers)
497
+ expect(result).toBe('OK')
498
+ })
499
+ })
500
+
501
+ // ── getMedia ─────────────────────────────────────────────────────
502
+
503
+ describe('getMedia', () => {
504
+ const page: ContactMediaPage = { data: [], limit: 50, hasNextPage: false, nextCursor: null }
505
+
506
+ it('calls client.get with /contacts/:id/media when no query is provided', async () => {
507
+ vi.mocked(client.get).mockResolvedValue(page)
508
+ const result = await api.getMedia('c1')
509
+ expect(client.get).toHaveBeenCalledWith('/contacts/c1/media', undefined)
510
+ expect(result).toEqual(page)
511
+ })
512
+
513
+ it('serializes the type, cursor and perPage', async () => {
514
+ await api.getMedia('c1', {
515
+ where: { type: 'document', cursor: '2026-01-01T00:00:00Z' },
516
+ perPage: 10,
517
+ })
518
+ const url = decodeURIComponent(vi.mocked(client.get).mock.calls[0]?.[0] as string)
519
+ expect(url).toBe(
520
+ '/contacts/c1/media?query={"where":{"type":"document","cursor":"2026-01-01T00:00:00Z"},"perPage":10}',
521
+ )
522
+ })
523
+ })
524
+
525
+ // ── bulkTransferTickets ──────────────────────────────────────────
526
+
527
+ describe('bulkTransferTickets', () => {
528
+ it('calls client.post with /contacts/ticket/bulk-transfer and body', async () => {
529
+ const response: BulkTransferTicketsResult = {
530
+ message: 'Transferência realizada com sucesso',
531
+ ticketsSelectedId: ['t1'],
532
+ }
533
+ vi.mocked(client.post).mockResolvedValue(response)
534
+ const body: BulkTransferTicketsPayload = {
535
+ departmentId: 'd1',
536
+ userId: null,
537
+ ticketsSelectedId: ['t1'],
538
+ }
539
+ const result = await api.bulkTransferTickets(body)
540
+ expect(client.post).toHaveBeenCalledWith('/contacts/ticket/bulk-transfer', body, undefined)
541
+ expect(result).toEqual(response)
542
+ })
543
+ })
544
+
368
545
  // ── Error propagation ────────────────────────────────────────────
369
546
 
370
547
  describe('error propagation', () => {
@@ -3,12 +3,22 @@ import type { ApiClient } from '../../core/ApiClient'
3
3
  import { BaseCrudApi } from '../../core/BaseCrudApi'
4
4
  import type { ListQuery, Paginated } from '../../core/types'
5
5
  import type {
6
+ BlockContactPayload,
7
+ BulkTransferTicketsPayload,
8
+ BulkTransferTicketsResult,
6
9
  Contact,
10
+ ContactMediaPage,
11
+ ContactMediaQuery,
12
+ ContactsSelection,
7
13
  CountContactsQuery,
8
14
  CountMediaResult,
9
15
  CreateContactPayload,
16
+ CreateManyContactsItem,
10
17
  ExistsContactsParams,
18
+ ExportCsvPayload,
11
19
  ExportTemplatePayload,
20
+ ImportContactsPayload,
21
+ SyncContactPayload,
12
22
  TransferTicketPayload,
13
23
  UpdateContactPayload,
14
24
  } from './types'
@@ -120,4 +130,122 @@ export class ContactsApi extends BaseCrudApi<Contact, CreateContactPayload, Upda
120
130
  headers,
121
131
  )
122
132
  }
133
+
134
+ /**
135
+ * Creates or updates several contacts in one call. Existing contacts (same service and
136
+ * number or e-mail) are updated; the others are created. Returns the resulting contacts.
137
+ * @permissions contacts.view OR contacts.update OR contacts.create
138
+ */
139
+ createMany(
140
+ body: CreateManyContactsItem[],
141
+ query?: ListQuery<Contact>,
142
+ headers?: Record<string, string>,
143
+ ): Promise<Contact[]> {
144
+ const queryString = this.toQueryString(query)
145
+ return this.client.post<Contact[], CreateManyContactsItem[]>(
146
+ `${this.basePath}/many${queryString}`,
147
+ body,
148
+ headers,
149
+ )
150
+ }
151
+
152
+ /**
153
+ * Deletes every contact of the account that matches the selection.
154
+ * @permissions contacts.view OR contacts.destroy
155
+ */
156
+ deleteMany(body: ContactsSelection, headers?: Record<string, string>): Promise<boolean> {
157
+ return this.client.request<boolean, ContactsSelection>(
158
+ 'DELETE',
159
+ `${this.basePath}/many`,
160
+ body,
161
+ headers,
162
+ )
163
+ }
164
+
165
+ /**
166
+ * Exports the contacts that match the filter as CSV. Resolves to the CSV text.
167
+ * @permissions contacts.view AND contacts.export
168
+ */
169
+ exportCsv(body: ExportCsvPayload, headers?: Record<string, string>): Promise<string> {
170
+ return this.client.post<string, ExportCsvPayload>(`${this.basePath}/export/csv`, body, headers)
171
+ }
172
+
173
+ /**
174
+ * Starts the import of a CSV file previously uploaded through `FilesApi`. The import runs
175
+ * in the background; the header line is validated against the service type template.
176
+ * Resolves to `'OK'`.
177
+ * @permissions contacts.view OR contacts.update OR contacts.create
178
+ */
179
+ importCsv(body: ImportContactsPayload, headers?: Record<string, string>): Promise<string> {
180
+ return this.client.post<string, ImportContactsPayload>(
181
+ `${this.basePath}/import-contacts`,
182
+ body,
183
+ headers,
184
+ )
185
+ }
186
+
187
+ /**
188
+ * Marks the contact as read and, when needed, syncs it with the messaging service.
189
+ * Resolves to `'OK'`.
190
+ * @permissions contacts.view OR contacts.update
191
+ */
192
+ sync(id: string, body?: SyncContactPayload, headers?: Record<string, string>): Promise<string> {
193
+ return this.client.post<string, SyncContactPayload>(
194
+ `${this.basePath}/${id}/sync`,
195
+ body ?? {},
196
+ headers,
197
+ )
198
+ }
199
+
200
+ /**
201
+ * Blocks or unblocks a contact. Blocking closes the contact's open ticket. Requires the
202
+ * block list to be active on the account.
203
+ * @permissions contacts.block
204
+ */
205
+ block(id: string, body: BlockContactPayload, headers?: Record<string, string>): Promise<Contact> {
206
+ return this.client.post<Contact, BlockContactPayload>(
207
+ `${this.basePath}/${id}/block`,
208
+ body,
209
+ headers,
210
+ )
211
+ }
212
+
213
+ /**
214
+ * Resets the contact's unread counter. Resolves to `'OK'`.
215
+ * @permissions contacts.view OR contacts.update
216
+ */
217
+ markRead(id: string, headers?: Record<string, string>): Promise<string> {
218
+ return this.client.post<string>(`${this.basePath}/${id}/mark-read`, undefined, headers)
219
+ }
220
+
221
+ /**
222
+ * Returns the files and links exchanged with a contact, cursor-paginated.
223
+ * @permissions contacts.view
224
+ */
225
+ getMedia(
226
+ contactId: string,
227
+ query?: ContactMediaQuery,
228
+ headers?: Record<string, string>,
229
+ ): Promise<ContactMediaPage> {
230
+ const queryString = this.toQueryString(query)
231
+ return this.client.get<ContactMediaPage>(
232
+ `${this.basePath}/${contactId}/media${queryString}`,
233
+ headers,
234
+ )
235
+ }
236
+
237
+ /**
238
+ * Transfers several tickets at once to a department and/or user.
239
+ * @permissions tickets.transfer.all.bulk
240
+ */
241
+ bulkTransferTickets(
242
+ body: BulkTransferTicketsPayload,
243
+ headers?: Record<string, string>,
244
+ ): Promise<BulkTransferTicketsResult> {
245
+ return this.client.post<BulkTransferTicketsResult, BulkTransferTicketsPayload>(
246
+ `${this.basePath}/ticket/bulk-transfer`,
247
+ body,
248
+ headers,
249
+ )
250
+ }
123
251
  }