@delofarag/crm-utils 0.2.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/README.md +151 -0
- package/dist/BaseCrm.d.ts +37 -0
- package/dist/BaseCrm.d.ts.map +1 -0
- package/dist/BaseCrm.js +3 -0
- package/dist/BaseCrm.js.map +1 -0
- package/dist/CRM.d.ts +37 -0
- package/dist/CRM.d.ts.map +1 -0
- package/dist/CRM.js +3 -0
- package/dist/CRM.js.map +1 -0
- package/dist/CrmConnection.d.ts +4 -0
- package/dist/CrmConnection.d.ts.map +1 -0
- package/dist/CrmConnection.js +3 -0
- package/dist/CrmConnection.js.map +1 -0
- package/dist/crms/hubspot/hubspot.d.ts +183 -0
- package/dist/crms/hubspot/hubspot.d.ts.map +1 -0
- package/dist/crms/hubspot/hubspot.js +349 -0
- package/dist/crms/hubspot/hubspot.js.map +1 -0
- package/dist/crms/hubspot/types.d.ts +52 -0
- package/dist/crms/hubspot/types.d.ts.map +1 -0
- package/dist/crms/hubspot/types.js +18 -0
- package/dist/crms/hubspot/types.js.map +1 -0
- package/dist/crms/hubspot.d.ts +108 -0
- package/dist/crms/hubspot.d.ts.map +1 -0
- package/dist/crms/hubspot.js +254 -0
- package/dist/crms/hubspot.js.map +1 -0
- package/dist/getCRM.d.ts +15 -0
- package/dist/getCRM.d.ts.map +1 -0
- package/dist/getCRM.js +13 -0
- package/dist/getCRM.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth-helpers.d.ts +5 -0
- package/dist/oauth-helpers.d.ts.map +1 -0
- package/dist/oauth-helpers.js +21 -0
- package/dist/oauth-helpers.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# `@delofarag/crm-utils`
|
|
2
|
+
|
|
3
|
+
TypeScript-Hilfsbibliothek für **CRM-Integrationen**: ein gemeinsames Datenmodell für Tokens (`TokenStore`), eine abstrakte **CRM-API** (Contacts, Companies, Notes, Search) und pro Anbieter eine **OAuth-Verbindung** plus HTTP-Wrapper.
|
|
4
|
+
|
|
5
|
+
**Aktuell implementiert:** HubSpot (`Hubspot`, `HubspotConnection`).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Für KI / Cursor — Kurzüberblick
|
|
10
|
+
|
|
11
|
+
| Frage | Antwort |
|
|
12
|
+
|--------|---------|
|
|
13
|
+
| Wie instanziiere ich den CRM-Client? | `getCRM("hubspot", { clientId, redirectUri })` → `Hubspot` |
|
|
14
|
+
| Wo ist OAuth? | `hub.connection` (`HubspotConnection`): `buildAuthorizeUrl` → User zu HubSpot → Callback mit `code` → `exchangeAuthorizationCode(clientSecret, { code })` |
|
|
15
|
+
| Wo sind CRM-Daten-APIs? | `hub.getContacts`, `hub.getCompanies`, `hub.createContact`, … — immer mit `accessToken` (serverseitig) |
|
|
16
|
+
| Darf `clientSecret` ins Frontend? | **Nein.** Nur Server (Route Handler, Backend). |
|
|
17
|
+
| Tokens speichern? | `TokenStore` ist das beabsichtigte Shape; Persistenz (DB) passiert **in deiner App** nach den Connection-Returns. |
|
|
18
|
+
| Neues CRM hinzufügen? | `CRM` + `CrmConnection` erweitern, `getCRM` + `CRMInitMap` / `CRMInstanceMap` in `getCRM.ts` ergänzen, `CRMs`-Array erweitern. |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm add @delofarag/crm-utils
|
|
26
|
+
# oder npm / yarn
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Paket baut nach `dist/` (`pnpm build` im Package). Consumer importieren aus dem Package-Root (`@delofarag/crm-utils`).
|
|
30
|
+
|
|
31
|
+
**Peer-Umgebung:** Node mit `fetch` (Node 18+) oder entsprechende Polyfills. `oauth-helpers` nutzt `node:crypto` für `randomState` — für reine Browser-Nutzung der OAuth-Helfer ggf. eigenes State erzeugen.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Architektur
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
getCRM(name, init)
|
|
39
|
+
└── Hubspot
|
|
40
|
+
├── connection: HubspotConnection ← OAuth (authorize, code exchange, refresh, metadata)
|
|
41
|
+
└── CRM-Methoden ← REST (Contacts, Companies, Notes, Search)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- **`CRM` (abstrakt):** gemeinsame Methodensignatur für alle CRMs (`getContacts`, `getCompanies`, `createContact`, `updateContact`, `createNote`, `searchRecords`).
|
|
45
|
+
- **`CrmConnection` (abstrakt):** OAuth-Schicht; `HubspotConnection` setzt HubSpot-URLs und Token-Flow um.
|
|
46
|
+
- **`TokenStore`:** flaches Objekt für OAuth-State und Tokens (`access_token`, `refresh_token`, `token_expires_at`, `provider_account_id`, `id` für eure User-DB, …).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Öffentliche Exports (`src/index.ts`)
|
|
51
|
+
|
|
52
|
+
| Export | Rolle |
|
|
53
|
+
|--------|--------|
|
|
54
|
+
| `getCRM`, `CRMs`, `CRMName`, `CRMInitMap`, `CRMInstanceMap` | Factory und Typen für unterstützte CRMs |
|
|
55
|
+
| `CRM` | Abstrakte Basisklasse für CRM-Implementierungen |
|
|
56
|
+
| `CrmConnection` | Abstrakte Basisklasse für OAuth (`provider`) |
|
|
57
|
+
| `TokenStore` | Token-/State-Shape |
|
|
58
|
+
| `Hubspot`, `HubspotConnection` | HubSpot-Implementierung |
|
|
59
|
+
| `HubspotInit` | `{ clientId, redirectUri }` |
|
|
60
|
+
| HubSpot-Zod-Typen | `HubspotTokenResponse`, Schemas (Parsing von Token-JSON) |
|
|
61
|
+
| `oauth-helpers` | `randomState`, `buildQueryString`, `postFormUrlEncoded`, `toExpiresAt` |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## HubSpot: Initialisierung
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { getCRM } from "@delofarag/crm-utils"
|
|
69
|
+
|
|
70
|
+
const hub = getCRM("hubspot", {
|
|
71
|
+
clientId: process.env.HUBSPOT_CLIENT_ID!,
|
|
72
|
+
redirectUri: "https://your-domain.com/api/hubspot/callback",
|
|
73
|
+
})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- **`redirectUri`:** muss **exakt** mit einer in der HubSpot-App eingetragenen Redirect-URL übereinstimmen und bei `buildAuthorizeUrl` und `exchangeAuthorizationCode` identisch sein (OAuth). Das ist die URL, auf die HubSpot den Browser mit `code` und `state` zurückschickt.
|
|
77
|
+
- **`clientId`:** öffentlich; **`clientSecret`** wird **nicht** im Constructor gespeichert, sondern nur an `exchangeAuthorizationCode` und `refreshAccessToken` / `getValidAccessToken` übergeben.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## HubSpot: OAuth-Ablauf (Reihenfolge)
|
|
82
|
+
|
|
83
|
+
1. **`hub.connection.buildAuthorizeUrl({ scopes, supabase_id? })`**
|
|
84
|
+
- Erzeugt `state` (CSRF) und ein `tokenStore`-Objekt mit `state` (und optional `id` aus `supabase_id`).
|
|
85
|
+
- Rückgabe: `{ authorizeUrl, state, tokenStore }` — Browser des Users zu `authorizeUrl` navigieren (volle Seiten-Navigation, kein `fetch` für den Start). State/Tokens bei dir persistieren, wenn du willst (nach dem Return).
|
|
86
|
+
|
|
87
|
+
2. **Callback-Route** (Query: `code`, `state`):
|
|
88
|
+
- `state` mit gespeichertem State abgleichen (Session/DB/Cookie).
|
|
89
|
+
- **`hub.connection.exchangeAuthorizationCode(clientSecret, { code, id? })`**
|
|
90
|
+
- Liefert u. a. `tokenStore` (inkl. `access_token`, `refresh_token`, `provider_account_id` / Portal-ID aus Metadata) und `raw` (HubSpot-Antwort).
|
|
91
|
+
|
|
92
|
+
3. **Später / bei abgelaufenem Access Token:**
|
|
93
|
+
- **`hub.connection.refreshAccessToken(clientSecret, { refreshToken })`**
|
|
94
|
+
- oder **`hub.connection.getValidAccessToken(clientSecret, { accessToken, expiresAt, refreshToken, skewMs? })`** — refresht bei Bedarf automatisch.
|
|
95
|
+
|
|
96
|
+
4. **Optional:** **`hub.connection.fetchAccessTokenMetadata(accessToken)`** — u. a. `hub_id` (Portal).
|
|
97
|
+
|
|
98
|
+
**Nicht** für den Refresh: `redirectUri` (nur Authorize + Code-Exchange).
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## HubSpot: CRM-API (Datenebene)
|
|
103
|
+
|
|
104
|
+
Alle folgenden Methoden erwarten ein gültiges **`accessToken`** (serverseitig). Rückgaben sind bewusst **`Promise<unknown>`** — Response-Shapes kommen von HubSpot; bei Bedarf in der App casten oder validieren.
|
|
105
|
+
|
|
106
|
+
| Methode | Kurzbeschreibung |
|
|
107
|
+
|---------|------------------|
|
|
108
|
+
| `getContacts({ accessToken, limit?, after? })` | Liste Contacts (Pagination `after`) |
|
|
109
|
+
| `getCompanies({ accessToken, limit?, after? })` | Liste Companies |
|
|
110
|
+
| `createContact({ accessToken, properties })` | Neuer Contact |
|
|
111
|
+
| `updateContact({ accessToken, id, properties })` | Contact PATCH |
|
|
112
|
+
| `createNote({ accessToken, body, associateToObjectType, associateToId })` | Note + Association zu Contact/Company/Deal |
|
|
113
|
+
| `searchRecords({ accessToken, objectType, filterGroups?, properties?, limit?, after? })` | CRM Search API |
|
|
114
|
+
|
|
115
|
+
HubSpot-HTTP-Basis: `https://api.hubapi.com`; Fehler werden als `Error` mit Status-Text geworfen.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## `TokenStore`
|
|
120
|
+
|
|
121
|
+
`TokenStore` (`src/types.ts`) bündelt u. a.:
|
|
122
|
+
|
|
123
|
+
- **`state`** — OAuth CSRF (vor dem Callback).
|
|
124
|
+
- **`id`** — eure interne User-/Tenant-ID (z. B. Supabase), z. B. über `buildAuthorizeUrl({ supabase_id })` oder `exchangeAuthorizationCode` `{ id }`.
|
|
125
|
+
- **`provider_account_id`** — z. B. HubSpot Portal-ID (String).
|
|
126
|
+
- **`access_token` / `refresh_token` / `token_expires_at` / `token_last_refreshed_at`**
|
|
127
|
+
|
|
128
|
+
Persistenz (Datenbank, Session) implementierst **du** in der App, sobald du `tokenStore` aus den Methoden zurückbekommst — **crm-utils** bleibt ohne DB.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Neues CRM ergänzen (Checkliste)
|
|
133
|
+
|
|
134
|
+
1. Ordner `src/crms/<name>/` mit Implementierung.
|
|
135
|
+
2. Klasse erweitert `CRM` (alle abstrakten Methoden implementieren).
|
|
136
|
+
3. Connection-Klasse erweitert `CrmConnection` mit `provider` und OAuth-Logik.
|
|
137
|
+
4. **`getCRM.ts`:** `CRMs` um Namen erweitern, `CRMInitMap` / `CRMInstanceMap` und `switch` in `getCRM` ergänzen.
|
|
138
|
+
5. **`src/index.ts`:** neue Typen/Klassen exportieren.
|
|
139
|
+
6. README / Changelog im Repo pflegen.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Sicherheit — Kurz
|
|
144
|
+
|
|
145
|
+
- **`clientSecret`**, **Refresh/Access Tokens** nur auf dem Server halten.
|
|
146
|
+
- **`redirectUri`** in der OAuth-App registrieren; keine Wildcards nachlässig mischen.
|
|
147
|
+
- **`state`** immer prüfen, bevor `code` getauscht wird.
|
|
148
|
+
- Öffentliche Repos: keine echten Tokens committen.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export default abstract class BaseCrm {
|
|
2
|
+
abstract readonly provider: string;
|
|
3
|
+
abstract getContacts(options: {
|
|
4
|
+
accessToken: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
after?: string;
|
|
7
|
+
}): Promise<unknown>;
|
|
8
|
+
abstract getCompanies(options: {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
limit?: number;
|
|
11
|
+
after?: string;
|
|
12
|
+
}): Promise<unknown>;
|
|
13
|
+
abstract createContact(options: {
|
|
14
|
+
accessToken: string;
|
|
15
|
+
properties: Record<string, string | number | boolean | null>;
|
|
16
|
+
}): Promise<unknown>;
|
|
17
|
+
abstract updateContact(options: {
|
|
18
|
+
accessToken: string;
|
|
19
|
+
id: string;
|
|
20
|
+
properties: Record<string, string | number | boolean | null>;
|
|
21
|
+
}): Promise<unknown>;
|
|
22
|
+
abstract createNote(options: {
|
|
23
|
+
accessToken: string;
|
|
24
|
+
body: string;
|
|
25
|
+
associateToObjectType: string;
|
|
26
|
+
associateToId: string;
|
|
27
|
+
}): Promise<unknown>;
|
|
28
|
+
abstract searchRecords(options: {
|
|
29
|
+
accessToken: string;
|
|
30
|
+
objectType: string;
|
|
31
|
+
filterGroups?: unknown[];
|
|
32
|
+
properties?: string[];
|
|
33
|
+
limit?: number;
|
|
34
|
+
after?: string;
|
|
35
|
+
}): Promise<unknown>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=BaseCrm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseCrm.d.ts","sourceRoot":"","sources":["../src/BaseCrm.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,OAAO;IACjC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAElC,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KACjB,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE;QAC3B,WAAW,EAAE,MAAM,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KACjB,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE;QAC5B,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAA;KAC/D,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE;QAC5B,WAAW,EAAE,MAAM,CAAA;QACnB,EAAE,EAAE,MAAM,CAAA;QACV,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAA;KAC/D,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE;QACzB,WAAW,EAAE,MAAM,CAAA;QACnB,IAAI,EAAE,MAAM,CAAA;QACZ,qBAAqB,EAAE,MAAM,CAAA;QAC7B,aAAa,EAAE,MAAM,CAAA;KACxB,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE;QAC5B,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;QACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;QACrB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KACjB,GAAG,OAAO,CAAC,OAAO,CAAC;CACvB"}
|
package/dist/BaseCrm.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseCrm.js","sourceRoot":"","sources":["../src/BaseCrm.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAgB,OAAO;CAyCpC"}
|
package/dist/CRM.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export default abstract class CRM {
|
|
2
|
+
abstract readonly provider: string;
|
|
3
|
+
abstract getContacts(options: {
|
|
4
|
+
accessToken: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
after?: string;
|
|
7
|
+
}): Promise<unknown>;
|
|
8
|
+
abstract getCompanies(options: {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
limit?: number;
|
|
11
|
+
after?: string;
|
|
12
|
+
}): Promise<unknown>;
|
|
13
|
+
abstract createContact(options: {
|
|
14
|
+
accessToken: string;
|
|
15
|
+
properties: Record<string, string | number | boolean | null>;
|
|
16
|
+
}): Promise<unknown>;
|
|
17
|
+
abstract updateContact(options: {
|
|
18
|
+
accessToken: string;
|
|
19
|
+
id: string;
|
|
20
|
+
properties: Record<string, string | number | boolean | null>;
|
|
21
|
+
}): Promise<unknown>;
|
|
22
|
+
abstract createNote(options: {
|
|
23
|
+
accessToken: string;
|
|
24
|
+
body: string;
|
|
25
|
+
associateToObjectType: string;
|
|
26
|
+
associateToId: string;
|
|
27
|
+
}): Promise<unknown>;
|
|
28
|
+
abstract searchRecords(options: {
|
|
29
|
+
accessToken: string;
|
|
30
|
+
objectType: string;
|
|
31
|
+
filterGroups?: unknown[];
|
|
32
|
+
properties?: string[];
|
|
33
|
+
limit?: number;
|
|
34
|
+
after?: string;
|
|
35
|
+
}): Promise<unknown>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=CRM.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CRM.d.ts","sourceRoot":"","sources":["../src/CRM.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,GAAG;IAChC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAElC,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE;QAC7B,WAAW,EAAE,MAAM,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE;QAC9B,WAAW,EAAE,MAAM,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE;QAC/B,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAA;KAC5D,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE;QAC/B,WAAW,EAAE,MAAM,CAAA;QACnB,EAAE,EAAE,MAAM,CAAA;QACV,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAA;KAC5D,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE;QAC5B,WAAW,EAAE,MAAM,CAAA;QACnB,IAAI,EAAE,MAAM,CAAA;QACZ,qBAAqB,EAAE,MAAM,CAAA;QAC7B,aAAa,EAAE,MAAM,CAAA;KACrB,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE;QAC/B,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;QACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;QACrB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,OAAO,CAAC;CACpB"}
|
package/dist/CRM.js
ADDED
package/dist/CRM.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CRM.js","sourceRoot":"","sources":["../src/CRM.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAgB,GAAG;CAyChC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrmConnection.d.ts","sourceRoot":"","sources":["../src/CrmConnection.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa;IACvC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrmConnection.js","sourceRoot":"","sources":["../src/CrmConnection.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAgB,aAAa;CAE1C"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import CRM from "../../CRM";
|
|
2
|
+
import CrmConnection from "../../CrmConnection";
|
|
3
|
+
import { HubspotInit } from "./types";
|
|
4
|
+
import type { HubspotAccessTokenMetadata, HubspotTokenResponse } from "./types";
|
|
5
|
+
import type { TokenStore } from "../../types";
|
|
6
|
+
export declare class HubspotConnection extends CrmConnection {
|
|
7
|
+
readonly provider: "hubspot";
|
|
8
|
+
private clientId;
|
|
9
|
+
private redirectUri;
|
|
10
|
+
constructor(args: HubspotInit);
|
|
11
|
+
/**
|
|
12
|
+
* OAuth-Start: Authorize-URL + state.
|
|
13
|
+
*
|
|
14
|
+
* frontend && server
|
|
15
|
+
*/
|
|
16
|
+
buildAuthUrl(args: {
|
|
17
|
+
scopes: string[];
|
|
18
|
+
supabase_id?: string;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
authorizeUrl: string;
|
|
21
|
+
tokenStore: TokenStore;
|
|
22
|
+
state: string;
|
|
23
|
+
} | {
|
|
24
|
+
authorizeUrl: string;
|
|
25
|
+
state: string;
|
|
26
|
+
tokenStore?: undefined;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Callback: code → Tokens.
|
|
30
|
+
*
|
|
31
|
+
* server-only
|
|
32
|
+
*/
|
|
33
|
+
codeToTokens(clientSecret: string, args: {
|
|
34
|
+
code: string;
|
|
35
|
+
supabase_id?: string;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
raw: {
|
|
38
|
+
access_token: string;
|
|
39
|
+
refresh_token?: string | undefined;
|
|
40
|
+
expires_in?: number | undefined;
|
|
41
|
+
token_type?: string | undefined;
|
|
42
|
+
};
|
|
43
|
+
tokenStore: TokenStore;
|
|
44
|
+
portalId: number | undefined;
|
|
45
|
+
} | {
|
|
46
|
+
raw: {
|
|
47
|
+
access_token: string;
|
|
48
|
+
refresh_token?: string | undefined;
|
|
49
|
+
expires_in?: number | undefined;
|
|
50
|
+
token_type?: string | undefined;
|
|
51
|
+
};
|
|
52
|
+
portalId: number | undefined;
|
|
53
|
+
tokenStore?: undefined;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Refresh: refresh_token → new access_token.
|
|
57
|
+
*
|
|
58
|
+
* server-only
|
|
59
|
+
*/
|
|
60
|
+
refreshAccessToken(clientSecret: string, args: {
|
|
61
|
+
refreshToken: string;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
raw: HubspotTokenResponse;
|
|
64
|
+
tokenStore: TokenStore;
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* HubSpot: GET /oauth/v1/access-tokens/{token} — u.a. hub_id (Portal).
|
|
68
|
+
*
|
|
69
|
+
* frontend && server
|
|
70
|
+
*/
|
|
71
|
+
fetchAccessTokenMetadata(accessToken: string): Promise<HubspotAccessTokenMetadata>;
|
|
72
|
+
/**
|
|
73
|
+
* Hilfe: gültigen Access Token — entweder aus tokenStore oder nach Refresh.
|
|
74
|
+
*
|
|
75
|
+
* server-only
|
|
76
|
+
*/
|
|
77
|
+
getValidAccessToken(clientSecret: string, args: {
|
|
78
|
+
accessToken?: string | undefined;
|
|
79
|
+
expiresAt?: Date | string | null;
|
|
80
|
+
refreshToken?: string | null;
|
|
81
|
+
skewMs?: number;
|
|
82
|
+
}): Promise<string>;
|
|
83
|
+
}
|
|
84
|
+
export declare class Hubspot extends CRM {
|
|
85
|
+
readonly provider: "hubspot";
|
|
86
|
+
connection: HubspotConnection;
|
|
87
|
+
constructor({ clientId, redirectUri }: HubspotInit);
|
|
88
|
+
/**
|
|
89
|
+
* Holt eine Seite von HubSpot Contacts.
|
|
90
|
+
*
|
|
91
|
+
* - `limit`: wie viele Contacts du pro Request willst (Pagination Page Size)
|
|
92
|
+
* - `after`: Cursor für die nächste Seite (kommt typischerweise aus `paging.next.after`)
|
|
93
|
+
*
|
|
94
|
+
* Typical use: UI-Liste anzeigen oder initial Candidates laden.
|
|
95
|
+
*
|
|
96
|
+
* server-only (weil `accessToken` ein Secret ist)
|
|
97
|
+
*/
|
|
98
|
+
getContacts(options: {
|
|
99
|
+
accessToken: string;
|
|
100
|
+
limit?: number;
|
|
101
|
+
after?: string;
|
|
102
|
+
}): Promise<unknown>;
|
|
103
|
+
/**
|
|
104
|
+
* Holt eine Seite von HubSpot Companies.
|
|
105
|
+
*
|
|
106
|
+
* - `limit`: wie viele Companies pro Request
|
|
107
|
+
* - `after`: Cursor für die nächste Seite
|
|
108
|
+
*
|
|
109
|
+
* server-only (weil `accessToken` ein Secret ist)
|
|
110
|
+
*/
|
|
111
|
+
getCompanies(options: {
|
|
112
|
+
accessToken: string;
|
|
113
|
+
limit?: number;
|
|
114
|
+
after?: string;
|
|
115
|
+
}): Promise<unknown>;
|
|
116
|
+
/**
|
|
117
|
+
* Erstellt einen neuen Contact.
|
|
118
|
+
*
|
|
119
|
+
* `properties` sind HubSpot-Property-Namen → Values. Beispiel: `{ email: \"a@b.com\", firstname: \"Max\" }`.
|
|
120
|
+
*
|
|
121
|
+
* server-only (weil `accessToken` ein Secret ist)
|
|
122
|
+
*/
|
|
123
|
+
createContact(options: {
|
|
124
|
+
accessToken: string;
|
|
125
|
+
properties: Record<string, string | number | boolean | null>;
|
|
126
|
+
}): Promise<unknown>;
|
|
127
|
+
/**
|
|
128
|
+
* Updated einen bestehenden Contact (PATCH).
|
|
129
|
+
*
|
|
130
|
+
* - `id`: HubSpot Contact ID
|
|
131
|
+
* - `properties`: Partial Update (nur die Felder, die du ändern willst)
|
|
132
|
+
*
|
|
133
|
+
* Typical use: nach AI-Screening `status`, `ai_score`, `ai_summary` etc. zurückschreiben.
|
|
134
|
+
*
|
|
135
|
+
* server-only (weil `accessToken` ein Secret ist)
|
|
136
|
+
*/
|
|
137
|
+
updateContact(options: {
|
|
138
|
+
accessToken: string;
|
|
139
|
+
id: string;
|
|
140
|
+
properties: Record<string, string | number | boolean | null>;
|
|
141
|
+
}): Promise<unknown>;
|
|
142
|
+
/**
|
|
143
|
+
* Erstellt eine Note (Timeline/History Eintrag) und hängt sie an ein Objekt (Contact/Company/Deal).
|
|
144
|
+
*
|
|
145
|
+
* Notes sind super, um Ergebnisse „auditierbar“ abzulegen (was hat die AI gemacht / was kam beim Call raus),
|
|
146
|
+
* ohne dass du zig neue Custom Properties brauchst.
|
|
147
|
+
*
|
|
148
|
+
* - `body`: Text/HTML Inhalt der Note (HubSpot Property: `hs_note_body`)
|
|
149
|
+
* - `associateToObjectType`: z.B. `contact`, `company`, `deal`
|
|
150
|
+
* - `associateToId`: ID des Ziel-Objekts in HubSpot
|
|
151
|
+
*
|
|
152
|
+
* server-only (weil `accessToken` ein Secret ist)
|
|
153
|
+
*/
|
|
154
|
+
createNote(options: {
|
|
155
|
+
accessToken: string;
|
|
156
|
+
body: string;
|
|
157
|
+
associateToObjectType: string;
|
|
158
|
+
associateToId: string;
|
|
159
|
+
}): Promise<unknown>;
|
|
160
|
+
/**
|
|
161
|
+
* Generische Suche über HubSpot-Objekte (contacts/companies/deals/custom objects).
|
|
162
|
+
*
|
|
163
|
+
* Im Gegensatz zu `getContacts()` (nur Listen) kannst du hier **Filter** angeben.
|
|
164
|
+
*
|
|
165
|
+
* - `objectType`: z.B. `contacts`, `companies`, `deals`
|
|
166
|
+
* - `filterGroups`: HubSpot Search-Filter (Raw-Shape; du gibst das HubSpot-Format direkt rein)
|
|
167
|
+
* - `properties`: welche Properties du zurückhaben willst
|
|
168
|
+
* - `limit`/`after`: Pagination
|
|
169
|
+
*
|
|
170
|
+
* Typical use: „gib mir alle Kandidaten mit status = X“ ohne alles zu laden.
|
|
171
|
+
*
|
|
172
|
+
* server-only (weil `accessToken` ein Secret ist)
|
|
173
|
+
*/
|
|
174
|
+
searchRecords(options: {
|
|
175
|
+
accessToken: string;
|
|
176
|
+
objectType: string;
|
|
177
|
+
filterGroups?: unknown[];
|
|
178
|
+
properties?: string[];
|
|
179
|
+
limit?: number;
|
|
180
|
+
after?: string;
|
|
181
|
+
}): Promise<unknown>;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=hubspot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hubspot.d.ts","sourceRoot":"","sources":["../../../src/crms/hubspot/hubspot.ts"],"names":[],"mappings":"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"}
|