@walkeros/server-destination-hubspot 3.4.2 → 4.0.0-next-1777463920154

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 CHANGED
@@ -50,11 +50,11 @@ npm install @walkeros/server-destination-hubspot
50
50
 
51
51
  Per-event mapping settings control behavior per rule:
52
52
 
53
- | Setting | Effect | Use with `skip: true` |
54
- | ------------ | ------------------------------------------------------------ | --------------------- |
55
- | `eventName` | Overrides auto-generated event name (prefix still prepended) | No |
56
- | `identify` | Upserts contact via CRM API | Yes, for login events |
57
- | `properties` | Maps event data to HubSpot event properties | No |
53
+ | Setting | Effect | Use with `silent: true` |
54
+ | ------------ | ------------------------------------------------------------ | ----------------------- |
55
+ | `eventName` | Overrides auto-generated event name (prefix still prepended) | No |
56
+ | `identify` | Upserts contact via CRM API | Yes, for login events |
57
+ | `properties` | Maps event data to HubSpot event properties | No |
58
58
 
59
59
  ## Identity
60
60
 
package/dist/dev.d.mts CHANGED
@@ -146,13 +146,13 @@ declare namespace env {
146
146
  * At push time, the destination invokes the `@hubspot/api-client` SDK. The
147
147
  * public method paths users see on the client are:
148
148
  *
149
- * - `events.send.basicApi.send(eventRequest)` fires an event
150
- * - `events.send.batchApi.send({ inputs: [...] })` flushes a batch
151
- * - `crm.contacts.basicApi.update(id, data, idProperty)` contact upsert
149
+ * - `events.send.basicApi.send(eventRequest)` - fires an event
150
+ * - `events.send.batchApi.send({ inputs: [...] })` - flushes a batch
151
+ * - `crm.contacts.basicApi.update(id, data, idProperty)` - contact upsert
152
152
  *
153
153
  * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`
154
154
  * matching the actual SDK call order. `identify` fires before the event.
155
- * When the destination skips an event (`skip: true`, `ignore: true`, or
155
+ * When the destination skips an event (`silent: true`, `ignore: true`, or
156
156
  * missing identity), `out` is `[]`.
157
157
  */
158
158
  /**
@@ -182,7 +182,7 @@ declare const defaultProperties: HubSpotStepExample;
182
182
  */
183
183
  declare const destinationIdentify: HubSpotStepExample;
184
184
  /**
185
- * Per-event identify with skip -- user login fires contact upsert only,
185
+ * Per-event identify with silent -- user login fires contact upsert only,
186
186
  * no custom event sent.
187
187
  */
188
188
  declare const userLoginIdentify: HubSpotStepExample;
package/dist/dev.d.ts CHANGED
@@ -146,13 +146,13 @@ declare namespace env {
146
146
  * At push time, the destination invokes the `@hubspot/api-client` SDK. The
147
147
  * public method paths users see on the client are:
148
148
  *
149
- * - `events.send.basicApi.send(eventRequest)` fires an event
150
- * - `events.send.batchApi.send({ inputs: [...] })` flushes a batch
151
- * - `crm.contacts.basicApi.update(id, data, idProperty)` contact upsert
149
+ * - `events.send.basicApi.send(eventRequest)` - fires an event
150
+ * - `events.send.batchApi.send({ inputs: [...] })` - flushes a batch
151
+ * - `crm.contacts.basicApi.update(id, data, idProperty)` - contact upsert
152
152
  *
153
153
  * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`
154
154
  * matching the actual SDK call order. `identify` fires before the event.
155
- * When the destination skips an event (`skip: true`, `ignore: true`, or
155
+ * When the destination skips an event (`silent: true`, `ignore: true`, or
156
156
  * missing identity), `out` is `[]`.
157
157
  */
158
158
  /**
@@ -182,7 +182,7 @@ declare const defaultProperties: HubSpotStepExample;
182
182
  */
183
183
  declare const destinationIdentify: HubSpotStepExample;
184
184
  /**
185
- * Per-event identify with skip -- user login fires contact upsert only,
185
+ * Per-event identify with silent -- user login fires contact upsert only,
186
186
  * no custom event sent.
187
187
  */
188
188
  declare const userLoginIdentify: HubSpotStepExample;
package/dist/dev.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,r=(e,a)=>{for(var i in a)t(e,i,{get:a[i],enumerable:!0})},n={};r(n,{examples:()=>b,schemas:()=>o}),module.exports=(e=n,((e,r,n,o)=>{if(r&&"object"==typeof r||"function"==typeof r)for(let p of i(r))s.call(e,p)||p===n||t(e,p,{get:()=>r[p],enumerable:!(o=a(r,p))||o.enumerable});return e})(t({},"__esModule",{value:!0}),e));var o={};r(o,{MappingSchema:()=>d,SettingsSchema:()=>l,mapping:()=>v,settings:()=>u});var p=require("@walkeros/core/dev"),c=require("@walkeros/core/dev"),l=c.z.object({accessToken:c.z.string().min(1).describe("HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope."),eventNamePrefix:c.z.string().min(1).describe("Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events."),email:c.z.string().describe("walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.").optional(),objectId:c.z.string().describe("walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.").optional(),identify:c.z.unknown().describe("Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.").optional(),defaultProperties:c.z.record(c.z.string(),c.z.string()).describe("Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.").optional(),batch:c.z.boolean().describe("Use batch API for events (accumulate and flush). Default: false.").optional(),batchSize:c.z.number().int().positive().max(500).describe("Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.").optional()}),m=require("@walkeros/core/dev"),d=m.z.object({eventName:m.z.string().describe("Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.").optional(),identify:m.z.unknown().describe("Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with skip: true on login/identify events.").optional(),properties:m.z.unknown().describe("Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.").optional()}),u=(0,p.zodToSchema)(l),v=(0,p.zodToSchema)(d),b={};r(b,{env:()=>f,step:()=>_});var f={};r(f,{push:()=>h,simulation:()=>y});var g=()=>Promise.resolve();var h={client:{events:{send:{basicApi:{send:g},batchApi:{send:g}}},crm:{contacts:{basicApi:{update:g}}}}},y=["call:events.send.basicApi.send","call:events.send.batchApi.send","call:crm.contacts.basicApi.update"],_={};r(_,{defaultEvent:()=>A,defaultProperties:()=>S,destinationIdentify:()=>k,mappedEventName:()=>D,noIdentity:()=>N,objectIdAssociation:()=>x,userLoginIdentify:()=>z,wildcardIgnored:()=>P});var w=require("@walkeros/core"),A={title:"Default event",description:"A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.",in:(0,w.getEvent)("product view",{timestamp:1700000100,user:{email:"user@example.com"}}),out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",email:"user@example.com",occurredAt:new Date(1700000100),properties:{}}]]},D={title:"Custom event name",description:"A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.",in:(0,w.getEvent)("order complete",{timestamp:1700000101,user:{email:"user@example.com"},data:{total:99.5,currency:"EUR",id:"ord-123"}}),mapping:{name:"order complete",settings:{eventName:"purchase_completed",properties:{map:{revenue:"data.total",currency:"data.currency",order_id:"data.id"}}}},out:[["events.send.basicApi.send",{eventName:"pe12345678_purchase_completed",email:"user@example.com",occurredAt:new Date(1700000101),properties:{revenue:"99.5",currency:"EUR",order_id:"ord-123"}}]]},S={title:"Default properties",description:"Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.",in:(0,w.getEvent)("page view",{timestamp:1700000102,user:{email:"user@example.com"}}),settings:{defaultProperties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}},out:[["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000102),properties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}}]]},k={title:"Destination identify",description:"Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.",in:(0,w.getEvent)("page view",{timestamp:1700000103,user:{email:"user@example.com",firstName:"Jane",lastName:"Doe"}}),settings:{identify:{map:{email:"user.email",properties:{map:{firstname:"user.firstName",lastname:"user.lastName"}}}}},out:[["crm.contacts.basicApi.update","user@example.com",{properties:{firstname:"Jane",lastname:"Doe"}},"email"],["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000103),properties:{}}]]},z={title:"User login identify",description:"A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.",in:(0,w.getEvent)("user login",{timestamp:1700000104,user:{email:"user@example.com"},data:{email:"login@acme.com",first_name:"Jane",last_name:"Doe",lifecycle:"lead"}}),mapping:{skip:!0,settings:{identify:{map:{email:"data.email",properties:{map:{firstname:"data.first_name",lastname:"data.last_name",lifecyclestage:"data.lifecycle"}}}}}},out:[["crm.contacts.basicApi.update","login@acme.com",{properties:{firstname:"Jane",lastname:"Doe",lifecyclestage:"lead"}},"email"]]},x={title:"Object id association",description:"The HubSpot event is associated via objectId instead of email, resolved from the walker user id.",in:(0,w.getEvent)("product view",{timestamp:1700000105,user:{id:"hs-contact-789"}}),settings:{email:void 0,objectId:"user.id"},out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",objectId:"hs-contact-789",occurredAt:new Date(1700000105),properties:{}}]]},N={public:!1,in:(0,w.getEvent)("product view",{timestamp:1700000106,user:{}}),out:[]},P={public:!1,in:(0,w.getEvent)("debug noise",{timestamp:1700000107,user:{email:"user@example.com"}}),mapping:{ignore:!0},out:[]};//# sourceMappingURL=dev.js.map
1
+ "use strict";var e,t=Object.defineProperty,a=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,n=(e,a)=>{for(var i in a)t(e,i,{get:a[i],enumerable:!0})},r={};n(r,{examples:()=>b,schemas:()=>o}),module.exports=(e=r,((e,n,r,o)=>{if(n&&"object"==typeof n||"function"==typeof n)for(let p of i(n))s.call(e,p)||p===r||t(e,p,{get:()=>n[p],enumerable:!(o=a(n,p))||o.enumerable});return e})(t({},"__esModule",{value:!0}),e));var o={};n(o,{MappingSchema:()=>d,SettingsSchema:()=>l,mapping:()=>v,settings:()=>u});var p=require("@walkeros/core/dev"),c=require("@walkeros/core/dev"),l=c.z.object({accessToken:c.z.string().min(1).describe("HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope."),eventNamePrefix:c.z.string().min(1).describe("Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events."),email:c.z.string().describe("walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.").optional(),objectId:c.z.string().describe("walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.").optional(),identify:c.z.unknown().describe("Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.").optional(),defaultProperties:c.z.record(c.z.string(),c.z.string()).describe("Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.").optional(),batch:c.z.boolean().describe("Use batch API for events (accumulate and flush). Default: false.").optional(),batchSize:c.z.number().int().positive().max(500).describe("Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.").optional()}),m=require("@walkeros/core/dev"),d=m.z.object({eventName:m.z.string().describe("Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.").optional(),identify:m.z.unknown().describe("Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with silent: true on login/identify events.").optional(),properties:m.z.unknown().describe("Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.").optional()}),u=(0,p.zodToSchema)(l),v=(0,p.zodToSchema)(d),b={};n(b,{env:()=>f,step:()=>_});var f={};n(f,{push:()=>h,simulation:()=>y});var g=()=>Promise.resolve();var h={client:{events:{send:{basicApi:{send:g},batchApi:{send:g}}},crm:{contacts:{basicApi:{update:g}}}}},y=["call:events.send.basicApi.send","call:events.send.batchApi.send","call:crm.contacts.basicApi.update"],_={};n(_,{defaultEvent:()=>A,defaultProperties:()=>S,destinationIdentify:()=>z,mappedEventName:()=>D,noIdentity:()=>N,objectIdAssociation:()=>k,userLoginIdentify:()=>x,wildcardIgnored:()=>P});var w=require("@walkeros/core"),A={title:"Default event",description:"A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.",in:(0,w.getEvent)("product view",{timestamp:1700000100,user:{email:"user@example.com"}}),out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",email:"user@example.com",occurredAt:new Date(1700000100),properties:{}}]]},D={title:"Custom event name",description:"A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.",in:(0,w.getEvent)("order complete",{timestamp:1700000101,user:{email:"user@example.com"},data:{total:99.5,currency:"EUR",id:"ord-123"}}),mapping:{name:"order complete",settings:{eventName:"purchase_completed",properties:{map:{revenue:"data.total",currency:"data.currency",order_id:"data.id"}}}},out:[["events.send.basicApi.send",{eventName:"pe12345678_purchase_completed",email:"user@example.com",occurredAt:new Date(1700000101),properties:{revenue:"99.5",currency:"EUR",order_id:"ord-123"}}]]},S={title:"Default properties",description:"Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.",in:(0,w.getEvent)("page view",{timestamp:1700000102,user:{email:"user@example.com"}}),settings:{defaultProperties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}},out:[["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000102),properties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}}]]},z={title:"Destination identify",description:"Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.",in:(0,w.getEvent)("page view",{timestamp:1700000103,user:{email:"user@example.com",firstName:"Jane",lastName:"Doe"}}),settings:{identify:{map:{email:"user.email",properties:{map:{firstname:"user.firstName",lastname:"user.lastName"}}}}},out:[["crm.contacts.basicApi.update","user@example.com",{properties:{firstname:"Jane",lastname:"Doe"}},"email"],["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000103),properties:{}}]]},x={title:"User login identify",description:"A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.",in:(0,w.getEvent)("user login",{timestamp:1700000104,user:{email:"user@example.com"},data:{email:"login@acme.com",first_name:"Jane",last_name:"Doe",lifecycle:"lead"}}),mapping:{silent:!0,settings:{identify:{map:{email:"data.email",properties:{map:{firstname:"data.first_name",lastname:"data.last_name",lifecyclestage:"data.lifecycle"}}}}}},out:[["crm.contacts.basicApi.update","login@acme.com",{properties:{firstname:"Jane",lastname:"Doe",lifecyclestage:"lead"}},"email"]]},k={title:"Object id association",description:"The HubSpot event is associated via objectId instead of email, resolved from the walker user id.",in:(0,w.getEvent)("product view",{timestamp:1700000105,user:{id:"hs-contact-789"}}),settings:{email:void 0,objectId:"user.id"},out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",objectId:"hs-contact-789",occurredAt:new Date(1700000105),properties:{}}]]},N={public:!1,in:(0,w.getEvent)("product view",{timestamp:1700000106,user:{}}),out:[]},P={public:!1,in:(0,w.getEvent)("debug noise",{timestamp:1700000107,user:{email:"user@example.com"}}),mapping:{ignore:!0},out:[]};//# sourceMappingURL=dev.js.map
package/dist/dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope.',\n ),\n eventNamePrefix: z\n .string()\n .min(1)\n .describe(\n 'Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events.',\n ),\n email: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.',\n )\n .optional(),\n objectId: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.',\n )\n .optional(),\n defaultProperties: z\n .record(z.string(), z.string())\n .describe(\n 'Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.',\n )\n .optional(),\n batch: z\n .boolean()\n .describe(\n 'Use batch API for events (accumulate and flush). Default: false.',\n )\n .optional(),\n batchSize: z\n .number()\n .int()\n .positive()\n .max(500)\n .describe(\n 'Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n eventName: z\n .string()\n .describe(\n 'Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with skip: true on login/identify events.',\n )\n .optional(),\n properties: z\n .unknown()\n .describe(\n 'Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { Env, HubSpotClientMock } from '../types';\n\nconst asyncNoop = () => Promise.resolve();\n\nfunction createMockClient(): HubSpotClientMock {\n return {\n events: {\n send: {\n basicApi: { send: asyncNoop },\n batchApi: { send: asyncNoop },\n },\n },\n crm: {\n contacts: {\n basicApi: { update: asyncNoop },\n },\n },\n };\n}\n\nexport const push: Env = {\n client: createMockClient(),\n};\n\nexport const simulation = [\n 'call:events.send.basicApi.send',\n 'call:events.send.batchApi.send',\n 'call:crm.contacts.basicApi.update',\n];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent } from '@walkeros/core';\nimport type { Settings } from '../types';\n\n/**\n * HubSpot SDK step examples.\n *\n * At push time, the destination invokes the `@hubspot/api-client` SDK. The\n * public method paths users see on the client are:\n *\n * - `events.send.basicApi.send(eventRequest)` — fires an event\n * - `events.send.batchApi.send({ inputs: [...] })` — flushes a batch\n * - `crm.contacts.basicApi.update(id, data, idProperty)` — contact upsert\n *\n * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`\n * matching the actual SDK call order. `identify` fires before the event.\n * When the destination skips an event (`skip: true`, `ignore: true`, or\n * missing identity), `out` is `[]`.\n */\n\n/**\n * Extended step example that may carry destination-level settings overrides.\n */\nexport type HubSpotStepExample = Flow.StepExample & {\n settings?: Partial<Settings>;\n};\n\n/**\n * Default event forwarding -- events.send.basicApi.send() with auto-generated\n * event name. Email resolved from default settings.email = 'user.email'.\n */\nexport const defaultEvent: HubSpotStepExample = {\n title: 'Default event',\n description:\n 'A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.',\n in: getEvent('product view', {\n timestamp: 1700000100,\n user: { email: 'user@example.com' },\n }),\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000100),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Mapped event name -- mapping.settings.eventName overrides the auto-generated\n * name. The prefix is still prepended.\n */\nexport const mappedEventName: HubSpotStepExample = {\n title: 'Custom event name',\n description:\n 'A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.',\n in: getEvent('order complete', {\n timestamp: 1700000101,\n user: { email: 'user@example.com' },\n data: { total: 99.5, currency: 'EUR', id: 'ord-123' },\n }),\n mapping: {\n name: 'order complete',\n settings: {\n eventName: 'purchase_completed',\n properties: {\n map: {\n revenue: 'data.total',\n currency: 'data.currency',\n order_id: 'data.id',\n },\n },\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_purchase_completed',\n email: 'user@example.com',\n occurredAt: new Date(1700000101),\n properties: {\n revenue: '99.5',\n currency: 'EUR',\n order_id: 'ord-123',\n },\n },\n ],\n ],\n};\n\n/**\n * Event with defaultProperties -- settings.defaultProperties are merged\n * into every event. Per-event properties override defaults.\n */\nexport const defaultProperties: HubSpotStepExample = {\n title: 'Default properties',\n description:\n 'Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.',\n in: getEvent('page view', {\n timestamp: 1700000102,\n user: { email: 'user@example.com' },\n }),\n settings: {\n defaultProperties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000102),\n properties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n ],\n ],\n};\n\n/**\n * Destination-level identify -- fires crm.contacts.basicApi.update() on\n * first push when settings.identify mapping resolves. Then fires the event.\n */\nexport const destinationIdentify: HubSpotStepExample = {\n title: 'Destination identify',\n description:\n 'Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.',\n in: getEvent('page view', {\n timestamp: 1700000103,\n user: { email: 'user@example.com', firstName: 'Jane', lastName: 'Doe' },\n }),\n settings: {\n identify: {\n map: {\n email: 'user.email',\n properties: {\n map: {\n firstname: 'user.firstName',\n lastname: 'user.lastName',\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'user@example.com',\n { properties: { firstname: 'Jane', lastname: 'Doe' } },\n 'email',\n ],\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000103),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Per-event identify with skip -- user login fires contact upsert only,\n * no custom event sent.\n */\nexport const userLoginIdentify: HubSpotStepExample = {\n title: 'User login identify',\n description:\n 'A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.',\n in: getEvent('user login', {\n timestamp: 1700000104,\n user: { email: 'user@example.com' },\n data: {\n email: 'login@acme.com',\n first_name: 'Jane',\n last_name: 'Doe',\n lifecycle: 'lead',\n },\n }),\n mapping: {\n skip: true,\n settings: {\n identify: {\n map: {\n email: 'data.email',\n properties: {\n map: {\n firstname: 'data.first_name',\n lastname: 'data.last_name',\n lifecyclestage: 'data.lifecycle',\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'login@acme.com',\n {\n properties: {\n firstname: 'Jane',\n lastname: 'Doe',\n lifecyclestage: 'lead',\n },\n },\n 'email',\n ],\n ],\n};\n\n/**\n * objectId association -- use objectId instead of email for contact\n * association on the event.\n */\nexport const objectIdAssociation: HubSpotStepExample = {\n title: 'Object id association',\n description:\n 'The HubSpot event is associated via objectId instead of email, resolved from the walker user id.',\n in: getEvent('product view', {\n timestamp: 1700000105,\n user: { id: 'hs-contact-789' },\n }),\n settings: {\n email: undefined,\n objectId: 'user.id',\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n objectId: 'hs-contact-789',\n occurredAt: new Date(1700000105),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * No identity resolved -- event is skipped with a warning. Neither email\n * nor objectId can be resolved from the event.\n */\nexport const noIdentity: HubSpotStepExample = {\n public: false,\n in: getEvent('product view', {\n timestamp: 1700000106,\n user: {},\n }),\n out: [],\n};\n\n/**\n * Wildcard ignore -- the event matches a mapping rule with ignore: true.\n * The destination fires zero SDK calls.\n */\nexport const wildcardIgnored: HubSpotStepExample = {\n public: false,\n in: getEvent('debug noise', {\n timestamp: 1700000107,\n user: { email: 'user@example.com' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n"],"mappings":"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","names":["import_dev","import_dev"]}
1
+ {"version":3,"sources":["../src/dev.ts","../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["export * as schemas from './schemas';\nexport * as examples from './examples';\n","import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope.',\n ),\n eventNamePrefix: z\n .string()\n .min(1)\n .describe(\n 'Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events.',\n ),\n email: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.',\n )\n .optional(),\n objectId: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.',\n )\n .optional(),\n defaultProperties: z\n .record(z.string(), z.string())\n .describe(\n 'Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.',\n )\n .optional(),\n batch: z\n .boolean()\n .describe(\n 'Use batch API for events (accumulate and flush). Default: false.',\n )\n .optional(),\n batchSize: z\n .number()\n .int()\n .positive()\n .max(500)\n .describe(\n 'Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n eventName: z\n .string()\n .describe(\n 'Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with silent: true on login/identify events.',\n )\n .optional(),\n properties: z\n .unknown()\n .describe(\n 'Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { Env, HubSpotClientMock } from '../types';\n\nconst asyncNoop = () => Promise.resolve();\n\nfunction createMockClient(): HubSpotClientMock {\n return {\n events: {\n send: {\n basicApi: { send: asyncNoop },\n batchApi: { send: asyncNoop },\n },\n },\n crm: {\n contacts: {\n basicApi: { update: asyncNoop },\n },\n },\n };\n}\n\nexport const push: Env = {\n client: createMockClient(),\n};\n\nexport const simulation = [\n 'call:events.send.basicApi.send',\n 'call:events.send.batchApi.send',\n 'call:crm.contacts.basicApi.update',\n];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent } from '@walkeros/core';\nimport type { Settings } from '../types';\n\n/**\n * HubSpot SDK step examples.\n *\n * At push time, the destination invokes the `@hubspot/api-client` SDK. The\n * public method paths users see on the client are:\n *\n * - `events.send.basicApi.send(eventRequest)` - fires an event\n * - `events.send.batchApi.send({ inputs: [...] })` - flushes a batch\n * - `crm.contacts.basicApi.update(id, data, idProperty)` - contact upsert\n *\n * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`\n * matching the actual SDK call order. `identify` fires before the event.\n * When the destination skips an event (`silent: true`, `ignore: true`, or\n * missing identity), `out` is `[]`.\n */\n\n/**\n * Extended step example that may carry destination-level settings overrides.\n */\nexport type HubSpotStepExample = Flow.StepExample & {\n settings?: Partial<Settings>;\n};\n\n/**\n * Default event forwarding -- events.send.basicApi.send() with auto-generated\n * event name. Email resolved from default settings.email = 'user.email'.\n */\nexport const defaultEvent: HubSpotStepExample = {\n title: 'Default event',\n description:\n 'A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.',\n in: getEvent('product view', {\n timestamp: 1700000100,\n user: { email: 'user@example.com' },\n }),\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000100),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Mapped event name -- mapping.settings.eventName overrides the auto-generated\n * name. The prefix is still prepended.\n */\nexport const mappedEventName: HubSpotStepExample = {\n title: 'Custom event name',\n description:\n 'A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.',\n in: getEvent('order complete', {\n timestamp: 1700000101,\n user: { email: 'user@example.com' },\n data: { total: 99.5, currency: 'EUR', id: 'ord-123' },\n }),\n mapping: {\n name: 'order complete',\n settings: {\n eventName: 'purchase_completed',\n properties: {\n map: {\n revenue: 'data.total',\n currency: 'data.currency',\n order_id: 'data.id',\n },\n },\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_purchase_completed',\n email: 'user@example.com',\n occurredAt: new Date(1700000101),\n properties: {\n revenue: '99.5',\n currency: 'EUR',\n order_id: 'ord-123',\n },\n },\n ],\n ],\n};\n\n/**\n * Event with defaultProperties -- settings.defaultProperties are merged\n * into every event. Per-event properties override defaults.\n */\nexport const defaultProperties: HubSpotStepExample = {\n title: 'Default properties',\n description:\n 'Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.',\n in: getEvent('page view', {\n timestamp: 1700000102,\n user: { email: 'user@example.com' },\n }),\n settings: {\n defaultProperties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000102),\n properties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n ],\n ],\n};\n\n/**\n * Destination-level identify -- fires crm.contacts.basicApi.update() on\n * first push when settings.identify mapping resolves. Then fires the event.\n */\nexport const destinationIdentify: HubSpotStepExample = {\n title: 'Destination identify',\n description:\n 'Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.',\n in: getEvent('page view', {\n timestamp: 1700000103,\n user: { email: 'user@example.com', firstName: 'Jane', lastName: 'Doe' },\n }),\n settings: {\n identify: {\n map: {\n email: 'user.email',\n properties: {\n map: {\n firstname: 'user.firstName',\n lastname: 'user.lastName',\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'user@example.com',\n { properties: { firstname: 'Jane', lastname: 'Doe' } },\n 'email',\n ],\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000103),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Per-event identify with silent -- user login fires contact upsert only,\n * no custom event sent.\n */\nexport const userLoginIdentify: HubSpotStepExample = {\n title: 'User login identify',\n description:\n 'A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.',\n in: getEvent('user login', {\n timestamp: 1700000104,\n user: { email: 'user@example.com' },\n data: {\n email: 'login@acme.com',\n first_name: 'Jane',\n last_name: 'Doe',\n lifecycle: 'lead',\n },\n }),\n mapping: {\n silent: true,\n settings: {\n identify: {\n map: {\n email: 'data.email',\n properties: {\n map: {\n firstname: 'data.first_name',\n lastname: 'data.last_name',\n lifecyclestage: 'data.lifecycle',\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'login@acme.com',\n {\n properties: {\n firstname: 'Jane',\n lastname: 'Doe',\n lifecyclestage: 'lead',\n },\n },\n 'email',\n ],\n ],\n};\n\n/**\n * objectId association -- use objectId instead of email for contact\n * association on the event.\n */\nexport const objectIdAssociation: HubSpotStepExample = {\n title: 'Object id association',\n description:\n 'The HubSpot event is associated via objectId instead of email, resolved from the walker user id.',\n in: getEvent('product view', {\n timestamp: 1700000105,\n user: { id: 'hs-contact-789' },\n }),\n settings: {\n email: undefined,\n objectId: 'user.id',\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n objectId: 'hs-contact-789',\n occurredAt: new Date(1700000105),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * No identity resolved -- event is skipped with a warning. Neither email\n * nor objectId can be resolved from the event.\n */\nexport const noIdentity: HubSpotStepExample = {\n public: false,\n in: getEvent('product view', {\n timestamp: 1700000106,\n user: {},\n }),\n out: [],\n};\n\n/**\n * Wildcard ignore -- the event matches a mapping rule with ignore: true.\n * The destination fires zero SDK calls.\n */\nexport const wildcardIgnored: HubSpotStepExample = {\n public: false,\n in: getEvent('debug noise', {\n timestamp: 1700000107,\n user: { email: 'user@example.com' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n"],"mappings":"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","names":["import_dev","import_dev"]}
package/dist/dev.mjs CHANGED
@@ -1 +1 @@
1
- var e=Object.defineProperty,t=(t,a)=>{for(var i in a)e(t,i,{get:a[i],enumerable:!0})},a={};t(a,{MappingSchema:()=>o,SettingsSchema:()=>r,mapping:()=>c,settings:()=>p});import{zodToSchema as i}from"@walkeros/core/dev";import{z as s}from"@walkeros/core/dev";var r=s.object({accessToken:s.string().min(1).describe("HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope."),eventNamePrefix:s.string().min(1).describe("Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events."),email:s.string().describe("walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.").optional(),objectId:s.string().describe("walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.").optional(),identify:s.unknown().describe("Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.").optional(),defaultProperties:s.record(s.string(),s.string()).describe("Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.").optional(),batch:s.boolean().describe("Use batch API for events (accumulate and flush). Default: false.").optional(),batchSize:s.number().int().positive().max(500).describe("Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.").optional()});import{z as n}from"@walkeros/core/dev";var o=n.object({eventName:n.string().describe("Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.").optional(),identify:n.unknown().describe("Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with skip: true on login/identify events.").optional(),properties:n.unknown().describe("Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.").optional()}),p=i(r),c=i(o),l={};t(l,{env:()=>m,step:()=>f});var m={};t(m,{push:()=>u,simulation:()=>v});var d=()=>Promise.resolve();var u={client:{events:{send:{basicApi:{send:d},batchApi:{send:d}}},crm:{contacts:{basicApi:{update:d}}}}},v=["call:events.send.basicApi.send","call:events.send.batchApi.send","call:crm.contacts.basicApi.update"],f={};t(f,{defaultEvent:()=>g,defaultProperties:()=>_,destinationIdentify:()=>y,mappedEventName:()=>h,noIdentity:()=>D,objectIdAssociation:()=>A,userLoginIdentify:()=>w,wildcardIgnored:()=>S});import{getEvent as b}from"@walkeros/core";var g={title:"Default event",description:"A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.",in:b("product view",{timestamp:1700000100,user:{email:"user@example.com"}}),out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",email:"user@example.com",occurredAt:new Date(1700000100),properties:{}}]]},h={title:"Custom event name",description:"A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.",in:b("order complete",{timestamp:1700000101,user:{email:"user@example.com"},data:{total:99.5,currency:"EUR",id:"ord-123"}}),mapping:{name:"order complete",settings:{eventName:"purchase_completed",properties:{map:{revenue:"data.total",currency:"data.currency",order_id:"data.id"}}}},out:[["events.send.basicApi.send",{eventName:"pe12345678_purchase_completed",email:"user@example.com",occurredAt:new Date(1700000101),properties:{revenue:"99.5",currency:"EUR",order_id:"ord-123"}}]]},_={title:"Default properties",description:"Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.",in:b("page view",{timestamp:1700000102,user:{email:"user@example.com"}}),settings:{defaultProperties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}},out:[["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000102),properties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}}]]},y={title:"Destination identify",description:"Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.",in:b("page view",{timestamp:1700000103,user:{email:"user@example.com",firstName:"Jane",lastName:"Doe"}}),settings:{identify:{map:{email:"user.email",properties:{map:{firstname:"user.firstName",lastname:"user.lastName"}}}}},out:[["crm.contacts.basicApi.update","user@example.com",{properties:{firstname:"Jane",lastname:"Doe"}},"email"],["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000103),properties:{}}]]},w={title:"User login identify",description:"A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.",in:b("user login",{timestamp:1700000104,user:{email:"user@example.com"},data:{email:"login@acme.com",first_name:"Jane",last_name:"Doe",lifecycle:"lead"}}),mapping:{skip:!0,settings:{identify:{map:{email:"data.email",properties:{map:{firstname:"data.first_name",lastname:"data.last_name",lifecyclestage:"data.lifecycle"}}}}}},out:[["crm.contacts.basicApi.update","login@acme.com",{properties:{firstname:"Jane",lastname:"Doe",lifecyclestage:"lead"}},"email"]]},A={title:"Object id association",description:"The HubSpot event is associated via objectId instead of email, resolved from the walker user id.",in:b("product view",{timestamp:1700000105,user:{id:"hs-contact-789"}}),settings:{email:void 0,objectId:"user.id"},out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",objectId:"hs-contact-789",occurredAt:new Date(1700000105),properties:{}}]]},D={public:!1,in:b("product view",{timestamp:1700000106,user:{}}),out:[]},S={public:!1,in:b("debug noise",{timestamp:1700000107,user:{email:"user@example.com"}}),mapping:{ignore:!0},out:[]};export{l as examples,a as schemas};//# sourceMappingURL=dev.mjs.map
1
+ var e=Object.defineProperty,t=(t,a)=>{for(var i in a)e(t,i,{get:a[i],enumerable:!0})},a={};t(a,{MappingSchema:()=>o,SettingsSchema:()=>n,mapping:()=>c,settings:()=>p});import{zodToSchema as i}from"@walkeros/core/dev";import{z as s}from"@walkeros/core/dev";var n=s.object({accessToken:s.string().min(1).describe("HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope."),eventNamePrefix:s.string().min(1).describe("Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events."),email:s.string().describe("walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.").optional(),objectId:s.string().describe("walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.").optional(),identify:s.unknown().describe("Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.").optional(),defaultProperties:s.record(s.string(),s.string()).describe("Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.").optional(),batch:s.boolean().describe("Use batch API for events (accumulate and flush). Default: false.").optional(),batchSize:s.number().int().positive().max(500).describe("Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.").optional()});import{z as r}from"@walkeros/core/dev";var o=r.object({eventName:r.string().describe("Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.").optional(),identify:r.unknown().describe("Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with silent: true on login/identify events.").optional(),properties:r.unknown().describe("Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.").optional()}),p=i(n),c=i(o),l={};t(l,{env:()=>m,step:()=>f});var m={};t(m,{push:()=>u,simulation:()=>v});var d=()=>Promise.resolve();var u={client:{events:{send:{basicApi:{send:d},batchApi:{send:d}}},crm:{contacts:{basicApi:{update:d}}}}},v=["call:events.send.basicApi.send","call:events.send.batchApi.send","call:crm.contacts.basicApi.update"],f={};t(f,{defaultEvent:()=>g,defaultProperties:()=>_,destinationIdentify:()=>y,mappedEventName:()=>h,noIdentity:()=>D,objectIdAssociation:()=>A,userLoginIdentify:()=>w,wildcardIgnored:()=>S});import{getEvent as b}from"@walkeros/core";var g={title:"Default event",description:"A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.",in:b("product view",{timestamp:1700000100,user:{email:"user@example.com"}}),out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",email:"user@example.com",occurredAt:new Date(1700000100),properties:{}}]]},h={title:"Custom event name",description:"A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.",in:b("order complete",{timestamp:1700000101,user:{email:"user@example.com"},data:{total:99.5,currency:"EUR",id:"ord-123"}}),mapping:{name:"order complete",settings:{eventName:"purchase_completed",properties:{map:{revenue:"data.total",currency:"data.currency",order_id:"data.id"}}}},out:[["events.send.basicApi.send",{eventName:"pe12345678_purchase_completed",email:"user@example.com",occurredAt:new Date(1700000101),properties:{revenue:"99.5",currency:"EUR",order_id:"ord-123"}}]]},_={title:"Default properties",description:"Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.",in:b("page view",{timestamp:1700000102,user:{email:"user@example.com"}}),settings:{defaultProperties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}},out:[["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000102),properties:{hs_touchpoint_source:"walkerOS",hs_page_content_type:"STANDARD_PAGE"}}]]},y={title:"Destination identify",description:"Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.",in:b("page view",{timestamp:1700000103,user:{email:"user@example.com",firstName:"Jane",lastName:"Doe"}}),settings:{identify:{map:{email:"user.email",properties:{map:{firstname:"user.firstName",lastname:"user.lastName"}}}}},out:[["crm.contacts.basicApi.update","user@example.com",{properties:{firstname:"Jane",lastname:"Doe"}},"email"],["events.send.basicApi.send",{eventName:"pe12345678_page_view",email:"user@example.com",occurredAt:new Date(1700000103),properties:{}}]]},w={title:"User login identify",description:"A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.",in:b("user login",{timestamp:1700000104,user:{email:"user@example.com"},data:{email:"login@acme.com",first_name:"Jane",last_name:"Doe",lifecycle:"lead"}}),mapping:{silent:!0,settings:{identify:{map:{email:"data.email",properties:{map:{firstname:"data.first_name",lastname:"data.last_name",lifecyclestage:"data.lifecycle"}}}}}},out:[["crm.contacts.basicApi.update","login@acme.com",{properties:{firstname:"Jane",lastname:"Doe",lifecyclestage:"lead"}},"email"]]},A={title:"Object id association",description:"The HubSpot event is associated via objectId instead of email, resolved from the walker user id.",in:b("product view",{timestamp:1700000105,user:{id:"hs-contact-789"}}),settings:{email:void 0,objectId:"user.id"},out:[["events.send.basicApi.send",{eventName:"pe12345678_product_view",objectId:"hs-contact-789",occurredAt:new Date(1700000105),properties:{}}]]},D={public:!1,in:b("product view",{timestamp:1700000106,user:{}}),out:[]},S={public:!1,in:b("debug noise",{timestamp:1700000107,user:{email:"user@example.com"}}),mapping:{ignore:!0},out:[]};export{l as examples,a as schemas};//# sourceMappingURL=dev.mjs.map
package/dist/dev.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope.',\n ),\n eventNamePrefix: z\n .string()\n .min(1)\n .describe(\n 'Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events.',\n ),\n email: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.',\n )\n .optional(),\n objectId: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.',\n )\n .optional(),\n defaultProperties: z\n .record(z.string(), z.string())\n .describe(\n 'Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.',\n )\n .optional(),\n batch: z\n .boolean()\n .describe(\n 'Use batch API for events (accumulate and flush). Default: false.',\n )\n .optional(),\n batchSize: z\n .number()\n .int()\n .positive()\n .max(500)\n .describe(\n 'Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n eventName: z\n .string()\n .describe(\n 'Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with skip: true on login/identify events.',\n )\n .optional(),\n properties: z\n .unknown()\n .describe(\n 'Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { Env, HubSpotClientMock } from '../types';\n\nconst asyncNoop = () => Promise.resolve();\n\nfunction createMockClient(): HubSpotClientMock {\n return {\n events: {\n send: {\n basicApi: { send: asyncNoop },\n batchApi: { send: asyncNoop },\n },\n },\n crm: {\n contacts: {\n basicApi: { update: asyncNoop },\n },\n },\n };\n}\n\nexport const push: Env = {\n client: createMockClient(),\n};\n\nexport const simulation = [\n 'call:events.send.basicApi.send',\n 'call:events.send.batchApi.send',\n 'call:crm.contacts.basicApi.update',\n];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent } from '@walkeros/core';\nimport type { Settings } from '../types';\n\n/**\n * HubSpot SDK step examples.\n *\n * At push time, the destination invokes the `@hubspot/api-client` SDK. The\n * public method paths users see on the client are:\n *\n * - `events.send.basicApi.send(eventRequest)` — fires an event\n * - `events.send.batchApi.send({ inputs: [...] })` — flushes a batch\n * - `crm.contacts.basicApi.update(id, data, idProperty)` — contact upsert\n *\n * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`\n * matching the actual SDK call order. `identify` fires before the event.\n * When the destination skips an event (`skip: true`, `ignore: true`, or\n * missing identity), `out` is `[]`.\n */\n\n/**\n * Extended step example that may carry destination-level settings overrides.\n */\nexport type HubSpotStepExample = Flow.StepExample & {\n settings?: Partial<Settings>;\n};\n\n/**\n * Default event forwarding -- events.send.basicApi.send() with auto-generated\n * event name. Email resolved from default settings.email = 'user.email'.\n */\nexport const defaultEvent: HubSpotStepExample = {\n title: 'Default event',\n description:\n 'A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.',\n in: getEvent('product view', {\n timestamp: 1700000100,\n user: { email: 'user@example.com' },\n }),\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000100),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Mapped event name -- mapping.settings.eventName overrides the auto-generated\n * name. The prefix is still prepended.\n */\nexport const mappedEventName: HubSpotStepExample = {\n title: 'Custom event name',\n description:\n 'A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.',\n in: getEvent('order complete', {\n timestamp: 1700000101,\n user: { email: 'user@example.com' },\n data: { total: 99.5, currency: 'EUR', id: 'ord-123' },\n }),\n mapping: {\n name: 'order complete',\n settings: {\n eventName: 'purchase_completed',\n properties: {\n map: {\n revenue: 'data.total',\n currency: 'data.currency',\n order_id: 'data.id',\n },\n },\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_purchase_completed',\n email: 'user@example.com',\n occurredAt: new Date(1700000101),\n properties: {\n revenue: '99.5',\n currency: 'EUR',\n order_id: 'ord-123',\n },\n },\n ],\n ],\n};\n\n/**\n * Event with defaultProperties -- settings.defaultProperties are merged\n * into every event. Per-event properties override defaults.\n */\nexport const defaultProperties: HubSpotStepExample = {\n title: 'Default properties',\n description:\n 'Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.',\n in: getEvent('page view', {\n timestamp: 1700000102,\n user: { email: 'user@example.com' },\n }),\n settings: {\n defaultProperties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000102),\n properties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n ],\n ],\n};\n\n/**\n * Destination-level identify -- fires crm.contacts.basicApi.update() on\n * first push when settings.identify mapping resolves. Then fires the event.\n */\nexport const destinationIdentify: HubSpotStepExample = {\n title: 'Destination identify',\n description:\n 'Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.',\n in: getEvent('page view', {\n timestamp: 1700000103,\n user: { email: 'user@example.com', firstName: 'Jane', lastName: 'Doe' },\n }),\n settings: {\n identify: {\n map: {\n email: 'user.email',\n properties: {\n map: {\n firstname: 'user.firstName',\n lastname: 'user.lastName',\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'user@example.com',\n { properties: { firstname: 'Jane', lastname: 'Doe' } },\n 'email',\n ],\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000103),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Per-event identify with skip -- user login fires contact upsert only,\n * no custom event sent.\n */\nexport const userLoginIdentify: HubSpotStepExample = {\n title: 'User login identify',\n description:\n 'A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.',\n in: getEvent('user login', {\n timestamp: 1700000104,\n user: { email: 'user@example.com' },\n data: {\n email: 'login@acme.com',\n first_name: 'Jane',\n last_name: 'Doe',\n lifecycle: 'lead',\n },\n }),\n mapping: {\n skip: true,\n settings: {\n identify: {\n map: {\n email: 'data.email',\n properties: {\n map: {\n firstname: 'data.first_name',\n lastname: 'data.last_name',\n lifecyclestage: 'data.lifecycle',\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'login@acme.com',\n {\n properties: {\n firstname: 'Jane',\n lastname: 'Doe',\n lifecyclestage: 'lead',\n },\n },\n 'email',\n ],\n ],\n};\n\n/**\n * objectId association -- use objectId instead of email for contact\n * association on the event.\n */\nexport const objectIdAssociation: HubSpotStepExample = {\n title: 'Object id association',\n description:\n 'The HubSpot event is associated via objectId instead of email, resolved from the walker user id.',\n in: getEvent('product view', {\n timestamp: 1700000105,\n user: { id: 'hs-contact-789' },\n }),\n settings: {\n email: undefined,\n objectId: 'user.id',\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n objectId: 'hs-contact-789',\n occurredAt: new Date(1700000105),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * No identity resolved -- event is skipped with a warning. Neither email\n * nor objectId can be resolved from the event.\n */\nexport const noIdentity: HubSpotStepExample = {\n public: false,\n in: getEvent('product view', {\n timestamp: 1700000106,\n user: {},\n }),\n out: [],\n};\n\n/**\n * Wildcard ignore -- the event matches a mapping rule with ignore: true.\n * The destination fires zero SDK calls.\n */\nexport const wildcardIgnored: HubSpotStepExample = {\n public: false,\n in: getEvent('debug noise', {\n timestamp: 1700000107,\n user: { email: 'user@example.com' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n"],"mappings":"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","names":["z"]}
1
+ {"version":3,"sources":["../src/schemas/index.ts","../src/schemas/settings.ts","../src/schemas/mapping.ts","../src/examples/index.ts","../src/examples/env.ts","../src/examples/step.ts"],"sourcesContent":["import { zodToSchema } from '@walkeros/core/dev';\nimport { SettingsSchema } from './settings';\nimport { MappingSchema } from './mapping';\n\nexport { SettingsSchema, type Settings } from './settings';\nexport { MappingSchema, type Mapping } from './mapping';\n\n// JSON Schema\nexport const settings = zodToSchema(SettingsSchema);\nexport const mapping = zodToSchema(MappingSchema);\n","import { z } from '@walkeros/core/dev';\n\nexport const SettingsSchema = z.object({\n accessToken: z\n .string()\n .min(1)\n .describe(\n 'HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral_events.send scope.',\n ),\n eventNamePrefix: z\n .string()\n .min(1)\n .describe(\n 'Fully qualified event name prefix: pe{HubID}_ (e.g. pe12345678_). Find it in HubSpot under Data Management > Custom Events.',\n ),\n email: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.',\n )\n .optional(),\n objectId: z\n .string()\n .describe(\n 'walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.',\n )\n .optional(),\n defaultProperties: z\n .record(z.string(), z.string())\n .describe(\n 'Static event properties added to every event occurrence. Useful for hs_touchpoint_source, hs_page_content_type, etc.',\n )\n .optional(),\n batch: z\n .boolean()\n .describe(\n 'Use batch API for events (accumulate and flush). Default: false.',\n )\n .optional(),\n batchSize: z\n .number()\n .int()\n .positive()\n .max(500)\n .describe(\n 'Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.',\n )\n .optional(),\n});\n\nexport type Settings = z.infer<typeof SettingsSchema>;\n","import { z } from '@walkeros/core/dev';\n\nexport const MappingSchema = z.object({\n eventName: z\n .string()\n .describe(\n 'Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically.',\n )\n .optional(),\n identify: z\n .unknown()\n .describe(\n 'Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with silent: true on login/identify events.',\n )\n .optional(),\n properties: z\n .unknown()\n .describe(\n 'Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.',\n )\n .optional(),\n});\n\nexport type Mapping = z.infer<typeof MappingSchema>;\n","export * as env from './env';\nexport * as step from './step';\n","import type { Env, HubSpotClientMock } from '../types';\n\nconst asyncNoop = () => Promise.resolve();\n\nfunction createMockClient(): HubSpotClientMock {\n return {\n events: {\n send: {\n basicApi: { send: asyncNoop },\n batchApi: { send: asyncNoop },\n },\n },\n crm: {\n contacts: {\n basicApi: { update: asyncNoop },\n },\n },\n };\n}\n\nexport const push: Env = {\n client: createMockClient(),\n};\n\nexport const simulation = [\n 'call:events.send.basicApi.send',\n 'call:events.send.batchApi.send',\n 'call:crm.contacts.basicApi.update',\n];\n","import type { Flow } from '@walkeros/core';\nimport { getEvent } from '@walkeros/core';\nimport type { Settings } from '../types';\n\n/**\n * HubSpot SDK step examples.\n *\n * At push time, the destination invokes the `@hubspot/api-client` SDK. The\n * public method paths users see on the client are:\n *\n * - `events.send.basicApi.send(eventRequest)` - fires an event\n * - `events.send.batchApi.send({ inputs: [...] })` - flushes a batch\n * - `crm.contacts.basicApi.update(id, data, idProperty)` - contact upsert\n *\n * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`\n * matching the actual SDK call order. `identify` fires before the event.\n * When the destination skips an event (`silent: true`, `ignore: true`, or\n * missing identity), `out` is `[]`.\n */\n\n/**\n * Extended step example that may carry destination-level settings overrides.\n */\nexport type HubSpotStepExample = Flow.StepExample & {\n settings?: Partial<Settings>;\n};\n\n/**\n * Default event forwarding -- events.send.basicApi.send() with auto-generated\n * event name. Email resolved from default settings.email = 'user.email'.\n */\nexport const defaultEvent: HubSpotStepExample = {\n title: 'Default event',\n description:\n 'A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.',\n in: getEvent('product view', {\n timestamp: 1700000100,\n user: { email: 'user@example.com' },\n }),\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000100),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Mapped event name -- mapping.settings.eventName overrides the auto-generated\n * name. The prefix is still prepended.\n */\nexport const mappedEventName: HubSpotStepExample = {\n title: 'Custom event name',\n description:\n 'A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.',\n in: getEvent('order complete', {\n timestamp: 1700000101,\n user: { email: 'user@example.com' },\n data: { total: 99.5, currency: 'EUR', id: 'ord-123' },\n }),\n mapping: {\n name: 'order complete',\n settings: {\n eventName: 'purchase_completed',\n properties: {\n map: {\n revenue: 'data.total',\n currency: 'data.currency',\n order_id: 'data.id',\n },\n },\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_purchase_completed',\n email: 'user@example.com',\n occurredAt: new Date(1700000101),\n properties: {\n revenue: '99.5',\n currency: 'EUR',\n order_id: 'ord-123',\n },\n },\n ],\n ],\n};\n\n/**\n * Event with defaultProperties -- settings.defaultProperties are merged\n * into every event. Per-event properties override defaults.\n */\nexport const defaultProperties: HubSpotStepExample = {\n title: 'Default properties',\n description:\n 'Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.',\n in: getEvent('page view', {\n timestamp: 1700000102,\n user: { email: 'user@example.com' },\n }),\n settings: {\n defaultProperties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000102),\n properties: {\n hs_touchpoint_source: 'walkerOS',\n hs_page_content_type: 'STANDARD_PAGE',\n },\n },\n ],\n ],\n};\n\n/**\n * Destination-level identify -- fires crm.contacts.basicApi.update() on\n * first push when settings.identify mapping resolves. Then fires the event.\n */\nexport const destinationIdentify: HubSpotStepExample = {\n title: 'Destination identify',\n description:\n 'Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.',\n in: getEvent('page view', {\n timestamp: 1700000103,\n user: { email: 'user@example.com', firstName: 'Jane', lastName: 'Doe' },\n }),\n settings: {\n identify: {\n map: {\n email: 'user.email',\n properties: {\n map: {\n firstname: 'user.firstName',\n lastname: 'user.lastName',\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'user@example.com',\n { properties: { firstname: 'Jane', lastname: 'Doe' } },\n 'email',\n ],\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_page_view',\n email: 'user@example.com',\n occurredAt: new Date(1700000103),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * Per-event identify with silent -- user login fires contact upsert only,\n * no custom event sent.\n */\nexport const userLoginIdentify: HubSpotStepExample = {\n title: 'User login identify',\n description:\n 'A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.',\n in: getEvent('user login', {\n timestamp: 1700000104,\n user: { email: 'user@example.com' },\n data: {\n email: 'login@acme.com',\n first_name: 'Jane',\n last_name: 'Doe',\n lifecycle: 'lead',\n },\n }),\n mapping: {\n silent: true,\n settings: {\n identify: {\n map: {\n email: 'data.email',\n properties: {\n map: {\n firstname: 'data.first_name',\n lastname: 'data.last_name',\n lifecyclestage: 'data.lifecycle',\n },\n },\n },\n },\n },\n },\n out: [\n [\n 'crm.contacts.basicApi.update',\n 'login@acme.com',\n {\n properties: {\n firstname: 'Jane',\n lastname: 'Doe',\n lifecyclestage: 'lead',\n },\n },\n 'email',\n ],\n ],\n};\n\n/**\n * objectId association -- use objectId instead of email for contact\n * association on the event.\n */\nexport const objectIdAssociation: HubSpotStepExample = {\n title: 'Object id association',\n description:\n 'The HubSpot event is associated via objectId instead of email, resolved from the walker user id.',\n in: getEvent('product view', {\n timestamp: 1700000105,\n user: { id: 'hs-contact-789' },\n }),\n settings: {\n email: undefined,\n objectId: 'user.id',\n },\n out: [\n [\n 'events.send.basicApi.send',\n {\n eventName: 'pe12345678_product_view',\n objectId: 'hs-contact-789',\n occurredAt: new Date(1700000105),\n properties: {},\n },\n ],\n ],\n};\n\n/**\n * No identity resolved -- event is skipped with a warning. Neither email\n * nor objectId can be resolved from the event.\n */\nexport const noIdentity: HubSpotStepExample = {\n public: false,\n in: getEvent('product view', {\n timestamp: 1700000106,\n user: {},\n }),\n out: [],\n};\n\n/**\n * Wildcard ignore -- the event matches a mapping rule with ignore: true.\n * The destination fires zero SDK calls.\n */\nexport const wildcardIgnored: HubSpotStepExample = {\n public: false,\n in: getEvent('debug noise', {\n timestamp: 1700000107,\n user: { email: 'user@example.com' },\n }),\n mapping: { ignore: true },\n out: [],\n};\n"],"mappings":"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","names":["z"]}
@@ -113,13 +113,13 @@ declare namespace env {
113
113
  * At push time, the destination invokes the `@hubspot/api-client` SDK. The
114
114
  * public method paths users see on the client are:
115
115
  *
116
- * - `events.send.basicApi.send(eventRequest)` fires an event
117
- * - `events.send.batchApi.send({ inputs: [...] })` flushes a batch
118
- * - `crm.contacts.basicApi.update(id, data, idProperty)` contact upsert
116
+ * - `events.send.basicApi.send(eventRequest)` - fires an event
117
+ * - `events.send.batchApi.send({ inputs: [...] })` - flushes a batch
118
+ * - `crm.contacts.basicApi.update(id, data, idProperty)` - contact upsert
119
119
  *
120
120
  * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`
121
121
  * matching the actual SDK call order. `identify` fires before the event.
122
- * When the destination skips an event (`skip: true`, `ignore: true`, or
122
+ * When the destination skips an event (`silent: true`, `ignore: true`, or
123
123
  * missing identity), `out` is `[]`.
124
124
  */
125
125
  /**
@@ -149,7 +149,7 @@ declare const defaultProperties: HubSpotStepExample;
149
149
  */
150
150
  declare const destinationIdentify: HubSpotStepExample;
151
151
  /**
152
- * Per-event identify with skip -- user login fires contact upsert only,
152
+ * Per-event identify with silent -- user login fires contact upsert only,
153
153
  * no custom event sent.
154
154
  */
155
155
  declare const userLoginIdentify: HubSpotStepExample;
@@ -113,13 +113,13 @@ declare namespace env {
113
113
  * At push time, the destination invokes the `@hubspot/api-client` SDK. The
114
114
  * public method paths users see on the client are:
115
115
  *
116
- * - `events.send.basicApi.send(eventRequest)` fires an event
117
- * - `events.send.batchApi.send({ inputs: [...] })` flushes a batch
118
- * - `crm.contacts.basicApi.update(id, data, idProperty)` contact upsert
116
+ * - `events.send.basicApi.send(eventRequest)` - fires an event
117
+ * - `events.send.batchApi.send({ inputs: [...] })` - flushes a batch
118
+ * - `crm.contacts.basicApi.update(id, data, idProperty)` - contact upsert
119
119
  *
120
120
  * Each `out` is therefore a list of tuples `[['method.path', ...args], ...]`
121
121
  * matching the actual SDK call order. `identify` fires before the event.
122
- * When the destination skips an event (`skip: true`, `ignore: true`, or
122
+ * When the destination skips an event (`silent: true`, `ignore: true`, or
123
123
  * missing identity), `out` is `[]`.
124
124
  */
125
125
  /**
@@ -149,7 +149,7 @@ declare const defaultProperties: HubSpotStepExample;
149
149
  */
150
150
  declare const destinationIdentify: HubSpotStepExample;
151
151
  /**
152
- * Per-event identify with skip -- user login fires contact upsert only,
152
+ * Per-event identify with silent -- user login fires contact upsert only,
153
153
  * no custom event sent.
154
154
  */
155
155
  declare const userLoginIdentify: HubSpotStepExample;
@@ -205,7 +205,7 @@ var userLoginIdentify = {
205
205
  }
206
206
  }),
207
207
  mapping: {
208
- skip: true,
208
+ silent: true,
209
209
  settings: {
210
210
  identify: {
211
211
  map: {
@@ -184,7 +184,7 @@ var userLoginIdentify = {
184
184
  }
185
185
  }),
186
186
  mapping: {
187
- skip: true,
187
+ silent: true,
188
188
  settings: {
189
189
  identify: {
190
190
  map: {
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,a={};((e,n)=>{for(var i in n)t(e,i,{get:n[i],enumerable:!0})})(a,{DestinationHubspot:()=>p,default:()=>g,destinationHubspot:()=>f}),module.exports=(e=a,((e,a,r,s)=>{if(a&&"object"==typeof a||"function"==typeof a)for(let c of i(a))o.call(e,c)||c===r||t(e,c,{get:()=>a[c],enumerable:!(s=n(a,c))||s.enumerable});return e})(t({},"__esModule",{value:!0}),e));var r=require("@walkeros/core"),s=async function(e,{config:t,rule:n,collector:i,env:o,logger:a}){var s;const p=t.settings,f=(null==o?void 0:o.client)||p._client;if(!f)return void a.warn("HubSpot client not initialized");const g=p._state||{},v=(null==n?void 0:n.settings)||{},d=p.email?c(await(0,r.getMappingValue)(e,p.email,{collector:i})):void 0,b=p.objectId?c(await(0,r.getMappingValue)(e,p.objectId,{collector:i})):void 0;if(!d&&!b)return void a.warn("HubSpot requires email or objectId; skipping event",{event:e.name});const m=null!=(s=v.identify)?s:p.identify;if(void 0!==m){const t=await(0,r.getMappingValue)(e,m,{collector:i});(0,r.isObject)(t)&&await async function(e,t,n,i){var o;const a=(0,r.isString)(t.email)?t.email:void 0;if(!a)return void i.warn("HubSpot identify requires email; skipping contact upsert");const s=(0,r.isObject)(t.properties)?l(t.properties):void 0,c=function(e){if(!e)return"";try{return JSON.stringify(e)}catch(e){return""}}(s),u=n.lastIdentity||{},p=a!==u.email,f=c!==(null!=(o=u.propertiesHash)?o:"");if(!p&&!f)return;s&&await e.crm.contacts.basicApi.update(a,{properties:s},"email");n.lastIdentity={email:a,propertiesHash:c}}(f,t,g,a)}if(!0!==(null==n?void 0:n.skip)){const t=function(e,t,n){const i=t||n.toLowerCase().replace(/\s+/g,"_");return`${e}${i}`}(p.eventNamePrefix,v.eventName,(0,r.isString)(null==n?void 0:n.name)?n.name:e.name);let o={...p.defaultProperties||{}};if(void 0!==v.properties){const t=await(0,r.getMappingValue)(e,v.properties,{collector:i});(0,r.isObject)(t)&&(o={...o,...l(t)})}const a={eventName:t,occurredAt:new Date(e.timestamp||Date.now()),properties:o};d&&(a.email=d),b&&(a.objectId=b),p.batch?(p._eventQueue||(p._eventQueue=[]),p._eventQueue.push(a),p._eventQueue.length>=(p.batchSize||50)&&await u(f,p)):await f.events.send.basicApi.send(a)}p._state=g};function c(e){if((0,r.isString)(e)&&e.length>0)return e}function l(e){const t={};for(const[n,i]of Object.entries(e))null!=i&&(t[n]=String(i));return t}async function u(e,t){const n=t._eventQueue;if(!n||0===n.length)return;const i=Math.min(t.batchSize||50,500);for(;n.length>0;){const t=n.splice(0,i);await e.events.send.batchApi.send({inputs:t})}}var p={},f={type:"hubspot",config:{},init({config:e,logger:t,env:n}){const i=function(e={},t){var n,i,o;const a=e.settings||{},{accessToken:r,eventNamePrefix:s}=a;r||t.throw("Config settings accessToken missing"),s||t.throw("Config settings eventNamePrefix missing");const c={...a,accessToken:r,eventNamePrefix:s,email:null!=(n=a.email)?n:"user.email",batch:null!=(i=a.batch)&&i,batchSize:Math.min(null!=(o=a.batchSize)?o:50,500)};return{...e,settings:c}}(e,t),o=i.settings;if(!(null==n?void 0:n.client))try{const{Client:e}=require("@hubspot/api-client");o._client=new e({accessToken:o.accessToken})}catch(e){t.throw(`Failed to initialize HubSpot SDK: ${e}`)}return o._state={},o.batch&&(o._eventQueue=[]),i},push:async(e,t)=>await s(e,t),async destroy({config:e}){const t=(null==e?void 0:e.settings)||{};if(t.batch&&t._eventQueue&&t._eventQueue.length>0){const e=t._client;e&&await u(e,t)}}},g=f;//# sourceMappingURL=index.js.map
1
+ "use strict";var e,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,s={};((e,n)=>{for(var i in n)t(e,i,{get:n[i],enumerable:!0})})(s,{DestinationHubspot:()=>p,default:()=>g,destinationHubspot:()=>f}),module.exports=(e=s,((e,s,a,r)=>{if(s&&"object"==typeof s||"function"==typeof s)for(let c of i(s))o.call(e,c)||c===a||t(e,c,{get:()=>s[c],enumerable:!(r=n(s,c))||r.enumerable});return e})(t({},"__esModule",{value:!0}),e));var a=require("@walkeros/core"),r=async function(e,{config:t,rule:n,collector:i,env:o,logger:s}){const r=t.settings,p=o?.client,f=p||r._client;if(!f)return void s.warn("HubSpot client not initialized");const g=r._state||{},b=n?.settings||{},m=r.email?c(await(0,a.getMappingValue)(e,r.email,{collector:i})):void 0,v=r.objectId?c(await(0,a.getMappingValue)(e,r.objectId,{collector:i})):void 0;if(!m&&!v)return void s.warn("HubSpot requires email or objectId; skipping event",{event:e.name});const d=b.identify??r.identify;if(void 0!==d){const t=await(0,a.getMappingValue)(e,d,{collector:i});(0,a.isObject)(t)&&await async function(e,t,n,i){const o=(0,a.isString)(t.email)?t.email:void 0;if(!o)return void i.warn("HubSpot identify requires email; skipping contact upsert");const s=(0,a.isObject)(t.properties)?u(t.properties):void 0,r=function(e){if(!e)return"";try{return JSON.stringify(e)}catch{return""}}(s),c=n.lastIdentity||{},l=o!==c.email,p=r!==(c.propertiesHash??"");if(!l&&!p)return;s&&await e.crm.contacts.basicApi.update(o,{properties:s},"email");n.lastIdentity={email:o,propertiesHash:r}}(f,t,g,s)}if(!0!==n?.silent){const t=function(e,t,n){const i=t||n.toLowerCase().replace(/\s+/g,"_");return`${e}${i}`}(r.eventNamePrefix,b.eventName,(0,a.isString)(n?.name)?n.name:e.name);let o={...r.defaultProperties||{}};if(void 0!==b.properties){const t=await(0,a.getMappingValue)(e,b.properties,{collector:i});(0,a.isObject)(t)&&(o={...o,...u(t)})}const s={eventName:t,occurredAt:new Date(e.timestamp||Date.now()),properties:o};m&&(s.email=m),v&&(s.objectId=v),r.batch?(r._eventQueue||(r._eventQueue=[]),r._eventQueue.push(s),r._eventQueue.length>=(r.batchSize||50)&&await l(f,r)):await f.events.send.basicApi.send(s)}r._state=g};function c(e){if((0,a.isString)(e)&&e.length>0)return e}function u(e){const t={};for(const[n,i]of Object.entries(e))null!=i&&(t[n]=String(i));return t}async function l(e,t){const n=t._eventQueue;if(!n||0===n.length)return;const i=Math.min(t.batchSize||50,500);for(;n.length>0;){const t=n.splice(0,i);await e.events.send.batchApi.send({inputs:t})}}var p={},f={type:"hubspot",config:{},init({config:e,logger:t,env:n}){const i=function(e={},t){const n=e.settings||{},{accessToken:i,eventNamePrefix:o}=n;i||t.throw("Config settings accessToken missing"),o||t.throw("Config settings eventNamePrefix missing");const s={...n,accessToken:i,eventNamePrefix:o,email:n.email??"user.email",batch:n.batch??!1,batchSize:Math.min(n.batchSize??50,500)};return{...e,settings:s}}(e,t),o=i.settings,s=n?.client;if(!s)try{const{Client:e}=require("@hubspot/api-client");o._client=new e({accessToken:o.accessToken})}catch(e){t.throw(`Failed to initialize HubSpot SDK: ${e}`)}return o._state={},o.batch&&(o._eventQueue=[]),i},push:async(e,t)=>await r(e,t),async destroy({config:e}){const t=e?.settings||{};if(t.batch&&t._eventQueue&&t._eventQueue.length>0){const e=t._client;e&&await l(e,t)}}},g=f;//# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type { Destination, Settings, HubSpotClientMock } from './types';\nimport { getConfig } from './config';\nimport { push, flushBatch } from './push';\n\n// Types\nexport * as DestinationHubspot from './types';\n\nexport const destinationHubspot: Destination = {\n type: 'hubspot',\n\n config: {},\n\n init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n\n // Use env.client mock if provided (testing), otherwise create real SDK\n const envClient = (env as { client?: HubSpotClientMock } | undefined)\n ?.client;\n\n if (!envClient) {\n // Production path: create real HubSpot Client instance\n try {\n const { Client } = require('@hubspot/api-client');\n settings._client = new Client({\n accessToken: settings.accessToken,\n });\n } catch (err) {\n logger.throw(`Failed to initialize HubSpot SDK: ${err}`);\n }\n }\n\n settings._state = {};\n if (settings.batch) settings._eventQueue = [];\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = (config?.settings || {}) as Settings;\n\n // Flush remaining queued events in batch mode\n if (\n settings.batch &&\n settings._eventQueue &&\n settings._eventQueue.length > 0\n ) {\n const sdk = settings._client;\n if (sdk) {\n await flushBatch(sdk, settings);\n }\n }\n },\n};\n\nexport default destinationHubspot;\n","import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, eventNamePrefix } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!eventNamePrefix) logger.throw('Config settings eventNamePrefix missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n eventNamePrefix,\n // Default identity resolution path\n email: settings.email ?? 'user.email',\n // Batch defaults\n batch: settings.batch ?? false,\n batchSize: Math.min(settings.batchSize ?? 50, 500),\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n Settings,\n RuntimeState,\n HubSpotClientMock,\n HubSpotEventRequest,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, collector, env, logger },\n) {\n const settings = config.settings as Settings;\n const envClient = (env as { client?: HubSpotClientMock } | undefined)?.client;\n const sdk = envClient || settings._client;\n\n if (!sdk) {\n logger.warn('HubSpot client not initialized');\n return;\n }\n\n const state: RuntimeState = settings._state || {};\n const mappingSettings = rule?.settings || {};\n\n // 1. Resolve identity from event\n const email = settings.email\n ? resolveString(await getMappingValue(event, settings.email, { collector }))\n : undefined;\n const objectId = settings.objectId\n ? resolveString(\n await getMappingValue(event, settings.objectId, { collector }),\n )\n : undefined;\n\n if (!email && !objectId) {\n logger.warn('HubSpot requires email or objectId; skipping event', {\n event: event.name,\n });\n return;\n }\n\n // 2. Contact upsert -- rule-level overrides destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n await applyIdentify(\n sdk,\n resolved as Record<string, unknown>,\n state,\n logger,\n );\n }\n }\n\n // 3. Send event (unless skip: true)\n if (rule?.skip !== true) {\n const eventName = buildEventName(\n settings.eventNamePrefix,\n mappingSettings.eventName,\n isString(rule?.name) ? rule.name : event.name,\n );\n\n // Build properties: defaultProperties + mapped properties, all strings\n let properties: Record<string, string> = {\n ...(settings.defaultProperties || {}),\n };\n\n if (mappingSettings.properties !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.properties,\n { collector },\n );\n if (isObject(resolved)) {\n properties = {\n ...properties,\n ...toStringProperties(resolved as Record<string, unknown>),\n };\n }\n }\n\n const occurredAt = new Date(event.timestamp || Date.now());\n\n const eventRequest: HubSpotEventRequest = {\n eventName,\n occurredAt,\n properties,\n };\n\n // Attach identity\n if (email) eventRequest.email = email;\n if (objectId) eventRequest.objectId = objectId;\n\n if (settings.batch) {\n // Queue for batch flush\n if (!settings._eventQueue) settings._eventQueue = [];\n settings._eventQueue.push(eventRequest);\n\n if (settings._eventQueue.length >= (settings.batchSize || 50)) {\n await flushBatch(sdk, settings);\n }\n } else {\n await sdk.events.send.basicApi.send(eventRequest);\n }\n }\n\n settings._state = state;\n};\n\nfunction resolveString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n return undefined;\n}\n\nfunction buildEventName(\n prefix: string,\n override: string | undefined,\n eventName: string,\n): string {\n const name = override || eventName.toLowerCase().replace(/\\s+/g, '_');\n return `${prefix}${name}`;\n}\n\n/**\n * Serialize all values to strings per HubSpot's API contract.\n */\nexport function toStringProperties(\n data: Record<string, unknown>,\n): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(data)) {\n if (value !== undefined && value !== null) {\n result[key] = String(value);\n }\n }\n return result;\n}\n\nfunction hashProperties(\n properties: Record<string, string> | undefined,\n): string {\n if (!properties) return '';\n try {\n return JSON.stringify(properties);\n } catch {\n return '';\n }\n}\n\nasync function applyIdentify(\n sdk: HubSpotClientMock,\n resolved: Record<string, unknown>,\n state: RuntimeState,\n logger: Logger.Instance,\n): Promise<void> {\n const identifyEmail = isString(resolved.email) ? resolved.email : undefined;\n if (!identifyEmail) {\n logger.warn('HubSpot identify requires email; skipping contact upsert');\n return;\n }\n\n const rawProperties = isObject(resolved.properties)\n ? toStringProperties(resolved.properties as Record<string, unknown>)\n : undefined;\n\n const propertiesHash = hashProperties(rawProperties);\n const last = state.lastIdentity || {};\n\n const emailChanged = identifyEmail !== last.email;\n const propertiesChanged = propertiesHash !== (last.propertiesHash ?? '');\n\n if (!emailChanged && !propertiesChanged) return;\n\n if (rawProperties) {\n await sdk.crm.contacts.basicApi.update(\n identifyEmail,\n { properties: rawProperties },\n 'email',\n );\n }\n\n state.lastIdentity = {\n email: identifyEmail,\n propertiesHash,\n };\n}\n\nexport async function flushBatch(\n sdk: HubSpotClientMock,\n settings: Settings,\n): Promise<void> {\n const queue = settings._eventQueue;\n if (!queue || queue.length === 0) return;\n\n // Flush in chunks of batchSize (max 500)\n const batchSize = Math.min(settings.batchSize || 50, 500);\n while (queue.length > 0) {\n const batch = queue.splice(0, batchSize);\n await sdk.events.send.batchApi.send({ inputs: batch });\n }\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/** Shape of a single custom event occurrence sent to HubSpot. */\nexport interface HubSpotEventRequest {\n eventName: string;\n email?: string;\n objectId?: string;\n utk?: string;\n uuid?: string;\n occurredAt?: Date;\n properties?: Record<string, string>;\n}\n\n/**\n * Mock-friendly interface for the HubSpot Client methods the destination\n * actually calls. Tests provide this via env.client instead of the real SDK.\n */\nexport interface HubSpotClientMock {\n events: {\n send: {\n basicApi: {\n send: (data: HubSpotEventRequest) => Promise<void>;\n };\n batchApi: {\n send: (data: { inputs: HubSpotEventRequest[] }) => Promise<void>;\n };\n };\n };\n crm: {\n contacts: {\n basicApi: {\n update: (\n id: string,\n data: { properties: Record<string, string> },\n idProperty?: string,\n ) => Promise<void>;\n };\n };\n };\n}\n\nexport interface Settings {\n /** HubSpot private app access token (required). */\n accessToken: string;\n\n /**\n * Fully qualified event name prefix: pe{HubID}_\n * Used to construct eventName from walkerOS event names.\n * Example: 'pe12345678_'\n */\n eventNamePrefix: string;\n\n /**\n * walkerOS mapping value path to resolve contact email from events.\n * Default: 'user.email'\n */\n email?: string;\n\n /**\n * walkerOS mapping value path to resolve HubSpot objectId from events.\n * Default: undefined (use email for association)\n */\n objectId?: string;\n\n /**\n * Destination-level contact upsert mapping.\n * Resolves to { email, properties } and upserts the contact on each push\n * (with dedup via state hash).\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Static event properties added to every event occurrence.\n * Useful for hs_touchpoint_source, hs_page_content_type, etc.\n */\n defaultProperties?: Record<string, string>;\n\n /**\n * Whether to use batch API for events (accumulate and flush).\n * Default: false (single event sends).\n */\n batch?: boolean;\n\n /**\n * Batch size before auto-flush. Only used when batch: true.\n * Default: 50. Max: 500.\n */\n batchSize?: number;\n\n /** Runtime state -- not user-facing. Mutated by init/push. */\n _client?: HubSpotClientMock;\n _state?: RuntimeState;\n _eventQueue?: HubSpotEventRequest[];\n}\n\nexport interface RuntimeState {\n lastIdentity?: {\n email?: string;\n propertiesHash?: string;\n };\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings.\n */\nexport interface Mapping {\n /**\n * Override eventName for this rule. If not set, the walkerOS event name\n * is transformed: spaces to underscores, lowercased, prefixed with\n * eventNamePrefix.\n */\n eventName?: string;\n\n /**\n * Per-event contact upsert. Resolves to { email, properties }.\n * Overrides destination-level identify.\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Additional event properties mapping. Resolved values are merged\n * with defaultProperties and sent as the event's properties field.\n */\n properties?: WalkerOSMapping.Value;\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination creates a real Client instance. Tests provide a mock via\n * env.client.\n */\nexport interface Env extends DestinationServer.Env {\n client?: HubSpotClientMock;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type { Destination, Settings, HubSpotClientMock } from './types';\nimport { getConfig } from './config';\nimport { push, flushBatch } from './push';\n\n// Types\nexport * as DestinationHubspot from './types';\n\nexport const destinationHubspot: Destination = {\n type: 'hubspot',\n\n config: {},\n\n init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n\n // Use env.client mock if provided (testing), otherwise create real SDK\n const envClient = (env as { client?: HubSpotClientMock } | undefined)\n ?.client;\n\n if (!envClient) {\n // Production path: create real HubSpot Client instance\n try {\n const { Client } = require('@hubspot/api-client');\n settings._client = new Client({\n accessToken: settings.accessToken,\n });\n } catch (err) {\n logger.throw(`Failed to initialize HubSpot SDK: ${err}`);\n }\n }\n\n settings._state = {};\n if (settings.batch) settings._eventQueue = [];\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = (config?.settings || {}) as Settings;\n\n // Flush remaining queued events in batch mode\n if (\n settings.batch &&\n settings._eventQueue &&\n settings._eventQueue.length > 0\n ) {\n const sdk = settings._client;\n if (sdk) {\n await flushBatch(sdk, settings);\n }\n }\n },\n};\n\nexport default destinationHubspot;\n","import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, eventNamePrefix } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!eventNamePrefix) logger.throw('Config settings eventNamePrefix missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n eventNamePrefix,\n // Default identity resolution path\n email: settings.email ?? 'user.email',\n // Batch defaults\n batch: settings.batch ?? false,\n batchSize: Math.min(settings.batchSize ?? 50, 500),\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n Settings,\n RuntimeState,\n HubSpotClientMock,\n HubSpotEventRequest,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, collector, env, logger },\n) {\n const settings = config.settings as Settings;\n const envClient = (env as { client?: HubSpotClientMock } | undefined)?.client;\n const sdk = envClient || settings._client;\n\n if (!sdk) {\n logger.warn('HubSpot client not initialized');\n return;\n }\n\n const state: RuntimeState = settings._state || {};\n const mappingSettings = rule?.settings || {};\n\n // 1. Resolve identity from event\n const email = settings.email\n ? resolveString(await getMappingValue(event, settings.email, { collector }))\n : undefined;\n const objectId = settings.objectId\n ? resolveString(\n await getMappingValue(event, settings.objectId, { collector }),\n )\n : undefined;\n\n if (!email && !objectId) {\n logger.warn('HubSpot requires email or objectId; skipping event', {\n event: event.name,\n });\n return;\n }\n\n // 2. Contact upsert -- rule-level overrides destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n await applyIdentify(\n sdk,\n resolved as Record<string, unknown>,\n state,\n logger,\n );\n }\n }\n\n // 3. Send event (unless silent: true)\n if (rule?.silent !== true) {\n const eventName = buildEventName(\n settings.eventNamePrefix,\n mappingSettings.eventName,\n isString(rule?.name) ? rule.name : event.name,\n );\n\n // Build properties: defaultProperties + mapped properties, all strings\n let properties: Record<string, string> = {\n ...(settings.defaultProperties || {}),\n };\n\n if (mappingSettings.properties !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.properties,\n { collector },\n );\n if (isObject(resolved)) {\n properties = {\n ...properties,\n ...toStringProperties(resolved as Record<string, unknown>),\n };\n }\n }\n\n const occurredAt = new Date(event.timestamp || Date.now());\n\n const eventRequest: HubSpotEventRequest = {\n eventName,\n occurredAt,\n properties,\n };\n\n // Attach identity\n if (email) eventRequest.email = email;\n if (objectId) eventRequest.objectId = objectId;\n\n if (settings.batch) {\n // Queue for batch flush\n if (!settings._eventQueue) settings._eventQueue = [];\n settings._eventQueue.push(eventRequest);\n\n if (settings._eventQueue.length >= (settings.batchSize || 50)) {\n await flushBatch(sdk, settings);\n }\n } else {\n await sdk.events.send.basicApi.send(eventRequest);\n }\n }\n\n settings._state = state;\n};\n\nfunction resolveString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n return undefined;\n}\n\nfunction buildEventName(\n prefix: string,\n override: string | undefined,\n eventName: string,\n): string {\n const name = override || eventName.toLowerCase().replace(/\\s+/g, '_');\n return `${prefix}${name}`;\n}\n\n/**\n * Serialize all values to strings per HubSpot's API contract.\n */\nexport function toStringProperties(\n data: Record<string, unknown>,\n): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(data)) {\n if (value !== undefined && value !== null) {\n result[key] = String(value);\n }\n }\n return result;\n}\n\nfunction hashProperties(\n properties: Record<string, string> | undefined,\n): string {\n if (!properties) return '';\n try {\n return JSON.stringify(properties);\n } catch {\n return '';\n }\n}\n\nasync function applyIdentify(\n sdk: HubSpotClientMock,\n resolved: Record<string, unknown>,\n state: RuntimeState,\n logger: Logger.Instance,\n): Promise<void> {\n const identifyEmail = isString(resolved.email) ? resolved.email : undefined;\n if (!identifyEmail) {\n logger.warn('HubSpot identify requires email; skipping contact upsert');\n return;\n }\n\n const rawProperties = isObject(resolved.properties)\n ? toStringProperties(resolved.properties as Record<string, unknown>)\n : undefined;\n\n const propertiesHash = hashProperties(rawProperties);\n const last = state.lastIdentity || {};\n\n const emailChanged = identifyEmail !== last.email;\n const propertiesChanged = propertiesHash !== (last.propertiesHash ?? '');\n\n if (!emailChanged && !propertiesChanged) return;\n\n if (rawProperties) {\n await sdk.crm.contacts.basicApi.update(\n identifyEmail,\n { properties: rawProperties },\n 'email',\n );\n }\n\n state.lastIdentity = {\n email: identifyEmail,\n propertiesHash,\n };\n}\n\nexport async function flushBatch(\n sdk: HubSpotClientMock,\n settings: Settings,\n): Promise<void> {\n const queue = settings._eventQueue;\n if (!queue || queue.length === 0) return;\n\n // Flush in chunks of batchSize (max 500)\n const batchSize = Math.min(settings.batchSize || 50, 500);\n while (queue.length > 0) {\n const batch = queue.splice(0, batchSize);\n await sdk.events.send.batchApi.send({ inputs: batch });\n }\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/** Shape of a single custom event occurrence sent to HubSpot. */\nexport interface HubSpotEventRequest {\n eventName: string;\n email?: string;\n objectId?: string;\n utk?: string;\n uuid?: string;\n occurredAt?: Date;\n properties?: Record<string, string>;\n}\n\n/**\n * Mock-friendly interface for the HubSpot Client methods the destination\n * actually calls. Tests provide this via env.client instead of the real SDK.\n */\nexport interface HubSpotClientMock {\n events: {\n send: {\n basicApi: {\n send: (data: HubSpotEventRequest) => Promise<void>;\n };\n batchApi: {\n send: (data: { inputs: HubSpotEventRequest[] }) => Promise<void>;\n };\n };\n };\n crm: {\n contacts: {\n basicApi: {\n update: (\n id: string,\n data: { properties: Record<string, string> },\n idProperty?: string,\n ) => Promise<void>;\n };\n };\n };\n}\n\nexport interface Settings {\n /** HubSpot private app access token (required). */\n accessToken: string;\n\n /**\n * Fully qualified event name prefix: pe{HubID}_\n * Used to construct eventName from walkerOS event names.\n * Example: 'pe12345678_'\n */\n eventNamePrefix: string;\n\n /**\n * walkerOS mapping value path to resolve contact email from events.\n * Default: 'user.email'\n */\n email?: string;\n\n /**\n * walkerOS mapping value path to resolve HubSpot objectId from events.\n * Default: undefined (use email for association)\n */\n objectId?: string;\n\n /**\n * Destination-level contact upsert mapping.\n * Resolves to { email, properties } and upserts the contact on each push\n * (with dedup via state hash).\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Static event properties added to every event occurrence.\n * Useful for hs_touchpoint_source, hs_page_content_type, etc.\n */\n defaultProperties?: Record<string, string>;\n\n /**\n * Whether to use batch API for events (accumulate and flush).\n * Default: false (single event sends).\n */\n batch?: boolean;\n\n /**\n * Batch size before auto-flush. Only used when batch: true.\n * Default: 50. Max: 500.\n */\n batchSize?: number;\n\n /** Runtime state -- not user-facing. Mutated by init/push. */\n _client?: HubSpotClientMock;\n _state?: RuntimeState;\n _eventQueue?: HubSpotEventRequest[];\n}\n\nexport interface RuntimeState {\n lastIdentity?: {\n email?: string;\n propertiesHash?: string;\n };\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings.\n */\nexport interface Mapping {\n /**\n * Override eventName for this rule. If not set, the walkerOS event name\n * is transformed: spaces to underscores, lowercased, prefixed with\n * eventNamePrefix.\n */\n eventName?: string;\n\n /**\n * Per-event contact upsert. Resolves to { email, properties }.\n * Overrides destination-level identify.\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Additional event properties mapping. Resolved values are merged\n * with defaultProperties and sent as the event's properties field.\n */\n properties?: WalkerOSMapping.Value;\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination creates a real Client instance. Tests provide a mock via\n * env.client.\n */\nexport interface Env extends DestinationServer.Env {\n client?: HubSpotClientMock;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var e=(e=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(e,{get:(e,t)=>("undefined"!=typeof require?require:e)[t]}):e)(function(e){if("undefined"!=typeof require)return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import{getMappingValue as t,isObject as n,isString as i}from"@walkeros/core";var o=async function(e,{config:o,rule:c,collector:u,env:l,logger:p}){var f;const d=o.settings,v=(null==l?void 0:l.client)||d._client;if(!v)return void p.warn("HubSpot client not initialized");const m=d._state||{},g=(null==c?void 0:c.settings)||{},h=d.email?r(await t(e,d.email,{collector:u})):void 0,b=d.objectId?r(await t(e,d.objectId,{collector:u})):void 0;if(!h&&!b)return void p.warn("HubSpot requires email or objectId; skipping event",{event:e.name});const w=null!=(f=g.identify)?f:d.identify;if(void 0!==w){const o=await t(e,w,{collector:u});n(o)&&await async function(e,t,o,r){var a;const c=i(t.email)?t.email:void 0;if(!c)return void r.warn("HubSpot identify requires email; skipping contact upsert");const u=n(t.properties)?s(t.properties):void 0,l=function(e){if(!e)return"";try{return JSON.stringify(e)}catch(e){return""}}(u),p=o.lastIdentity||{},f=c!==p.email,d=l!==(null!=(a=p.propertiesHash)?a:"");if(!f&&!d)return;u&&await e.crm.contacts.basicApi.update(c,{properties:u},"email");o.lastIdentity={email:c,propertiesHash:l}}(v,o,m,p)}if(!0!==(null==c?void 0:c.skip)){const o=function(e,t,n){const i=t||n.toLowerCase().replace(/\s+/g,"_");return`${e}${i}`}(d.eventNamePrefix,g.eventName,i(null==c?void 0:c.name)?c.name:e.name);let r={...d.defaultProperties||{}};if(void 0!==g.properties){const i=await t(e,g.properties,{collector:u});n(i)&&(r={...r,...s(i)})}const l={eventName:o,occurredAt:new Date(e.timestamp||Date.now()),properties:r};h&&(l.email=h),b&&(l.objectId=b),d.batch?(d._eventQueue||(d._eventQueue=[]),d._eventQueue.push(l),d._eventQueue.length>=(d.batchSize||50)&&await a(v,d)):await v.events.send.basicApi.send(l)}d._state=m};function r(e){if(i(e)&&e.length>0)return e}function s(e){const t={};for(const[n,i]of Object.entries(e))null!=i&&(t[n]=String(i));return t}async function a(e,t){const n=t._eventQueue;if(!n||0===n.length)return;const i=Math.min(t.batchSize||50,500);for(;n.length>0;){const t=n.splice(0,i);await e.events.send.batchApi.send({inputs:t})}}var c={},u={type:"hubspot",config:{},init({config:t,logger:n,env:i}){const o=function(e={},t){var n,i,o;const r=e.settings||{},{accessToken:s,eventNamePrefix:a}=r;s||t.throw("Config settings accessToken missing"),a||t.throw("Config settings eventNamePrefix missing");const c={...r,accessToken:s,eventNamePrefix:a,email:null!=(n=r.email)?n:"user.email",batch:null!=(i=r.batch)&&i,batchSize:Math.min(null!=(o=r.batchSize)?o:50,500)};return{...e,settings:c}}(t,n),r=o.settings;if(!(null==i?void 0:i.client))try{const{Client:t}=e("@hubspot/api-client");r._client=new t({accessToken:r.accessToken})}catch(e){n.throw(`Failed to initialize HubSpot SDK: ${e}`)}return r._state={},r.batch&&(r._eventQueue=[]),o},push:async(e,t)=>await o(e,t),async destroy({config:e}){const t=(null==e?void 0:e.settings)||{};if(t.batch&&t._eventQueue&&t._eventQueue.length>0){const e=t._client;e&&await a(e,t)}}},l=u;export{c as DestinationHubspot,l as default,u as destinationHubspot};//# sourceMappingURL=index.mjs.map
1
+ var e=(e=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(e,{get:(e,t)=>("undefined"!=typeof require?require:e)[t]}):e)(function(e){if("undefined"!=typeof require)return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import{getMappingValue as t,isObject as n,isString as i}from"@walkeros/core";var o=async function(e,{config:o,rule:c,collector:u,env:l,logger:f}){const p=o.settings,d=l?.client,m=d||p._client;if(!m)return void f.warn("HubSpot client not initialized");const v=p._state||{},g=c?.settings||{},h=p.email?r(await t(e,p.email,{collector:u})):void 0,b=p.objectId?r(await t(e,p.objectId,{collector:u})):void 0;if(!h&&!b)return void f.warn("HubSpot requires email or objectId; skipping event",{event:e.name});const w=g.identify??p.identify;if(void 0!==w){const o=await t(e,w,{collector:u});n(o)&&await async function(e,t,o,r){const a=i(t.email)?t.email:void 0;if(!a)return void r.warn("HubSpot identify requires email; skipping contact upsert");const c=n(t.properties)?s(t.properties):void 0,u=function(e){if(!e)return"";try{return JSON.stringify(e)}catch{return""}}(c),l=o.lastIdentity||{},f=a!==l.email,p=u!==(l.propertiesHash??"");if(!f&&!p)return;c&&await e.crm.contacts.basicApi.update(a,{properties:c},"email");o.lastIdentity={email:a,propertiesHash:u}}(m,o,v,f)}if(!0!==c?.silent){const o=function(e,t,n){const i=t||n.toLowerCase().replace(/\s+/g,"_");return`${e}${i}`}(p.eventNamePrefix,g.eventName,i(c?.name)?c.name:e.name);let r={...p.defaultProperties||{}};if(void 0!==g.properties){const i=await t(e,g.properties,{collector:u});n(i)&&(r={...r,...s(i)})}const l={eventName:o,occurredAt:new Date(e.timestamp||Date.now()),properties:r};h&&(l.email=h),b&&(l.objectId=b),p.batch?(p._eventQueue||(p._eventQueue=[]),p._eventQueue.push(l),p._eventQueue.length>=(p.batchSize||50)&&await a(m,p)):await m.events.send.basicApi.send(l)}p._state=v};function r(e){if(i(e)&&e.length>0)return e}function s(e){const t={};for(const[n,i]of Object.entries(e))null!=i&&(t[n]=String(i));return t}async function a(e,t){const n=t._eventQueue;if(!n||0===n.length)return;const i=Math.min(t.batchSize||50,500);for(;n.length>0;){const t=n.splice(0,i);await e.events.send.batchApi.send({inputs:t})}}var c={},u={type:"hubspot",config:{},init({config:t,logger:n,env:i}){const o=function(e={},t){const n=e.settings||{},{accessToken:i,eventNamePrefix:o}=n;i||t.throw("Config settings accessToken missing"),o||t.throw("Config settings eventNamePrefix missing");const r={...n,accessToken:i,eventNamePrefix:o,email:n.email??"user.email",batch:n.batch??!1,batchSize:Math.min(n.batchSize??50,500)};return{...e,settings:r}}(t,n),r=o.settings,s=i?.client;if(!s)try{const{Client:t}=e("@hubspot/api-client");r._client=new t({accessToken:r.accessToken})}catch(e){n.throw(`Failed to initialize HubSpot SDK: ${e}`)}return r._state={},r.batch&&(r._eventQueue=[]),o},push:async(e,t)=>await o(e,t),async destroy({config:e}){const t=e?.settings||{};if(t.batch&&t._eventQueue&&t._eventQueue.length>0){const e=t._client;e&&await a(e,t)}}},l=u;export{c as DestinationHubspot,l as default,u as destinationHubspot};//# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, eventNamePrefix } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!eventNamePrefix) logger.throw('Config settings eventNamePrefix missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n eventNamePrefix,\n // Default identity resolution path\n email: settings.email ?? 'user.email',\n // Batch defaults\n batch: settings.batch ?? false,\n batchSize: Math.min(settings.batchSize ?? 50, 500),\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n Settings,\n RuntimeState,\n HubSpotClientMock,\n HubSpotEventRequest,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, collector, env, logger },\n) {\n const settings = config.settings as Settings;\n const envClient = (env as { client?: HubSpotClientMock } | undefined)?.client;\n const sdk = envClient || settings._client;\n\n if (!sdk) {\n logger.warn('HubSpot client not initialized');\n return;\n }\n\n const state: RuntimeState = settings._state || {};\n const mappingSettings = rule?.settings || {};\n\n // 1. Resolve identity from event\n const email = settings.email\n ? resolveString(await getMappingValue(event, settings.email, { collector }))\n : undefined;\n const objectId = settings.objectId\n ? resolveString(\n await getMappingValue(event, settings.objectId, { collector }),\n )\n : undefined;\n\n if (!email && !objectId) {\n logger.warn('HubSpot requires email or objectId; skipping event', {\n event: event.name,\n });\n return;\n }\n\n // 2. Contact upsert -- rule-level overrides destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n await applyIdentify(\n sdk,\n resolved as Record<string, unknown>,\n state,\n logger,\n );\n }\n }\n\n // 3. Send event (unless skip: true)\n if (rule?.skip !== true) {\n const eventName = buildEventName(\n settings.eventNamePrefix,\n mappingSettings.eventName,\n isString(rule?.name) ? rule.name : event.name,\n );\n\n // Build properties: defaultProperties + mapped properties, all strings\n let properties: Record<string, string> = {\n ...(settings.defaultProperties || {}),\n };\n\n if (mappingSettings.properties !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.properties,\n { collector },\n );\n if (isObject(resolved)) {\n properties = {\n ...properties,\n ...toStringProperties(resolved as Record<string, unknown>),\n };\n }\n }\n\n const occurredAt = new Date(event.timestamp || Date.now());\n\n const eventRequest: HubSpotEventRequest = {\n eventName,\n occurredAt,\n properties,\n };\n\n // Attach identity\n if (email) eventRequest.email = email;\n if (objectId) eventRequest.objectId = objectId;\n\n if (settings.batch) {\n // Queue for batch flush\n if (!settings._eventQueue) settings._eventQueue = [];\n settings._eventQueue.push(eventRequest);\n\n if (settings._eventQueue.length >= (settings.batchSize || 50)) {\n await flushBatch(sdk, settings);\n }\n } else {\n await sdk.events.send.basicApi.send(eventRequest);\n }\n }\n\n settings._state = state;\n};\n\nfunction resolveString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n return undefined;\n}\n\nfunction buildEventName(\n prefix: string,\n override: string | undefined,\n eventName: string,\n): string {\n const name = override || eventName.toLowerCase().replace(/\\s+/g, '_');\n return `${prefix}${name}`;\n}\n\n/**\n * Serialize all values to strings per HubSpot's API contract.\n */\nexport function toStringProperties(\n data: Record<string, unknown>,\n): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(data)) {\n if (value !== undefined && value !== null) {\n result[key] = String(value);\n }\n }\n return result;\n}\n\nfunction hashProperties(\n properties: Record<string, string> | undefined,\n): string {\n if (!properties) return '';\n try {\n return JSON.stringify(properties);\n } catch {\n return '';\n }\n}\n\nasync function applyIdentify(\n sdk: HubSpotClientMock,\n resolved: Record<string, unknown>,\n state: RuntimeState,\n logger: Logger.Instance,\n): Promise<void> {\n const identifyEmail = isString(resolved.email) ? resolved.email : undefined;\n if (!identifyEmail) {\n logger.warn('HubSpot identify requires email; skipping contact upsert');\n return;\n }\n\n const rawProperties = isObject(resolved.properties)\n ? toStringProperties(resolved.properties as Record<string, unknown>)\n : undefined;\n\n const propertiesHash = hashProperties(rawProperties);\n const last = state.lastIdentity || {};\n\n const emailChanged = identifyEmail !== last.email;\n const propertiesChanged = propertiesHash !== (last.propertiesHash ?? '');\n\n if (!emailChanged && !propertiesChanged) return;\n\n if (rawProperties) {\n await sdk.crm.contacts.basicApi.update(\n identifyEmail,\n { properties: rawProperties },\n 'email',\n );\n }\n\n state.lastIdentity = {\n email: identifyEmail,\n propertiesHash,\n };\n}\n\nexport async function flushBatch(\n sdk: HubSpotClientMock,\n settings: Settings,\n): Promise<void> {\n const queue = settings._eventQueue;\n if (!queue || queue.length === 0) return;\n\n // Flush in chunks of batchSize (max 500)\n const batchSize = Math.min(settings.batchSize || 50, 500);\n while (queue.length > 0) {\n const batch = queue.splice(0, batchSize);\n await sdk.events.send.batchApi.send({ inputs: batch });\n }\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/** Shape of a single custom event occurrence sent to HubSpot. */\nexport interface HubSpotEventRequest {\n eventName: string;\n email?: string;\n objectId?: string;\n utk?: string;\n uuid?: string;\n occurredAt?: Date;\n properties?: Record<string, string>;\n}\n\n/**\n * Mock-friendly interface for the HubSpot Client methods the destination\n * actually calls. Tests provide this via env.client instead of the real SDK.\n */\nexport interface HubSpotClientMock {\n events: {\n send: {\n basicApi: {\n send: (data: HubSpotEventRequest) => Promise<void>;\n };\n batchApi: {\n send: (data: { inputs: HubSpotEventRequest[] }) => Promise<void>;\n };\n };\n };\n crm: {\n contacts: {\n basicApi: {\n update: (\n id: string,\n data: { properties: Record<string, string> },\n idProperty?: string,\n ) => Promise<void>;\n };\n };\n };\n}\n\nexport interface Settings {\n /** HubSpot private app access token (required). */\n accessToken: string;\n\n /**\n * Fully qualified event name prefix: pe{HubID}_\n * Used to construct eventName from walkerOS event names.\n * Example: 'pe12345678_'\n */\n eventNamePrefix: string;\n\n /**\n * walkerOS mapping value path to resolve contact email from events.\n * Default: 'user.email'\n */\n email?: string;\n\n /**\n * walkerOS mapping value path to resolve HubSpot objectId from events.\n * Default: undefined (use email for association)\n */\n objectId?: string;\n\n /**\n * Destination-level contact upsert mapping.\n * Resolves to { email, properties } and upserts the contact on each push\n * (with dedup via state hash).\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Static event properties added to every event occurrence.\n * Useful for hs_touchpoint_source, hs_page_content_type, etc.\n */\n defaultProperties?: Record<string, string>;\n\n /**\n * Whether to use batch API for events (accumulate and flush).\n * Default: false (single event sends).\n */\n batch?: boolean;\n\n /**\n * Batch size before auto-flush. Only used when batch: true.\n * Default: 50. Max: 500.\n */\n batchSize?: number;\n\n /** Runtime state -- not user-facing. Mutated by init/push. */\n _client?: HubSpotClientMock;\n _state?: RuntimeState;\n _eventQueue?: HubSpotEventRequest[];\n}\n\nexport interface RuntimeState {\n lastIdentity?: {\n email?: string;\n propertiesHash?: string;\n };\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings.\n */\nexport interface Mapping {\n /**\n * Override eventName for this rule. If not set, the walkerOS event name\n * is transformed: spaces to underscores, lowercased, prefixed with\n * eventNamePrefix.\n */\n eventName?: string;\n\n /**\n * Per-event contact upsert. Resolves to { email, properties }.\n * Overrides destination-level identify.\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Additional event properties mapping. Resolved values are merged\n * with defaultProperties and sent as the event's properties field.\n */\n properties?: WalkerOSMapping.Value;\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination creates a real Client instance. Tests provide a mock via\n * env.client.\n */\nexport interface Env extends DestinationServer.Env {\n client?: HubSpotClientMock;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { Destination, Settings, HubSpotClientMock } from './types';\nimport { getConfig } from './config';\nimport { push, flushBatch } from './push';\n\n// Types\nexport * as DestinationHubspot from './types';\n\nexport const destinationHubspot: Destination = {\n type: 'hubspot',\n\n config: {},\n\n init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n\n // Use env.client mock if provided (testing), otherwise create real SDK\n const envClient = (env as { client?: HubSpotClientMock } | undefined)\n ?.client;\n\n if (!envClient) {\n // Production path: create real HubSpot Client instance\n try {\n const { Client } = require('@hubspot/api-client');\n settings._client = new Client({\n accessToken: settings.accessToken,\n });\n } catch (err) {\n logger.throw(`Failed to initialize HubSpot SDK: ${err}`);\n }\n }\n\n settings._state = {};\n if (settings.batch) settings._eventQueue = [];\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = (config?.settings || {}) as Settings;\n\n // Flush remaining queued events in batch mode\n if (\n settings.batch &&\n settings._eventQueue &&\n settings._eventQueue.length > 0\n ) {\n const sdk = settings._client;\n if (sdk) {\n await flushBatch(sdk, settings);\n }\n }\n },\n};\n\nexport default destinationHubspot;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, eventNamePrefix } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!eventNamePrefix) logger.throw('Config settings eventNamePrefix missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n eventNamePrefix,\n // Default identity resolution path\n email: settings.email ?? 'user.email',\n // Batch defaults\n batch: settings.batch ?? false,\n batchSize: Math.min(settings.batchSize ?? 50, 500),\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n Settings,\n RuntimeState,\n HubSpotClientMock,\n HubSpotEventRequest,\n} from './types';\nimport type { Logger } from '@walkeros/core';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, collector, env, logger },\n) {\n const settings = config.settings as Settings;\n const envClient = (env as { client?: HubSpotClientMock } | undefined)?.client;\n const sdk = envClient || settings._client;\n\n if (!sdk) {\n logger.warn('HubSpot client not initialized');\n return;\n }\n\n const state: RuntimeState = settings._state || {};\n const mappingSettings = rule?.settings || {};\n\n // 1. Resolve identity from event\n const email = settings.email\n ? resolveString(await getMappingValue(event, settings.email, { collector }))\n : undefined;\n const objectId = settings.objectId\n ? resolveString(\n await getMappingValue(event, settings.objectId, { collector }),\n )\n : undefined;\n\n if (!email && !objectId) {\n logger.warn('HubSpot requires email or objectId; skipping event', {\n event: event.name,\n });\n return;\n }\n\n // 2. Contact upsert -- rule-level overrides destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n if (identifyMapping !== undefined) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n await applyIdentify(\n sdk,\n resolved as Record<string, unknown>,\n state,\n logger,\n );\n }\n }\n\n // 3. Send event (unless silent: true)\n if (rule?.silent !== true) {\n const eventName = buildEventName(\n settings.eventNamePrefix,\n mappingSettings.eventName,\n isString(rule?.name) ? rule.name : event.name,\n );\n\n // Build properties: defaultProperties + mapped properties, all strings\n let properties: Record<string, string> = {\n ...(settings.defaultProperties || {}),\n };\n\n if (mappingSettings.properties !== undefined) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.properties,\n { collector },\n );\n if (isObject(resolved)) {\n properties = {\n ...properties,\n ...toStringProperties(resolved as Record<string, unknown>),\n };\n }\n }\n\n const occurredAt = new Date(event.timestamp || Date.now());\n\n const eventRequest: HubSpotEventRequest = {\n eventName,\n occurredAt,\n properties,\n };\n\n // Attach identity\n if (email) eventRequest.email = email;\n if (objectId) eventRequest.objectId = objectId;\n\n if (settings.batch) {\n // Queue for batch flush\n if (!settings._eventQueue) settings._eventQueue = [];\n settings._eventQueue.push(eventRequest);\n\n if (settings._eventQueue.length >= (settings.batchSize || 50)) {\n await flushBatch(sdk, settings);\n }\n } else {\n await sdk.events.send.basicApi.send(eventRequest);\n }\n }\n\n settings._state = state;\n};\n\nfunction resolveString(value: unknown): string | undefined {\n if (isString(value) && value.length > 0) return value;\n return undefined;\n}\n\nfunction buildEventName(\n prefix: string,\n override: string | undefined,\n eventName: string,\n): string {\n const name = override || eventName.toLowerCase().replace(/\\s+/g, '_');\n return `${prefix}${name}`;\n}\n\n/**\n * Serialize all values to strings per HubSpot's API contract.\n */\nexport function toStringProperties(\n data: Record<string, unknown>,\n): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(data)) {\n if (value !== undefined && value !== null) {\n result[key] = String(value);\n }\n }\n return result;\n}\n\nfunction hashProperties(\n properties: Record<string, string> | undefined,\n): string {\n if (!properties) return '';\n try {\n return JSON.stringify(properties);\n } catch {\n return '';\n }\n}\n\nasync function applyIdentify(\n sdk: HubSpotClientMock,\n resolved: Record<string, unknown>,\n state: RuntimeState,\n logger: Logger.Instance,\n): Promise<void> {\n const identifyEmail = isString(resolved.email) ? resolved.email : undefined;\n if (!identifyEmail) {\n logger.warn('HubSpot identify requires email; skipping contact upsert');\n return;\n }\n\n const rawProperties = isObject(resolved.properties)\n ? toStringProperties(resolved.properties as Record<string, unknown>)\n : undefined;\n\n const propertiesHash = hashProperties(rawProperties);\n const last = state.lastIdentity || {};\n\n const emailChanged = identifyEmail !== last.email;\n const propertiesChanged = propertiesHash !== (last.propertiesHash ?? '');\n\n if (!emailChanged && !propertiesChanged) return;\n\n if (rawProperties) {\n await sdk.crm.contacts.basicApi.update(\n identifyEmail,\n { properties: rawProperties },\n 'email',\n );\n }\n\n state.lastIdentity = {\n email: identifyEmail,\n propertiesHash,\n };\n}\n\nexport async function flushBatch(\n sdk: HubSpotClientMock,\n settings: Settings,\n): Promise<void> {\n const queue = settings._eventQueue;\n if (!queue || queue.length === 0) return;\n\n // Flush in chunks of batchSize (max 500)\n const batchSize = Math.min(settings.batchSize || 50, 500);\n while (queue.length > 0) {\n const batch = queue.splice(0, batchSize);\n await sdk.events.send.batchApi.send({ inputs: batch });\n }\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer } from '@walkeros/server-core';\n\n/** Shape of a single custom event occurrence sent to HubSpot. */\nexport interface HubSpotEventRequest {\n eventName: string;\n email?: string;\n objectId?: string;\n utk?: string;\n uuid?: string;\n occurredAt?: Date;\n properties?: Record<string, string>;\n}\n\n/**\n * Mock-friendly interface for the HubSpot Client methods the destination\n * actually calls. Tests provide this via env.client instead of the real SDK.\n */\nexport interface HubSpotClientMock {\n events: {\n send: {\n basicApi: {\n send: (data: HubSpotEventRequest) => Promise<void>;\n };\n batchApi: {\n send: (data: { inputs: HubSpotEventRequest[] }) => Promise<void>;\n };\n };\n };\n crm: {\n contacts: {\n basicApi: {\n update: (\n id: string,\n data: { properties: Record<string, string> },\n idProperty?: string,\n ) => Promise<void>;\n };\n };\n };\n}\n\nexport interface Settings {\n /** HubSpot private app access token (required). */\n accessToken: string;\n\n /**\n * Fully qualified event name prefix: pe{HubID}_\n * Used to construct eventName from walkerOS event names.\n * Example: 'pe12345678_'\n */\n eventNamePrefix: string;\n\n /**\n * walkerOS mapping value path to resolve contact email from events.\n * Default: 'user.email'\n */\n email?: string;\n\n /**\n * walkerOS mapping value path to resolve HubSpot objectId from events.\n * Default: undefined (use email for association)\n */\n objectId?: string;\n\n /**\n * Destination-level contact upsert mapping.\n * Resolves to { email, properties } and upserts the contact on each push\n * (with dedup via state hash).\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Static event properties added to every event occurrence.\n * Useful for hs_touchpoint_source, hs_page_content_type, etc.\n */\n defaultProperties?: Record<string, string>;\n\n /**\n * Whether to use batch API for events (accumulate and flush).\n * Default: false (single event sends).\n */\n batch?: boolean;\n\n /**\n * Batch size before auto-flush. Only used when batch: true.\n * Default: 50. Max: 500.\n */\n batchSize?: number;\n\n /** Runtime state -- not user-facing. Mutated by init/push. */\n _client?: HubSpotClientMock;\n _state?: RuntimeState;\n _eventQueue?: HubSpotEventRequest[];\n}\n\nexport interface RuntimeState {\n lastIdentity?: {\n email?: string;\n propertiesHash?: string;\n };\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings.\n */\nexport interface Mapping {\n /**\n * Override eventName for this rule. If not set, the walkerOS event name\n * is transformed: spaces to underscores, lowercased, prefixed with\n * eventNamePrefix.\n */\n eventName?: string;\n\n /**\n * Per-event contact upsert. Resolves to { email, properties }.\n * Overrides destination-level identify.\n */\n identify?: WalkerOSMapping.Value;\n\n /**\n * Additional event properties mapping. Resolved values are merged\n * with defaultProperties and sent as the event's properties field.\n */\n properties?: WalkerOSMapping.Value;\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination creates a real Client instance. Tests provide a mock via\n * env.client.\n */\nexport interface Env extends DestinationServer.Env {\n client?: HubSpotClientMock;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n","import type { Destination, Settings, HubSpotClientMock } from './types';\nimport { getConfig } from './config';\nimport { push, flushBatch } from './push';\n\n// Types\nexport * as DestinationHubspot from './types';\n\nexport const destinationHubspot: Destination = {\n type: 'hubspot',\n\n config: {},\n\n init({ config: partialConfig, logger, env }) {\n const config = getConfig(partialConfig, logger);\n const settings = config.settings as Settings;\n\n // Use env.client mock if provided (testing), otherwise create real SDK\n const envClient = (env as { client?: HubSpotClientMock } | undefined)\n ?.client;\n\n if (!envClient) {\n // Production path: create real HubSpot Client instance\n try {\n const { Client } = require('@hubspot/api-client');\n settings._client = new Client({\n accessToken: settings.accessToken,\n });\n } catch (err) {\n logger.throw(`Failed to initialize HubSpot SDK: ${err}`);\n }\n }\n\n settings._state = {};\n if (settings.batch) settings._eventQueue = [];\n\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n\n async destroy({ config }) {\n const settings = (config?.settings || {}) as Settings;\n\n // Flush remaining queued events in batch mode\n if (\n settings.batch &&\n settings._eventQueue &&\n settings._eventQueue.length > 0\n ) {\n const sdk = settings._client;\n if (sdk) {\n await flushBatch(sdk, settings);\n }\n }\n },\n};\n\nexport default destinationHubspot;\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/server-destination-hubspot",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777463920154",
5
5
  "type": "destination",
6
6
  "platform": [
7
7
  "server"
@@ -19,7 +19,7 @@
19
19
  "description": "Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase_completed). The eventNamePrefix is prepended automatically."
20
20
  },
21
21
  "identify": {
22
- "description": "Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with skip: true on login/identify events."
22
+ "description": "Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with silent: true on login/identify events."
23
23
  },
24
24
  "properties": {
25
25
  "description": "Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings."
@@ -147,22 +147,15 @@
147
147
  "consent": {
148
148
  "functional": true
149
149
  },
150
- "id": "1700000100-gr0up-1",
150
+ "id": "848cf84d0d2ff715",
151
151
  "trigger": "load",
152
152
  "entity": "product",
153
153
  "action": "view",
154
154
  "timestamp": 1700000100,
155
155
  "timing": 3.14,
156
- "group": "gr0up",
157
- "count": 1,
158
- "version": {
159
- "source": "3.4.2",
160
- "tagging": 1
161
- },
162
156
  "source": {
163
- "type": "web",
164
- "id": "https://localhost:80",
165
- "previous_id": "http://remotehost:9001"
157
+ "type": "collector",
158
+ "schema": "4"
166
159
  }
167
160
  },
168
161
  "out": [
@@ -210,35 +203,21 @@
210
203
  "entity": "child",
211
204
  "data": {
212
205
  "is": "subordinated"
213
- },
214
- "nested": [],
215
- "context": {
216
- "element": [
217
- "child",
218
- 0
219
- ]
220
206
  }
221
207
  }
222
208
  ],
223
209
  "consent": {
224
210
  "functional": true
225
211
  },
226
- "id": "1700000102-gr0up-1",
212
+ "id": "060b27ec1de296ba",
227
213
  "trigger": "load",
228
214
  "entity": "page",
229
215
  "action": "view",
230
216
  "timestamp": 1700000102,
231
217
  "timing": 3.14,
232
- "group": "gr0up",
233
- "count": 1,
234
- "version": {
235
- "source": "3.4.2",
236
- "tagging": 1
237
- },
238
218
  "source": {
239
- "type": "web",
240
- "id": "https://localhost:80",
241
- "previous_id": "http://remotehost:9001"
219
+ "type": "collector",
220
+ "schema": "4"
242
221
  }
243
222
  },
244
223
  "settings": {
@@ -297,35 +276,21 @@
297
276
  "entity": "child",
298
277
  "data": {
299
278
  "is": "subordinated"
300
- },
301
- "nested": [],
302
- "context": {
303
- "element": [
304
- "child",
305
- 0
306
- ]
307
279
  }
308
280
  }
309
281
  ],
310
282
  "consent": {
311
283
  "functional": true
312
284
  },
313
- "id": "1700000103-gr0up-1",
285
+ "id": "be8ded51ff732d36",
314
286
  "trigger": "load",
315
287
  "entity": "page",
316
288
  "action": "view",
317
289
  "timestamp": 1700000103,
318
290
  "timing": 3.14,
319
- "group": "gr0up",
320
- "count": 1,
321
- "version": {
322
- "source": "3.4.2",
323
- "tagging": 1
324
- },
325
291
  "source": {
326
- "type": "web",
327
- "id": "https://localhost:80",
328
- "previous_id": "http://remotehost:9001"
292
+ "type": "collector",
293
+ "schema": "4"
329
294
  }
330
295
  },
331
296
  "settings": {
@@ -440,22 +405,15 @@
440
405
  "consent": {
441
406
  "functional": true
442
407
  },
443
- "id": "1700000101-gr0up-1",
408
+ "id": "027db7f1235cd9fc",
444
409
  "trigger": "load",
445
410
  "entity": "order",
446
411
  "action": "complete",
447
412
  "timestamp": 1700000101,
448
413
  "timing": 3.14,
449
- "group": "gr0up",
450
- "count": 1,
451
- "version": {
452
- "source": "3.4.2",
453
- "tagging": 1
454
- },
455
414
  "source": {
456
- "type": "web",
457
- "id": "https://localhost:80",
458
- "previous_id": "http://remotehost:9001"
415
+ "type": "collector",
416
+ "schema": "4"
459
417
  }
460
418
  },
461
419
  "mapping": {
@@ -515,22 +473,15 @@
515
473
  "consent": {
516
474
  "functional": true
517
475
  },
518
- "id": "1700000106-gr0up-1",
476
+ "id": "c05c25ebedf85296",
519
477
  "trigger": "load",
520
478
  "entity": "product",
521
479
  "action": "view",
522
480
  "timestamp": 1700000106,
523
481
  "timing": 3.14,
524
- "group": "gr0up",
525
- "count": 1,
526
- "version": {
527
- "source": "3.4.2",
528
- "tagging": 1
529
- },
530
482
  "source": {
531
- "type": "web",
532
- "id": "https://localhost:80",
533
- "previous_id": "http://remotehost:9001"
483
+ "type": "collector",
484
+ "schema": "4"
534
485
  }
535
486
  },
536
487
  "out": []
@@ -566,22 +517,15 @@
566
517
  "consent": {
567
518
  "functional": true
568
519
  },
569
- "id": "1700000105-gr0up-1",
520
+ "id": "60b21e86d7a9f3ce",
570
521
  "trigger": "load",
571
522
  "entity": "product",
572
523
  "action": "view",
573
524
  "timestamp": 1700000105,
574
525
  "timing": 3.14,
575
- "group": "gr0up",
576
- "count": 1,
577
- "version": {
578
- "source": "3.4.2",
579
- "tagging": 1
580
- },
581
526
  "source": {
582
- "type": "web",
583
- "id": "https://localhost:80",
584
- "previous_id": "http://remotehost:9001"
527
+ "type": "collector",
528
+ "schema": "4"
585
529
  }
586
530
  },
587
531
  "settings": {
@@ -630,39 +574,25 @@
630
574
  "entity": "child",
631
575
  "data": {
632
576
  "is": "subordinated"
633
- },
634
- "nested": [],
635
- "context": {
636
- "element": [
637
- "child",
638
- 0
639
- ]
640
577
  }
641
578
  }
642
579
  ],
643
580
  "consent": {
644
581
  "functional": true
645
582
  },
646
- "id": "1700000104-gr0up-1",
583
+ "id": "da815a50e35c2351",
647
584
  "trigger": "test",
648
585
  "entity": "user",
649
586
  "action": "login",
650
587
  "timestamp": 1700000104,
651
588
  "timing": 3.14,
652
- "group": "gr0up",
653
- "count": 1,
654
- "version": {
655
- "source": "3.4.2",
656
- "tagging": 1
657
- },
658
589
  "source": {
659
- "type": "web",
660
- "id": "https://localhost:80",
661
- "previous_id": "http://remotehost:9001"
590
+ "type": "collector",
591
+ "schema": "4"
662
592
  }
663
593
  },
664
594
  "mapping": {
665
- "skip": true,
595
+ "silent": true,
666
596
  "settings": {
667
597
  "identify": {
668
598
  "map": {
@@ -727,35 +657,21 @@
727
657
  "entity": "child",
728
658
  "data": {
729
659
  "is": "subordinated"
730
- },
731
- "nested": [],
732
- "context": {
733
- "element": [
734
- "child",
735
- 0
736
- ]
737
660
  }
738
661
  }
739
662
  ],
740
663
  "consent": {
741
664
  "functional": true
742
665
  },
743
- "id": "1700000107-gr0up-1",
666
+ "id": "886db1dba6e2b6f5",
744
667
  "trigger": "test",
745
668
  "entity": "debug",
746
669
  "action": "noise",
747
670
  "timestamp": 1700000107,
748
671
  "timing": 3.14,
749
- "group": "gr0up",
750
- "count": 1,
751
- "version": {
752
- "source": "3.4.2",
753
- "tagging": 1
754
- },
755
672
  "source": {
756
- "type": "web",
757
- "id": "https://localhost:80",
758
- "previous_id": "http://remotehost:9001"
673
+ "type": "collector",
674
+ "schema": "4"
759
675
  }
760
676
  },
761
677
  "mapping": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/server-destination-hubspot",
3
3
  "description": "HubSpot CRM server destination for walkerOS (@hubspot/api-client, custom events + contact upsert)",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777463920154",
5
5
  "license": "MIT",
6
6
  "exports": {
7
7
  ".": {
@@ -35,11 +35,11 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@hubspot/api-client": "^13.0.0",
38
- "@walkeros/core": "3.4.2",
39
- "@walkeros/server-core": "3.4.2"
38
+ "@walkeros/core": "4.0.0-next-1777463920154",
39
+ "@walkeros/server-core": "4.0.0-next-1777463920154"
40
40
  },
41
41
  "devDependencies": {
42
- "@walkeros/collector": "3.4.2"
42
+ "@walkeros/collector": "4.0.0-next-1777463920154"
43
43
  },
44
44
  "repository": {
45
45
  "url": "git+https://github.com/elbwalker/walkerOS.git",