@startsimpli/api 0.5.9 → 0.5.13
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/package.json
CHANGED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnrichmentApi unit tests — Apollo enrichment.
|
|
3
|
+
*
|
|
4
|
+
* Phase 2 of user-facing Apollo enrichment (raise-simpli-iz2).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
8
|
+
import { EnrichmentApi } from '../lib/enrichment-api';
|
|
9
|
+
import type { ApiClient } from '../lib/api-client';
|
|
10
|
+
import type { ApolloEnrichmentSummary } from '../types/enrichment';
|
|
11
|
+
|
|
12
|
+
function makeClient(postReturn: unknown = {}): ApiClient {
|
|
13
|
+
const post = vi.fn().mockResolvedValue(postReturn);
|
|
14
|
+
return {
|
|
15
|
+
get: vi.fn(),
|
|
16
|
+
post,
|
|
17
|
+
patch: vi.fn(),
|
|
18
|
+
delete: vi.fn(),
|
|
19
|
+
baseUrl: 'http://localhost:8000',
|
|
20
|
+
fetch: { post } as any,
|
|
21
|
+
setTokenGetter: vi.fn(),
|
|
22
|
+
setUnauthorizedHandler: vi.fn(),
|
|
23
|
+
} as unknown as ApiClient;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const mockSummary: ApolloEnrichmentSummary = {
|
|
27
|
+
total: 2,
|
|
28
|
+
enriched: ['c-1'],
|
|
29
|
+
skipped: [{ contact_id: 'c-2', reason: 'insufficient query fields' }],
|
|
30
|
+
errors: [],
|
|
31
|
+
missing: [],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
describe('EnrichmentApi.enrichApollo', () => {
|
|
36
|
+
it('POSTs to /contacts/enrich-apollo/ with contact_ids body', async () => {
|
|
37
|
+
const client = makeClient(mockSummary);
|
|
38
|
+
const api = new EnrichmentApi(client);
|
|
39
|
+
|
|
40
|
+
const result = await api.enrichApollo(['c-1', 'c-2']);
|
|
41
|
+
|
|
42
|
+
expect(client.fetch.post).toHaveBeenCalledTimes(1);
|
|
43
|
+
const [endpoint, body] = (client.fetch.post as any).mock.calls[0];
|
|
44
|
+
expect(endpoint).toContain('contacts/enrich-apollo');
|
|
45
|
+
expect(body).toEqual({ contact_ids: ['c-1', 'c-2'] });
|
|
46
|
+
expect(result).toEqual(mockSummary);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('returns the structured summary unchanged', async () => {
|
|
50
|
+
const summary: ApolloEnrichmentSummary = {
|
|
51
|
+
total: 3,
|
|
52
|
+
enriched: ['c-1', 'c-3'],
|
|
53
|
+
skipped: [],
|
|
54
|
+
errors: [{ contact_id: 'c-2', error: 'Apollo error: 401' }],
|
|
55
|
+
missing: [],
|
|
56
|
+
};
|
|
57
|
+
const client = makeClient(summary);
|
|
58
|
+
const api = new EnrichmentApi(client);
|
|
59
|
+
|
|
60
|
+
const result = await api.enrichApollo(['c-1', 'c-2', 'c-3']);
|
|
61
|
+
expect(result).toEqual(summary);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('rejects empty contact_ids list before calling the API', async () => {
|
|
65
|
+
const client = makeClient(mockSummary);
|
|
66
|
+
const api = new EnrichmentApi(client);
|
|
67
|
+
|
|
68
|
+
await expect(api.enrichApollo([])).rejects.toThrow(/non-empty/);
|
|
69
|
+
expect(client.fetch.post).not.toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('rejects > 100 contact_ids before calling the API', async () => {
|
|
73
|
+
const client = makeClient(mockSummary);
|
|
74
|
+
const api = new EnrichmentApi(client);
|
|
75
|
+
|
|
76
|
+
const ids = Array.from({ length: 101 }, (_, i) => `c-${i}`);
|
|
77
|
+
await expect(api.enrichApollo(ids)).rejects.toThrow(/100/);
|
|
78
|
+
expect(client.fetch.post).not.toHaveBeenCalled();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('passes through API errors', async () => {
|
|
82
|
+
const client = makeClient(mockSummary);
|
|
83
|
+
(client.fetch.post as any).mockRejectedValueOnce(new Error('network'));
|
|
84
|
+
const api = new EnrichmentApi(client);
|
|
85
|
+
|
|
86
|
+
await expect(api.enrichApollo(['c-1'])).rejects.toThrow(/network/);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -57,6 +57,7 @@ export const ENDPOINTS = {
|
|
|
57
57
|
// Enrichment
|
|
58
58
|
ENRICHMENT_QUEUE: 'api/v1/enrichment/start-processing',
|
|
59
59
|
CONTACT_ENRICH: (id: string) => `api/v1/contacts/${id}/enrich`,
|
|
60
|
+
CONTACTS_ENRICH_APOLLO: 'api/v1/contacts/enrich-apollo',
|
|
60
61
|
|
|
61
62
|
// Users
|
|
62
63
|
USER_ME: 'api/v1/users/me',
|
|
@@ -2,13 +2,35 @@
|
|
|
2
2
|
* Enrichment API wrapper for /api/v1/enrichment/ and /api/v1/contacts/:id/enrich/
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { EnrichmentResult, QueueStatus } from '../types';
|
|
5
|
+
import type { EnrichmentResult, QueueStatus, ApolloEnrichmentSummary } from '../types';
|
|
6
6
|
import { ENDPOINTS } from '../constants/endpoints';
|
|
7
7
|
import type { ApiClient } from './api-client';
|
|
8
8
|
|
|
9
|
+
const APOLLO_BATCH_CAP = 100;
|
|
10
|
+
|
|
9
11
|
export class EnrichmentApi {
|
|
10
12
|
constructor(private client: ApiClient) {}
|
|
11
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Trigger Apollo enrichment for one or more contacts.
|
|
16
|
+
*
|
|
17
|
+
* Backend: POST /api/v1/contacts/enrich-apollo/. Team-scoped — contact
|
|
18
|
+
* ids the user can't see come back under `missing`. Calls fail fast on
|
|
19
|
+
* empty list or > 100 ids without round-tripping the server.
|
|
20
|
+
*/
|
|
21
|
+
async enrichApollo(contactIds: string[]): Promise<ApolloEnrichmentSummary> {
|
|
22
|
+
if (!Array.isArray(contactIds) || contactIds.length === 0) {
|
|
23
|
+
throw new Error('enrichApollo requires a non-empty list of contact_ids');
|
|
24
|
+
}
|
|
25
|
+
if (contactIds.length > APOLLO_BATCH_CAP) {
|
|
26
|
+
throw new Error(`enrichApollo accepts at most ${APOLLO_BATCH_CAP} contact_ids per call`);
|
|
27
|
+
}
|
|
28
|
+
return this.client.fetch.post<ApolloEnrichmentSummary>(
|
|
29
|
+
ENDPOINTS.CONTACTS_ENRICH_APOLLO,
|
|
30
|
+
{ contact_ids: contactIds },
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
12
34
|
/**
|
|
13
35
|
* Enrich a single contact by ID
|
|
14
36
|
*/
|
package/src/types/enrichment.ts
CHANGED
|
@@ -26,3 +26,21 @@ export interface IntegrationStatus {
|
|
|
26
26
|
description: string;
|
|
27
27
|
lastSync?: string;
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Apollo bulk enrichment summary returned by
|
|
32
|
+
* POST /api/v1/contacts/enrich-apollo/.
|
|
33
|
+
*
|
|
34
|
+
* `enriched` — contact ids whose fields were updated by Apollo.
|
|
35
|
+
* `skipped` — contacts the service ran but didn't change (per-entry reason).
|
|
36
|
+
* `errors` — contacts that errored at the Apollo API boundary.
|
|
37
|
+
* `missing` — contact ids the user couldn't see (team-scoped) or that
|
|
38
|
+
* don't exist. Reported back so the UI can flag them.
|
|
39
|
+
*/
|
|
40
|
+
export interface ApolloEnrichmentSummary {
|
|
41
|
+
total: number;
|
|
42
|
+
enriched: string[];
|
|
43
|
+
skipped: Array<{ contact_id: string; reason: string }>;
|
|
44
|
+
errors: Array<{ contact_id: string; error: string }>;
|
|
45
|
+
missing: string[];
|
|
46
|
+
}
|