@xapp/stentor-service-hubspot 1.78.5 → 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.
@@ -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;
@@ -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.hubspotClient = new api_client_1.Client({ accessToken: process.env.HUBSPOT_TOKEN });
23
- this.props = Object.assign({}, props);
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 lead = {
55
- properties: {
56
- firstname: externalLead.fields.find((x) => x.name == "FIRST_NAME").value,
57
- lastname: externalLead.fields.find((x) => x.name == "LAST_NAME").value,
58
- email: externalLead.fields.find((x) => x.name == "EMAIL").value,
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":"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"}
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.78.5",
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",
@@ -20,9 +20,9 @@
20
20
  "@xapp/config": "0.3.0",
21
21
  "chai": "4.5.0",
22
22
  "mocha": "11.7.5",
23
- "stentor-logger": "1.72.1",
24
- "stentor-models": "1.72.0",
25
- "stentor-service-fetch": "1.72.0",
23
+ "stentor-logger": "1.72.3",
24
+ "stentor-models": "1.72.3",
25
+ "stentor-service-fetch": "1.72.3",
26
26
  "ts-node": "10.9.2",
27
27
  "typescript": "5.9.3"
28
28
  },
@@ -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": "c4febaf8f8b758d43a902134038cc6a4fe8f76bd"
42
+ "gitHead": "34ce220a44ff054cc3818f1900e703c97eb2a579"
43
43
  }