@walkeros/server-destination-customerio 3.4.0-next-1776749829492
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 +73 -0
- package/dist/dev.d.mts +205 -0
- package/dist/dev.d.ts +205 -0
- package/dist/dev.js +1 -0
- package/dist/dev.js.map +1 -0
- package/dist/dev.mjs +1 -0
- package/dist/dev.mjs.map +1 -0
- package/dist/examples/index.d.mts +156 -0
- package/dist/examples/index.d.ts +156 -0
- package/dist/examples/index.js +318 -0
- package/dist/examples/index.mjs +296 -0
- package/dist/index.d.mts +138 -0
- package/dist/index.d.ts +138 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -0
- package/dist/walkerOS.json +1074 -0
- package/package.json +77 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// src/examples/env.ts
|
|
8
|
+
var env_exports = {};
|
|
9
|
+
__export(env_exports, {
|
|
10
|
+
push: () => push,
|
|
11
|
+
simulation: () => simulation
|
|
12
|
+
});
|
|
13
|
+
var asyncIdentify = () => Promise.resolve();
|
|
14
|
+
var asyncEvent = () => Promise.resolve();
|
|
15
|
+
var asyncAnonymous = () => Promise.resolve();
|
|
16
|
+
var asyncPage = () => Promise.resolve();
|
|
17
|
+
var asyncOne = () => Promise.resolve();
|
|
18
|
+
var asyncAddDevice = () => Promise.resolve();
|
|
19
|
+
var asyncDeleteDevice = () => Promise.resolve();
|
|
20
|
+
var asyncMerge = () => Promise.resolve();
|
|
21
|
+
var asyncSend = () => Promise.resolve();
|
|
22
|
+
function createMockTrackClient() {
|
|
23
|
+
return {
|
|
24
|
+
identify: asyncIdentify,
|
|
25
|
+
track: asyncEvent,
|
|
26
|
+
trackAnonymous: asyncAnonymous,
|
|
27
|
+
trackPageView: asyncPage,
|
|
28
|
+
destroy: asyncOne,
|
|
29
|
+
suppress: asyncOne,
|
|
30
|
+
unsuppress: asyncOne,
|
|
31
|
+
addDevice: asyncAddDevice,
|
|
32
|
+
deleteDevice: asyncDeleteDevice,
|
|
33
|
+
mergeCustomers: asyncMerge
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function createMockApiClient() {
|
|
37
|
+
return {
|
|
38
|
+
sendEmail: asyncSend,
|
|
39
|
+
sendPush: asyncSend
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
var push = {
|
|
43
|
+
trackClient: createMockTrackClient(),
|
|
44
|
+
apiClient: createMockApiClient()
|
|
45
|
+
};
|
|
46
|
+
var simulation = [
|
|
47
|
+
"call:trackClient.identify",
|
|
48
|
+
"call:trackClient.track",
|
|
49
|
+
"call:trackClient.trackAnonymous",
|
|
50
|
+
"call:trackClient.trackPageView",
|
|
51
|
+
"call:trackClient.destroy",
|
|
52
|
+
"call:trackClient.suppress",
|
|
53
|
+
"call:trackClient.unsuppress",
|
|
54
|
+
"call:trackClient.addDevice",
|
|
55
|
+
"call:trackClient.deleteDevice",
|
|
56
|
+
"call:trackClient.mergeCustomers",
|
|
57
|
+
"call:apiClient.sendEmail",
|
|
58
|
+
"call:apiClient.sendPush"
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// src/examples/step.ts
|
|
62
|
+
var step_exports = {};
|
|
63
|
+
__export(step_exports, {
|
|
64
|
+
anonymousTrack: () => anonymousTrack,
|
|
65
|
+
defaultTrack: () => defaultTrack,
|
|
66
|
+
destinationIdentify: () => destinationIdentify,
|
|
67
|
+
destroyPerson: () => destroyPerson,
|
|
68
|
+
mappedData: () => mappedData,
|
|
69
|
+
mappedEventName: () => mappedEventName,
|
|
70
|
+
pageView: () => pageView,
|
|
71
|
+
suppressPerson: () => suppressPerson,
|
|
72
|
+
unsuppressPerson: () => unsuppressPerson,
|
|
73
|
+
userLoginIdentify: () => userLoginIdentify,
|
|
74
|
+
wildcardIgnored: () => wildcardIgnored
|
|
75
|
+
});
|
|
76
|
+
import { getEvent } from "@walkeros/core";
|
|
77
|
+
var defaultTrack = {
|
|
78
|
+
in: getEvent("product view", {
|
|
79
|
+
timestamp: 1700000100,
|
|
80
|
+
user: { id: "us3r", session: "s3ss10n" }
|
|
81
|
+
}),
|
|
82
|
+
out: [
|
|
83
|
+
[
|
|
84
|
+
"trackClient.track",
|
|
85
|
+
"us3r",
|
|
86
|
+
{
|
|
87
|
+
name: "product view",
|
|
88
|
+
data: {},
|
|
89
|
+
timestamp: 17e5
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
var mappedEventName = {
|
|
95
|
+
in: getEvent("order complete", {
|
|
96
|
+
timestamp: 1700000101,
|
|
97
|
+
user: { id: "us3r", session: "s3ss10n" }
|
|
98
|
+
}),
|
|
99
|
+
mapping: {
|
|
100
|
+
name: "purchase"
|
|
101
|
+
},
|
|
102
|
+
out: [
|
|
103
|
+
[
|
|
104
|
+
"trackClient.track",
|
|
105
|
+
"us3r",
|
|
106
|
+
{
|
|
107
|
+
name: "purchase",
|
|
108
|
+
data: {},
|
|
109
|
+
timestamp: 17e5
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
]
|
|
113
|
+
};
|
|
114
|
+
var mappedData = {
|
|
115
|
+
in: getEvent("order complete", {
|
|
116
|
+
timestamp: 1700000102,
|
|
117
|
+
user: { id: "us3r", session: "s3ss10n" },
|
|
118
|
+
data: { id: "0rd3r1d", total: 555, currency: "EUR" }
|
|
119
|
+
}),
|
|
120
|
+
mapping: {
|
|
121
|
+
name: "purchase",
|
|
122
|
+
data: {
|
|
123
|
+
map: {
|
|
124
|
+
order_id: "data.id",
|
|
125
|
+
value: "data.total",
|
|
126
|
+
currency: "data.currency"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
out: [
|
|
131
|
+
[
|
|
132
|
+
"trackClient.track",
|
|
133
|
+
"us3r",
|
|
134
|
+
{
|
|
135
|
+
name: "purchase",
|
|
136
|
+
data: { order_id: "0rd3r1d", value: 555, currency: "EUR" },
|
|
137
|
+
timestamp: 17e5
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
]
|
|
141
|
+
};
|
|
142
|
+
var anonymousTrack = {
|
|
143
|
+
in: getEvent("product view", {
|
|
144
|
+
timestamp: 1700000103,
|
|
145
|
+
user: { session: "s3ss10n" }
|
|
146
|
+
}),
|
|
147
|
+
settings: {
|
|
148
|
+
customerId: void 0
|
|
149
|
+
},
|
|
150
|
+
out: [
|
|
151
|
+
[
|
|
152
|
+
"trackClient.trackAnonymous",
|
|
153
|
+
"s3ss10n",
|
|
154
|
+
{
|
|
155
|
+
name: "product view",
|
|
156
|
+
data: {},
|
|
157
|
+
timestamp: 17e5
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
]
|
|
161
|
+
};
|
|
162
|
+
var destinationIdentify = {
|
|
163
|
+
in: getEvent("page view", {
|
|
164
|
+
timestamp: 1700000104,
|
|
165
|
+
user: { id: "us3r", session: "s3ss10n", email: "user@example.com" }
|
|
166
|
+
}),
|
|
167
|
+
settings: {
|
|
168
|
+
identify: {
|
|
169
|
+
map: {
|
|
170
|
+
email: "user.email"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
out: [
|
|
175
|
+
["trackClient.identify", "us3r", { email: "user@example.com" }],
|
|
176
|
+
[
|
|
177
|
+
"trackClient.track",
|
|
178
|
+
"us3r",
|
|
179
|
+
{
|
|
180
|
+
name: "page view",
|
|
181
|
+
data: {},
|
|
182
|
+
timestamp: 17e5
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
]
|
|
186
|
+
};
|
|
187
|
+
var userLoginIdentify = {
|
|
188
|
+
in: getEvent("user login", {
|
|
189
|
+
timestamp: 1700000105,
|
|
190
|
+
user: { id: "us3r", session: "s3ss10n" },
|
|
191
|
+
data: {
|
|
192
|
+
email: "user@acme.com",
|
|
193
|
+
first_name: "Jane",
|
|
194
|
+
plan: "premium"
|
|
195
|
+
}
|
|
196
|
+
}),
|
|
197
|
+
mapping: {
|
|
198
|
+
skip: true,
|
|
199
|
+
settings: {
|
|
200
|
+
identify: {
|
|
201
|
+
map: {
|
|
202
|
+
email: "data.email",
|
|
203
|
+
first_name: "data.first_name",
|
|
204
|
+
plan: "data.plan"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
out: [
|
|
210
|
+
[
|
|
211
|
+
"trackClient.identify",
|
|
212
|
+
"us3r",
|
|
213
|
+
{ email: "user@acme.com", first_name: "Jane", plan: "premium" }
|
|
214
|
+
]
|
|
215
|
+
]
|
|
216
|
+
};
|
|
217
|
+
var pageView = {
|
|
218
|
+
in: getEvent("page view", {
|
|
219
|
+
timestamp: 1700000106,
|
|
220
|
+
user: { id: "us3r", session: "s3ss10n" },
|
|
221
|
+
data: {
|
|
222
|
+
url: "https://example.com/pricing",
|
|
223
|
+
referrer: "https://google.com"
|
|
224
|
+
}
|
|
225
|
+
}),
|
|
226
|
+
mapping: {
|
|
227
|
+
skip: true,
|
|
228
|
+
settings: {
|
|
229
|
+
page: {
|
|
230
|
+
map: {
|
|
231
|
+
url: "data.url",
|
|
232
|
+
referrer: "data.referrer"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
out: [
|
|
238
|
+
[
|
|
239
|
+
"trackClient.trackPageView",
|
|
240
|
+
"us3r",
|
|
241
|
+
"https://example.com/pricing",
|
|
242
|
+
{ referrer: "https://google.com" }
|
|
243
|
+
]
|
|
244
|
+
]
|
|
245
|
+
};
|
|
246
|
+
var destroyPerson = {
|
|
247
|
+
in: getEvent("user delete", {
|
|
248
|
+
timestamp: 1700000107,
|
|
249
|
+
user: { id: "us3r", session: "s3ss10n" }
|
|
250
|
+
}),
|
|
251
|
+
mapping: {
|
|
252
|
+
skip: true,
|
|
253
|
+
settings: {
|
|
254
|
+
destroy: true
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
out: [["trackClient.destroy", "us3r"]]
|
|
258
|
+
};
|
|
259
|
+
var suppressPerson = {
|
|
260
|
+
in: getEvent("user suppress", {
|
|
261
|
+
timestamp: 1700000108,
|
|
262
|
+
user: { id: "us3r", session: "s3ss10n" }
|
|
263
|
+
}),
|
|
264
|
+
mapping: {
|
|
265
|
+
skip: true,
|
|
266
|
+
settings: {
|
|
267
|
+
suppress: true
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
out: [["trackClient.suppress", "us3r"]]
|
|
271
|
+
};
|
|
272
|
+
var unsuppressPerson = {
|
|
273
|
+
in: getEvent("user unsuppress", {
|
|
274
|
+
timestamp: 1700000109,
|
|
275
|
+
user: { id: "us3r", session: "s3ss10n" }
|
|
276
|
+
}),
|
|
277
|
+
mapping: {
|
|
278
|
+
skip: true,
|
|
279
|
+
settings: {
|
|
280
|
+
unsuppress: true
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
out: [["trackClient.unsuppress", "us3r"]]
|
|
284
|
+
};
|
|
285
|
+
var wildcardIgnored = {
|
|
286
|
+
in: getEvent("debug noise", {
|
|
287
|
+
timestamp: 1700000110,
|
|
288
|
+
user: { id: "us3r", session: "s3ss10n" }
|
|
289
|
+
}),
|
|
290
|
+
mapping: { ignore: true },
|
|
291
|
+
out: []
|
|
292
|
+
};
|
|
293
|
+
export {
|
|
294
|
+
env_exports as env,
|
|
295
|
+
step_exports as step
|
|
296
|
+
};
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Mapping as Mapping$1, Destination as Destination$1 } from '@walkeros/core';
|
|
2
|
+
import { DestinationServer } from '@walkeros/server-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mock-friendly interface for the TrackClient methods the
|
|
6
|
+
* destination actually calls. Tests provide this via env.trackClient
|
|
7
|
+
* instead of the real SDK.
|
|
8
|
+
*/
|
|
9
|
+
interface CustomerIoTrackClientMock {
|
|
10
|
+
identify: (customerId: string | number, attributes: Record<string, unknown>) => Promise<void>;
|
|
11
|
+
track: (customerId: string | number, eventData: {
|
|
12
|
+
name: string;
|
|
13
|
+
data?: Record<string, unknown>;
|
|
14
|
+
timestamp?: number;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
trackAnonymous: (anonymousId: string, eventData: {
|
|
17
|
+
name: string;
|
|
18
|
+
data?: Record<string, unknown>;
|
|
19
|
+
timestamp?: number;
|
|
20
|
+
}) => Promise<void>;
|
|
21
|
+
trackPageView: (customerId: string | number, url: string, data?: Record<string, unknown>) => Promise<void>;
|
|
22
|
+
destroy: (customerId: string | number) => Promise<void>;
|
|
23
|
+
suppress: (customerId: string | number) => Promise<void>;
|
|
24
|
+
unsuppress: (customerId: string | number) => Promise<void>;
|
|
25
|
+
addDevice: (customerId: string | number, deviceId: string, platform: string, data?: Record<string, unknown>) => Promise<void>;
|
|
26
|
+
deleteDevice: (customerId: string | number, deviceId: string, platform: string) => Promise<void>;
|
|
27
|
+
mergeCustomers: (primaryType: string, primaryId: string, secondaryType: string, secondaryId: string) => Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Mock-friendly interface for the APIClient methods the
|
|
31
|
+
* destination actually calls. Tests provide this via env.apiClient
|
|
32
|
+
* instead of the real SDK.
|
|
33
|
+
*/
|
|
34
|
+
interface CustomerIoApiClientMock {
|
|
35
|
+
sendEmail: (request: unknown) => Promise<void>;
|
|
36
|
+
sendPush: (request: unknown) => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
interface Settings {
|
|
39
|
+
/** Customer.io Site ID (required for Track API). */
|
|
40
|
+
siteId: string;
|
|
41
|
+
/** Customer.io API Key (required for Track API). */
|
|
42
|
+
apiKey: string;
|
|
43
|
+
/** App API Key for transactional messaging (optional). */
|
|
44
|
+
appApiKey?: string;
|
|
45
|
+
/** Region: 'us' or 'eu'. Default: 'us'. */
|
|
46
|
+
region?: 'us' | 'eu';
|
|
47
|
+
/** HTTP request timeout in ms. Default: 10000. */
|
|
48
|
+
timeout?: number;
|
|
49
|
+
/** walkerOS mapping value path to resolve customerId from each event. */
|
|
50
|
+
customerId?: string;
|
|
51
|
+
/** walkerOS mapping value path to resolve anonymousId from each event. */
|
|
52
|
+
anonymousId?: string;
|
|
53
|
+
/** Destination-level identify mapping (fires identify() on first push / change). */
|
|
54
|
+
identify?: Mapping$1.Value;
|
|
55
|
+
/** Runtime state -- not user-facing. */
|
|
56
|
+
_trackClient?: CustomerIoTrackClientMock;
|
|
57
|
+
_apiClient?: CustomerIoApiClientMock;
|
|
58
|
+
_state?: RuntimeState;
|
|
59
|
+
}
|
|
60
|
+
interface RuntimeState {
|
|
61
|
+
lastIdentity?: {
|
|
62
|
+
customerId?: string;
|
|
63
|
+
attributesHash?: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
type InitSettings = Partial<Settings>;
|
|
67
|
+
/**
|
|
68
|
+
* Per-rule mapping settings. Controls which Customer.io methods are called
|
|
69
|
+
* beyond the default track(). Resolved via getMappingValue() in push().
|
|
70
|
+
*/
|
|
71
|
+
interface Mapping {
|
|
72
|
+
/** Per-event identify attributes. Resolves to { email?, first_name?, ... }. */
|
|
73
|
+
identify?: Mapping$1.Value;
|
|
74
|
+
/** Fire trackPageView(). Resolves to { url, ... }. */
|
|
75
|
+
page?: Mapping$1.Value;
|
|
76
|
+
/** Fire destroy(). Boolean true triggers deletion. */
|
|
77
|
+
destroy?: boolean;
|
|
78
|
+
/** Fire suppress(). Boolean true triggers suppression. */
|
|
79
|
+
suppress?: boolean;
|
|
80
|
+
/** Fire unsuppress(). Boolean true triggers unsuppression. */
|
|
81
|
+
unsuppress?: boolean;
|
|
82
|
+
/** Fire addDevice(). Resolves to { deviceId, platform, data? }. */
|
|
83
|
+
addDevice?: Mapping$1.Value;
|
|
84
|
+
/** Fire deleteDevice(). Resolves to { deviceId, platform }. */
|
|
85
|
+
deleteDevice?: Mapping$1.Value;
|
|
86
|
+
/** Fire mergeCustomers(). Resolves to { primaryType, primaryId, secondaryType, secondaryId }. */
|
|
87
|
+
merge?: Mapping$1.Value;
|
|
88
|
+
/** Fire sendEmail(). Resolves to { to, transactional_message_id, message_data?, identifiers? }. */
|
|
89
|
+
sendEmail?: Mapping$1.Value;
|
|
90
|
+
/** Fire sendPush(). Resolves to { transactional_message_id, message_data?, identifiers? }. */
|
|
91
|
+
sendPush?: Mapping$1.Value;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Env -- optional SDK override. Production leaves this undefined and the
|
|
95
|
+
* destination creates real TrackClient/APIClient instances. Tests provide
|
|
96
|
+
* mocks via env.trackClient and env.apiClient.
|
|
97
|
+
*/
|
|
98
|
+
interface Env extends DestinationServer.Env {
|
|
99
|
+
trackClient?: CustomerIoTrackClientMock;
|
|
100
|
+
apiClient?: CustomerIoApiClientMock;
|
|
101
|
+
}
|
|
102
|
+
type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
|
|
103
|
+
interface Destination extends DestinationServer.Destination<Types> {
|
|
104
|
+
init: DestinationServer.InitFn<Types>;
|
|
105
|
+
}
|
|
106
|
+
type Config = {
|
|
107
|
+
settings: Settings;
|
|
108
|
+
} & DestinationServer.Config<Types>;
|
|
109
|
+
type InitFn = DestinationServer.InitFn<Types>;
|
|
110
|
+
type PushFn = DestinationServer.PushFn<Types>;
|
|
111
|
+
type PartialConfig = DestinationServer.PartialConfig<Types>;
|
|
112
|
+
type PushEvents = DestinationServer.PushEvents<Mapping>;
|
|
113
|
+
type Rule = Mapping$1.Rule<Mapping>;
|
|
114
|
+
type Rules = Mapping$1.Rules<Rule>;
|
|
115
|
+
|
|
116
|
+
type index_Config = Config;
|
|
117
|
+
type index_CustomerIoApiClientMock = CustomerIoApiClientMock;
|
|
118
|
+
type index_CustomerIoTrackClientMock = CustomerIoTrackClientMock;
|
|
119
|
+
type index_Destination = Destination;
|
|
120
|
+
type index_Env = Env;
|
|
121
|
+
type index_InitFn = InitFn;
|
|
122
|
+
type index_InitSettings = InitSettings;
|
|
123
|
+
type index_Mapping = Mapping;
|
|
124
|
+
type index_PartialConfig = PartialConfig;
|
|
125
|
+
type index_PushEvents = PushEvents;
|
|
126
|
+
type index_PushFn = PushFn;
|
|
127
|
+
type index_Rule = Rule;
|
|
128
|
+
type index_Rules = Rules;
|
|
129
|
+
type index_RuntimeState = RuntimeState;
|
|
130
|
+
type index_Settings = Settings;
|
|
131
|
+
type index_Types = Types;
|
|
132
|
+
declare namespace index {
|
|
133
|
+
export type { index_Config as Config, index_CustomerIoApiClientMock as CustomerIoApiClientMock, index_CustomerIoTrackClientMock as CustomerIoTrackClientMock, index_Destination as Destination, index_Env as Env, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PushEvents as PushEvents, index_PushFn as PushFn, index_Rule as Rule, index_Rules as Rules, index_RuntimeState as RuntimeState, index_Settings as Settings, index_Types as Types };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
declare const destinationCustomerIo: Destination;
|
|
137
|
+
|
|
138
|
+
export { index as DestinationCustomerIo, destinationCustomerIo as default, destinationCustomerIo };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Mapping as Mapping$1, Destination as Destination$1 } from '@walkeros/core';
|
|
2
|
+
import { DestinationServer } from '@walkeros/server-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mock-friendly interface for the TrackClient methods the
|
|
6
|
+
* destination actually calls. Tests provide this via env.trackClient
|
|
7
|
+
* instead of the real SDK.
|
|
8
|
+
*/
|
|
9
|
+
interface CustomerIoTrackClientMock {
|
|
10
|
+
identify: (customerId: string | number, attributes: Record<string, unknown>) => Promise<void>;
|
|
11
|
+
track: (customerId: string | number, eventData: {
|
|
12
|
+
name: string;
|
|
13
|
+
data?: Record<string, unknown>;
|
|
14
|
+
timestamp?: number;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
trackAnonymous: (anonymousId: string, eventData: {
|
|
17
|
+
name: string;
|
|
18
|
+
data?: Record<string, unknown>;
|
|
19
|
+
timestamp?: number;
|
|
20
|
+
}) => Promise<void>;
|
|
21
|
+
trackPageView: (customerId: string | number, url: string, data?: Record<string, unknown>) => Promise<void>;
|
|
22
|
+
destroy: (customerId: string | number) => Promise<void>;
|
|
23
|
+
suppress: (customerId: string | number) => Promise<void>;
|
|
24
|
+
unsuppress: (customerId: string | number) => Promise<void>;
|
|
25
|
+
addDevice: (customerId: string | number, deviceId: string, platform: string, data?: Record<string, unknown>) => Promise<void>;
|
|
26
|
+
deleteDevice: (customerId: string | number, deviceId: string, platform: string) => Promise<void>;
|
|
27
|
+
mergeCustomers: (primaryType: string, primaryId: string, secondaryType: string, secondaryId: string) => Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Mock-friendly interface for the APIClient methods the
|
|
31
|
+
* destination actually calls. Tests provide this via env.apiClient
|
|
32
|
+
* instead of the real SDK.
|
|
33
|
+
*/
|
|
34
|
+
interface CustomerIoApiClientMock {
|
|
35
|
+
sendEmail: (request: unknown) => Promise<void>;
|
|
36
|
+
sendPush: (request: unknown) => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
interface Settings {
|
|
39
|
+
/** Customer.io Site ID (required for Track API). */
|
|
40
|
+
siteId: string;
|
|
41
|
+
/** Customer.io API Key (required for Track API). */
|
|
42
|
+
apiKey: string;
|
|
43
|
+
/** App API Key for transactional messaging (optional). */
|
|
44
|
+
appApiKey?: string;
|
|
45
|
+
/** Region: 'us' or 'eu'. Default: 'us'. */
|
|
46
|
+
region?: 'us' | 'eu';
|
|
47
|
+
/** HTTP request timeout in ms. Default: 10000. */
|
|
48
|
+
timeout?: number;
|
|
49
|
+
/** walkerOS mapping value path to resolve customerId from each event. */
|
|
50
|
+
customerId?: string;
|
|
51
|
+
/** walkerOS mapping value path to resolve anonymousId from each event. */
|
|
52
|
+
anonymousId?: string;
|
|
53
|
+
/** Destination-level identify mapping (fires identify() on first push / change). */
|
|
54
|
+
identify?: Mapping$1.Value;
|
|
55
|
+
/** Runtime state -- not user-facing. */
|
|
56
|
+
_trackClient?: CustomerIoTrackClientMock;
|
|
57
|
+
_apiClient?: CustomerIoApiClientMock;
|
|
58
|
+
_state?: RuntimeState;
|
|
59
|
+
}
|
|
60
|
+
interface RuntimeState {
|
|
61
|
+
lastIdentity?: {
|
|
62
|
+
customerId?: string;
|
|
63
|
+
attributesHash?: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
type InitSettings = Partial<Settings>;
|
|
67
|
+
/**
|
|
68
|
+
* Per-rule mapping settings. Controls which Customer.io methods are called
|
|
69
|
+
* beyond the default track(). Resolved via getMappingValue() in push().
|
|
70
|
+
*/
|
|
71
|
+
interface Mapping {
|
|
72
|
+
/** Per-event identify attributes. Resolves to { email?, first_name?, ... }. */
|
|
73
|
+
identify?: Mapping$1.Value;
|
|
74
|
+
/** Fire trackPageView(). Resolves to { url, ... }. */
|
|
75
|
+
page?: Mapping$1.Value;
|
|
76
|
+
/** Fire destroy(). Boolean true triggers deletion. */
|
|
77
|
+
destroy?: boolean;
|
|
78
|
+
/** Fire suppress(). Boolean true triggers suppression. */
|
|
79
|
+
suppress?: boolean;
|
|
80
|
+
/** Fire unsuppress(). Boolean true triggers unsuppression. */
|
|
81
|
+
unsuppress?: boolean;
|
|
82
|
+
/** Fire addDevice(). Resolves to { deviceId, platform, data? }. */
|
|
83
|
+
addDevice?: Mapping$1.Value;
|
|
84
|
+
/** Fire deleteDevice(). Resolves to { deviceId, platform }. */
|
|
85
|
+
deleteDevice?: Mapping$1.Value;
|
|
86
|
+
/** Fire mergeCustomers(). Resolves to { primaryType, primaryId, secondaryType, secondaryId }. */
|
|
87
|
+
merge?: Mapping$1.Value;
|
|
88
|
+
/** Fire sendEmail(). Resolves to { to, transactional_message_id, message_data?, identifiers? }. */
|
|
89
|
+
sendEmail?: Mapping$1.Value;
|
|
90
|
+
/** Fire sendPush(). Resolves to { transactional_message_id, message_data?, identifiers? }. */
|
|
91
|
+
sendPush?: Mapping$1.Value;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Env -- optional SDK override. Production leaves this undefined and the
|
|
95
|
+
* destination creates real TrackClient/APIClient instances. Tests provide
|
|
96
|
+
* mocks via env.trackClient and env.apiClient.
|
|
97
|
+
*/
|
|
98
|
+
interface Env extends DestinationServer.Env {
|
|
99
|
+
trackClient?: CustomerIoTrackClientMock;
|
|
100
|
+
apiClient?: CustomerIoApiClientMock;
|
|
101
|
+
}
|
|
102
|
+
type Types = Destination$1.Types<Settings, Mapping, Env, InitSettings>;
|
|
103
|
+
interface Destination extends DestinationServer.Destination<Types> {
|
|
104
|
+
init: DestinationServer.InitFn<Types>;
|
|
105
|
+
}
|
|
106
|
+
type Config = {
|
|
107
|
+
settings: Settings;
|
|
108
|
+
} & DestinationServer.Config<Types>;
|
|
109
|
+
type InitFn = DestinationServer.InitFn<Types>;
|
|
110
|
+
type PushFn = DestinationServer.PushFn<Types>;
|
|
111
|
+
type PartialConfig = DestinationServer.PartialConfig<Types>;
|
|
112
|
+
type PushEvents = DestinationServer.PushEvents<Mapping>;
|
|
113
|
+
type Rule = Mapping$1.Rule<Mapping>;
|
|
114
|
+
type Rules = Mapping$1.Rules<Rule>;
|
|
115
|
+
|
|
116
|
+
type index_Config = Config;
|
|
117
|
+
type index_CustomerIoApiClientMock = CustomerIoApiClientMock;
|
|
118
|
+
type index_CustomerIoTrackClientMock = CustomerIoTrackClientMock;
|
|
119
|
+
type index_Destination = Destination;
|
|
120
|
+
type index_Env = Env;
|
|
121
|
+
type index_InitFn = InitFn;
|
|
122
|
+
type index_InitSettings = InitSettings;
|
|
123
|
+
type index_Mapping = Mapping;
|
|
124
|
+
type index_PartialConfig = PartialConfig;
|
|
125
|
+
type index_PushEvents = PushEvents;
|
|
126
|
+
type index_PushFn = PushFn;
|
|
127
|
+
type index_Rule = Rule;
|
|
128
|
+
type index_Rules = Rules;
|
|
129
|
+
type index_RuntimeState = RuntimeState;
|
|
130
|
+
type index_Settings = Settings;
|
|
131
|
+
type index_Types = Types;
|
|
132
|
+
declare namespace index {
|
|
133
|
+
export type { index_Config as Config, index_CustomerIoApiClientMock as CustomerIoApiClientMock, index_CustomerIoTrackClientMock as CustomerIoTrackClientMock, index_Destination as Destination, index_Env as Env, index_InitFn as InitFn, index_InitSettings as InitSettings, index_Mapping as Mapping, index_PartialConfig as PartialConfig, index_PushEvents as PushEvents, index_PushFn as PushFn, index_Rule as Rule, index_Rules as Rules, index_RuntimeState as RuntimeState, index_Settings as Settings, index_Types as Types };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
declare const destinationCustomerIo: Destination;
|
|
137
|
+
|
|
138
|
+
export { index as DestinationCustomerIo, destinationCustomerIo as default, destinationCustomerIo };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e,t=Object.defineProperty,i=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,a={};((e,i)=>{for(var n in i)t(e,n,{get:i[n],enumerable:!0})})(a,{DestinationCustomerIo:()=>l,default:()=>d,destinationCustomerIo:()=>u}),module.exports=(e=a,((e,a,r,s)=>{if(a&&"object"==typeof a||"function"==typeof a)for(let c of n(a))o.call(e,c)||c===r||t(e,c,{get:()=>a[c],enumerable:!(s=i(a,c))||s.enumerable});return e})(t({},"__esModule",{value:!0}),e));var r=require("@walkeros/core"),s=async function(e,{config:t,rule:i,data:n,collector:o,env:a,logger:s}){var l;const u=t.settings,d=a,p=(null==d?void 0:d.trackClient)||u._trackClient,g=(null==d?void 0:d.apiClient)||u._apiClient;if(!p)return void s.warn("Customer.io TrackClient not initialized");const m=u._state||{},f=(null==i?void 0:i.settings)||{},y=e.timestamp?Math.floor(e.timestamp/1e3):void 0,v=u.customerId?c(await(0,r.getMappingValue)(e,u.customerId,{collector:o})):void 0,w=u.anonymousId?c(await(0,r.getMappingValue)(e,u.anonymousId,{collector:o})):void 0;if(!v&&!w)return void s.warn("Customer.io requires customerId or anonymousId; skipping event",{event:e.name});const I=null!=(l=f.identify)?l:u.identify;if(void 0!==I&&v){const t=await(0,r.getMappingValue)(e,I,{collector:o});(0,r.isObject)(t)&&await async function(e,t,i,n){var o;const a=n.lastIdentity||{},r=function(e){if(!e)return"";try{return JSON.stringify(e)}catch(e){return""}}(i),s=t!==a.customerId,c=r!==(null!=(o=a.attributesHash)?o:"");if(!s&&!c)return;await e.identify(t,i),n.lastIdentity={customerId:t,attributesHash:r}}(p,v,t,m)}if(void 0!==f.page&&v){const t=await(0,r.getMappingValue)(e,f.page,{collector:o});if((0,r.isObject)(t)){const e=t,i=(0,r.isString)(e.url)?e.url:void 0;if(i){const{url:t,...n}=e,o=Object.keys(n).length>0?n:void 0;await p.trackPageView(v,i,o)}}}if(!0===f.destroy&&v&&await p.destroy(v),!0===f.suppress&&v&&await p.suppress(v),!0===f.unsuppress&&v&&await p.unsuppress(v),void 0!==f.addDevice&&v){const t=await(0,r.getMappingValue)(e,f.addDevice,{collector:o});if((0,r.isObject)(t)){const e=t;(0,r.isString)(e.deviceId)&&(0,r.isString)(e.platform)&&await p.addDevice(v,e.deviceId,e.platform,(0,r.isObject)(e.data)?e.data:void 0)}}if(void 0!==f.deleteDevice&&v){const t=await(0,r.getMappingValue)(e,f.deleteDevice,{collector:o});if((0,r.isObject)(t)){const e=t;(0,r.isString)(e.deviceId)&&(0,r.isString)(e.platform)&&await p.deleteDevice(v,e.deviceId,e.platform)}}if(void 0!==f.merge&&v){const t=await(0,r.getMappingValue)(e,f.merge,{collector:o});if((0,r.isObject)(t)){const e=t;(0,r.isString)(e.primaryType)&&(0,r.isString)(e.primaryId)&&(0,r.isString)(e.secondaryType)&&(0,r.isString)(e.secondaryId)&&await p.mergeCustomers(e.primaryType,e.primaryId,e.secondaryType,e.secondaryId)}}if(void 0!==f.sendEmail&&g){const t=await(0,r.getMappingValue)(e,f.sendEmail,{collector:o});(0,r.isObject)(t)&&await g.sendEmail(t)}if(void 0!==f.sendPush&&g){const t=await(0,r.getMappingValue)(e,f.sendPush,{collector:o});(0,r.isObject)(t)&&await g.sendPush(t)}if(!0!==(null==i?void 0:i.skip)){const t=(0,r.isString)(null==i?void 0:i.name)?i.name:e.name,o=(0,r.isObject)(n)?n:{},a={name:t};a.data=o,void 0!==y&&(a.timestamp=y),v?await p.track(v,a):w&&await p.trackAnonymous(w,a)}u._state=m};function c(e){if((0,r.isString)(e)&&e.length>0)return e}var l={},u={type:"customerio",config:{},init({config:e,logger:t,env:i}){const n=function(e={},t){var i,n;const o=e.settings||{},{siteId:a,apiKey:r}=o;a||t.throw("Config settings siteId missing"),r||t.throw("Config settings apiKey missing");const s={...o,siteId:a,apiKey:r,customerId:null!=(i=o.customerId)?i:"user.id",anonymousId:null!=(n=o.anonymousId)?n:"user.session"};return{...e,settings:s}}(e,t),o=n.settings,a=i;if(!(null==a?void 0:a.trackClient))try{const e=require("customerio-node"),{TrackClient:t,RegionUS:i,RegionEU:n}=e,a="eu"===o.region?n:i,r=new t(o.siteId,o.apiKey,{region:a,...o.timeout?{timeout:o.timeout}:{}});o._trackClient=r}catch(e){t.throw(`Failed to initialize Customer.io TrackClient: ${e}`)}if(!(null==a?void 0:a.apiClient)&&o.appApiKey)try{const e=require("customerio-node"),{APIClient:t,RegionUS:i,RegionEU:n}=e,a="eu"===o.region?n:i,r=new t(o.appApiKey,{region:a,...o.timeout?{timeout:o.timeout}:{}});o._apiClient=r}catch(e){t.throw(`Failed to initialize Customer.io APIClient: ${e}`)}return o._state={},n},push:async(e,t)=>await s(e,t),async destroy({config:e}){const t=(null==e?void 0:e.settings)||{};t._trackClient=void 0,t._apiClient=void 0}},d=u;//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/push.ts","../src/types/index.ts"],"sourcesContent":["import type {\n Destination,\n Settings,\n CustomerIoTrackClientMock,\n CustomerIoApiClientMock,\n} from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationCustomerIo from './types';\n\nexport const destinationCustomerIo: Destination = {\n type: 'customerio',\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 mocks if provided (testing), otherwise create real SDK clients\n const envTyped = env as\n | {\n trackClient?: CustomerIoTrackClientMock;\n apiClient?: CustomerIoApiClientMock;\n }\n | undefined;\n\n if (!envTyped?.trackClient) {\n // Production path: create real TrackClient\n try {\n // Use dynamic require to allow tests to mock via jest.mock('customerio-node').\n const customerioSdk = require('customerio-node');\n const { TrackClient, RegionUS, RegionEU } = customerioSdk;\n const region = settings.region === 'eu' ? RegionEU : RegionUS;\n const trackClient = new TrackClient(settings.siteId, settings.apiKey, {\n region,\n ...(settings.timeout ? { timeout: settings.timeout } : {}),\n });\n settings._trackClient = trackClient as CustomerIoTrackClientMock;\n } catch (err) {\n logger.throw(`Failed to initialize Customer.io TrackClient: ${err}`);\n }\n }\n\n if (!envTyped?.apiClient && settings.appApiKey) {\n // Production path: create real APIClient for transactional messaging\n try {\n const customerioSdk = require('customerio-node');\n const { APIClient, RegionUS, RegionEU } = customerioSdk;\n const region = settings.region === 'eu' ? RegionEU : RegionUS;\n const apiClient = new APIClient(settings.appApiKey, {\n region,\n ...(settings.timeout ? { timeout: settings.timeout } : {}),\n });\n settings._apiClient = apiClient as CustomerIoApiClientMock;\n } catch (err) {\n logger.throw(`Failed to initialize Customer.io APIClient: ${err}`);\n }\n }\n\n settings._state = {};\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 // TrackClient has no flush -- just clear references\n settings._trackClient = undefined;\n settings._apiClient = undefined;\n },\n};\n\nexport default destinationCustomerIo;\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 { siteId, apiKey } = settings;\n\n if (!siteId) logger.throw('Config settings siteId missing');\n if (!apiKey) logger.throw('Config settings apiKey missing');\n\n const settingsConfig: Settings = {\n ...settings,\n siteId: siteId as string,\n apiKey: apiKey as string,\n // Default identity resolution paths\n customerId: settings.customerId ?? 'user.id',\n anonymousId: settings.anonymousId ?? 'user.session',\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n PushFn,\n Settings,\n RuntimeState,\n CustomerIoTrackClientMock,\n CustomerIoApiClientMock,\n} from './types';\nimport { getMappingValue, isObject, isString } from '@walkeros/core';\n\nexport const push: PushFn = async function (\n event,\n { config, rule, data, collector, env, logger },\n) {\n const settings = config.settings as Settings;\n const envTyped = env as\n | {\n trackClient?: CustomerIoTrackClientMock;\n apiClient?: CustomerIoApiClientMock;\n }\n | undefined;\n const trackClient = envTyped?.trackClient || settings._trackClient;\n const apiClient = envTyped?.apiClient || settings._apiClient;\n\n if (!trackClient) {\n logger.warn('Customer.io TrackClient not initialized');\n return;\n }\n\n const state: RuntimeState = settings._state || {};\n const mappingSettings = rule?.settings || {};\n\n // Convert ms timestamp to Unix seconds\n const timestampSec = event.timestamp\n ? Math.floor(event.timestamp / 1000)\n : undefined;\n\n // 1. Resolve identity from event\n const customerId = settings.customerId\n ? resolveString(\n await getMappingValue(event, settings.customerId, { collector }),\n )\n : undefined;\n const anonymousId = settings.anonymousId\n ? resolveString(\n await getMappingValue(event, settings.anonymousId, { collector }),\n )\n : undefined;\n\n if (!customerId && !anonymousId) {\n logger.warn(\n 'Customer.io requires customerId or anonymousId; skipping event',\n { event: event.name },\n );\n return;\n }\n\n // 2. Identify -- rule-level overrides destination-level\n const identifyMapping = mappingSettings.identify ?? settings.identify;\n if (identifyMapping !== undefined && customerId) {\n const resolved = await getMappingValue(event, identifyMapping, {\n collector,\n });\n if (isObject(resolved)) {\n await applyIdentify(\n trackClient,\n customerId,\n resolved as Record<string, unknown>,\n state,\n );\n }\n }\n\n // 3. Page (trackPageView)\n if (mappingSettings.page !== undefined && customerId) {\n const resolved = await getMappingValue(event, mappingSettings.page, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as { url?: unknown; [key: string]: unknown };\n const url = isString(r.url) ? r.url : undefined;\n if (url) {\n const { url: _u, ...extraData } = r;\n void _u;\n const pageData =\n Object.keys(extraData).length > 0 ? extraData : undefined;\n await trackClient.trackPageView(customerId, url, pageData);\n }\n }\n }\n\n // 4. Destroy / Suppress / Unsuppress\n if (mappingSettings.destroy === true && customerId) {\n await trackClient.destroy(customerId);\n }\n if (mappingSettings.suppress === true && customerId) {\n await trackClient.suppress(customerId);\n }\n if (mappingSettings.unsuppress === true && customerId) {\n await trackClient.unsuppress(customerId);\n }\n\n // 5. Device management\n if (mappingSettings.addDevice !== undefined && customerId) {\n const resolved = await getMappingValue(event, mappingSettings.addDevice, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as {\n deviceId?: unknown;\n platform?: unknown;\n data?: unknown;\n };\n if (isString(r.deviceId) && isString(r.platform)) {\n await trackClient.addDevice(\n customerId,\n r.deviceId,\n r.platform,\n isObject(r.data) ? (r.data as Record<string, unknown>) : undefined,\n );\n }\n }\n }\n if (mappingSettings.deleteDevice !== undefined && customerId) {\n const resolved = await getMappingValue(\n event,\n mappingSettings.deleteDevice,\n { collector },\n );\n if (isObject(resolved)) {\n const r = resolved as { deviceId?: unknown; platform?: unknown };\n if (isString(r.deviceId) && isString(r.platform)) {\n await trackClient.deleteDevice(customerId, r.deviceId, r.platform);\n }\n }\n }\n\n // 6. Merge\n if (mappingSettings.merge !== undefined && customerId) {\n const resolved = await getMappingValue(event, mappingSettings.merge, {\n collector,\n });\n if (isObject(resolved)) {\n const r = resolved as {\n primaryType?: unknown;\n primaryId?: unknown;\n secondaryType?: unknown;\n secondaryId?: unknown;\n };\n if (\n isString(r.primaryType) &&\n isString(r.primaryId) &&\n isString(r.secondaryType) &&\n isString(r.secondaryId)\n ) {\n await trackClient.mergeCustomers(\n r.primaryType,\n r.primaryId,\n r.secondaryType,\n r.secondaryId,\n );\n }\n }\n }\n\n // 7. Transactional (sendEmail / sendPush)\n if (mappingSettings.sendEmail !== undefined && apiClient) {\n const resolved = await getMappingValue(event, mappingSettings.sendEmail, {\n collector,\n });\n if (isObject(resolved)) {\n await apiClient.sendEmail(resolved);\n }\n }\n if (mappingSettings.sendPush !== undefined && apiClient) {\n const resolved = await getMappingValue(event, mappingSettings.sendPush, {\n collector,\n });\n if (isObject(resolved)) {\n await apiClient.sendPush(resolved);\n }\n }\n\n // 8. Track (unless skip: true)\n if (rule?.skip !== true) {\n const eventName = isString(rule?.name) ? rule.name : event.name;\n const properties = isObject(data) ? (data as Record<string, unknown>) : {};\n\n const eventData: {\n name: string;\n data?: Record<string, unknown>;\n timestamp?: number;\n } = { name: eventName };\n eventData.data = properties;\n if (timestampSec !== undefined) eventData.timestamp = timestampSec;\n\n if (customerId) {\n await trackClient.track(customerId, eventData);\n } else if (anonymousId) {\n await trackClient.trackAnonymous(anonymousId, eventData);\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 hashAttributes(attrs: Record<string, unknown> | undefined): string {\n if (!attrs) return '';\n try {\n return JSON.stringify(attrs);\n } catch {\n return '';\n }\n}\n\nasync function applyIdentify(\n trackClient: CustomerIoTrackClientMock,\n customerId: string,\n resolved: Record<string, unknown>,\n state: RuntimeState,\n): Promise<void> {\n const last = state.lastIdentity || {};\n\n const attributesHash = hashAttributes(resolved);\n const customerIdChanged = customerId !== last.customerId;\n const attributesChanged = attributesHash !== (last.attributesHash ?? '');\n\n if (!customerIdChanged && !attributesChanged) return;\n\n await trackClient.identify(customerId, resolved);\n\n state.lastIdentity = {\n customerId,\n attributesHash,\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/**\n * Mock-friendly interface for the TrackClient methods the\n * destination actually calls. Tests provide this via env.trackClient\n * instead of the real SDK.\n */\nexport interface CustomerIoTrackClientMock {\n identify: (\n customerId: string | number,\n attributes: Record<string, unknown>,\n ) => Promise<void>;\n track: (\n customerId: string | number,\n eventData: {\n name: string;\n data?: Record<string, unknown>;\n timestamp?: number;\n },\n ) => Promise<void>;\n trackAnonymous: (\n anonymousId: string,\n eventData: {\n name: string;\n data?: Record<string, unknown>;\n timestamp?: number;\n },\n ) => Promise<void>;\n trackPageView: (\n customerId: string | number,\n url: string,\n data?: Record<string, unknown>,\n ) => Promise<void>;\n destroy: (customerId: string | number) => Promise<void>;\n suppress: (customerId: string | number) => Promise<void>;\n unsuppress: (customerId: string | number) => Promise<void>;\n addDevice: (\n customerId: string | number,\n deviceId: string,\n platform: string,\n data?: Record<string, unknown>,\n ) => Promise<void>;\n deleteDevice: (\n customerId: string | number,\n deviceId: string,\n platform: string,\n ) => Promise<void>;\n mergeCustomers: (\n primaryType: string,\n primaryId: string,\n secondaryType: string,\n secondaryId: string,\n ) => Promise<void>;\n}\n\n/**\n * Mock-friendly interface for the APIClient methods the\n * destination actually calls. Tests provide this via env.apiClient\n * instead of the real SDK.\n */\nexport interface CustomerIoApiClientMock {\n sendEmail: (request: unknown) => Promise<void>;\n sendPush: (request: unknown) => Promise<void>;\n}\n\nexport interface Settings {\n /** Customer.io Site ID (required for Track API). */\n siteId: string;\n /** Customer.io API Key (required for Track API). */\n apiKey: string;\n /** App API Key for transactional messaging (optional). */\n appApiKey?: string;\n /** Region: 'us' or 'eu'. Default: 'us'. */\n region?: 'us' | 'eu';\n /** HTTP request timeout in ms. Default: 10000. */\n timeout?: number;\n /** walkerOS mapping value path to resolve customerId from each event. */\n customerId?: string;\n /** walkerOS mapping value path to resolve anonymousId from each event. */\n anonymousId?: string;\n /** Destination-level identify mapping (fires identify() on first push / change). */\n identify?: WalkerOSMapping.Value;\n /** Runtime state -- not user-facing. */\n _trackClient?: CustomerIoTrackClientMock;\n _apiClient?: CustomerIoApiClientMock;\n _state?: RuntimeState;\n}\n\nexport interface RuntimeState {\n lastIdentity?: {\n customerId?: string;\n attributesHash?: string;\n };\n}\n\nexport type InitSettings = Partial<Settings>;\n\n/**\n * Per-rule mapping settings. Controls which Customer.io methods are called\n * beyond the default track(). Resolved via getMappingValue() in push().\n */\nexport interface Mapping {\n /** Per-event identify attributes. Resolves to { email?, first_name?, ... }. */\n identify?: WalkerOSMapping.Value;\n /** Fire trackPageView(). Resolves to { url, ... }. */\n page?: WalkerOSMapping.Value;\n /** Fire destroy(). Boolean true triggers deletion. */\n destroy?: boolean;\n /** Fire suppress(). Boolean true triggers suppression. */\n suppress?: boolean;\n /** Fire unsuppress(). Boolean true triggers unsuppression. */\n unsuppress?: boolean;\n /** Fire addDevice(). Resolves to { deviceId, platform, data? }. */\n addDevice?: WalkerOSMapping.Value;\n /** Fire deleteDevice(). Resolves to { deviceId, platform }. */\n deleteDevice?: WalkerOSMapping.Value;\n /** Fire mergeCustomers(). Resolves to { primaryType, primaryId, secondaryType, secondaryId }. */\n merge?: WalkerOSMapping.Value;\n /** Fire sendEmail(). Resolves to { to, transactional_message_id, message_data?, identifiers? }. */\n sendEmail?: WalkerOSMapping.Value;\n /** Fire sendPush(). Resolves to { transactional_message_id, message_data?, identifiers? }. */\n sendPush?: WalkerOSMapping.Value;\n}\n\n/**\n * Env -- optional SDK override. Production leaves this undefined and the\n * destination creates real TrackClient/APIClient instances. Tests provide\n * mocks via env.trackClient and env.apiClient.\n */\nexport interface Env extends DestinationServer.Env {\n trackClient?: CustomerIoTrackClientMock;\n apiClient?: CustomerIoApiClientMock;\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
ADDED
|
@@ -0,0 +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 i,isString as o}from"@walkeros/core";var n=async function(e,{config:n,rule:r,data:s,collector:c,env:d,logger:u}){var l;const m=n.settings,p=d,f=(null==p?void 0:p.trackClient)||m._trackClient,y=(null==p?void 0:p.apiClient)||m._apiClient;if(!f)return void u.warn("Customer.io TrackClient not initialized");const v=m._state||{},g=(null==r?void 0:r.settings)||{},w=e.timestamp?Math.floor(e.timestamp/1e3):void 0,I=m.customerId?a(await t(e,m.customerId,{collector:c})):void 0,C=m.anonymousId?a(await t(e,m.anonymousId,{collector:c})):void 0;if(!I&&!C)return void u.warn("Customer.io requires customerId or anonymousId; skipping event",{event:e.name});const h=null!=(l=g.identify)?l:m.identify;if(void 0!==h&&I){const o=await t(e,h,{collector:c});i(o)&&await async function(e,t,i,o){var n;const a=o.lastIdentity||{},r=function(e){if(!e)return"";try{return JSON.stringify(e)}catch(e){return""}}(i),s=t!==a.customerId,c=r!==(null!=(n=a.attributesHash)?n:"");if(!s&&!c)return;await e.identify(t,i),o.lastIdentity={customerId:t,attributesHash:r}}(f,I,o,v)}if(void 0!==g.page&&I){const n=await t(e,g.page,{collector:c});if(i(n)){const e=n,t=o(e.url)?e.url:void 0;if(t){const{url:i,...o}=e,n=Object.keys(o).length>0?o:void 0;await f.trackPageView(I,t,n)}}}if(!0===g.destroy&&I&&await f.destroy(I),!0===g.suppress&&I&&await f.suppress(I),!0===g.unsuppress&&I&&await f.unsuppress(I),void 0!==g.addDevice&&I){const n=await t(e,g.addDevice,{collector:c});if(i(n)){const e=n;o(e.deviceId)&&o(e.platform)&&await f.addDevice(I,e.deviceId,e.platform,i(e.data)?e.data:void 0)}}if(void 0!==g.deleteDevice&&I){const n=await t(e,g.deleteDevice,{collector:c});if(i(n)){const e=n;o(e.deviceId)&&o(e.platform)&&await f.deleteDevice(I,e.deviceId,e.platform)}}if(void 0!==g.merge&&I){const n=await t(e,g.merge,{collector:c});if(i(n)){const e=n;o(e.primaryType)&&o(e.primaryId)&&o(e.secondaryType)&&o(e.secondaryId)&&await f.mergeCustomers(e.primaryType,e.primaryId,e.secondaryType,e.secondaryId)}}if(void 0!==g.sendEmail&&y){const o=await t(e,g.sendEmail,{collector:c});i(o)&&await y.sendEmail(o)}if(void 0!==g.sendPush&&y){const o=await t(e,g.sendPush,{collector:c});i(o)&&await y.sendPush(o)}if(!0!==(null==r?void 0:r.skip)){const t=o(null==r?void 0:r.name)?r.name:e.name,n=i(s)?s:{},a={name:t};a.data=n,void 0!==w&&(a.timestamp=w),I?await f.track(I,a):C&&await f.trackAnonymous(C,a)}m._state=v};function a(e){if(o(e)&&e.length>0)return e}var r={},s={type:"customerio",config:{},init({config:t,logger:i,env:o}){const n=function(e={},t){var i,o;const n=e.settings||{},{siteId:a,apiKey:r}=n;a||t.throw("Config settings siteId missing"),r||t.throw("Config settings apiKey missing");const s={...n,siteId:a,apiKey:r,customerId:null!=(i=n.customerId)?i:"user.id",anonymousId:null!=(o=n.anonymousId)?o:"user.session"};return{...e,settings:s}}(t,i),a=n.settings,r=o;if(!(null==r?void 0:r.trackClient))try{const t=e("customerio-node"),{TrackClient:i,RegionUS:o,RegionEU:n}=t,r="eu"===a.region?n:o,s=new i(a.siteId,a.apiKey,{region:r,...a.timeout?{timeout:a.timeout}:{}});a._trackClient=s}catch(e){i.throw(`Failed to initialize Customer.io TrackClient: ${e}`)}if(!(null==r?void 0:r.apiClient)&&a.appApiKey)try{const t=e("customerio-node"),{APIClient:i,RegionUS:o,RegionEU:n}=t,r="eu"===a.region?n:o,s=new i(a.appApiKey,{region:r,...a.timeout?{timeout:a.timeout}:{}});a._apiClient=s}catch(e){i.throw(`Failed to initialize Customer.io APIClient: ${e}`)}return a._state={},n},push:async(e,t)=>await n(e,t),async destroy({config:e}){const t=(null==e?void 0:e.settings)||{};t._trackClient=void 0,t._apiClient=void 0}},c=s;export{r as DestinationCustomerIo,c as default,s as destinationCustomerIo};//# sourceMappingURL=index.mjs.map
|