@rawdash/connector-hubspot 0.15.0 → 0.17.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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseConnector, ConnectorContext, SyncOptions, StorageHandle, SyncResult, AggregateRequest, AggregateValue, FilterClause } from '@rawdash/core';
1
+ import { BaseConnector, ConnectorContext, SyncOptions, StorageHandle, SyncResult, ConnectorDoc } from '@rawdash/core';
2
2
  import { z } from 'zod';
3
3
 
4
4
  declare const configFields: z.ZodObject<{
@@ -14,6 +14,7 @@ declare const configFields: z.ZodObject<{
14
14
  email_stats: "email_stats";
15
15
  }>>>;
16
16
  }, z.core.$strip>;
17
+ declare const doc: ConnectorDoc;
17
18
  interface HubSpotSettings {
18
19
  resources?: readonly HubSpotResource[];
19
20
  }
@@ -27,12 +28,246 @@ type HubSpotCredentials = typeof hubspotCredentials;
27
28
  declare const PHASE_ORDER: readonly ["contacts", "companies", "deals", "deal_events", "email_campaigns", "email_stats"];
28
29
  type HubSpotPhase = (typeof PHASE_ORDER)[number];
29
30
  type HubSpotResource = HubSpotPhase;
31
+ declare const hubspotResources: {
32
+ readonly hubspot_contact: {
33
+ readonly shape: "entity";
34
+ readonly description: "CRM contacts with email, lifecycle stage, lead status, owner, and creation time.";
35
+ readonly endpoint: "POST /crm/v3/objects/contacts/search";
36
+ readonly responses: {
37
+ readonly contacts: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
38
+ };
39
+ };
40
+ readonly hubspot_company: {
41
+ readonly shape: "entity";
42
+ readonly description: "CRM companies with name, domain, industry, lifecycle stage, and creation time.";
43
+ readonly endpoint: "POST /crm/v3/objects/companies/search";
44
+ readonly responses: {
45
+ readonly companies: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
46
+ };
47
+ };
48
+ readonly hubspot_deal: {
49
+ readonly shape: "entity";
50
+ readonly description: "CRM deals with name, stage, pipeline, amount, close date, owner, and creation time.";
51
+ readonly endpoint: "POST /crm/v3/objects/deals/search";
52
+ readonly responses: {
53
+ readonly deals: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
54
+ };
55
+ };
56
+ readonly hubspot_deal_stage_change: {
57
+ readonly shape: "event";
58
+ readonly description: "Deal stage-change events derived from deal property history, one event per stage transition.";
59
+ readonly endpoint: "GET /crm/v3/objects/deals?propertiesWithHistory=dealstage";
60
+ readonly responses: {
61
+ readonly deal_events: z.ZodArray<z.ZodObject<{
62
+ id: z.ZodString;
63
+ propertiesWithHistory: z.ZodOptional<z.ZodObject<{
64
+ dealstage: z.ZodOptional<z.ZodArray<z.ZodObject<{
65
+ value: z.ZodOptional<z.ZodNullable<z.ZodString>>;
66
+ timestamp: z.ZodOptional<z.ZodNullable<z.ZodString>>;
67
+ sourceType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
68
+ }, z.core.$strip>>>;
69
+ }, z.core.$strip>>;
70
+ }, z.core.$strip>>;
71
+ };
72
+ };
73
+ readonly hubspot_email_campaign: {
74
+ readonly shape: "entity";
75
+ readonly description: "Marketing email campaigns with name, subject, sender, type, send date, and recipient count.";
76
+ readonly endpoint: "GET /email/public/v1/campaigns";
77
+ readonly responses: {
78
+ readonly email_campaigns: z.ZodArray<z.ZodObject<{
79
+ id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
80
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
81
+ subject: z.ZodOptional<z.ZodNullable<z.ZodString>>;
82
+ fromName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
83
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
84
+ lastProcessingFinishedAt: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
85
+ numIncluded: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
86
+ counters: z.ZodOptional<z.ZodObject<{
87
+ sent: z.ZodOptional<z.ZodNumber>;
88
+ delivered: z.ZodOptional<z.ZodNumber>;
89
+ open: z.ZodOptional<z.ZodNumber>;
90
+ click: z.ZodOptional<z.ZodNumber>;
91
+ bounce: z.ZodOptional<z.ZodNumber>;
92
+ unsubscribed: z.ZodOptional<z.ZodNumber>;
93
+ }, z.core.$strip>>;
94
+ }, z.core.$strip>>;
95
+ };
96
+ };
97
+ readonly hubspot_email_stats: {
98
+ readonly shape: "metric";
99
+ readonly description: "Per-campaign marketing email engagement stats (sent, delivered, opened, clicked, bounced, unsubscribed) timestamped at the campaign send time.";
100
+ readonly endpoint: "GET /email/public/v1/campaigns/{id}";
101
+ readonly unit: "emails";
102
+ readonly notes: "One sample per campaign; value is the sent count, and every counter (delivered, opened, clicked, bounced, unsubscribed) is also exposed in attributes.";
103
+ readonly dimensions: [{
104
+ readonly name: "campaignId";
105
+ readonly description: "HubSpot campaign id.";
106
+ }, {
107
+ readonly name: "campaignName";
108
+ readonly description: "Campaign name.";
109
+ }, {
110
+ readonly name: "delivered";
111
+ readonly description: "Number of emails delivered.";
112
+ }, {
113
+ readonly name: "opened";
114
+ readonly description: "Number of emails opened.";
115
+ }, {
116
+ readonly name: "clicked";
117
+ readonly description: "Number of emails clicked.";
118
+ }, {
119
+ readonly name: "bounced";
120
+ readonly description: "Number of emails bounced.";
121
+ }, {
122
+ readonly name: "unsubscribed";
123
+ readonly description: "Number of recipients who unsubscribed.";
124
+ }];
125
+ readonly responses: {
126
+ readonly email_stats: z.ZodArray<z.ZodObject<{
127
+ id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
128
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
129
+ subject: z.ZodOptional<z.ZodNullable<z.ZodString>>;
130
+ fromName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
131
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
132
+ lastProcessingFinishedAt: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
133
+ numIncluded: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
134
+ counters: z.ZodOptional<z.ZodObject<{
135
+ sent: z.ZodOptional<z.ZodNumber>;
136
+ delivered: z.ZodOptional<z.ZodNumber>;
137
+ open: z.ZodOptional<z.ZodNumber>;
138
+ click: z.ZodOptional<z.ZodNumber>;
139
+ bounce: z.ZodOptional<z.ZodNumber>;
140
+ unsubscribed: z.ZodOptional<z.ZodNumber>;
141
+ }, z.core.$strip>>;
142
+ }, z.core.$strip>>;
143
+ };
144
+ };
145
+ };
146
+ declare const id = "hubspot";
30
147
  declare class HubSpotConnector extends BaseConnector<HubSpotSettings, HubSpotCredentials> {
31
148
  static readonly id = "hubspot";
149
+ static readonly resources: {
150
+ readonly hubspot_contact: {
151
+ readonly shape: "entity";
152
+ readonly description: "CRM contacts with email, lifecycle stage, lead status, owner, and creation time.";
153
+ readonly endpoint: "POST /crm/v3/objects/contacts/search";
154
+ readonly responses: {
155
+ readonly contacts: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
156
+ };
157
+ };
158
+ readonly hubspot_company: {
159
+ readonly shape: "entity";
160
+ readonly description: "CRM companies with name, domain, industry, lifecycle stage, and creation time.";
161
+ readonly endpoint: "POST /crm/v3/objects/companies/search";
162
+ readonly responses: {
163
+ readonly companies: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
164
+ };
165
+ };
166
+ readonly hubspot_deal: {
167
+ readonly shape: "entity";
168
+ readonly description: "CRM deals with name, stage, pipeline, amount, close date, owner, and creation time.";
169
+ readonly endpoint: "POST /crm/v3/objects/deals/search";
170
+ readonly responses: {
171
+ readonly deals: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
172
+ };
173
+ };
174
+ readonly hubspot_deal_stage_change: {
175
+ readonly shape: "event";
176
+ readonly description: "Deal stage-change events derived from deal property history, one event per stage transition.";
177
+ readonly endpoint: "GET /crm/v3/objects/deals?propertiesWithHistory=dealstage";
178
+ readonly responses: {
179
+ readonly deal_events: z.ZodArray<z.ZodObject<{
180
+ id: z.ZodString;
181
+ propertiesWithHistory: z.ZodOptional<z.ZodObject<{
182
+ dealstage: z.ZodOptional<z.ZodArray<z.ZodObject<{
183
+ value: z.ZodOptional<z.ZodNullable<z.ZodString>>;
184
+ timestamp: z.ZodOptional<z.ZodNullable<z.ZodString>>;
185
+ sourceType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
186
+ }, z.core.$strip>>>;
187
+ }, z.core.$strip>>;
188
+ }, z.core.$strip>>;
189
+ };
190
+ };
191
+ readonly hubspot_email_campaign: {
192
+ readonly shape: "entity";
193
+ readonly description: "Marketing email campaigns with name, subject, sender, type, send date, and recipient count.";
194
+ readonly endpoint: "GET /email/public/v1/campaigns";
195
+ readonly responses: {
196
+ readonly email_campaigns: z.ZodArray<z.ZodObject<{
197
+ id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
198
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
199
+ subject: z.ZodOptional<z.ZodNullable<z.ZodString>>;
200
+ fromName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
201
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
202
+ lastProcessingFinishedAt: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
203
+ numIncluded: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
204
+ counters: z.ZodOptional<z.ZodObject<{
205
+ sent: z.ZodOptional<z.ZodNumber>;
206
+ delivered: z.ZodOptional<z.ZodNumber>;
207
+ open: z.ZodOptional<z.ZodNumber>;
208
+ click: z.ZodOptional<z.ZodNumber>;
209
+ bounce: z.ZodOptional<z.ZodNumber>;
210
+ unsubscribed: z.ZodOptional<z.ZodNumber>;
211
+ }, z.core.$strip>>;
212
+ }, z.core.$strip>>;
213
+ };
214
+ };
215
+ readonly hubspot_email_stats: {
216
+ readonly shape: "metric";
217
+ readonly description: "Per-campaign marketing email engagement stats (sent, delivered, opened, clicked, bounced, unsubscribed) timestamped at the campaign send time.";
218
+ readonly endpoint: "GET /email/public/v1/campaigns/{id}";
219
+ readonly unit: "emails";
220
+ readonly notes: "One sample per campaign; value is the sent count, and every counter (delivered, opened, clicked, bounced, unsubscribed) is also exposed in attributes.";
221
+ readonly dimensions: [{
222
+ readonly name: "campaignId";
223
+ readonly description: "HubSpot campaign id.";
224
+ }, {
225
+ readonly name: "campaignName";
226
+ readonly description: "Campaign name.";
227
+ }, {
228
+ readonly name: "delivered";
229
+ readonly description: "Number of emails delivered.";
230
+ }, {
231
+ readonly name: "opened";
232
+ readonly description: "Number of emails opened.";
233
+ }, {
234
+ readonly name: "clicked";
235
+ readonly description: "Number of emails clicked.";
236
+ }, {
237
+ readonly name: "bounced";
238
+ readonly description: "Number of emails bounced.";
239
+ }, {
240
+ readonly name: "unsubscribed";
241
+ readonly description: "Number of recipients who unsubscribed.";
242
+ }];
243
+ readonly responses: {
244
+ readonly email_stats: z.ZodArray<z.ZodObject<{
245
+ id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
246
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
247
+ subject: z.ZodOptional<z.ZodNullable<z.ZodString>>;
248
+ fromName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
249
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
250
+ lastProcessingFinishedAt: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
251
+ numIncluded: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
252
+ counters: z.ZodOptional<z.ZodObject<{
253
+ sent: z.ZodOptional<z.ZodNumber>;
254
+ delivered: z.ZodOptional<z.ZodNumber>;
255
+ open: z.ZodOptional<z.ZodNumber>;
256
+ click: z.ZodOptional<z.ZodNumber>;
257
+ bounce: z.ZodOptional<z.ZodNumber>;
258
+ unsubscribed: z.ZodOptional<z.ZodNumber>;
259
+ }, z.core.$strip>>;
260
+ }, z.core.$strip>>;
261
+ };
262
+ };
263
+ };
32
264
  static readonly schemas: {
33
265
  readonly contacts: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
266
+ } & {
34
267
  readonly companies: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
268
+ } & {
35
269
  readonly deals: z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
270
+ } & {
36
271
  readonly deal_events: z.ZodArray<z.ZodObject<{
37
272
  id: z.ZodString;
38
273
  propertiesWithHistory: z.ZodOptional<z.ZodObject<{
@@ -43,6 +278,7 @@ declare class HubSpotConnector extends BaseConnector<HubSpotSettings, HubSpotCre
43
278
  }, z.core.$strip>>>;
44
279
  }, z.core.$strip>>;
45
280
  }, z.core.$strip>>;
281
+ } & {
46
282
  readonly email_campaigns: z.ZodArray<z.ZodObject<{
47
283
  id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
48
284
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -60,6 +296,7 @@ declare class HubSpotConnector extends BaseConnector<HubSpotSettings, HubSpotCre
60
296
  unsubscribed: z.ZodOptional<z.ZodNumber>;
61
297
  }, z.core.$strip>>;
62
298
  }, z.core.$strip>>;
299
+ } & {
63
300
  readonly email_stats: z.ZodArray<z.ZodObject<{
64
301
  id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
65
302
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -77,7 +314,7 @@ declare class HubSpotConnector extends BaseConnector<HubSpotSettings, HubSpotCre
77
314
  unsubscribed: z.ZodOptional<z.ZodNumber>;
78
315
  }, z.core.$strip>>;
79
316
  }, z.core.$strip>>;
80
- };
317
+ } & Readonly<Record<string, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
81
318
  static create(input: unknown, ctx?: ConnectorContext): HubSpotConnector;
82
319
  readonly id = "hubspot";
83
320
  readonly credentials: {
@@ -101,9 +338,6 @@ declare class HubSpotConnector extends BaseConnector<HubSpotSettings, HubSpotCre
101
338
  private clearScopeOnFirstPage;
102
339
  private writePhase;
103
340
  sync(options: SyncOptions, storage: StorageHandle, signal?: AbortSignal): Promise<SyncResult>;
104
- aggregate(req: AggregateRequest, signal?: AbortSignal): Promise<AggregateValue>;
105
- validateCountFilter(resource: string, filter: FilterClause[]): void;
106
- private translateCountFilter;
107
341
  }
108
342
 
109
- export { HubSpotConnector, type HubSpotResource, type HubSpotSettings, configFields, HubSpotConnector as default };
343
+ export { HubSpotConnector, type HubSpotResource, type HubSpotSettings, configFields, HubSpotConnector as default, doc, id, hubspotResources as resources };
package/dist/index.js CHANGED
@@ -30,8 +30,11 @@ function parseEpoch(value, unit) {
30
30
  import {
31
31
  BaseConnector,
32
32
  defineConfigFields,
33
+ defineConnectorDoc,
34
+ defineResources,
33
35
  makeChunkedCursorGuard,
34
36
  paginateChunked,
37
+ schemasFromResources,
35
38
  selectActivePhases
36
39
  } from "@rawdash/core";
37
40
  import { z } from "zod";
@@ -58,6 +61,32 @@ var configFields = defineConfigFields(
58
61
  })
59
62
  })
60
63
  );
64
+ var doc = defineConnectorDoc({
65
+ displayName: "HubSpot",
66
+ category: "sales",
67
+ brandColor: "#FF7A59",
68
+ tagline: "Sync CRM contacts, companies, and deals plus deal stage-change events and marketing email campaign stats from HubSpot.",
69
+ vendor: {
70
+ name: "HubSpot",
71
+ apiDocs: "https://developers.hubspot.com/docs/api/overview",
72
+ website: "https://www.hubspot.com"
73
+ },
74
+ auth: {
75
+ summary: "A HubSpot private app access token with read scopes for the resources you sync (contacts, companies, deals, and marketing email).",
76
+ setup: [
77
+ "In HubSpot, go to Settings \u2192 Integrations \u2192 Private Apps and create a private app.",
78
+ "Grant read scopes for the resources you intend to sync (CRM contacts, companies, deals, and marketing email).",
79
+ "Copy the generated access token (starts with `pat-`).",
80
+ 'Store it as a secret and reference it from the connector config as `accessToken: secret("HUBSPOT_ACCESS_TOKEN")`.'
81
+ ]
82
+ },
83
+ rateLimit: "HubSpot allows 100 requests / 10s; the Search API caps results at 10,000 per query.",
84
+ limitations: [
85
+ "Deal stage-change events are rewritten on every sync because the deal list endpoint has no incremental `since` filter.",
86
+ "Marketing email campaign data comes from the legacy email campaigns API and is only available for marketing emails.",
87
+ "Very large CRM portfolios may not backfill in full because the Search API caps at 10,000 results per query."
88
+ ]
89
+ });
61
90
  var hubspotCredentials = {
62
91
  accessToken: {
63
92
  description: "HubSpot private app access token",
@@ -117,20 +146,6 @@ var ENTITY_TYPE_BY_PHASE = {
117
146
  };
118
147
  var DEAL_STAGE_EVENT = "hubspot_deal_stage_change";
119
148
  var EMAIL_STATS_METRIC = "hubspot_email_stats";
120
- var COUNT_RESOURCE_TO_OBJECT = {
121
- hubspot_contact: "contacts",
122
- hubspot_company: "companies",
123
- hubspot_deal: "deals"
124
- };
125
- var FILTER_OP_TO_HUBSPOT = {
126
- eq: "EQ",
127
- neq: "NEQ",
128
- gt: "GT",
129
- gte: "GTE",
130
- lt: "LT",
131
- lte: "LTE",
132
- contains: "CONTAINS_TOKEN"
133
- };
134
149
  function finiteNumberOrNull(value) {
135
150
  if (value === null || value === void 0 || value.trim() === "") {
136
151
  return null;
@@ -141,11 +156,6 @@ function finiteNumberOrNull(value) {
141
156
  function counterValue(value) {
142
157
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
143
158
  }
144
- function unsupportedAggregate(req) {
145
- return new Error(
146
- `HubSpot aggregate: unsupported ${req.fn} for resource=${req.resource}`
147
- );
148
- }
149
159
  var idString = z.string().min(1);
150
160
  var contactProperties = z.object({
151
161
  email: z.string().nullish(),
@@ -211,16 +221,68 @@ var campaignDetailSchema = z.object({
211
221
  unsubscribed: z.number().optional()
212
222
  }).optional()
213
223
  });
224
+ var contactsSchema = z.array(crmRecordSchema(contactProperties));
225
+ var companiesSchema = z.array(crmRecordSchema(companyProperties));
226
+ var dealsSchema = z.array(crmRecordSchema(dealProperties));
227
+ var dealEventsSchema = z.array(dealHistoryRecordSchema);
228
+ var campaignsSchema = z.array(campaignDetailSchema);
229
+ var hubspotResources = defineResources({
230
+ hubspot_contact: {
231
+ shape: "entity",
232
+ description: "CRM contacts with email, lifecycle stage, lead status, owner, and creation time.",
233
+ endpoint: "POST /crm/v3/objects/contacts/search",
234
+ responses: { contacts: contactsSchema }
235
+ },
236
+ hubspot_company: {
237
+ shape: "entity",
238
+ description: "CRM companies with name, domain, industry, lifecycle stage, and creation time.",
239
+ endpoint: "POST /crm/v3/objects/companies/search",
240
+ responses: { companies: companiesSchema }
241
+ },
242
+ hubspot_deal: {
243
+ shape: "entity",
244
+ description: "CRM deals with name, stage, pipeline, amount, close date, owner, and creation time.",
245
+ endpoint: "POST /crm/v3/objects/deals/search",
246
+ responses: { deals: dealsSchema }
247
+ },
248
+ hubspot_deal_stage_change: {
249
+ shape: "event",
250
+ description: "Deal stage-change events derived from deal property history, one event per stage transition.",
251
+ endpoint: "GET /crm/v3/objects/deals?propertiesWithHistory=dealstage",
252
+ responses: { deal_events: dealEventsSchema }
253
+ },
254
+ hubspot_email_campaign: {
255
+ shape: "entity",
256
+ description: "Marketing email campaigns with name, subject, sender, type, send date, and recipient count.",
257
+ endpoint: "GET /email/public/v1/campaigns",
258
+ responses: { email_campaigns: campaignsSchema }
259
+ },
260
+ hubspot_email_stats: {
261
+ shape: "metric",
262
+ description: "Per-campaign marketing email engagement stats (sent, delivered, opened, clicked, bounced, unsubscribed) timestamped at the campaign send time.",
263
+ endpoint: "GET /email/public/v1/campaigns/{id}",
264
+ unit: "emails",
265
+ notes: "One sample per campaign; value is the sent count, and every counter (delivered, opened, clicked, bounced, unsubscribed) is also exposed in attributes.",
266
+ dimensions: [
267
+ { name: "campaignId", description: "HubSpot campaign id." },
268
+ { name: "campaignName", description: "Campaign name." },
269
+ { name: "delivered", description: "Number of emails delivered." },
270
+ { name: "opened", description: "Number of emails opened." },
271
+ { name: "clicked", description: "Number of emails clicked." },
272
+ { name: "bounced", description: "Number of emails bounced." },
273
+ {
274
+ name: "unsubscribed",
275
+ description: "Number of recipients who unsubscribed."
276
+ }
277
+ ],
278
+ responses: { email_stats: campaignsSchema }
279
+ }
280
+ });
281
+ var id = "hubspot";
214
282
  var HubSpotConnector = class _HubSpotConnector extends BaseConnector {
215
- static id = "hubspot";
216
- static schemas = {
217
- contacts: z.array(crmRecordSchema(contactProperties)),
218
- companies: z.array(crmRecordSchema(companyProperties)),
219
- deals: z.array(crmRecordSchema(dealProperties)),
220
- deal_events: z.array(dealHistoryRecordSchema),
221
- email_campaigns: z.array(campaignDetailSchema),
222
- email_stats: z.array(campaignDetailSchema)
223
- };
283
+ static id = id;
284
+ static resources = hubspotResources;
285
+ static schemas = schemasFromResources(hubspotResources);
224
286
  static create(input, ctx) {
225
287
  const parsed = configFields.parse(input);
226
288
  return new _HubSpotConnector(
@@ -229,7 +291,7 @@ var HubSpotConnector = class _HubSpotConnector extends BaseConnector {
229
291
  ctx
230
292
  );
231
293
  }
232
- id = "hubspot";
294
+ id = id;
233
295
  credentials = hubspotCredentials;
234
296
  buildHeaders() {
235
297
  return {
@@ -383,9 +445,9 @@ var HubSpotConnector = class _HubSpotConnector extends BaseConnector {
383
445
  // -------------------------------------------------------------------------
384
446
  // Marketing email campaigns + stats (legacy email campaigns API)
385
447
  // -------------------------------------------------------------------------
386
- async fetchCampaignDetail(id, resource, signal) {
448
+ async fetchCampaignDetail(id2, resource, signal) {
387
449
  const res = await this.apiGet(
388
- `${BASE_URL}/email/public/v1/campaigns/${id}`,
450
+ `${BASE_URL}/email/public/v1/campaigns/${id2}`,
389
451
  resource,
390
452
  signal
391
453
  );
@@ -525,69 +587,6 @@ var HubSpotConnector = class _HubSpotConnector extends BaseConnector {
525
587
  }
526
588
  });
527
589
  }
528
- // -------------------------------------------------------------------------
529
- // Aggregates — count via the CRM Search API `total` (one request)
530
- // -------------------------------------------------------------------------
531
- async aggregate(req, signal) {
532
- if (req.fn !== "count") {
533
- throw unsupportedAggregate(req);
534
- }
535
- const object = COUNT_RESOURCE_TO_OBJECT[req.resource];
536
- if (!object) {
537
- throw unsupportedAggregate(req);
538
- }
539
- const filterGroups = this.translateCountFilter(req.filter);
540
- const res = await this.apiPost(
541
- `${BASE_URL}/crm/v3/objects/${object}/search`,
542
- object,
543
- { filterGroups, properties: [], limit: 1 },
544
- signal
545
- );
546
- const value = res.body.total ?? 0;
547
- this.logger.info("aggregate", {
548
- fn: "count",
549
- resource: req.resource,
550
- filter: req.filter,
551
- value,
552
- via: "CRM search API"
553
- });
554
- return value;
555
- }
556
- validateCountFilter(resource, filter) {
557
- if (!COUNT_RESOURCE_TO_OBJECT[resource]) {
558
- throw new Error(
559
- `HubSpot aggregate count: unsupported resource=${resource}`
560
- );
561
- }
562
- this.translateCountFilter(filter);
563
- }
564
- // Translates flat AND filter conditions into HubSpot search `filterGroups`.
565
- // OR clauses aren't expressible alongside the rest of the group model, so
566
- // they throw "unsupported" and the runner falls back to storage rows.
567
- translateCountFilter(filter) {
568
- if (!filter || filter.length === 0) {
569
- return [];
570
- }
571
- const filters = filter.map((clause) => {
572
- if ("or" in clause) {
573
- throw new Error(
574
- "HubSpot aggregate count: OR filter clauses are not supported"
575
- );
576
- }
577
- const operator = FILTER_OP_TO_HUBSPOT[clause.op];
578
- if (!operator) {
579
- throw new Error(
580
- `HubSpot aggregate count: unsupported filter operator ${clause.op}`
581
- );
582
- }
583
- return {
584
- propertyName: clause.field,
585
- operator,
586
- value: String(clause.value)
587
- };
588
- });
589
- return [{ filters }];
590
- }
591
590
  };
592
591
 
593
592
  // src/index.ts
@@ -595,6 +594,9 @@ var index_default = HubSpotConnector;
595
594
  export {
596
595
  HubSpotConnector,
597
596
  configFields,
598
- index_default as default
597
+ index_default as default,
598
+ doc,
599
+ id,
600
+ hubspotResources as resources
599
601
  };
600
602
  //# sourceMappingURL=index.js.map