@ikatec/digisac-api-sdk 2.2.1 → 3.1.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/acceptanceTerms/types.d.ts +18 -2
- package/dist/apis/acceptanceTerms/types.d.ts.map +1 -1
- package/dist/apis/accounts/types.d.ts +2 -0
- package/dist/apis/accounts/types.d.ts.map +1 -1
- package/dist/apis/cards/types.d.ts +89 -7
- package/dist/apis/cards/types.d.ts.map +1 -1
- package/dist/apis/pipeline/types.d.ts +67 -3
- package/dist/apis/pipeline/types.d.ts.map +1 -1
- package/dist/apis/terms/TermsApi.cjs +34 -6
- package/dist/apis/terms/TermsApi.cjs.map +1 -1
- package/dist/apis/terms/TermsApi.d.ts +27 -6
- package/dist/apis/terms/TermsApi.d.ts.map +1 -1
- package/dist/apis/terms/TermsApi.mjs +34 -6
- package/dist/apis/terms/TermsApi.mjs.map +1 -1
- package/dist/apis/terms/types.d.ts +0 -14
- package/dist/apis/terms/types.d.ts.map +1 -1
- package/dist/core/BaseApiClient.cjs +26 -1
- package/dist/core/BaseApiClient.cjs.map +1 -1
- package/dist/core/BaseApiClient.d.ts.map +1 -1
- package/dist/core/BaseApiClient.mjs +26 -1
- package/dist/core/BaseApiClient.mjs.map +1 -1
- package/dist/incommingWebhooks/index.d.ts +3 -3
- package/dist/incommingWebhooks/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/apis/acceptanceTerms/AcceptanceTermsApi.test.ts +96 -0
- package/src/apis/acceptanceTerms/types.ts +19 -2
- package/src/apis/accounts/types.ts +2 -0
- package/src/apis/cards/types.ts +104 -7
- package/src/apis/pipeline/types.ts +71 -3
- package/src/apis/terms/TermsApi.test.ts +56 -102
- package/src/apis/terms/TermsApi.ts +41 -12
- package/src/apis/terms/types.ts +0 -16
- package/src/core/BaseApiClient.test.ts +53 -0
- package/src/core/BaseApiClient.ts +37 -1
- package/src/incommingWebhooks/index.ts +3 -3
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
2
|
import { TermsApi } from './TermsApi'
|
|
3
3
|
import type { ApiClient } from '../../core/ApiClient'
|
|
4
|
-
import type { Term
|
|
5
|
-
import type { Paginated } from '../../core/types'
|
|
4
|
+
import type { Term } from './types'
|
|
6
5
|
|
|
7
6
|
// ── Mock client factory ──────────────────────────────────────────────
|
|
8
7
|
|
|
@@ -34,17 +33,6 @@ const term: Term = {
|
|
|
34
33
|
updatedAt: '2024-01-01T00:00:00Z',
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
const paginated: Paginated<Term> = {
|
|
38
|
-
data: [term],
|
|
39
|
-
total: 1,
|
|
40
|
-
limit: 10,
|
|
41
|
-
skip: 0,
|
|
42
|
-
currentPage: 1,
|
|
43
|
-
lastPage: 1,
|
|
44
|
-
from: 1,
|
|
45
|
-
to: 1,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
36
|
// ── Tests ────────────────────────────────────────────────────────────
|
|
49
37
|
|
|
50
38
|
describe('TermsApi', () => {
|
|
@@ -56,30 +44,13 @@ describe('TermsApi', () => {
|
|
|
56
44
|
api = new TermsApi(client)
|
|
57
45
|
})
|
|
58
46
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
expect(result).toEqual(paginated)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('serializes query parameters', async () => {
|
|
70
|
-
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
71
|
-
await api.getMany({ page: 2 })
|
|
72
|
-
const url = vi.mocked(client.get).mock.calls[0][0] as string
|
|
73
|
-
expect(url).toContain('/terms?')
|
|
74
|
-
expect(url).toContain('page=2')
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('forwards custom headers', async () => {
|
|
78
|
-
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
79
|
-
const headers = { 'X-Custom': 'value' }
|
|
80
|
-
await api.getMany(undefined, headers)
|
|
81
|
-
expect(client.get).toHaveBeenCalledWith('/terms', headers)
|
|
82
|
-
})
|
|
47
|
+
it('exposes only the read routes served by the backend', () => {
|
|
48
|
+
expect(api.basePath).toBe('/terms')
|
|
49
|
+
// /terms has no list/create/update/delete routes (404 "Route not found.")
|
|
50
|
+
expect(api).not.toHaveProperty('getMany')
|
|
51
|
+
expect(api).not.toHaveProperty('create')
|
|
52
|
+
expect(api).not.toHaveProperty('updateById')
|
|
53
|
+
expect(api).not.toHaveProperty('deleteById')
|
|
83
54
|
})
|
|
84
55
|
|
|
85
56
|
// ── getById ──────────────────────────────────────────────────────
|
|
@@ -92,100 +63,83 @@ describe('TermsApi', () => {
|
|
|
92
63
|
expect(result).toEqual(term)
|
|
93
64
|
})
|
|
94
65
|
|
|
66
|
+
it('serializes the query', async () => {
|
|
67
|
+
vi.mocked(client.get).mockResolvedValue(term)
|
|
68
|
+
await api.getById('term-1', { attributes: ['id', 'version'] })
|
|
69
|
+
const url = vi.mocked(client.get).mock.calls[0][0] as string
|
|
70
|
+
expect(url).toContain('/terms/term-1?')
|
|
71
|
+
expect(url).toContain('attributes')
|
|
72
|
+
})
|
|
73
|
+
|
|
95
74
|
it('forwards custom headers', async () => {
|
|
96
75
|
vi.mocked(client.get).mockResolvedValue(term)
|
|
97
76
|
const headers = { 'X-Tenant': 'abc' }
|
|
98
77
|
await api.getById('term-1', undefined, headers)
|
|
99
78
|
expect(client.get).toHaveBeenCalledWith('/terms/term-1', headers)
|
|
100
79
|
})
|
|
101
|
-
})
|
|
102
80
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const body: CreateTermPayload = {
|
|
109
|
-
title: { en: 'ToS' },
|
|
110
|
-
text: { en: 'Text' },
|
|
111
|
-
expirationDate: '2025-01-01',
|
|
112
|
-
version: '1.0',
|
|
113
|
-
agnusId: 'agnus-1',
|
|
114
|
-
}
|
|
115
|
-
const result = await api.create(body)
|
|
116
|
-
expect(client.post).toHaveBeenCalledWith('/terms', body, undefined)
|
|
117
|
-
expect(result).toEqual(term)
|
|
81
|
+
it('keeps working when detached from the instance', async () => {
|
|
82
|
+
vi.mocked(client.get).mockResolvedValue(term)
|
|
83
|
+
const { getById } = api
|
|
84
|
+
await getById('term-1')
|
|
85
|
+
expect(client.get).toHaveBeenCalledWith('/terms/term-1', undefined)
|
|
118
86
|
})
|
|
119
87
|
})
|
|
120
88
|
|
|
121
|
-
// ──
|
|
89
|
+
// ── getNotAgreed ─────────────────────────────────────────────────
|
|
122
90
|
|
|
123
|
-
describe('
|
|
124
|
-
it('calls client.
|
|
125
|
-
vi.mocked(client.
|
|
126
|
-
const result = await api.
|
|
127
|
-
expect(client.
|
|
128
|
-
expect(result).toEqual(term)
|
|
91
|
+
describe('getNotAgreed', () => {
|
|
92
|
+
it('calls client.get with /terms/terms-not-agreed and returns the plain array', async () => {
|
|
93
|
+
vi.mocked(client.get).mockResolvedValue([term])
|
|
94
|
+
const result = await api.getNotAgreed()
|
|
95
|
+
expect(client.get).toHaveBeenCalledWith('/terms/terms-not-agreed', undefined)
|
|
96
|
+
expect(result).toEqual([term])
|
|
129
97
|
})
|
|
130
98
|
|
|
131
99
|
it('forwards custom headers', async () => {
|
|
132
|
-
vi.mocked(client.
|
|
133
|
-
const headers = { '
|
|
134
|
-
await api.
|
|
135
|
-
expect(client.
|
|
100
|
+
vi.mocked(client.get).mockResolvedValue([])
|
|
101
|
+
const headers = { 'X-Custom': 'h' }
|
|
102
|
+
await api.getNotAgreed(headers)
|
|
103
|
+
expect(client.get).toHaveBeenCalledWith('/terms/terms-not-agreed', headers)
|
|
136
104
|
})
|
|
137
105
|
})
|
|
138
106
|
|
|
139
|
-
// ──
|
|
140
|
-
|
|
141
|
-
describe('
|
|
142
|
-
it('calls client.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
expect(
|
|
107
|
+
// ── agree ────────────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
describe('agree', () => {
|
|
110
|
+
it('calls client.patch with /terms/agree and the term ids', async () => {
|
|
111
|
+
const agnusResponse = { agreed: true }
|
|
112
|
+
vi.mocked(client.patch).mockResolvedValue(agnusResponse)
|
|
113
|
+
const result = await api.agree(['term-1', 'term-2'])
|
|
114
|
+
expect(client.patch).toHaveBeenCalledWith(
|
|
115
|
+
'/terms/agree',
|
|
116
|
+
{ terms: ['term-1', 'term-2'] },
|
|
117
|
+
undefined,
|
|
118
|
+
)
|
|
119
|
+
expect(result).toEqual(agnusResponse)
|
|
147
120
|
})
|
|
148
121
|
|
|
149
122
|
it('forwards custom headers', async () => {
|
|
150
|
-
vi.mocked(client.
|
|
151
|
-
const headers = { 'X-
|
|
152
|
-
await api.
|
|
153
|
-
expect(client.
|
|
154
|
-
})
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
// ── getNotAgreed ─────────────────────────────────────────────────
|
|
158
|
-
|
|
159
|
-
describe('getNotAgreed', () => {
|
|
160
|
-
it('calls client.get with /terms/terms-not-agreed when no query is provided', async () => {
|
|
161
|
-
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
162
|
-
const result = await api.getNotAgreed()
|
|
163
|
-
expect(client.get).toHaveBeenCalledWith('/terms/terms-not-agreed', undefined)
|
|
164
|
-
expect(result).toEqual(paginated)
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
it('serializes query parameters', async () => {
|
|
168
|
-
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
169
|
-
await api.getNotAgreed({ page: 1, perPage: 5 })
|
|
170
|
-
const url = vi.mocked(client.get).mock.calls[0][0] as string
|
|
171
|
-
expect(url).toContain('/terms/terms-not-agreed?')
|
|
172
|
-
expect(url).toContain('page=1')
|
|
123
|
+
vi.mocked(client.patch).mockResolvedValue({})
|
|
124
|
+
const headers = { 'X-Custom': 'h' }
|
|
125
|
+
await api.agree(['term-1'], headers)
|
|
126
|
+
expect(client.patch).toHaveBeenCalledWith('/terms/agree', { terms: ['term-1'] }, headers)
|
|
173
127
|
})
|
|
174
128
|
|
|
175
|
-
it('
|
|
176
|
-
vi.mocked(client.
|
|
177
|
-
const
|
|
178
|
-
await
|
|
179
|
-
expect(client.
|
|
129
|
+
it('keeps working when detached from the instance', async () => {
|
|
130
|
+
vi.mocked(client.patch).mockResolvedValue({})
|
|
131
|
+
const { agree } = api
|
|
132
|
+
await agree(['term-1'])
|
|
133
|
+
expect(client.patch).toHaveBeenCalledWith('/terms/agree', { terms: ['term-1'] }, undefined)
|
|
180
134
|
})
|
|
181
135
|
})
|
|
182
136
|
|
|
183
137
|
// ── Error propagation ────────────────────────────────────────────
|
|
184
138
|
|
|
185
139
|
describe('error propagation', () => {
|
|
186
|
-
it('propagates errors from
|
|
140
|
+
it('propagates errors from getById', async () => {
|
|
187
141
|
vi.mocked(client.get).mockRejectedValue(new Error('Network error'))
|
|
188
|
-
await expect(api.
|
|
142
|
+
await expect(api.getById('term-1')).rejects.toThrow('Network error')
|
|
189
143
|
})
|
|
190
144
|
|
|
191
145
|
it('propagates errors from getNotAgreed', async () => {
|
|
@@ -1,22 +1,51 @@
|
|
|
1
1
|
import qs from 'qs'
|
|
2
2
|
import type { ApiClient } from '../../core/ApiClient'
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
5
|
-
|
|
3
|
+
import type { GetByIdQuery, HasGetById } from '../../core/types'
|
|
4
|
+
import type { Term } from './types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Platform terms of use. Terms are published by Agnus (billing) and accepted by the account users,
|
|
8
|
+
* so the `/terms` route has no create/list/update/delete — only the routes below.
|
|
9
|
+
*
|
|
10
|
+
* `GET /terms/:id/export-pdf` is not exposed: it answers a binary PDF, and `ApiClient` only
|
|
11
|
+
* handles JSON/text bodies.
|
|
12
|
+
*/
|
|
13
|
+
export class TermsApi implements HasGetById<Term> {
|
|
14
|
+
protected readonly client: ApiClient
|
|
15
|
+
public readonly basePath = '/terms'
|
|
6
16
|
|
|
7
|
-
export class TermsApi extends BaseCrudApi<Term, CreateTermPayload, UpdateTermPayload> {
|
|
8
17
|
constructor(client: ApiClient) {
|
|
9
|
-
|
|
18
|
+
this.client = client
|
|
19
|
+
this.getById = this.getById.bind(this)
|
|
20
|
+
this.getNotAgreed = this.getNotAgreed.bind(this)
|
|
21
|
+
this.agree = this.agree.bind(this)
|
|
10
22
|
}
|
|
11
23
|
|
|
12
|
-
/** Returns
|
|
13
|
-
|
|
14
|
-
query?: ListQuery<Term>,
|
|
15
|
-
headers?: Record<string, string>,
|
|
16
|
-
): Promise<Paginated<Term>> {
|
|
24
|
+
/** Returns a single term by its ID, scoped to the current account (`null` when not found). */
|
|
25
|
+
getById(id: string, query?: GetByIdQuery<Term>, headers?: Record<string, string>): Promise<Term> {
|
|
17
26
|
const queryString = query ? `?${qs.stringify(query)}` : ''
|
|
18
|
-
return this.client.get<
|
|
19
|
-
|
|
27
|
+
return this.client.get<Term>(`${this.basePath}/${id}${queryString}`, headers)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns the terms of the current account that were not agreed to yet (`agreementDate` null).
|
|
32
|
+
* The backend answers a plain array (not paginated) and ignores query parameters.
|
|
33
|
+
*/
|
|
34
|
+
getNotAgreed(headers?: Record<string, string>): Promise<Term[]> {
|
|
35
|
+
return this.client.get<Term[]>(`${this.basePath}/terms-not-agreed`, headers)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Agrees to the given terms on behalf of the authenticated user. IRREVERSIBLE: the acceptance is
|
|
40
|
+
* registered on Agnus, the terms get `agreementDate`/`userId`, and the signed PDFs are e-mailed
|
|
41
|
+
* to the user. Only terms of the current account are affected.
|
|
42
|
+
*
|
|
43
|
+
* The response is passed through from Agnus as-is, so it is not typed.
|
|
44
|
+
*/
|
|
45
|
+
agree(termIds: string[], headers?: Record<string, string>): Promise<unknown> {
|
|
46
|
+
return this.client.patch<unknown, { terms: string[] }>(
|
|
47
|
+
`${this.basePath}/agree`,
|
|
48
|
+
{ terms: termIds },
|
|
20
49
|
headers,
|
|
21
50
|
)
|
|
22
51
|
}
|
package/src/apis/terms/types.ts
CHANGED
|
@@ -11,19 +11,3 @@ export type Term = {
|
|
|
11
11
|
createdAt: string
|
|
12
12
|
updatedAt: string
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
export type CreateTermPayload = {
|
|
16
|
-
title: Record<string, string>
|
|
17
|
-
text: Record<string, string>
|
|
18
|
-
expirationDate: string
|
|
19
|
-
version: string
|
|
20
|
-
agnusId: string
|
|
21
|
-
accountId?: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type UpdateTermPayload = {
|
|
25
|
-
title?: Record<string, string>
|
|
26
|
-
text?: Record<string, string>
|
|
27
|
-
expirationDate?: string
|
|
28
|
-
version?: string
|
|
29
|
-
}
|
|
@@ -230,6 +230,59 @@ describe('BaseApiClient', () => {
|
|
|
230
230
|
})
|
|
231
231
|
})
|
|
232
232
|
|
|
233
|
+
it('maps the Digisac field errors (errors.<location>.<field>) into validationErrors', async () => {
|
|
234
|
+
mockFetch({
|
|
235
|
+
ok: false,
|
|
236
|
+
status: 400,
|
|
237
|
+
statusText: 'Bad Request',
|
|
238
|
+
headers: { 'Content-Type': 'application/json' },
|
|
239
|
+
body: JSON.stringify({
|
|
240
|
+
error: 'ValidationError',
|
|
241
|
+
message: 'The given data was invalid.',
|
|
242
|
+
status: 400,
|
|
243
|
+
errors: {
|
|
244
|
+
body: {
|
|
245
|
+
name: { messages: ['Required.'], types: ['required'] },
|
|
246
|
+
title: {
|
|
247
|
+
messages: ['Required.', 'Should contain lesser than or equals 255 characters.'],
|
|
248
|
+
types: ['required', 'hasLengthLesserThanOrEqual'],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
params: { contactId: { messages: ['Should be an UUID v4 string.'], types: ['uuid4'] } },
|
|
252
|
+
},
|
|
253
|
+
}),
|
|
254
|
+
})
|
|
255
|
+
await expect(client.post('/fail', {})).rejects.toMatchObject({
|
|
256
|
+
errorClass: 'ValidationError',
|
|
257
|
+
status: 400,
|
|
258
|
+
validationErrors: [
|
|
259
|
+
{ path: 'body.name', message: 'Required.', code: 'required' },
|
|
260
|
+
{ path: 'body.title', message: 'Required.', code: 'required' },
|
|
261
|
+
{
|
|
262
|
+
path: 'body.title',
|
|
263
|
+
message: 'Should contain lesser than or equals 255 characters.',
|
|
264
|
+
code: 'hasLengthLesserThanOrEqual',
|
|
265
|
+
},
|
|
266
|
+
{ path: 'params.contactId', message: 'Should be an UUID v4 string.', code: 'uuid4' },
|
|
267
|
+
],
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('keeps validationErrors null when the error body has no field errors', async () => {
|
|
272
|
+
mockFetch({
|
|
273
|
+
ok: false,
|
|
274
|
+
status: 400,
|
|
275
|
+
statusText: 'Bad Request',
|
|
276
|
+
headers: { 'Content-Type': 'application/json' },
|
|
277
|
+
body: JSON.stringify({
|
|
278
|
+
error: 'BadRequestHttpError',
|
|
279
|
+
message: 'Já existe uma funil com esse nome',
|
|
280
|
+
status: 400,
|
|
281
|
+
}),
|
|
282
|
+
})
|
|
283
|
+
await expect(client.get('/fail')).rejects.toMatchObject({ validationErrors: null })
|
|
284
|
+
})
|
|
285
|
+
|
|
233
286
|
it('falls back to default message when JSON parsing fails', async () => {
|
|
234
287
|
mockFetch({
|
|
235
288
|
ok: false,
|
|
@@ -6,6 +6,42 @@ export interface ValidationError {
|
|
|
6
6
|
code: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Digisac field errors: `{ errors: { <location>: { <field>: { messages: string[], types: string[] } } } }`,
|
|
11
|
+
* where location is `body`, `params`, `query`, `headers` or `cookies` (backend `validate` middleware).
|
|
12
|
+
*/
|
|
13
|
+
type DigisacFieldErrors = Record<string, Record<string, { messages?: unknown; types?: unknown }>>
|
|
14
|
+
|
|
15
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
16
|
+
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Flattens the Digisac `errors` object into `ValidationError[]` — one entry per message, with
|
|
20
|
+
* `path` = `<location>.<field>` (e.g. `body.name`) and `code` = the rule type (e.g. `required`).
|
|
21
|
+
* Returns `null` when the body carries no field errors.
|
|
22
|
+
*/
|
|
23
|
+
function parseValidationErrors(errors: unknown): ValidationError[] | null {
|
|
24
|
+
if (!isRecord(errors)) {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const parsed: ValidationError[] = []
|
|
29
|
+
for (const [location, fields] of Object.entries(errors as DigisacFieldErrors)) {
|
|
30
|
+
if (!isRecord(fields)) {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
for (const [field, detail] of Object.entries(fields)) {
|
|
34
|
+
const messages = Array.isArray(detail?.messages) ? detail.messages.map(String) : []
|
|
35
|
+
const types = Array.isArray(detail?.types) ? detail.types.map(String) : []
|
|
36
|
+
messages.forEach((message, index) => {
|
|
37
|
+
parsed.push({ path: `${location}.${field}`, message, code: types[index] ?? types[0] ?? '' })
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return parsed.length ? parsed : null
|
|
43
|
+
}
|
|
44
|
+
|
|
9
45
|
export class ApiError extends Error {
|
|
10
46
|
public readonly errorClass?: string | undefined
|
|
11
47
|
public readonly status?: number | undefined
|
|
@@ -76,7 +112,7 @@ export class BaseApiClient implements ApiClient {
|
|
|
76
112
|
const errorData = JSON.parse(errorText)
|
|
77
113
|
errorMessage = errorData.message || errorData.error || errorMessage
|
|
78
114
|
errorClass = errorData.error
|
|
79
|
-
validationErrors = errorData.validationErrors ??
|
|
115
|
+
validationErrors = errorData.validationErrors ?? parseValidationErrors(errorData.errors)
|
|
80
116
|
}
|
|
81
117
|
} catch {
|
|
82
118
|
// If JSON parsing fails, use the default error message
|
|
@@ -5,7 +5,7 @@ import type { Department, DepartmentRelationships } from '../apis/departments'
|
|
|
5
5
|
import type { Message, MessageRelationships } from '../apis/messages'
|
|
6
6
|
import type { Organization, OrganizationRelationships } from '../apis/organizations'
|
|
7
7
|
import type { Person, PersonRelationships } from '../apis/people'
|
|
8
|
-
import type {
|
|
8
|
+
import type { PipelineRecord } from '../apis/pipeline'
|
|
9
9
|
import type { QuickReply, QuickReplyRelationships } from '../apis/quickReplies'
|
|
10
10
|
import type { Role, RoleRelationships } from '../apis/roles'
|
|
11
11
|
import type { Service, ServiceRelationships } from '../apis/services'
|
|
@@ -119,8 +119,8 @@ export interface WebhookEventPayloadMap {
|
|
|
119
119
|
'campaign.created': Omit<Campaign, CampaignRelationships>
|
|
120
120
|
'campaign.updated': Omit<Campaign, CampaignRelationships>
|
|
121
121
|
'campaign.destroyed': Omit<Campaign, CampaignRelationships>
|
|
122
|
-
'pipeline.created':
|
|
123
|
-
'pipeline.updated':
|
|
122
|
+
'pipeline.created': PipelineRecord
|
|
123
|
+
'pipeline.updated': PipelineRecord
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// ─── Webhook Envelope ────────────────────────────────────────────────────────
|