@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.
Files changed (42) hide show
  1. package/README.md +151 -0
  2. package/dist/BaseCrm.d.ts +37 -0
  3. package/dist/BaseCrm.d.ts.map +1 -0
  4. package/dist/BaseCrm.js +3 -0
  5. package/dist/BaseCrm.js.map +1 -0
  6. package/dist/CRM.d.ts +37 -0
  7. package/dist/CRM.d.ts.map +1 -0
  8. package/dist/CRM.js +3 -0
  9. package/dist/CRM.js.map +1 -0
  10. package/dist/CrmConnection.d.ts +4 -0
  11. package/dist/CrmConnection.d.ts.map +1 -0
  12. package/dist/CrmConnection.js +3 -0
  13. package/dist/CrmConnection.js.map +1 -0
  14. package/dist/crms/hubspot/hubspot.d.ts +183 -0
  15. package/dist/crms/hubspot/hubspot.d.ts.map +1 -0
  16. package/dist/crms/hubspot/hubspot.js +349 -0
  17. package/dist/crms/hubspot/hubspot.js.map +1 -0
  18. package/dist/crms/hubspot/types.d.ts +52 -0
  19. package/dist/crms/hubspot/types.d.ts.map +1 -0
  20. package/dist/crms/hubspot/types.js +18 -0
  21. package/dist/crms/hubspot/types.js.map +1 -0
  22. package/dist/crms/hubspot.d.ts +108 -0
  23. package/dist/crms/hubspot.d.ts.map +1 -0
  24. package/dist/crms/hubspot.js +254 -0
  25. package/dist/crms/hubspot.js.map +1 -0
  26. package/dist/getCRM.d.ts +15 -0
  27. package/dist/getCRM.d.ts.map +1 -0
  28. package/dist/getCRM.js +13 -0
  29. package/dist/getCRM.js.map +1 -0
  30. package/dist/index.d.ts +8 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +7 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/oauth-helpers.d.ts +5 -0
  35. package/dist/oauth-helpers.d.ts.map +1 -0
  36. package/dist/oauth-helpers.js +21 -0
  37. package/dist/oauth-helpers.js.map +1 -0
  38. package/dist/types.d.ts +24 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +2 -0
  41. package/dist/types.js.map +1 -0
  42. 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"}
@@ -0,0 +1,3 @@
1
+ export default class BaseCrm {
2
+ }
3
+ //# sourceMappingURL=BaseCrm.js.map
@@ -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
@@ -0,0 +1,3 @@
1
+ export default class CRM {
2
+ }
3
+ //# sourceMappingURL=CRM.js.map
@@ -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,4 @@
1
+ export default abstract class CrmConnection {
2
+ abstract readonly provider: string;
3
+ }
4
+ //# sourceMappingURL=CrmConnection.d.ts.map
@@ -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,3 @@
1
+ export default class CrmConnection {
2
+ }
3
+ //# sourceMappingURL=CrmConnection.js.map
@@ -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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"}