@xapp/stentor-service-hubspot 1.80.3 → 1.81.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/lib/HubspotService.d.ts +53 -0
- package/lib/HubspotService.js +64 -23
- package/lib/HubspotService.js.map +1 -1
- package/package.json +2 -2
package/lib/HubspotService.d.ts
CHANGED
|
@@ -4,6 +4,12 @@ import { BaseService, CrmResponse, CrmService, CrmServiceAvailability, CrmServic
|
|
|
4
4
|
import { Client } from "@hubspot/api-client";
|
|
5
5
|
export interface HubspotServiceProps extends BaseService {
|
|
6
6
|
appId: string;
|
|
7
|
+
/**
|
|
8
|
+
* Hubspot private app access token. If omitted, falls back to
|
|
9
|
+
* `process.env.HUBSPOT_TOKEN`. The stateless `buildHubspotContactRequest`
|
|
10
|
+
* helper requires this to be set explicitly.
|
|
11
|
+
*/
|
|
12
|
+
accessToken?: string;
|
|
7
13
|
}
|
|
8
14
|
export interface HubspotExternalLeadExtras {
|
|
9
15
|
/**
|
|
@@ -57,6 +63,41 @@ export interface HubspotResponse {
|
|
|
57
63
|
*/
|
|
58
64
|
Reason?: string;
|
|
59
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* The contact body Hubspot accepts both via the official SDK
|
|
68
|
+
* (`hubspotClient.crm.contacts.basicApi.create`) and at the REST endpoint
|
|
69
|
+
* (`POST /crm/v3/objects/contacts`). The shape is identical.
|
|
70
|
+
*/
|
|
71
|
+
export interface HubspotContactPayload {
|
|
72
|
+
properties: {
|
|
73
|
+
firstname?: string;
|
|
74
|
+
lastname?: string;
|
|
75
|
+
email?: string;
|
|
76
|
+
phone?: string;
|
|
77
|
+
message?: string;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Describes the HTTP request that should be POSTed to Hubspot's contact
|
|
82
|
+
* REST endpoint. Stateless callers (e.g. stentor-api's chain runner) execute
|
|
83
|
+
* the request themselves so they can capture it for audit logging.
|
|
84
|
+
*
|
|
85
|
+
* Note: `HubspotService.send()` itself does NOT use this descriptor's
|
|
86
|
+
* `url` or `headers` — the class routes through `@hubspot/api-client`,
|
|
87
|
+
* which manages its own auth headers and endpoint. `url` and `headers`
|
|
88
|
+
* are populated for REST callers (chain runners) that bypass the SDK.
|
|
89
|
+
* `body` is shared between both transports.
|
|
90
|
+
*
|
|
91
|
+
* SECURITY: `headers.Authorization` carries the Bearer access token.
|
|
92
|
+
* Callers that audit-log this descriptor must redact the `Authorization`
|
|
93
|
+
* header before persisting.
|
|
94
|
+
*/
|
|
95
|
+
export interface HubspotRequestDescriptor {
|
|
96
|
+
url: string;
|
|
97
|
+
method: "POST";
|
|
98
|
+
headers: Record<string, string>;
|
|
99
|
+
body: HubspotContactPayload;
|
|
100
|
+
}
|
|
60
101
|
export declare class HubspotService extends FetchService implements CrmService {
|
|
61
102
|
hubspotClient: Client;
|
|
62
103
|
private props;
|
|
@@ -65,3 +106,15 @@ export declare class HubspotService extends FetchService implements CrmService {
|
|
|
65
106
|
getJobType(message: string, externalLead?: ExternalLead): Promise<CrmServiceJobType>;
|
|
66
107
|
send(externalLead: ExternalLead, extras?: HubspotExternalLeadExtras): Promise<CrmResponse>;
|
|
67
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Builds the Hubspot contact request descriptor without performing any I/O.
|
|
111
|
+
*
|
|
112
|
+
* The body matches both the SDK input (`hubspotClient.crm.contacts.basicApi.create`)
|
|
113
|
+
* and the REST endpoint payload, so callers can execute via either transport.
|
|
114
|
+
*/
|
|
115
|
+
export declare function buildHubspotContactRequest(props: HubspotServiceProps, externalLead: ExternalLead, extras?: HubspotExternalLeadExtras): HubspotRequestDescriptor;
|
|
116
|
+
/**
|
|
117
|
+
* Parses a Hubspot contact response (from SDK or REST) into a `CrmResponse`.
|
|
118
|
+
* Both transports return the same shape with an `id` field on success.
|
|
119
|
+
*/
|
|
120
|
+
export declare function parseHubspotContactResponse(body: unknown): CrmResponse;
|
package/lib/HubspotService.js
CHANGED
|
@@ -10,17 +10,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.HubspotService = void 0;
|
|
13
|
+
exports.buildHubspotContactRequest = buildHubspotContactRequest;
|
|
14
|
+
exports.parseHubspotContactResponse = parseHubspotContactResponse;
|
|
13
15
|
/*! Copyright (c) 2022, XAPPmedia */
|
|
14
16
|
const stentor_service_fetch_1 = require("stentor-service-fetch");
|
|
15
17
|
const stentor_logger_1 = require("stentor-logger");
|
|
16
18
|
const util_1 = require("./util");
|
|
17
19
|
// Hubspot API Client
|
|
18
20
|
const api_client_1 = require("@hubspot/api-client");
|
|
21
|
+
const HUBSPOT_CONTACTS_ENDPOINT = "https://api.hubapi.com/crm/v3/objects/contacts";
|
|
19
22
|
class HubspotService extends stentor_service_fetch_1.FetchService {
|
|
20
23
|
constructor(props) {
|
|
21
24
|
super(props);
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
25
|
+
this.props = Object.assign(Object.assign({}, props), { accessToken: props.accessToken || process.env.HUBSPOT_TOKEN });
|
|
26
|
+
this.hubspotClient = new api_client_1.Client({ accessToken: this.props.accessToken });
|
|
24
27
|
(0, stentor_logger_1.log)().info(`app id: ${this.props.appId}`);
|
|
25
28
|
}
|
|
26
29
|
getAvailability(range, options) {
|
|
@@ -41,39 +44,77 @@ class HubspotService extends stentor_service_fetch_1.FetchService {
|
|
|
41
44
|
}
|
|
42
45
|
send(externalLead, extras) {
|
|
43
46
|
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
-
const transcript = (0, util_1.transformTranscript)(externalLead.transcript, extras === null || extras === void 0 ? void 0 : extras.botId);
|
|
45
|
-
let messages = "";
|
|
46
|
-
transcript.forEach((message) => {
|
|
47
|
-
messages += "input: " + message["question"] + "\n" + "response: " + message["answer"] + "\n";
|
|
48
|
-
});
|
|
49
47
|
const crmResponse = {
|
|
50
48
|
status: "Failure",
|
|
51
|
-
message: ""
|
|
49
|
+
message: ""
|
|
52
50
|
};
|
|
53
51
|
try {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
phone: externalLead.fields.find((x) => x.name == "PHONE").value,
|
|
60
|
-
message: messages,
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
const createContactResponse = yield this.hubspotClient.crm.contacts.basicApi.create(lead);
|
|
64
|
-
if (createContactResponse.id) {
|
|
65
|
-
crmResponse.status = "Success";
|
|
66
|
-
crmResponse.message = `contact id: ${createContactResponse.id}`;
|
|
67
|
-
(0, stentor_logger_1.log)().info(`Contact sent to Hubspot: ${createContactResponse.id}`);
|
|
68
|
-
return crmResponse;
|
|
52
|
+
const descriptor = buildHubspotContactRequest(this.props, externalLead, extras);
|
|
53
|
+
const sdkResponse = yield this.hubspotClient.crm.contacts.basicApi.create(descriptor.body);
|
|
54
|
+
const parsed = parseHubspotContactResponse(sdkResponse);
|
|
55
|
+
if (parsed.status === "Success") {
|
|
56
|
+
(0, stentor_logger_1.log)().info(`Contact sent to Hubspot: ${parsed.refId}`);
|
|
69
57
|
}
|
|
58
|
+
return parsed;
|
|
70
59
|
}
|
|
71
60
|
catch (e) {
|
|
72
61
|
(0, stentor_logger_1.log)().error(`Error sending lead to Hubspot ${e}`);
|
|
62
|
+
crmResponse.message = e instanceof Error ? e.message : String(e);
|
|
73
63
|
}
|
|
74
64
|
return crmResponse;
|
|
75
65
|
});
|
|
76
66
|
}
|
|
77
67
|
}
|
|
78
68
|
exports.HubspotService = HubspotService;
|
|
69
|
+
/**
|
|
70
|
+
* Builds the Hubspot contact request descriptor without performing any I/O.
|
|
71
|
+
*
|
|
72
|
+
* The body matches both the SDK input (`hubspotClient.crm.contacts.basicApi.create`)
|
|
73
|
+
* and the REST endpoint payload, so callers can execute via either transport.
|
|
74
|
+
*/
|
|
75
|
+
function buildHubspotContactRequest(props, externalLead, extras) {
|
|
76
|
+
var _a, _b, _c, _d;
|
|
77
|
+
if (!props.accessToken) {
|
|
78
|
+
throw new Error("Hubspot: access token is not set");
|
|
79
|
+
}
|
|
80
|
+
const transcript = (0, util_1.transformTranscript)(externalLead.transcript, extras === null || extras === void 0 ? void 0 : extras.botId);
|
|
81
|
+
let messages = "";
|
|
82
|
+
transcript.forEach((message) => {
|
|
83
|
+
messages += "input: " + message.question + "\n" + "response: " + message.answer + "\n";
|
|
84
|
+
});
|
|
85
|
+
const properties = {
|
|
86
|
+
firstname: (_a = externalLead.fields.find((x) => x.name === "FIRST_NAME")) === null || _a === void 0 ? void 0 : _a.value,
|
|
87
|
+
lastname: (_b = externalLead.fields.find((x) => x.name === "LAST_NAME")) === null || _b === void 0 ? void 0 : _b.value,
|
|
88
|
+
email: (_c = externalLead.fields.find((x) => x.name === "EMAIL")) === null || _c === void 0 ? void 0 : _c.value,
|
|
89
|
+
phone: (_d = externalLead.fields.find((x) => x.name === "PHONE")) === null || _d === void 0 ? void 0 : _d.value,
|
|
90
|
+
message: messages
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
url: HUBSPOT_CONTACTS_ENDPOINT,
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
"Authorization": `Bearer ${props.accessToken}`,
|
|
97
|
+
"Content-Type": "application/json"
|
|
98
|
+
},
|
|
99
|
+
body: { properties }
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parses a Hubspot contact response (from SDK or REST) into a `CrmResponse`.
|
|
104
|
+
* Both transports return the same shape with an `id` field on success.
|
|
105
|
+
*/
|
|
106
|
+
function parseHubspotContactResponse(body) {
|
|
107
|
+
const response = body;
|
|
108
|
+
if (response === null || response === void 0 ? void 0 : response.id) {
|
|
109
|
+
return {
|
|
110
|
+
status: "Success",
|
|
111
|
+
message: `contact id: ${response.id}`,
|
|
112
|
+
refId: response.id
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
status: "Failure",
|
|
117
|
+
message: "Hubspot did not return a contact id"
|
|
118
|
+
};
|
|
119
|
+
}
|
|
79
120
|
//# sourceMappingURL=HubspotService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HubspotService.js","sourceRoot":"","sources":["../src/HubspotService.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"HubspotService.js","sourceRoot":"","sources":["../src/HubspotService.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.81.0",
|
|
8
8
|
"description": "Service to interface the Hubspot CRM service",
|
|
9
9
|
"types": "lib/index",
|
|
10
10
|
"main": "lib/index",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"clean": "rm -rf ./lib/*",
|
|
40
40
|
"test": "mocha --recursive -r ts-node/register \"./src/**/*.test.ts\""
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "34ce220a44ff054cc3818f1900e703c97eb2a579"
|
|
43
43
|
}
|