@ikatec/digisac-api-sdk 4.12.0 → 4.14.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.
- package/dist/apis/absence/AbsenceApi.cjs +46 -2
- package/dist/apis/absence/AbsenceApi.cjs.map +1 -1
- package/dist/apis/absence/AbsenceApi.d.ts +38 -4
- package/dist/apis/absence/AbsenceApi.d.ts.map +1 -1
- package/dist/apis/absence/AbsenceApi.mjs +46 -2
- package/dist/apis/absence/AbsenceApi.mjs.map +1 -1
- package/dist/apis/absence/types.d.ts +51 -2
- package/dist/apis/absence/types.d.ts.map +1 -1
- package/dist/apis/activityLog/ActivityLogApi.cjs +10 -1
- package/dist/apis/activityLog/ActivityLogApi.cjs.map +1 -1
- package/dist/apis/activityLog/ActivityLogApi.d.ts +10 -3
- package/dist/apis/activityLog/ActivityLogApi.d.ts.map +1 -1
- package/dist/apis/activityLog/ActivityLogApi.mjs +10 -1
- package/dist/apis/activityLog/ActivityLogApi.mjs.map +1 -1
- package/dist/apis/activityLog/types.d.ts +48 -8
- package/dist/apis/activityLog/types.d.ts.map +1 -1
- package/dist/apis/creditMovements/CreditMovementsApi.cjs +31 -2
- package/dist/apis/creditMovements/CreditMovementsApi.cjs.map +1 -1
- package/dist/apis/creditMovements/CreditMovementsApi.d.ts +21 -3
- package/dist/apis/creditMovements/CreditMovementsApi.d.ts.map +1 -1
- package/dist/apis/creditMovements/CreditMovementsApi.mjs +31 -2
- package/dist/apis/creditMovements/CreditMovementsApi.mjs.map +1 -1
- package/dist/apis/creditMovements/types.d.ts +73 -2
- package/dist/apis/creditMovements/types.d.ts.map +1 -1
- package/dist/apis/knowledgeBase/KnowledgeBaseApi.cjs +27 -0
- package/dist/apis/knowledgeBase/KnowledgeBaseApi.cjs.map +1 -1
- package/dist/apis/knowledgeBase/KnowledgeBaseApi.d.ts +22 -1
- package/dist/apis/knowledgeBase/KnowledgeBaseApi.d.ts.map +1 -1
- package/dist/apis/knowledgeBase/KnowledgeBaseApi.mjs +27 -0
- package/dist/apis/knowledgeBase/KnowledgeBaseApi.mjs.map +1 -1
- package/dist/apis/knowledgeBase/types.d.ts +56 -2
- package/dist/apis/knowledgeBase/types.d.ts.map +1 -1
- package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.cjs +26 -0
- package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.cjs.map +1 -1
- package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.d.ts +24 -0
- package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.d.ts.map +1 -1
- package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.mjs +26 -0
- package/dist/apis/knowledgeBaseItem/KnowledgeBaseItemApi.mjs.map +1 -1
- package/dist/apis/knowledgeBaseItem/types.d.ts +23 -6
- package/dist/apis/knowledgeBaseItem/types.d.ts.map +1 -1
- package/dist/apis/notifications/NotificationsApi.cjs +50 -2
- package/dist/apis/notifications/NotificationsApi.cjs.map +1 -1
- package/dist/apis/notifications/NotificationsApi.d.ts +41 -3
- package/dist/apis/notifications/NotificationsApi.d.ts.map +1 -1
- package/dist/apis/notifications/NotificationsApi.mjs +50 -2
- package/dist/apis/notifications/NotificationsApi.mjs.map +1 -1
- package/dist/apis/notifications/types.d.ts +57 -8
- package/dist/apis/notifications/types.d.ts.map +1 -1
- package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.cjs.map +1 -1
- package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.d.ts +4 -1
- package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.d.ts.map +1 -1
- package/dist/apis/serviceAccessManagement/ServiceAccessManagementApi.mjs.map +1 -1
- package/dist/apis/serviceAccessManagement/types.d.ts +3 -0
- package/dist/apis/serviceAccessManagement/types.d.ts.map +1 -1
- package/dist/apis/services/ServicesApi.cjs +10 -0
- package/dist/apis/services/ServicesApi.cjs.map +1 -1
- package/dist/apis/services/ServicesApi.d.ts +9 -1
- package/dist/apis/services/ServicesApi.d.ts.map +1 -1
- package/dist/apis/services/ServicesApi.mjs +10 -0
- package/dist/apis/services/ServicesApi.mjs.map +1 -1
- package/dist/apis/services/types.d.ts +10 -0
- package/dist/apis/services/types.d.ts.map +1 -1
- package/dist/apis/stickerUsers/StickerUsersApi.cjs.map +1 -1
- package/dist/apis/stickerUsers/StickerUsersApi.d.ts +3 -1
- package/dist/apis/stickerUsers/StickerUsersApi.d.ts.map +1 -1
- package/dist/apis/stickerUsers/StickerUsersApi.mjs.map +1 -1
- package/dist/apis/stickerUsers/types.d.ts +4 -0
- package/dist/apis/stickerUsers/types.d.ts.map +1 -1
- package/dist/apis/stickers/StickersApi.cjs +27 -3
- package/dist/apis/stickers/StickersApi.cjs.map +1 -1
- package/dist/apis/stickers/StickersApi.d.ts +24 -4
- package/dist/apis/stickers/StickersApi.d.ts.map +1 -1
- package/dist/apis/stickers/StickersApi.mjs +27 -3
- package/dist/apis/stickers/StickersApi.mjs.map +1 -1
- package/dist/apis/stickers/types.d.ts +31 -4
- package/dist/apis/stickers/types.d.ts.map +1 -1
- package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.cjs +1 -2
- package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.cjs.map +1 -1
- package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.d.ts +1 -2
- package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.d.ts.map +1 -1
- package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.mjs +1 -2
- package/dist/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.mjs.map +1 -1
- package/package.json +1 -1
- package/src/apis/absence/AbsenceApi.test.ts +65 -0
- package/src/apis/absence/AbsenceApi.ts +77 -4
- package/src/apis/absence/types.ts +53 -2
- package/src/apis/activityLog/ActivityLogApi.test.ts +44 -0
- package/src/apis/activityLog/ActivityLogApi.ts +22 -3
- package/src/apis/activityLog/types.ts +47 -8
- package/src/apis/creditMovements/CreditMovementsApi.test.ts +88 -0
- package/src/apis/creditMovements/CreditMovementsApi.ts +73 -2
- package/src/apis/creditMovements/types.ts +74 -2
- package/src/apis/knowledgeBase/KnowledgeBaseApi.test.ts +54 -0
- package/src/apis/knowledgeBase/KnowledgeBaseApi.ts +61 -1
- package/src/apis/knowledgeBase/types.ts +62 -2
- package/src/apis/knowledgeBaseItem/KnowledgeBaseItemApi.test.ts +57 -0
- package/src/apis/knowledgeBaseItem/KnowledgeBaseItemApi.ts +45 -0
- package/src/apis/knowledgeBaseItem/types.ts +23 -6
- package/src/apis/me/MeApi.test.ts +1 -1
- package/src/apis/notifications/NotificationsApi.test.ts +74 -0
- package/src/apis/notifications/NotificationsApi.ts +88 -3
- package/src/apis/notifications/types.ts +68 -7
- package/src/apis/payloads.test-d.ts +66 -0
- package/src/apis/serviceAccessManagement/ServiceAccessManagementApi.ts +4 -1
- package/src/apis/serviceAccessManagement/types.ts +3 -0
- package/src/apis/services/ServicesApi.test.ts +11 -0
- package/src/apis/services/ServicesApi.ts +21 -0
- package/src/apis/services/types.ts +12 -0
- package/src/apis/stickerUsers/StickerUsersApi.ts +3 -1
- package/src/apis/stickerUsers/types.ts +4 -0
- package/src/apis/stickers/StickersApi.test.ts +58 -0
- package/src/apis/stickers/StickersApi.ts +46 -4
- package/src/apis/stickers/types.ts +32 -4
- package/src/apis/whatsappBusinessTemplates/WhatsappBusinessTemplatesApi.ts +1 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { KnowledgeBaseItem } from '../knowledgeBaseItem/types'
|
|
2
2
|
|
|
3
|
+
/** A knowledge base as the transformer answers it (`items` always comes: `[]` without the include). */
|
|
3
4
|
export type KnowledgeBase = {
|
|
4
5
|
id: string
|
|
5
6
|
name: string
|
|
@@ -7,19 +8,78 @@ export type KnowledgeBase = {
|
|
|
7
8
|
accountId: string
|
|
8
9
|
createdAt: string
|
|
9
10
|
updatedAt: string
|
|
10
|
-
|
|
11
|
+
/** @deprecated Not answered: the transformer of the backend does not send it. */
|
|
12
|
+
deletedAt?: string | null
|
|
11
13
|
// relationships
|
|
12
14
|
items?: KnowledgeBaseItem[]
|
|
15
|
+
account?: Record<string, unknown>
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
export type KnowledgeBaseRelationships = 'items'
|
|
18
|
+
export type KnowledgeBaseRelationships = 'items' | 'account'
|
|
16
19
|
|
|
17
20
|
export type CreateKnowledgeBasePayload = {
|
|
21
|
+
/** Up to 60 characters. */
|
|
18
22
|
name: string
|
|
23
|
+
/** Up to 600 characters. */
|
|
19
24
|
description?: string
|
|
20
25
|
}
|
|
21
26
|
|
|
27
|
+
/** The backend requires `name` on the update too (400 without it). */
|
|
22
28
|
export type UpdateKnowledgeBasePayload = {
|
|
23
29
|
name?: string
|
|
24
30
|
description?: string | null
|
|
25
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An item of `saveWithItems`. Any item VECTORIZES its content in the AI service (Haystack) on the save:
|
|
35
|
+
* `text` for `messages`, `url` for `urls` (the service fetches the page), `fileId` for `files`.
|
|
36
|
+
*/
|
|
37
|
+
export type SaveKnowledgeBaseItemInput = {
|
|
38
|
+
name: string
|
|
39
|
+
type: 'urls' | 'files' | 'messages'
|
|
40
|
+
url?: string
|
|
41
|
+
fileId?: string
|
|
42
|
+
text?: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The body of `saveWithItems`: creates the base, or updates the one of `id`, with its items. */
|
|
46
|
+
export type SaveKnowledgeBaseWithItemsPayload = {
|
|
47
|
+
/** 1 to 60 characters. */
|
|
48
|
+
name: string
|
|
49
|
+
/** Up to 600 characters. */
|
|
50
|
+
description?: string
|
|
51
|
+
/** The base to update (absent: a new base). */
|
|
52
|
+
id?: string
|
|
53
|
+
items?: SaveKnowledgeBaseItemInput[]
|
|
54
|
+
/** Items of the base to delete. */
|
|
55
|
+
deleteItemIds?: string[]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The stored base answered by `saveWithItems` (raw: with `synchronized`, without `items`). */
|
|
59
|
+
export type SavedKnowledgeBase = Omit<KnowledgeBase, 'items' | 'account' | 'deletedAt'> & {
|
|
60
|
+
synchronized: boolean | null
|
|
61
|
+
deletedAt: string | null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* What the suggestions answer: the suggested text, or a `message` code when nothing was suggested (e.g.
|
|
66
|
+
* `COPILOT_LIMIT_REACHED`, `COPILOT_TRANSCRIPTION_NOT_ENABLED`, `TRANSCRIBING_AUDIO_MESSAGES`).
|
|
67
|
+
*/
|
|
68
|
+
export type KnowledgeBaseSuggestion = {
|
|
69
|
+
message: string
|
|
70
|
+
hasAudioMessage?: boolean
|
|
71
|
+
hadEnoughCreditsToTranscribe?: boolean
|
|
72
|
+
[key: string]: unknown
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type SuggestByMessagePayload = {
|
|
76
|
+
messageId: string
|
|
77
|
+
/** Lets the AI answer beyond the knowledge base. */
|
|
78
|
+
outsideTheKnowledgeBase?: boolean
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type SuggestByTicketPayload = {
|
|
82
|
+
ticketId: string
|
|
83
|
+
/** Lets the AI answer beyond the knowledge base. */
|
|
84
|
+
outsideTheKnowledgeBase?: boolean
|
|
85
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { KnowledgeBaseItemApi } from './KnowledgeBaseItemApi'
|
|
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('KnowledgeBaseItemApi', () => {
|
|
23
|
+
let client: ReturnType<typeof createMockClient>
|
|
24
|
+
let api: KnowledgeBaseItemApi
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
client = createMockClient()
|
|
28
|
+
api = new KnowledgeBaseItemApi(client)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('fetchMany posts the ids to /knowledge-base-item/fetch-many', async () => {
|
|
32
|
+
vi.mocked(client.post).mockResolvedValue([])
|
|
33
|
+
await expect(api.fetchMany(['i-1'])).resolves.toEqual([])
|
|
34
|
+
expect(client.post).toHaveBeenCalledWith(
|
|
35
|
+
'/knowledge-base-item/fetch-many',
|
|
36
|
+
{ ids: ['i-1'] },
|
|
37
|
+
undefined,
|
|
38
|
+
)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('deleteMany sends DELETE /knowledge-base-item/many with the ids in the body', async () => {
|
|
42
|
+
vi.mocked(client.request).mockResolvedValue(true)
|
|
43
|
+
await expect(api.deleteMany(['i-1'])).resolves.toBe(true)
|
|
44
|
+
expect(client.request).toHaveBeenCalledWith(
|
|
45
|
+
'DELETE',
|
|
46
|
+
'/knowledge-base-item/many',
|
|
47
|
+
{ ids: ['i-1'] },
|
|
48
|
+
undefined,
|
|
49
|
+
)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('checkPdfText posts the file to /knowledge-base-item/check-pdf-text', async () => {
|
|
53
|
+
vi.mocked(client.post).mockResolvedValue({ hasText: false })
|
|
54
|
+
await expect(api.checkPdfText({})).resolves.toEqual({ hasText: false })
|
|
55
|
+
expect(client.post).toHaveBeenCalledWith('/knowledge-base-item/check-pdf-text', {}, undefined)
|
|
56
|
+
})
|
|
57
|
+
})
|
|
@@ -7,6 +7,10 @@ import type {
|
|
|
7
7
|
UpdateKnowledgeBaseItemPayload,
|
|
8
8
|
} from './types'
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Items of the knowledge bases. Creating an item VECTORIZES its content in the AI service; reading the
|
|
12
|
+
* `docs` (include, `fetchMany`) reads them from it.
|
|
13
|
+
*/
|
|
10
14
|
export class KnowledgeBaseItemApi extends BaseCrudApi<
|
|
11
15
|
KnowledgeBaseItem,
|
|
12
16
|
CreateKnowledgeBaseItemPayload,
|
|
@@ -26,4 +30,45 @@ export class KnowledgeBaseItemApi extends BaseCrudApi<
|
|
|
26
30
|
override deleteById(id: string, headers?: Record<string, string>): Promise<false> {
|
|
27
31
|
return super.deleteById(id, headers)
|
|
28
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Reads the items of `ids` with their documents (read from the AI service). Resolves the stored items, raw:
|
|
36
|
+
* unlike the other reads they carry `knowledgeBaseId`, `fileId` and `deletedAt`. An empty or absent `ids`
|
|
37
|
+
* answers 400 `Invalid knowledge base item ids`.
|
|
38
|
+
*/
|
|
39
|
+
fetchMany(ids: string[], headers?: Record<string, string>): Promise<KnowledgeBaseItem[]> {
|
|
40
|
+
return this.client.post<KnowledgeBaseItem[], { ids: string[] }>(
|
|
41
|
+
`${this.basePath}/fetch-many`,
|
|
42
|
+
{ ids },
|
|
43
|
+
headers,
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Deletes the items of `ids` of the account (soft delete; their documents stay in the AI service).
|
|
49
|
+
* Resolves `true`; an empty or absent `ids` answers 400 `Invalid knowledge base item ids`.
|
|
50
|
+
*/
|
|
51
|
+
deleteMany(ids: string[], headers?: Record<string, string>): Promise<true> {
|
|
52
|
+
return this.client.request<true, { ids: string[] }>(
|
|
53
|
+
'DELETE',
|
|
54
|
+
`${this.basePath}/many`,
|
|
55
|
+
{ ids },
|
|
56
|
+
headers,
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Tells whether the PDF of `fileId` has text to be vectorized (read locally, no AI). Without `fileId` it
|
|
62
|
+
* resolves `{ hasText: false }`.
|
|
63
|
+
*/
|
|
64
|
+
checkPdfText(
|
|
65
|
+
body: { fileId?: string },
|
|
66
|
+
headers?: Record<string, string>,
|
|
67
|
+
): Promise<{ hasText: boolean }> {
|
|
68
|
+
return this.client.post<{ hasText: boolean }, { fileId?: string }>(
|
|
69
|
+
`${this.basePath}/check-pdf-text`,
|
|
70
|
+
body,
|
|
71
|
+
headers,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
29
74
|
}
|
|
@@ -1,35 +1,52 @@
|
|
|
1
1
|
import type { File } from '../files/types'
|
|
2
2
|
import type { KnowledgeBase } from '../knowledgeBase/types'
|
|
3
3
|
|
|
4
|
+
/** An item as the transformer answers it (no `knowledgeBaseId`, `fileId` nor `deletedAt`). */
|
|
4
5
|
export type KnowledgeBaseItem = {
|
|
5
6
|
id: string
|
|
6
7
|
name: string
|
|
7
|
-
type: string
|
|
8
|
+
type: 'urls' | 'files' | 'messages' | (string & {})
|
|
8
9
|
sourceId: string | null
|
|
9
10
|
url: string | null
|
|
10
11
|
accountId: string
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
/** @deprecated Not answered: the transformer of the backend does not send it. */
|
|
13
|
+
knowledgeBaseId?: string
|
|
14
|
+
/** @deprecated Not answered: the transformer of the backend does not send it. */
|
|
15
|
+
fileId?: string | null
|
|
13
16
|
createdAt: string
|
|
14
17
|
updatedAt: string
|
|
15
|
-
|
|
18
|
+
/** @deprecated Not answered: the transformer of the backend does not send it. */
|
|
19
|
+
deletedAt?: string | null
|
|
16
20
|
// relationships
|
|
21
|
+
/** @deprecated Not served: the include is dropped by the backend. */
|
|
17
22
|
knowledgeBase?: KnowledgeBase
|
|
18
23
|
file?: File | null
|
|
24
|
+
/** The vectorized documents (the include reads them from the AI service). */
|
|
25
|
+
docs?: Record<string, unknown>[]
|
|
26
|
+
account?: Record<string, unknown>
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
export type KnowledgeBaseItemRelationships = 'knowledgeBase' | 'file'
|
|
29
|
+
export type KnowledgeBaseItemRelationships = 'knowledgeBase' | 'file' | 'docs' | 'account'
|
|
22
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Creates an item and VECTORIZES its content in the AI service right away: `text` (type `messages`), `url`
|
|
33
|
+
* (type `urls`, the service fetches the page) or `fileId` (type `files`). Without any of the three it
|
|
34
|
+
* answers 400 `You must provide fileId, text, or url`.
|
|
35
|
+
*/
|
|
23
36
|
export type CreateKnowledgeBaseItemPayload = {
|
|
24
37
|
name: string
|
|
25
|
-
type: string
|
|
38
|
+
type: 'urls' | 'files' | 'messages' | (string & {})
|
|
26
39
|
knowledgeBaseId: string
|
|
40
|
+
/** @deprecated Ignored by the backend. */
|
|
27
41
|
sourceId?: string
|
|
42
|
+
text?: string
|
|
28
43
|
url?: string
|
|
29
44
|
fileId?: string
|
|
30
45
|
}
|
|
31
46
|
|
|
47
|
+
/** The backend requires `name`, `type` and `knowledgeBaseId` on the update too (400 without them). */
|
|
32
48
|
export type UpdateKnowledgeBaseItemPayload = {
|
|
49
|
+
knowledgeBaseId?: string
|
|
33
50
|
name?: string
|
|
34
51
|
type?: string
|
|
35
52
|
sourceId?: string | null
|
|
@@ -296,7 +296,7 @@ describe('MeApi', () => {
|
|
|
296
296
|
describe('registerToken', () => {
|
|
297
297
|
it('calls client.post with /me/one-signal/register-token and body', async () => {
|
|
298
298
|
vi.mocked(client.post).mockResolvedValue(undefined)
|
|
299
|
-
const body: RegisterTokenPayload = {
|
|
299
|
+
const body: RegisterTokenPayload = { data: { oneSignalToken: 'abc123' } }
|
|
300
300
|
await api.registerToken(body)
|
|
301
301
|
expect(client.post).toHaveBeenCalledWith('/me/one-signal/register-token', body, undefined)
|
|
302
302
|
})
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { NotificationsApi } from './NotificationsApi'
|
|
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('NotificationsApi', () => {
|
|
23
|
+
let client: ReturnType<typeof createMockClient>
|
|
24
|
+
let api: NotificationsApi
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
client = createMockClient()
|
|
28
|
+
api = new NotificationsApi(client)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('count posts to /notifications/count and resolves the counts as text', async () => {
|
|
32
|
+
const counts = { count: { total: '3', read: '1', unread: '2' } }
|
|
33
|
+
vi.mocked(client.post).mockResolvedValue(counts)
|
|
34
|
+
await expect(api.count()).resolves.toEqual(counts)
|
|
35
|
+
expect(client.post).toHaveBeenCalledWith('/notifications/count', undefined, undefined)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('read puts to /notifications/:id/read', async () => {
|
|
39
|
+
await api.read('n-1')
|
|
40
|
+
expect(client.put).toHaveBeenCalledWith('/notifications/n-1/read', undefined, undefined)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('unread puts to /notifications/:id/unread', async () => {
|
|
44
|
+
await api.unread('n-1')
|
|
45
|
+
expect(client.put).toHaveBeenCalledWith('/notifications/n-1/unread', undefined, undefined)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('readMany posts the ids as the body', async () => {
|
|
49
|
+
await api.readMany(['n-1', 'n-2'])
|
|
50
|
+
expect(client.post).toHaveBeenCalledWith('/notifications/read-many', ['n-1', 'n-2'], undefined)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('readAll calls client.get with /notifications/read-all', async () => {
|
|
54
|
+
vi.mocked(client.get).mockResolvedValue({ total: 2, read: 2, unread: 0 })
|
|
55
|
+
await expect(api.readAll()).resolves.toEqual({ total: 2, read: 2, unread: 0 })
|
|
56
|
+
expect(client.get).toHaveBeenCalledWith('/notifications/read-all', undefined)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('resetBadgeCount posts to /notifications/reset-badge-count', async () => {
|
|
60
|
+
vi.mocked(client.post).mockResolvedValue({ success: true })
|
|
61
|
+
await expect(api.resetBadgeCount()).resolves.toEqual({ success: true })
|
|
62
|
+
expect(client.post).toHaveBeenCalledWith(
|
|
63
|
+
'/notifications/reset-badge-count',
|
|
64
|
+
undefined,
|
|
65
|
+
undefined,
|
|
66
|
+
)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('sendAll posts the announcement to /notifications/send-all', async () => {
|
|
70
|
+
const body = { text: 'Aviso', to: 'admin' as const }
|
|
71
|
+
await api.sendAll(body)
|
|
72
|
+
expect(client.post).toHaveBeenCalledWith('/notifications/send-all', body, undefined)
|
|
73
|
+
})
|
|
74
|
+
})
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import type { ApiClient } from '../../core/ApiClient'
|
|
2
2
|
import type { ListQuery } from '../../core/types'
|
|
3
3
|
import { BaseCrudApi } from '../../core/BaseCrudApi'
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
Notification,
|
|
6
|
+
CreateNotificationPayload,
|
|
7
|
+
UpdateNotificationPayload,
|
|
8
|
+
NotificationCountsResponse,
|
|
9
|
+
NotificationReadAllResponse,
|
|
10
|
+
SendAllNotificationsPayload,
|
|
11
|
+
} from './types'
|
|
5
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Notifications of the current user (all of the account with `notification.view.all`). Some types open a modal in the web app as soon as they arrive (`announcement`, `credits-90`,
|
|
15
|
+
* `credits-100`, `smart-summary`, `warn-service-reconnect`).
|
|
16
|
+
*/
|
|
6
17
|
export class NotificationsApi extends BaseCrudApi<
|
|
7
18
|
Notification,
|
|
8
19
|
CreateNotificationPayload,
|
|
@@ -15,10 +26,84 @@ export class NotificationsApi extends BaseCrudApi<
|
|
|
15
26
|
}
|
|
16
27
|
|
|
17
28
|
/**
|
|
18
|
-
* Deletes a notification. Resolves the text `'OK'`; an unknown id answers 500.
|
|
19
|
-
* no permission.
|
|
29
|
+
* Deletes a notification. Resolves the text `'OK'`; an unknown id answers 500.
|
|
20
30
|
*/
|
|
21
31
|
override deleteById(id: string, headers?: Record<string, string>): Promise<'OK'> {
|
|
22
32
|
return super.deleteById(id, headers)
|
|
23
33
|
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Counts the notifications the user sees: `{ count: { total, read, unread } }`, as TEXT.
|
|
37
|
+
*/
|
|
38
|
+
count(headers?: Record<string, string>): Promise<NotificationCountsResponse> {
|
|
39
|
+
return this.client.post<NotificationCountsResponse>(
|
|
40
|
+
`${this.basePath}/count`,
|
|
41
|
+
undefined,
|
|
42
|
+
headers,
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Marks a notification as read for the current user and resolves the new counts. An unknown id answers
|
|
48
|
+
* 400 `Notification not found.`.
|
|
49
|
+
*/
|
|
50
|
+
read(id: string, headers?: Record<string, string>): Promise<NotificationCountsResponse> {
|
|
51
|
+
return this.client.put<NotificationCountsResponse>(
|
|
52
|
+
`${this.basePath}/${id}/read`,
|
|
53
|
+
undefined,
|
|
54
|
+
headers,
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Marks a notification as unread for the current user and resolves the new counts. An unknown id
|
|
60
|
+
* answers 400 `Notification not found.`.
|
|
61
|
+
*/
|
|
62
|
+
unread(id: string, headers?: Record<string, string>): Promise<NotificationCountsResponse> {
|
|
63
|
+
return this.client.put<NotificationCountsResponse>(
|
|
64
|
+
`${this.basePath}/${id}/unread`,
|
|
65
|
+
undefined,
|
|
66
|
+
headers,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Marks the notifications of `ids` as read. Resolves with no body; a body that is not an array answers
|
|
72
|
+
* 500 `Body must be an array of notification IDs`.
|
|
73
|
+
*/
|
|
74
|
+
readMany(ids: string[], headers?: Record<string, string>): Promise<void> {
|
|
75
|
+
return this.client.post<void, string[]>(`${this.basePath}/read-many`, ids, headers)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Marks every notification the user sees as read (a GET that writes: it recreates the read receipts of
|
|
80
|
+
* the user) and resolves the counts, as numbers.
|
|
81
|
+
*/
|
|
82
|
+
readAll(headers?: Record<string, string>): Promise<NotificationReadAllResponse> {
|
|
83
|
+
return this.client.get<NotificationReadAllResponse>(`${this.basePath}/read-all`, headers)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Clears the push badge counter of the current user. Resolves `{ success: true }`. */
|
|
87
|
+
resetBadgeCount(headers?: Record<string, string>): Promise<{ success: true }> {
|
|
88
|
+
return this.client.post<{ success: true }>(
|
|
89
|
+
`${this.basePath}/reset-badge-count`,
|
|
90
|
+
undefined,
|
|
91
|
+
headers,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* SENDS an announcement (`type: 'announcement'`, which opens a modal in the web app) to every user of
|
|
97
|
+
* the account, or only to the admins with `to: 'admin'`. Resolves `{ message: 'Notificações enviadas' }` before the notifications are created.
|
|
98
|
+
*/
|
|
99
|
+
sendAll(
|
|
100
|
+
body: SendAllNotificationsPayload,
|
|
101
|
+
headers?: Record<string, string>,
|
|
102
|
+
): Promise<{ message: string }> {
|
|
103
|
+
return this.client.post<{ message: string }, SendAllNotificationsPayload>(
|
|
104
|
+
`${this.basePath}/send-all`,
|
|
105
|
+
body,
|
|
106
|
+
headers,
|
|
107
|
+
)
|
|
108
|
+
}
|
|
24
109
|
}
|
|
@@ -13,46 +13,107 @@ export type NotificationType =
|
|
|
13
13
|
| 'undefined'
|
|
14
14
|
| 'waba-health-warning'
|
|
15
15
|
| 'waba-health-block'
|
|
16
|
+
| 'kanban-board-initialized'
|
|
17
|
+
| 'users-bulk-archive-blocked'
|
|
18
|
+
| 'user-import'
|
|
19
|
+
| 'credits-90'
|
|
20
|
+
| 'credits-100'
|
|
21
|
+
| 'smart-summary'
|
|
22
|
+
| 'warn-service-reconnect'
|
|
16
23
|
|
|
17
|
-
/**
|
|
24
|
+
/** Extra data of the notification; the pipeline notifications carry the pipeline ids. */
|
|
18
25
|
export type NotificationConfig = {
|
|
19
|
-
pipelineId
|
|
20
|
-
pipelineAutomationId
|
|
26
|
+
pipelineId?: string
|
|
27
|
+
pipelineAutomationId?: string
|
|
28
|
+
[key: string]: unknown
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The read receipt of a notification for the current user. */
|
|
32
|
+
export type NotificationRead = {
|
|
33
|
+
id: string
|
|
34
|
+
notificationId: string
|
|
35
|
+
userId: string
|
|
36
|
+
readAt: string | null
|
|
37
|
+
createdAt: string
|
|
38
|
+
updatedAt: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Counts of the notifications the user sees (all of the account with `notification.view.all`).
|
|
43
|
+
* They come as TEXT: the backend answers the `COUNT` of the database as is (e.g. `"43"`).
|
|
44
|
+
*/
|
|
45
|
+
export type NotificationCounts = {
|
|
46
|
+
total: string
|
|
47
|
+
read: string
|
|
48
|
+
unread: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** What `read`, `unread` and `count` answer. */
|
|
52
|
+
export type NotificationCountsResponse = {
|
|
53
|
+
count: NotificationCounts
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** What `readAll` answers: the counts after marking everything as read, as numbers. */
|
|
57
|
+
export type NotificationReadAllResponse = {
|
|
58
|
+
total: number
|
|
59
|
+
read: number
|
|
60
|
+
unread: number
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** The body of `sendAll`: `to: 'admin'` sends only to the admins; any other value sends to every user. */
|
|
64
|
+
export type SendAllNotificationsPayload = {
|
|
65
|
+
/** Up to 255 characters. */
|
|
66
|
+
text: string
|
|
67
|
+
to: 'admin' | 'all' | (string & {})
|
|
68
|
+
image?: string
|
|
21
69
|
}
|
|
22
70
|
|
|
23
71
|
export type Notification = {
|
|
24
72
|
id: string
|
|
25
73
|
text: string
|
|
26
74
|
type: NotificationType | null
|
|
27
|
-
read
|
|
75
|
+
/** `null` on the announcements of `sendAll` until they are read. */
|
|
76
|
+
read: boolean | null
|
|
28
77
|
image: string | null
|
|
29
78
|
label: string | null
|
|
30
79
|
config: NotificationConfig | null
|
|
31
80
|
attachedType: string | null
|
|
81
|
+
/** @deprecated Not answered: the model has no such column, so the transformer never sends it. */
|
|
82
|
+
attachedId?: string | null
|
|
83
|
+
/** @deprecated Not answered: the model has no such column, so the transformer never sends it. */
|
|
84
|
+
notificationReadId?: string | null
|
|
32
85
|
contactId: string | null
|
|
33
86
|
userId: string
|
|
34
87
|
accountId: string
|
|
35
88
|
scheduleId: string | null
|
|
36
89
|
createdAt: string
|
|
37
90
|
updatedAt: string
|
|
38
|
-
|
|
91
|
+
/** @deprecated Not answered: the transformer of the backend does not send it. */
|
|
92
|
+
deletedAt?: string | null
|
|
39
93
|
// relationships
|
|
40
94
|
user?: User
|
|
41
95
|
schedule?: Schedule | null
|
|
96
|
+
/** @deprecated Not served: the model has no such association, so it never comes. */
|
|
42
97
|
contact?: Contact | null
|
|
98
|
+
/** The read receipts of the notification (a list: `[]` while it was never read). */
|
|
99
|
+
notificationRead?: NotificationRead[]
|
|
43
100
|
}
|
|
44
101
|
|
|
45
|
-
|
|
102
|
+
/** The backend serves `user`, `schedule` and `notificationRead` (`contact` is never answered). */
|
|
103
|
+
export type NotificationRelationships = 'user' | 'schedule' | 'contact' | 'notificationRead'
|
|
46
104
|
|
|
47
105
|
export type CreateNotificationPayload = {
|
|
106
|
+
/** Up to 255 characters. */
|
|
48
107
|
text: string
|
|
49
|
-
|
|
108
|
+
/** Ignored: the backend creates the notification for the current user. */
|
|
109
|
+
userId?: string
|
|
50
110
|
type?: NotificationType
|
|
51
111
|
label?: string
|
|
52
112
|
config?: NotificationConfig
|
|
53
113
|
attachedType?: string
|
|
54
114
|
contactId?: string
|
|
55
115
|
scheduleId?: string
|
|
116
|
+
image?: string
|
|
56
117
|
}
|
|
57
118
|
|
|
58
119
|
export type UpdateNotificationPayload = {
|
|
@@ -71,6 +71,18 @@ import { KnowledgeBaseApi } from './knowledgeBase/KnowledgeBaseApi'
|
|
|
71
71
|
import { KnowledgeBaseItemApi } from './knowledgeBaseItem/KnowledgeBaseItemApi'
|
|
72
72
|
import { MessagesApi } from './messages/MessagesApi'
|
|
73
73
|
import { NotificationsApi } from './notifications/NotificationsApi'
|
|
74
|
+
import type {
|
|
75
|
+
Notification,
|
|
76
|
+
NotificationCountsResponse,
|
|
77
|
+
NotificationRead,
|
|
78
|
+
} from './notifications/types'
|
|
79
|
+
import { AbsenceApi } from './absence/AbsenceApi'
|
|
80
|
+
import type { AbsenceReportItem, UnlockAbsenceResponse } from './absence/types'
|
|
81
|
+
import { ActivityLogApi } from './activityLog/ActivityLogApi'
|
|
82
|
+
import { CreditMovementsApi } from './creditMovements/CreditMovementsApi'
|
|
83
|
+
import type { CreditBalances, CreditTotalServices } from './creditMovements/types'
|
|
84
|
+
import { StickersApi } from './stickers/StickersApi'
|
|
85
|
+
import type { Sticker } from './stickers/types'
|
|
74
86
|
import { OrganizationsApi } from './organizations/OrganizationsApi'
|
|
75
87
|
import { PeopleApi } from './people/PeopleApi'
|
|
76
88
|
import { ServicesApi } from './services/ServicesApi'
|
|
@@ -703,3 +715,57 @@ expectAssignable<ApiClient>({
|
|
|
703
715
|
patch: async <T>() => undefined as T,
|
|
704
716
|
delete: async <T>() => undefined as T,
|
|
705
717
|
})
|
|
718
|
+
|
|
719
|
+
// ── QARC-1010: notifications, absence, log, knowledge base, credits, stickers ─────
|
|
720
|
+
|
|
721
|
+
expectType<Promise<NotificationCountsResponse>>(new NotificationsApi(client).count())
|
|
722
|
+
expectType<Promise<string>>(new NotificationsApi(client).count().then(({ count }) => count.total))
|
|
723
|
+
expectError(new NotificationsApi(client).sendAll({ to: 'admin' }))
|
|
724
|
+
expectType<Promise<void>>(new NotificationsApi(client).readMany(['n-1']))
|
|
725
|
+
expectType<Promise<Paginated<AbsenceReportItem>>>(
|
|
726
|
+
new AbsenceApi(client).report({ filters: { reason: 'x' }, order: 'ASC' }),
|
|
727
|
+
)
|
|
728
|
+
expectType<Promise<UnlockAbsenceResponse>>(new AbsenceApi(client).unlock({}))
|
|
729
|
+
expectError(new AbsenceApi(client).report({ sort: 'name' }))
|
|
730
|
+
expectType<Promise<string>>(
|
|
731
|
+
new ActivityLogApi(client).exportCsv({ filters: { from: 'a', to: 'b' } }),
|
|
732
|
+
)
|
|
733
|
+
expectAssignable<Parameters<ActivityLogApi['create']>[0]>({
|
|
734
|
+
resourceType: 'contact',
|
|
735
|
+
event: 'update',
|
|
736
|
+
})
|
|
737
|
+
expectType<Promise<true>>(new KnowledgeBaseItemApi(client).deleteMany(['i-1']))
|
|
738
|
+
expectError(
|
|
739
|
+
new KnowledgeBaseApi(client).saveWithItems({ name: 'qa', items: [{ name: 'x', type: 'pdf' }] }),
|
|
740
|
+
)
|
|
741
|
+
expectType<Promise<CreditBalances>>(new CreditMovementsApi(client).balances())
|
|
742
|
+
expectType<Promise<number>>(new CreditMovementsApi(client).balance('sms-wavy'))
|
|
743
|
+
expectType<Promise<CreditTotalServices | undefined>>(
|
|
744
|
+
new CreditMovementsApi(client).totalServices({
|
|
745
|
+
filters: { from: 'a', to: 'b', serviceType: 'summary' },
|
|
746
|
+
page: 1,
|
|
747
|
+
}),
|
|
748
|
+
)
|
|
749
|
+
expectType<Promise<ArrayBuffer>>(
|
|
750
|
+
new CreditMovementsApi(client).exportXlsx({ from: 'a', to: 'b', where: { $and: [] } }),
|
|
751
|
+
)
|
|
752
|
+
expectType<Promise<Sticker>>(new StickersApi(client).create({ base64: 'iVBOR', name: 'qa' }))
|
|
753
|
+
expectError(new StickersApi(client).create({ type: 'created' }))
|
|
754
|
+
expectType<Promise<'OK' | false>>(new StickersApi(client).remove('s-1'))
|
|
755
|
+
expectAssignable<Parameters<StickersApi['getMany']>[0]>({ include: ['file'] })
|
|
756
|
+
|
|
757
|
+
// ── QARC-1010 (4.13.1): the shapes observed on qa-rc ─────────────────
|
|
758
|
+
|
|
759
|
+
declare const notification: Notification
|
|
760
|
+
expectType<NotificationRead[] | undefined>(notification.notificationRead)
|
|
761
|
+
expectType<string | null | undefined>(notification.attachedId)
|
|
762
|
+
declare const sticker: Sticker
|
|
763
|
+
expectAssignable<Sticker>({ ...sticker, originMessage: null })
|
|
764
|
+
expectAssignable<Promise<{ message: string }>>(
|
|
765
|
+
new ServicesApi(client).accessManagement('s-1', { userIds: ['u-1'], deny: true }),
|
|
766
|
+
)
|
|
767
|
+
expectAssignable<Awaited<ReturnType<ServicesApi['accessManagement']>>>({
|
|
768
|
+
message: '2 users allowed access.',
|
|
769
|
+
})
|
|
770
|
+
expectNotAssignable<Awaited<ReturnType<ServicesApi['accessManagement']>>>({ message: 'denied' })
|
|
771
|
+
expectError(new ServicesApi(client).accessManagement('s-1', { userIds: ['u-1'] }))
|
|
@@ -6,7 +6,10 @@ export class ServiceAccessManagementApi
|
|
|
6
6
|
extends BaseApi
|
|
7
7
|
implements HasGetMany<ServiceAccessManagement>
|
|
8
8
|
{
|
|
9
|
-
/**
|
|
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'
|