@ikatec/digisac-api-sdk 4.5.1 → 4.7.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 (129) hide show
  1. package/README.md +16 -11
  2. package/dist/apis/answers/AnswersApi.cjs +38 -0
  3. package/dist/apis/answers/AnswersApi.cjs.map +1 -1
  4. package/dist/apis/answers/AnswersApi.d.ts +33 -2
  5. package/dist/apis/answers/AnswersApi.d.ts.map +1 -1
  6. package/dist/apis/answers/AnswersApi.mjs +38 -0
  7. package/dist/apis/answers/AnswersApi.mjs.map +1 -1
  8. package/dist/apis/answers/types.d.ts +64 -1
  9. package/dist/apis/answers/types.d.ts.map +1 -1
  10. package/dist/apis/botSimulators/BotSimulatorsApi.cjs +42 -0
  11. package/dist/apis/botSimulators/BotSimulatorsApi.cjs.map +1 -0
  12. package/dist/apis/botSimulators/BotSimulatorsApi.d.ts +31 -0
  13. package/dist/apis/botSimulators/BotSimulatorsApi.d.ts.map +1 -0
  14. package/dist/apis/botSimulators/BotSimulatorsApi.mjs +41 -0
  15. package/dist/apis/botSimulators/BotSimulatorsApi.mjs.map +1 -0
  16. package/dist/apis/botSimulators/index.cjs +4 -0
  17. package/dist/apis/botSimulators/index.d.ts +3 -0
  18. package/dist/apis/botSimulators/index.d.ts.map +1 -0
  19. package/dist/apis/botSimulators/index.mjs +3 -0
  20. package/dist/apis/botSimulators/types.cjs +0 -0
  21. package/dist/apis/botSimulators/types.d.ts +73 -0
  22. package/dist/apis/botSimulators/types.d.ts.map +1 -0
  23. package/dist/apis/botSimulators/types.mjs +0 -0
  24. package/dist/apis/botVersions/BotVersionsApi.cjs +25 -0
  25. package/dist/apis/botVersions/BotVersionsApi.cjs.map +1 -1
  26. package/dist/apis/botVersions/BotVersionsApi.d.ts +18 -0
  27. package/dist/apis/botVersions/BotVersionsApi.d.ts.map +1 -1
  28. package/dist/apis/botVersions/BotVersionsApi.mjs +25 -0
  29. package/dist/apis/botVersions/BotVersionsApi.mjs.map +1 -1
  30. package/dist/apis/botVersions/types.d.ts +4 -0
  31. package/dist/apis/botVersions/types.d.ts.map +1 -1
  32. package/dist/apis/bots/BotsApi.cjs +99 -4
  33. package/dist/apis/bots/BotsApi.cjs.map +1 -1
  34. package/dist/apis/bots/BotsApi.d.ts +78 -5
  35. package/dist/apis/bots/BotsApi.d.ts.map +1 -1
  36. package/dist/apis/bots/BotsApi.mjs +99 -4
  37. package/dist/apis/bots/BotsApi.mjs.map +1 -1
  38. package/dist/apis/bots/types.d.ts +266 -16
  39. package/dist/apis/bots/types.d.ts.map +1 -1
  40. package/dist/apis/index.cjs +3 -0
  41. package/dist/apis/index.d.ts +1 -0
  42. package/dist/apis/index.d.ts.map +1 -1
  43. package/dist/apis/index.mjs +3 -1
  44. package/dist/apis/questions/QuestionsApi.cjs +15 -0
  45. package/dist/apis/questions/QuestionsApi.cjs.map +1 -1
  46. package/dist/apis/questions/QuestionsApi.d.ts +15 -1
  47. package/dist/apis/questions/QuestionsApi.d.ts.map +1 -1
  48. package/dist/apis/questions/QuestionsApi.mjs +15 -0
  49. package/dist/apis/questions/QuestionsApi.mjs.map +1 -1
  50. package/dist/apis/questions/types.d.ts +25 -5
  51. package/dist/apis/questions/types.d.ts.map +1 -1
  52. package/dist/apis/quickReplies/QuickRepliesApi.cjs +16 -0
  53. package/dist/apis/quickReplies/QuickRepliesApi.cjs.map +1 -1
  54. package/dist/apis/quickReplies/QuickRepliesApi.d.ts +15 -2
  55. package/dist/apis/quickReplies/QuickRepliesApi.d.ts.map +1 -1
  56. package/dist/apis/quickReplies/QuickRepliesApi.mjs +16 -0
  57. package/dist/apis/quickReplies/QuickRepliesApi.mjs.map +1 -1
  58. package/dist/apis/quickReplies/types.d.ts +30 -2
  59. package/dist/apis/quickReplies/types.d.ts.map +1 -1
  60. package/dist/apis/schedule/ScheduleApi.cjs +37 -2
  61. package/dist/apis/schedule/ScheduleApi.cjs.map +1 -1
  62. package/dist/apis/schedule/ScheduleApi.d.ts +30 -3
  63. package/dist/apis/schedule/ScheduleApi.d.ts.map +1 -1
  64. package/dist/apis/schedule/ScheduleApi.mjs +37 -2
  65. package/dist/apis/schedule/ScheduleApi.mjs.map +1 -1
  66. package/dist/apis/schedule/types.d.ts +58 -11
  67. package/dist/apis/schedule/types.d.ts.map +1 -1
  68. package/dist/apis/ticketTopics/TicketTopicsApi.cjs +25 -2
  69. package/dist/apis/ticketTopics/TicketTopicsApi.cjs.map +1 -1
  70. package/dist/apis/ticketTopics/TicketTopicsApi.d.ts +18 -4
  71. package/dist/apis/ticketTopics/TicketTopicsApi.d.ts.map +1 -1
  72. package/dist/apis/ticketTopics/TicketTopicsApi.mjs +25 -2
  73. package/dist/apis/ticketTopics/TicketTopicsApi.mjs.map +1 -1
  74. package/dist/apis/ticketTopics/types.d.ts +22 -1
  75. package/dist/apis/ticketTopics/types.d.ts.map +1 -1
  76. package/dist/apis/tickets/TicketsApi.cjs +74 -1
  77. package/dist/apis/tickets/TicketsApi.cjs.map +1 -1
  78. package/dist/apis/tickets/TicketsApi.d.ts +68 -3
  79. package/dist/apis/tickets/TicketsApi.d.ts.map +1 -1
  80. package/dist/apis/tickets/TicketsApi.mjs +74 -1
  81. package/dist/apis/tickets/TicketsApi.mjs.map +1 -1
  82. package/dist/apis/tickets/types.d.ts +69 -8
  83. package/dist/apis/tickets/types.d.ts.map +1 -1
  84. package/dist/core/BaseCrudApi.cjs +5 -2
  85. package/dist/core/BaseCrudApi.cjs.map +1 -1
  86. package/dist/core/BaseCrudApi.d.ts +7 -4
  87. package/dist/core/BaseCrudApi.d.ts.map +1 -1
  88. package/dist/core/BaseCrudApi.mjs +5 -2
  89. package/dist/core/BaseCrudApi.mjs.map +1 -1
  90. package/dist/core/types.d.ts +1 -1
  91. package/dist/core/types.d.ts.map +1 -1
  92. package/dist/incommingWebhooks/index.d.ts +17 -9
  93. package/dist/incommingWebhooks/index.d.ts.map +1 -1
  94. package/package.json +1 -1
  95. package/src/apis/answers/AnswersApi.test.ts +67 -0
  96. package/src/apis/answers/AnswersApi.ts +66 -2
  97. package/src/apis/answers/types.ts +64 -2
  98. package/src/apis/botSimulators/BotSimulatorsApi.test.ts +58 -0
  99. package/src/apis/botSimulators/BotSimulatorsApi.ts +57 -0
  100. package/src/apis/botSimulators/index.ts +2 -0
  101. package/src/apis/botSimulators/types.ts +72 -0
  102. package/src/apis/botVersions/BotVersionsApi.test.ts +51 -0
  103. package/src/apis/botVersions/BotVersionsApi.ts +41 -0
  104. package/src/apis/botVersions/types.ts +4 -0
  105. package/src/apis/bots/BotsApi.test.ts +177 -0
  106. package/src/apis/bots/BotsApi.ts +162 -6
  107. package/src/apis/bots/types.ts +267 -15
  108. package/src/apis/index.ts +1 -0
  109. package/src/apis/payloads.test-d.ts +178 -1
  110. package/src/apis/queryFormat.test.ts +23 -0
  111. package/src/apis/questions/QuestionsApi.test.ts +49 -0
  112. package/src/apis/questions/QuestionsApi.ts +20 -1
  113. package/src/apis/questions/types.ts +25 -6
  114. package/src/apis/quickReplies/QuickRepliesApi.test.ts +69 -0
  115. package/src/apis/quickReplies/QuickRepliesApi.ts +35 -2
  116. package/src/apis/quickReplies/types.ts +34 -2
  117. package/src/apis/schedule/ScheduleApi.test.ts +80 -0
  118. package/src/apis/schedule/ScheduleApi.ts +59 -6
  119. package/src/apis/schedule/types.ts +66 -11
  120. package/src/apis/ticketTopics/TicketTopicsApi.test.ts +40 -0
  121. package/src/apis/ticketTopics/TicketTopicsApi.ts +35 -4
  122. package/src/apis/ticketTopics/types.ts +26 -1
  123. package/src/apis/tickets/TicketsApi.test.ts +142 -5
  124. package/src/apis/tickets/TicketsApi.ts +135 -3
  125. package/src/apis/tickets/types.ts +76 -6
  126. package/src/core/BaseCrudApi.ts +9 -5
  127. package/src/core/types.ts +2 -1
  128. package/src/incommingWebhooks/index.test-d.ts +23 -1
  129. package/src/incommingWebhooks/index.ts +18 -9
@@ -5,26 +5,158 @@ import type {
5
5
  CreateTicketPayload,
6
6
  UpdateTicketPayload,
7
7
  CloseManyTicketsPayload,
8
+ TicketsCount,
9
+ TicketsCountManyQuery,
10
+ TicketsCountPostPayload,
11
+ TicketsCounts,
12
+ TicketsListQuery,
8
13
  } from './types'
9
14
 
15
+ /**
16
+ * Tickets. The backend only serves them for reading (`getMany`, `getOne`, `getById`, the counts,
17
+ * the first waiting time and the exports) plus `closeMany`: a ticket is opened and transferred by
18
+ * `ContactsApi.transferTicket`. The reads check no permission (any authenticated user): the
19
+ * `@permissions` of the inherited `getMany`, `getOne` and `getById` do not apply here. `getById`
20
+ * of an unknown id resolves `null`. For a user who is not an admin, `getMany` leaves out the
21
+ * tickets of the contacts of the connections restricted to that user; the counts and `getById`
22
+ * do not.
23
+ */
10
24
  export class TicketsApi extends BaseCrudApi<Ticket, CreateTicketPayload, UpdateTicketPayload> {
11
25
  constructor(client: ApiClient) {
12
26
  super(client, '/tickets')
13
27
  }
14
28
 
29
+ /** @deprecated Not served: `POST /tickets` answers 404 `Route not found.`. Open a ticket through `ContactsApi.transferTicket`. */
30
+ override create(body: CreateTicketPayload, headers?: Record<string, string>): Promise<Ticket> {
31
+ return super.create(body, headers)
32
+ }
33
+
34
+ /** @deprecated Not served: `PUT /tickets/{id}` answers 404 `Route not found.`. Transfer through `ContactsApi.transferTicket`, close through `closeMany`. */
35
+ override updateById(
36
+ id: string,
37
+ body: UpdateTicketPayload,
38
+ headers?: Record<string, string>,
39
+ ): Promise<Ticket> {
40
+ return super.updateById(id, body, headers)
41
+ }
42
+
43
+ /** @deprecated Not served: `DELETE /tickets/{id}` answers 404 `Route not found.`. */
44
+ override deleteById(id: string, headers?: Record<string, string>): Promise<Ticket> {
45
+ return super.deleteById(id, headers)
46
+ }
47
+
15
48
  /**
16
49
  * Closes multiple tickets in a single request. This is the only ticket-close
17
50
  * endpoint exposed by the API — there is no per-ticket close/update route.
18
51
  *
19
52
  * Pass `{ ids }` to close specific tickets, or `{ allContactsSelected: true, query }`
20
- * to close every OPEN ticket matching `query` (the backend forces `isOpen: true`).
53
+ * to close every OPEN ticket matching `query` (the backend forces `isOpen: true`): an empty
54
+ * `where` closes every open ticket of the account. The answer has no body. Ids of closed,
55
+ * unknown or other accounts' tickets are skipped in silence; no id and no
56
+ * `allContactsSelected` answers 400 `ids not found`.
21
57
  * @permissions tickets.close.all OR tickets.close.me
22
58
  */
23
- closeMany(payload: CloseManyTicketsPayload, headers?: Record<string, string>): Promise<unknown> {
24
- return this.client.put<unknown, CloseManyTicketsPayload>(
59
+ closeMany(payload: CloseManyTicketsPayload, headers?: Record<string, string>): Promise<void> {
60
+ return this.client.put<void, CloseManyTicketsPayload>(
25
61
  `${this.basePath}/close-many`,
26
62
  payload,
27
63
  headers,
28
64
  )
29
65
  }
66
+
67
+ /**
68
+ * Counts the tickets matching the query. With `queries`, answers one count per query, in the
69
+ * same order (the root filters are then ignored).
70
+ */
71
+ count(query: TicketsCountManyQuery, headers?: Record<string, string>): Promise<TicketsCounts>
72
+ count(query?: TicketsListQuery, headers?: Record<string, string>): Promise<TicketsCount>
73
+ count(
74
+ query?: TicketsListQuery | TicketsCountManyQuery,
75
+ headers?: Record<string, string>,
76
+ ): Promise<TicketsCount | TicketsCounts> {
77
+ return this.client.get<TicketsCount | TicketsCounts>(
78
+ `${this.basePath}/count${this.toQueryString(query)}`,
79
+ headers,
80
+ )
81
+ }
82
+
83
+ /**
84
+ * POST variant of `count`, for queries too long for the URL. See {@link TicketsCountPostPayload}:
85
+ * `query` is required.
86
+ */
87
+ countPost(
88
+ body: TicketsCountPostPayload & { query: { queries: TicketsListQuery[] } },
89
+ headers?: Record<string, string>,
90
+ ): Promise<TicketsCounts>
91
+ countPost(body: TicketsCountPostPayload, headers?: Record<string, string>): Promise<TicketsCount>
92
+ countPost(
93
+ body: TicketsCountPostPayload,
94
+ headers?: Record<string, string>,
95
+ ): Promise<TicketsCount | TicketsCounts> {
96
+ return this.client.post<TicketsCount | TicketsCounts, TicketsCountPostPayload>(
97
+ `${this.basePath}/count`,
98
+ body,
99
+ headers,
100
+ )
101
+ }
102
+
103
+ /** Counts the open tickets of the contacts of a connection. An unknown id counts 0. */
104
+ countOpenByService(serviceId: string, headers?: Record<string, string>): Promise<number> {
105
+ return this.client.get<number>(`${this.basePath}/count-open/${serviceId}`, headers)
106
+ }
107
+
108
+ /** Counts the open tickets of a department. An unknown id counts 0. */
109
+ countOpenByDepartment(departmentId: string, headers?: Record<string, string>): Promise<number> {
110
+ return this.client.get<number>(
111
+ `${this.basePath}/count-open-by-department/${departmentId}`,
112
+ headers,
113
+ )
114
+ }
115
+
116
+ /** Counts the open tickets assigned to a user. An unknown id counts 0. */
117
+ countOpenByUser(userId: string, headers?: Record<string, string>): Promise<number> {
118
+ return this.client.get<number>(`${this.basePath}/count-open-by-user/${userId}`, headers)
119
+ }
120
+
121
+ /**
122
+ * The first waiting time of the ticket (`metrics.waitingTime`) as `HH:mm:ss`; `'00:00:00'` while
123
+ * it was not measured. The hours wrap every 24 h (a wait of 25 h answers `'01:00:00'`): read
124
+ * `metrics.waitingTime` (seconds) for the full value. An unknown id answers 500.
125
+ */
126
+ getFirstWaitingTime(id: string, headers?: Record<string, string>): Promise<string> {
127
+ return this.client.get<string>(`${this.basePath}/${id}/first-waiting-time`, headers)
128
+ }
129
+
130
+ /**
131
+ * Exports the conversation of a ticket as text, by its protocol (contact, attendants, subjects,
132
+ * summary, dates and the messages without the internal comments), sent as the attachment
133
+ * `<protocol>.txt` (Content-Type `plain/text`). Without a protocol the body is empty
134
+ * (`undefined`); an unknown protocol never answers.
135
+ */
136
+ exportTxt(protocol: string, headers?: Record<string, string>): Promise<string> {
137
+ return this.client.post<string, { protocol: string }>(
138
+ `${this.basePath}/export`,
139
+ { protocol },
140
+ headers,
141
+ )
142
+ }
143
+
144
+ /**
145
+ * Exports the tickets matching the query as CSV (`;`, a header of 20 columns in the language of
146
+ * the user, dates in the timezone of the account), streamed without a Content-Type.
147
+ *
148
+ * The query must include `contact` with its `service` (the History screen also includes
149
+ * `contact.tags`, `contact.person`, `user`, `department`, `ticketTopics` and `firstMessage`),
150
+ * and `order` must name unambiguous columns (e.g. `startedAt`): when a row fails after the header
151
+ * is sent, the answer never ends. Leave `page` out: the route pages through every match itself
152
+ * (`perPage` only sets the size of each batch), and a `page` in the query is read on every
153
+ * batch, so its rows are repeated or the CSV comes with the header only.
154
+ */
155
+ exportHistory(query: TicketsListQuery, headers?: Record<string, string>): Promise<string> {
156
+ return this.client.post<string>(
157
+ `${this.basePath}/export-history${this.toQueryString(query)}`,
158
+ undefined,
159
+ headers,
160
+ )
161
+ }
30
162
  }
@@ -1,7 +1,10 @@
1
+ import type { ListQuery } from '../../core/types'
2
+ import type { Account } from '../accounts/types'
1
3
  import type { Contact } from '../contacts/types'
2
4
  import type { Department } from '../departments/types'
3
5
  import type { Message } from '../messages/types'
4
6
  import type { Service } from '../services/types'
7
+ import type { TicketTopic } from '../ticketTopics/types'
5
8
  import type { User } from '../users/types'
6
9
 
7
10
  export type TicketOrigin = 'automatic' | 'manual' | 'widget'
@@ -22,6 +25,14 @@ export type TicketMetrics = {
22
25
  /** Average waiting time per transfer. */
23
26
  waitingTimeTransfersAvg?: number
24
27
  isActiveTicket?: boolean
28
+ /** Longest waiting time in seconds, among the opening and the transfers. */
29
+ maxWaitingTime?: number
30
+ /** Department where the longest wait happened. */
31
+ maxWaitingTimeDepartmentId?: string
32
+ /** Name of that department when the wait was measured (the history export prefers the current name). */
33
+ maxWaitingTimeDepartmentName?: string
34
+ maxWaitingTimeStartedAt?: string
35
+ maxWaitingTimeEndedAt?: string
25
36
  }
26
37
 
27
38
  export type TicketTransferAction = 'opened' | 'transferred' | 'closed'
@@ -61,6 +72,16 @@ export type TicketTransfer = {
61
72
  lastMessage?: Message | null
62
73
  }
63
74
 
75
+ /**
76
+ * A ticket as `GET /tickets` and `GET /tickets/{id}` answer it. The relationships come only when
77
+ * asked in `include`, except `firstMessage` and `lastMessage`, which always come: `null` when not
78
+ * included (or when the ticket has no message).
79
+ *
80
+ * The `include` whitelist of the route takes `contact` (and `contact.avatar`, `.thumbAvatar`,
81
+ * `.lastMessage`, `.tags`, `.service`, `.person`), `department`, `user`, `account`, `ticketTopics`,
82
+ * `firstMessage` and `ticketTransfers` (with `fromUser`, `toUser`, `fromDepartment`,
83
+ * `toDepartment`, `byUser`); anything else is dropped in silence.
84
+ */
64
85
  export type Ticket = {
65
86
  id: string
66
87
  isOpen: boolean
@@ -70,13 +91,18 @@ export type Ticket = {
70
91
  metrics: TicketMetrics
71
92
  startedAt: string | null
72
93
  endedAt: string | null
73
- isDistributing: boolean
74
- count: number | null
94
+ /** Only in the `ticket.*` webhooks (the stored ticket): the routes of `/tickets` never send it. */
95
+ isDistributing?: boolean
96
+ /** Only in the `ticket.*` webhooks (the stored ticket): the routes of `/tickets` never send it. */
97
+ distributingAt?: string | null
98
+ /** Only in the `ticket.*` webhooks (the stored ticket): the routes of `/tickets` never send it. */
99
+ count?: number | null
75
100
  accountId: string
76
101
  departmentId: string
77
102
  contactId: string
78
103
  userId: string | null
79
- serviceId: string | null
104
+ /** @deprecated Never comes: a ticket has no connection of its own. Read `contact.serviceId`. */
105
+ serviceId?: string | null
80
106
  firstMessageId: string | null
81
107
  lastMessageId: string | null
82
108
  currentTicketTransferId: string | null
@@ -86,12 +112,28 @@ export type Ticket = {
86
112
  contact?: Contact
87
113
  department?: Department
88
114
  user?: User | null
115
+ account?: Account
116
+ ticketTopics?: TicketTopic[]
117
+ firstMessage?: Message | null
118
+ /** @deprecated Always `null`: `lastMessage` is out of the include whitelist. Include `contact.lastMessage`. */
119
+ lastMessage?: Message | null
120
+ /** @deprecated Never comes: `service` is out of the include whitelist. Include `contact.service`. */
89
121
  service?: Service | null
90
122
  ticketTransfers?: TicketTransfer[]
91
123
  }
92
124
 
93
- export type TicketRelationships = 'contact' | 'department' | 'user' | 'service' | 'ticketTransfers'
125
+ export type TicketRelationships =
126
+ | 'contact'
127
+ | 'department'
128
+ | 'user'
129
+ | 'account'
130
+ | 'ticketTopics'
131
+ | 'firstMessage'
132
+ | 'lastMessage'
133
+ | 'service'
134
+ | 'ticketTransfers'
94
135
 
136
+ /** @deprecated Not served: the backend has no `POST /tickets`. A ticket is opened by `ContactsApi.transferTicket`. */
95
137
  export type CreateTicketPayload = {
96
138
  contactId: string
97
139
  departmentId: string
@@ -100,6 +142,7 @@ export type CreateTicketPayload = {
100
142
  origin?: TicketOrigin
101
143
  }
102
144
 
145
+ /** @deprecated Not served: the backend has no `PUT /tickets/{id}`. Transfer through `ContactsApi.transferTicket`, close through `TicketsApi.closeMany`. */
103
146
  export type UpdateTicketPayload = {
104
147
  departmentId?: string
105
148
  userId?: string | null
@@ -107,6 +150,14 @@ export type UpdateTicketPayload = {
107
150
  isOpen?: boolean
108
151
  }
109
152
 
153
+ /** What `closeMany` records on every ticket it closes. */
154
+ export type CloseTicketsData = {
155
+ /** Subjects of the closing (one id or a list). */
156
+ ticketTopicIds?: string[] | string
157
+ /** Summary of the closing, stored in `comments`. */
158
+ comments?: string
159
+ }
160
+
110
161
  /**
111
162
  * Body for `PUT /tickets/close-many`.
112
163
  *
@@ -116,5 +167,24 @@ export type UpdateTicketPayload = {
116
167
  * the backend always forces `where.isOpen = true`.
117
168
  */
118
169
  export type CloseManyTicketsPayload =
119
- | { ids: string[]; ticketTopicIds?: string[] | string; comments?: string }
120
- | { allContactsSelected: true; query: { query: string } }
170
+ | ({ ids: string[] } & CloseTicketsData)
171
+ | ({ allContactsSelected: true; query: { query: string } } & CloseTicketsData)
172
+
173
+ /** A list query of tickets, as `count` and `exportHistory` take it. */
174
+ export type TicketsListQuery = ListQuery<Ticket>
175
+
176
+ /** `count` with `queries`: one count per query, in the same order. */
177
+ export type TicketsCountManyQuery = TicketsListQuery & { queries: TicketsListQuery[] }
178
+
179
+ /**
180
+ * Body of `POST /tickets/count`. The filters go at the root, as in a list query, and `query` is
181
+ * required: without it the route answers 500. `query: {}` counts the root filters into
182
+ * `{ count }`; `query: { queries }` ignores them and answers `{ counts }`, one per query.
183
+ */
184
+ export type TicketsCountPostPayload = TicketsListQuery & {
185
+ query: { queries?: TicketsListQuery[] }
186
+ }
187
+
188
+ export type TicketsCount = { count: number }
189
+
190
+ export type TicketsCounts = { counts: number[] }
@@ -14,15 +14,19 @@ export type {
14
14
  CrudApi,
15
15
  } from './types'
16
16
 
17
- /** Generic CRUD resource: the reads of `BaseReadApi` plus `create`, `updateById` and `deleteById`. */
17
+ /**
18
+ * Generic CRUD resource: the reads of `BaseReadApi` plus `create`, `updateById` and `deleteById`.
19
+ * `TDeleteResponse` is what `deleteById` resolves to (most routes answer the text `'OK'`).
20
+ */
18
21
  export class BaseCrudApi<
19
22
  TResponse,
20
23
  TCreate,
21
24
  TUpdate = TCreate,
22
25
  TQuery extends ListQuery<TResponse> = ListQuery<TResponse>,
26
+ TDeleteResponse = TResponse,
23
27
  >
24
28
  extends BaseReadApi<TResponse, TQuery>
25
- implements CrudApi<TResponse, TCreate, TUpdate, TQuery>
29
+ implements CrudApi<TResponse, TCreate, TUpdate, TQuery, TDeleteResponse>
26
30
  {
27
31
  /**
28
32
  * Creates a new resource.
@@ -42,9 +46,9 @@ export class BaseCrudApi<
42
46
 
43
47
  /**
44
48
  * Deletes a resource by ID.
45
- * @permissions $resourceName.delete
49
+ * @permissions $resourceName.destroy
46
50
  */
47
- deleteById(id: string, headers?: Record<string, string>): Promise<TResponse> {
48
- return this.client.delete<TResponse>(`${this.basePath}/${id}`, headers)
51
+ deleteById(id: string, headers?: Record<string, string>): Promise<TDeleteResponse> {
52
+ return this.client.delete<TDeleteResponse>(`${this.basePath}/${id}`, headers)
49
53
  }
50
54
  }
package/src/core/types.ts CHANGED
@@ -159,8 +159,9 @@ export type CrudApi<
159
159
  TCreate,
160
160
  TUpdate = TCreate,
161
161
  TQuery extends ListQuery<TResponse> = ListQuery<TResponse>,
162
+ TDeleteResponse = TResponse,
162
163
  > = HasGetMany<TResponse, TQuery> &
163
164
  HasGetById<TResponse> &
164
165
  HasCreate<TResponse, TCreate> &
165
166
  HasUpdateById<TResponse, TUpdate> &
166
- HasDeleteById<TResponse>
167
+ HasDeleteById<TDeleteResponse>
@@ -1,7 +1,15 @@
1
1
  import { expectAssignable, expectNotAssignable, expectType } from 'tsd'
2
- import type { WebhookPayload, WebhookEvent, WebhookEventPayloadMap, BotCommandData } from './index'
2
+ import type {
3
+ WebhookPayload,
4
+ WebhookEvent,
5
+ WebhookEventPayloadMap,
6
+ BotCommandData,
7
+ TicketWebhookData,
8
+ } from './index'
9
+ import type { Contact, ContactRelationships } from '../apis/contacts'
3
10
  import type { Message, MessageRelationships } from '../apis/messages'
4
11
  import type { Ticket, TicketRelationships } from '../apis/tickets'
12
+ import type { BotApiSignalData, BotContexts } from '../apis/bots'
5
13
 
6
14
  // ── WebhookPayload (generic) ─────────────────────────────────────────────────
7
15
 
@@ -26,6 +34,12 @@ expectNotAssignable<WebhookPayload<'ticket.updated'>['data']>(
26
34
  {} as Pick<Ticket, TicketRelationships>,
27
35
  )
28
36
 
37
+ // ...except the contact, which the sender always attaches (stored contact, no relationships)
38
+ declare const ticketUpdated: WebhookPayload<'ticket.updated'>
39
+ expectType<TicketWebhookData>(ticketUpdated.data)
40
+ expectType<Omit<Contact, ContactRelationships>>(ticketUpdated.data.contact)
41
+ expectType<string>(ticketUpdated.data.contact.serviceId)
42
+
29
43
  // ── event narrowing tightens data type ───────────────────────────────────────
30
44
 
31
45
  declare const ticketPayload: WebhookPayload<'ticket.created'>
@@ -37,6 +51,14 @@ declare const botPayload: WebhookPayload<'bot.command'>
37
51
  expectType<BotCommandData>(botPayload.data)
38
52
  expectAssignable<{ id: string; command: string }>(botPayload.data)
39
53
 
54
+ // ── bot.* deliver the stored bot, with the contexts in the map form ──────────
55
+
56
+ declare const botCreated: WebhookPayload<'bot.created'>
57
+ expectType<BotContexts>(botCreated.data.contexts)
58
+
59
+ declare const apiSignal: WebhookPayload<'bot.api-signal'>
60
+ expectType<BotApiSignalData>(apiSignal.data)
61
+
40
62
  // ── invalid events are rejected ──────────────────────────────────────────────
41
63
 
42
64
  expectNotAssignable<WebhookEvent>('message.deleted')
@@ -1,4 +1,4 @@
1
- import type { Bot, BotRelationships } from '../apis/bots'
1
+ import type { BotApiSignalData, BotRecord } from '../apis/bots'
2
2
  import type { Campaign, CampaignRelationships } from '../apis/campaigns'
3
3
  import type { Contact, ContactRelationships } from '../apis/contacts'
4
4
  import type { Department, DepartmentRelationships } from '../apis/departments'
@@ -66,6 +66,15 @@ export type WebhookEvent =
66
66
 
67
67
  // ─── Event → Payload map ─────────────────────────────────────────────────────
68
68
 
69
+ /**
70
+ * `data` of `ticket.created` and `ticket.updated`: the stored ticket (so `isDistributing`,
71
+ * `distributingAt` and `count` come, and `serviceId` does not) plus its stored contact, which the
72
+ * sender always attaches. Read the connection of the ticket in `contact.serviceId`.
73
+ */
74
+ export type TicketWebhookData = Omit<Ticket, TicketRelationships> & {
75
+ contact: Omit<Contact, ContactRelationships>
76
+ }
77
+
69
78
  export type BotCommandData = {
70
79
  id: string
71
80
  contactId: string
@@ -77,8 +86,8 @@ export type BotCommandData = {
77
86
  export interface WebhookEventPayloadMap {
78
87
  'message.created': Omit<Message, MessageRelationships>
79
88
  'message.updated': Omit<Message, MessageRelationships>
80
- 'ticket.created': Omit<Ticket, TicketRelationships>
81
- 'ticket.updated': Omit<Ticket, TicketRelationships>
89
+ 'ticket.created': TicketWebhookData
90
+ 'ticket.updated': TicketWebhookData
82
91
  'service.created': Omit<Service, ServiceRelationships>
83
92
  'service.updated': Omit<Service, ServiceRelationships>
84
93
  'service.destroyed': Omit<Service, ServiceRelationships>
@@ -103,13 +112,13 @@ export interface WebhookEventPayloadMap {
103
112
  'role.created': Omit<Role, RoleRelationships>
104
113
  'role.updated': Omit<Role, RoleRelationships>
105
114
  'role.destroyed': Omit<Role, RoleRelationships>
106
- 'bot.created': Omit<Bot, BotRelationships>
107
- 'bot.updated': Omit<Bot, BotRelationships>
108
- 'bot.destroyed': Omit<Bot, BotRelationships>
115
+ 'bot.created': BotRecord
116
+ 'bot.updated': BotRecord
117
+ 'bot.destroyed': BotRecord
109
118
  'bot.command': BotCommandData
110
- 'bot.enter-context': Omit<Bot, BotRelationships>
111
- 'bot.leave-context': Omit<Bot, BotRelationships>
112
- 'bot.api-signal': Omit<Bot, BotRelationships>
119
+ 'bot.enter-context': BotRecord
120
+ 'bot.leave-context': BotRecord
121
+ 'bot.api-signal': BotApiSignalData
113
122
  'quickReplies.created': Omit<QuickReply, QuickReplyRelationships>
114
123
  'quickReplies.updated': Omit<QuickReply, QuickReplyRelationships>
115
124
  'quickReplies.destroyed': Omit<QuickReply, QuickReplyRelationships>