@tell-rs/node 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -0
- package/dist/chunk-HYQWDHQT.js +330 -0
- package/dist/chunk-HYQWDHQT.js.map +1 -0
- package/dist/events.cjs +85 -0
- package/dist/events.cjs.map +1 -0
- package/dist/events.d.cts +1 -0
- package/dist/events.d.ts +1 -0
- package/dist/events.js +7 -0
- package/dist/events.js.map +1 -0
- package/dist/index.cjs +829 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +68 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +498 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @tell-rs/node
|
|
2
|
+
|
|
3
|
+
Tell SDK for Node.js — analytics events and structured logging.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
# npm
|
|
9
|
+
npm install @tell-rs/node
|
|
10
|
+
|
|
11
|
+
# yarn
|
|
12
|
+
yarn add @tell-rs/node
|
|
13
|
+
|
|
14
|
+
# pnpm
|
|
15
|
+
pnpm add @tell-rs/node
|
|
16
|
+
|
|
17
|
+
# bun
|
|
18
|
+
bun add @tell-rs/node
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Tell } from "@tell-rs/node";
|
|
25
|
+
|
|
26
|
+
const tell = new Tell({ apiKey: "your-api-key" });
|
|
27
|
+
|
|
28
|
+
// Track an event
|
|
29
|
+
tell.track("user_123", "Sign Up", { plan: "pro" });
|
|
30
|
+
|
|
31
|
+
// Identify a user
|
|
32
|
+
tell.identify("user_123", { name: "Alice", email: "alice@example.com" });
|
|
33
|
+
|
|
34
|
+
// Structured logging
|
|
35
|
+
tell.logInfo("User signed up", "auth", { userId: "user_123" });
|
|
36
|
+
|
|
37
|
+
// Flush and close before process exit
|
|
38
|
+
await tell.close();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
### `new Tell(config)`
|
|
44
|
+
|
|
45
|
+
Creates a new Tell instance. Each instance manages its own batching, transport, and lifecycle.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const tell = new Tell({
|
|
49
|
+
apiKey: "your-api-key",
|
|
50
|
+
// All options below are optional:
|
|
51
|
+
endpoint: "https://collect.tell.app", // default
|
|
52
|
+
batchSize: 100, // events per batch
|
|
53
|
+
flushInterval: 10_000, // ms between auto-flushes
|
|
54
|
+
maxRetries: 3, // retry attempts on failure
|
|
55
|
+
closeTimeout: 5_000, // ms to wait on close()
|
|
56
|
+
networkTimeout: 30_000, // ms per HTTP request
|
|
57
|
+
logLevel: "info", // "error" | "warn" | "info" | "debug"
|
|
58
|
+
source: os.hostname(), // source identifier
|
|
59
|
+
disabled: false, // disable all tracking
|
|
60
|
+
maxQueueSize: 1000, // max queued items
|
|
61
|
+
gzip: false, // gzip request bodies
|
|
62
|
+
onError: (err) => console.error(err), // error callback
|
|
63
|
+
beforeSend: (event) => event, // transform/filter events
|
|
64
|
+
beforeSendLog: (log) => log, // transform/filter logs
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Events
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
tell.track(userId, eventName, properties?)
|
|
72
|
+
tell.identify(userId, traits?)
|
|
73
|
+
tell.group(userId, groupId, properties?)
|
|
74
|
+
tell.revenue(userId, amount, currency, orderId, properties?)
|
|
75
|
+
tell.alias(previousId, userId)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Logging
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
tell.log(level, message, service?, data?)
|
|
82
|
+
|
|
83
|
+
// Convenience methods
|
|
84
|
+
tell.logEmergency(message, service?, data?)
|
|
85
|
+
tell.logAlert(message, service?, data?)
|
|
86
|
+
tell.logCritical(message, service?, data?)
|
|
87
|
+
tell.logError(message, service?, data?)
|
|
88
|
+
tell.logWarning(message, service?, data?)
|
|
89
|
+
tell.logNotice(message, service?, data?)
|
|
90
|
+
tell.logInfo(message, service?, data?)
|
|
91
|
+
tell.logDebug(message, service?, data?)
|
|
92
|
+
tell.logTrace(message, service?, data?)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Lifecycle
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
await tell.flush() // flush all pending events and logs
|
|
99
|
+
await tell.close() // flush + shut down (call before process exit)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Config Presets
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { Tell, development, production } from "@tell-rs/node";
|
|
106
|
+
|
|
107
|
+
// Development: localhost:8080, small batches, debug logging
|
|
108
|
+
const dev = new Tell(development("your-api-key"));
|
|
109
|
+
|
|
110
|
+
// Production: default endpoint, error-only logging
|
|
111
|
+
const prod = new Tell(production("your-api-key"));
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Redaction
|
|
115
|
+
|
|
116
|
+
Use the built-in `redact()` factory to strip sensitive data before events leave your server:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { Tell, redact, redactLog, SENSITIVE_PARAMS } from "@tell-rs/node";
|
|
120
|
+
|
|
121
|
+
const tell = new Tell({
|
|
122
|
+
apiKey: "your-api-key",
|
|
123
|
+
beforeSend: redact({
|
|
124
|
+
dropRoutes: ["/health", "/readyz"],
|
|
125
|
+
stripParams: SENSITIVE_PARAMS,
|
|
126
|
+
redactKeys: ["email", "phone", "ssn"],
|
|
127
|
+
}),
|
|
128
|
+
beforeSendLog: redactLog({
|
|
129
|
+
redactKeys: ["password", "credit_card"],
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
See the [docs site](https://docs.tell.rs/tracking/sdks/javascript/node#redaction--beforesend) for more `beforeSend` patterns.
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
// ../core/src/constants.ts
|
|
2
|
+
var Events = {
|
|
3
|
+
// User Lifecycle
|
|
4
|
+
UserSignedUp: "User Signed Up",
|
|
5
|
+
UserSignedIn: "User Signed In",
|
|
6
|
+
UserSignedOut: "User Signed Out",
|
|
7
|
+
UserInvited: "User Invited",
|
|
8
|
+
UserOnboarded: "User Onboarded",
|
|
9
|
+
AuthenticationFailed: "Authentication Failed",
|
|
10
|
+
PasswordReset: "Password Reset",
|
|
11
|
+
TwoFactorEnabled: "Two Factor Enabled",
|
|
12
|
+
TwoFactorDisabled: "Two Factor Disabled",
|
|
13
|
+
// Revenue & Billing
|
|
14
|
+
OrderCompleted: "Order Completed",
|
|
15
|
+
OrderRefunded: "Order Refunded",
|
|
16
|
+
OrderCanceled: "Order Canceled",
|
|
17
|
+
PaymentFailed: "Payment Failed",
|
|
18
|
+
PaymentMethodAdded: "Payment Method Added",
|
|
19
|
+
PaymentMethodUpdated: "Payment Method Updated",
|
|
20
|
+
PaymentMethodRemoved: "Payment Method Removed",
|
|
21
|
+
// Subscription
|
|
22
|
+
SubscriptionStarted: "Subscription Started",
|
|
23
|
+
SubscriptionRenewed: "Subscription Renewed",
|
|
24
|
+
SubscriptionPaused: "Subscription Paused",
|
|
25
|
+
SubscriptionResumed: "Subscription Resumed",
|
|
26
|
+
SubscriptionChanged: "Subscription Changed",
|
|
27
|
+
SubscriptionCanceled: "Subscription Canceled",
|
|
28
|
+
// Trial
|
|
29
|
+
TrialStarted: "Trial Started",
|
|
30
|
+
TrialEndingSoon: "Trial Ending Soon",
|
|
31
|
+
TrialEnded: "Trial Ended",
|
|
32
|
+
TrialConverted: "Trial Converted",
|
|
33
|
+
// Shopping
|
|
34
|
+
CartViewed: "Cart Viewed",
|
|
35
|
+
CartUpdated: "Cart Updated",
|
|
36
|
+
CartAbandoned: "Cart Abandoned",
|
|
37
|
+
CheckoutStarted: "Checkout Started",
|
|
38
|
+
CheckoutCompleted: "Checkout Completed",
|
|
39
|
+
// Engagement
|
|
40
|
+
PageViewed: "Page Viewed",
|
|
41
|
+
FeatureUsed: "Feature Used",
|
|
42
|
+
SearchPerformed: "Search Performed",
|
|
43
|
+
FileUploaded: "File Uploaded",
|
|
44
|
+
NotificationSent: "Notification Sent",
|
|
45
|
+
NotificationClicked: "Notification Clicked",
|
|
46
|
+
// Communication
|
|
47
|
+
EmailSent: "Email Sent",
|
|
48
|
+
EmailOpened: "Email Opened",
|
|
49
|
+
EmailClicked: "Email Clicked",
|
|
50
|
+
EmailBounced: "Email Bounced",
|
|
51
|
+
EmailUnsubscribed: "Email Unsubscribed",
|
|
52
|
+
SupportTicketCreated: "Support Ticket Created",
|
|
53
|
+
SupportTicketResolved: "Support Ticket Resolved"
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// ../core/src/errors.ts
|
|
57
|
+
var TellError = class extends Error {
|
|
58
|
+
constructor(message) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = "TellError";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var ConfigurationError = class extends TellError {
|
|
64
|
+
constructor(message) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = "ConfigurationError";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var ValidationError = class extends TellError {
|
|
70
|
+
field;
|
|
71
|
+
constructor(field, message) {
|
|
72
|
+
super(`${field}: ${message}`);
|
|
73
|
+
this.name = "ValidationError";
|
|
74
|
+
this.field = field;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var NetworkError = class extends TellError {
|
|
78
|
+
statusCode;
|
|
79
|
+
constructor(message, statusCode) {
|
|
80
|
+
super(message);
|
|
81
|
+
this.name = "NetworkError";
|
|
82
|
+
this.statusCode = statusCode;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var ClosedError = class extends TellError {
|
|
86
|
+
constructor() {
|
|
87
|
+
super("Client is closed");
|
|
88
|
+
this.name = "ClosedError";
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var SerializationError = class extends TellError {
|
|
92
|
+
constructor(message) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.name = "SerializationError";
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// ../core/src/validation.ts
|
|
99
|
+
var HEX_RE = /^[0-9a-fA-F]{32}$/;
|
|
100
|
+
var MAX_EVENT_NAME = 256;
|
|
101
|
+
var MAX_LOG_MESSAGE = 65536;
|
|
102
|
+
function validateApiKey(key) {
|
|
103
|
+
if (!key) {
|
|
104
|
+
throw new ConfigurationError("apiKey is required");
|
|
105
|
+
}
|
|
106
|
+
if (!HEX_RE.test(key)) {
|
|
107
|
+
throw new ConfigurationError(
|
|
108
|
+
"apiKey must be exactly 32 hex characters"
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function validateEventName(name) {
|
|
113
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
114
|
+
throw new ValidationError("eventName", "must be a non-empty string");
|
|
115
|
+
}
|
|
116
|
+
if (name.length > MAX_EVENT_NAME) {
|
|
117
|
+
throw new ValidationError(
|
|
118
|
+
"eventName",
|
|
119
|
+
`must be at most ${MAX_EVENT_NAME} characters, got ${name.length}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function validateLogMessage(message) {
|
|
124
|
+
if (typeof message !== "string" || message.length === 0) {
|
|
125
|
+
throw new ValidationError("message", "must be a non-empty string");
|
|
126
|
+
}
|
|
127
|
+
if (message.length > MAX_LOG_MESSAGE) {
|
|
128
|
+
throw new ValidationError(
|
|
129
|
+
"message",
|
|
130
|
+
`must be at most ${MAX_LOG_MESSAGE} characters, got ${message.length}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function validateUserId(id) {
|
|
135
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
136
|
+
throw new ValidationError("userId", "must be a non-empty string");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ../core/src/batcher.ts
|
|
141
|
+
var Batcher = class {
|
|
142
|
+
queue = [];
|
|
143
|
+
timer = null;
|
|
144
|
+
closed = false;
|
|
145
|
+
flushing = null;
|
|
146
|
+
config;
|
|
147
|
+
constructor(config) {
|
|
148
|
+
this.config = config;
|
|
149
|
+
this.timer = setInterval(() => {
|
|
150
|
+
if (this.queue.length > 0) {
|
|
151
|
+
this.flush().catch(() => {
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}, config.interval);
|
|
155
|
+
if (this.timer && typeof this.timer.unref === "function") {
|
|
156
|
+
this.timer.unref();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
add(item) {
|
|
160
|
+
if (this.closed) return;
|
|
161
|
+
if (this.queue.length >= this.config.maxQueueSize) {
|
|
162
|
+
this.queue.shift();
|
|
163
|
+
if (this.config.onOverflow) {
|
|
164
|
+
this.config.onOverflow();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
this.queue.push(item);
|
|
168
|
+
if (this.queue.length >= this.config.size) {
|
|
169
|
+
this.flush().catch(() => {
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async flush() {
|
|
174
|
+
if (this.flushing) {
|
|
175
|
+
return this.flushing;
|
|
176
|
+
}
|
|
177
|
+
this.flushing = this.doFlush();
|
|
178
|
+
try {
|
|
179
|
+
await this.flushing;
|
|
180
|
+
} finally {
|
|
181
|
+
this.flushing = null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async close() {
|
|
185
|
+
this.closed = true;
|
|
186
|
+
if (this.timer !== null) {
|
|
187
|
+
clearInterval(this.timer);
|
|
188
|
+
this.timer = null;
|
|
189
|
+
}
|
|
190
|
+
await this.flush();
|
|
191
|
+
}
|
|
192
|
+
get pending() {
|
|
193
|
+
return this.queue.length;
|
|
194
|
+
}
|
|
195
|
+
drain() {
|
|
196
|
+
const items = this.queue;
|
|
197
|
+
this.queue = [];
|
|
198
|
+
return items;
|
|
199
|
+
}
|
|
200
|
+
halveBatchSize() {
|
|
201
|
+
this.config.size = Math.max(1, Math.floor(this.config.size / 2));
|
|
202
|
+
}
|
|
203
|
+
async doFlush() {
|
|
204
|
+
while (this.queue.length > 0) {
|
|
205
|
+
const batch = this.queue.slice(0, this.config.size);
|
|
206
|
+
try {
|
|
207
|
+
await this.config.send(batch);
|
|
208
|
+
this.queue.splice(0, batch.length);
|
|
209
|
+
} catch {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// ../core/src/before-send.ts
|
|
217
|
+
function runBeforeSend(item, fns) {
|
|
218
|
+
const pipeline = Array.isArray(fns) ? fns : [fns];
|
|
219
|
+
let current = item;
|
|
220
|
+
for (const fn of pipeline) {
|
|
221
|
+
if (current === null) return null;
|
|
222
|
+
current = fn(current);
|
|
223
|
+
}
|
|
224
|
+
return current;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ../core/src/redact.ts
|
|
228
|
+
var SENSITIVE_PARAMS = [
|
|
229
|
+
"token",
|
|
230
|
+
"api_key",
|
|
231
|
+
"key",
|
|
232
|
+
"secret",
|
|
233
|
+
"password",
|
|
234
|
+
"access_token",
|
|
235
|
+
"refresh_token",
|
|
236
|
+
"authorization"
|
|
237
|
+
];
|
|
238
|
+
function stripUrlParams(url, params) {
|
|
239
|
+
try {
|
|
240
|
+
const u = new URL(url);
|
|
241
|
+
for (const p of params) u.searchParams.delete(p);
|
|
242
|
+
return u.toString();
|
|
243
|
+
} catch {
|
|
244
|
+
return url;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function stripParamsInProperties(props, params) {
|
|
248
|
+
if (!props) return props;
|
|
249
|
+
const out = {};
|
|
250
|
+
for (const [k, v] of Object.entries(props)) {
|
|
251
|
+
if (typeof v === "string" && v.startsWith("http")) {
|
|
252
|
+
out[k] = stripUrlParams(v, params);
|
|
253
|
+
} else {
|
|
254
|
+
out[k] = v;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
function redactKeysInProperties(props, keys) {
|
|
260
|
+
if (!props) return props;
|
|
261
|
+
const out = {};
|
|
262
|
+
for (const [k, v] of Object.entries(props)) {
|
|
263
|
+
out[k] = keys.includes(k) ? "[REDACTED]" : v;
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
}
|
|
267
|
+
function redact(options) {
|
|
268
|
+
const { stripParams, redactKeys, dropRoutes } = options;
|
|
269
|
+
return (event) => {
|
|
270
|
+
if (dropRoutes && dropRoutes.length > 0 && event.context?.url) {
|
|
271
|
+
try {
|
|
272
|
+
const pathname = new URL(String(event.context.url)).pathname;
|
|
273
|
+
for (const prefix of dropRoutes) {
|
|
274
|
+
if (pathname.startsWith(prefix)) return null;
|
|
275
|
+
}
|
|
276
|
+
} catch {
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
let ctx = event.context;
|
|
280
|
+
let props = event.properties;
|
|
281
|
+
let traits = event.traits;
|
|
282
|
+
if (stripParams && stripParams.length > 0) {
|
|
283
|
+
if (ctx?.url && typeof ctx.url === "string") {
|
|
284
|
+
ctx = { ...ctx, url: stripUrlParams(ctx.url, stripParams) };
|
|
285
|
+
}
|
|
286
|
+
props = stripParamsInProperties(props, stripParams);
|
|
287
|
+
traits = stripParamsInProperties(traits, stripParams);
|
|
288
|
+
}
|
|
289
|
+
if (redactKeys && redactKeys.length > 0) {
|
|
290
|
+
props = redactKeysInProperties(props, redactKeys);
|
|
291
|
+
traits = redactKeysInProperties(traits, redactKeys);
|
|
292
|
+
}
|
|
293
|
+
if (ctx !== event.context || props !== event.properties || traits !== event.traits) {
|
|
294
|
+
return { ...event, context: ctx, properties: props, traits };
|
|
295
|
+
}
|
|
296
|
+
return event;
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
function redactLog(options) {
|
|
300
|
+
const { redactKeys } = options;
|
|
301
|
+
return (log) => {
|
|
302
|
+
if (redactKeys && redactKeys.length > 0 && log.data) {
|
|
303
|
+
const data = redactKeysInProperties(log.data, redactKeys);
|
|
304
|
+
if (data !== log.data) {
|
|
305
|
+
return { ...log, data };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return log;
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export {
|
|
313
|
+
Events,
|
|
314
|
+
TellError,
|
|
315
|
+
ConfigurationError,
|
|
316
|
+
ValidationError,
|
|
317
|
+
NetworkError,
|
|
318
|
+
ClosedError,
|
|
319
|
+
SerializationError,
|
|
320
|
+
validateApiKey,
|
|
321
|
+
validateEventName,
|
|
322
|
+
validateLogMessage,
|
|
323
|
+
validateUserId,
|
|
324
|
+
Batcher,
|
|
325
|
+
runBeforeSend,
|
|
326
|
+
SENSITIVE_PARAMS,
|
|
327
|
+
redact,
|
|
328
|
+
redactLog
|
|
329
|
+
};
|
|
330
|
+
//# sourceMappingURL=chunk-HYQWDHQT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/constants.ts","../../core/src/errors.ts","../../core/src/validation.ts","../../core/src/batcher.ts","../../core/src/before-send.ts","../../core/src/redact.ts"],"sourcesContent":["// Standard event names — typed constants matching the spec appendix A\n\nexport const Events = {\n // User Lifecycle\n UserSignedUp: \"User Signed Up\",\n UserSignedIn: \"User Signed In\",\n UserSignedOut: \"User Signed Out\",\n UserInvited: \"User Invited\",\n UserOnboarded: \"User Onboarded\",\n AuthenticationFailed: \"Authentication Failed\",\n PasswordReset: \"Password Reset\",\n TwoFactorEnabled: \"Two Factor Enabled\",\n TwoFactorDisabled: \"Two Factor Disabled\",\n\n // Revenue & Billing\n OrderCompleted: \"Order Completed\",\n OrderRefunded: \"Order Refunded\",\n OrderCanceled: \"Order Canceled\",\n PaymentFailed: \"Payment Failed\",\n PaymentMethodAdded: \"Payment Method Added\",\n PaymentMethodUpdated: \"Payment Method Updated\",\n PaymentMethodRemoved: \"Payment Method Removed\",\n\n // Subscription\n SubscriptionStarted: \"Subscription Started\",\n SubscriptionRenewed: \"Subscription Renewed\",\n SubscriptionPaused: \"Subscription Paused\",\n SubscriptionResumed: \"Subscription Resumed\",\n SubscriptionChanged: \"Subscription Changed\",\n SubscriptionCanceled: \"Subscription Canceled\",\n\n // Trial\n TrialStarted: \"Trial Started\",\n TrialEndingSoon: \"Trial Ending Soon\",\n TrialEnded: \"Trial Ended\",\n TrialConverted: \"Trial Converted\",\n\n // Shopping\n CartViewed: \"Cart Viewed\",\n CartUpdated: \"Cart Updated\",\n CartAbandoned: \"Cart Abandoned\",\n CheckoutStarted: \"Checkout Started\",\n CheckoutCompleted: \"Checkout Completed\",\n\n // Engagement\n PageViewed: \"Page Viewed\",\n FeatureUsed: \"Feature Used\",\n SearchPerformed: \"Search Performed\",\n FileUploaded: \"File Uploaded\",\n NotificationSent: \"Notification Sent\",\n NotificationClicked: \"Notification Clicked\",\n\n // Communication\n EmailSent: \"Email Sent\",\n EmailOpened: \"Email Opened\",\n EmailClicked: \"Email Clicked\",\n EmailBounced: \"Email Bounced\",\n EmailUnsubscribed: \"Email Unsubscribed\",\n SupportTicketCreated: \"Support Ticket Created\",\n SupportTicketResolved: \"Support Ticket Resolved\",\n} as const;\n\nexport type EventName = (typeof Events)[keyof typeof Events];\n","export class TellError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TellError\";\n }\n}\n\nexport class ConfigurationError extends TellError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class ValidationError extends TellError {\n public readonly field: string;\n\n constructor(field: string, message: string) {\n super(`${field}: ${message}`);\n this.name = \"ValidationError\";\n this.field = field;\n }\n}\n\nexport class NetworkError extends TellError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = \"NetworkError\";\n this.statusCode = statusCode;\n }\n}\n\nexport class ClosedError extends TellError {\n constructor() {\n super(\"Client is closed\");\n this.name = \"ClosedError\";\n }\n}\n\nexport class SerializationError extends TellError {\n constructor(message: string) {\n super(message);\n this.name = \"SerializationError\";\n }\n}\n","import { ConfigurationError, ValidationError } from \"./errors.js\";\n\nconst HEX_RE = /^[0-9a-fA-F]{32}$/;\nconst MAX_EVENT_NAME = 256;\nconst MAX_LOG_MESSAGE = 65_536;\n\nexport function validateApiKey(key: string): void {\n if (!key) {\n throw new ConfigurationError(\"apiKey is required\");\n }\n if (!HEX_RE.test(key)) {\n throw new ConfigurationError(\n \"apiKey must be exactly 32 hex characters\"\n );\n }\n}\n\nexport function validateEventName(name: unknown): void {\n if (typeof name !== \"string\" || name.length === 0) {\n throw new ValidationError(\"eventName\", \"must be a non-empty string\");\n }\n if (name.length > MAX_EVENT_NAME) {\n throw new ValidationError(\n \"eventName\",\n `must be at most ${MAX_EVENT_NAME} characters, got ${name.length}`\n );\n }\n}\n\nexport function validateLogMessage(message: unknown): void {\n if (typeof message !== \"string\" || message.length === 0) {\n throw new ValidationError(\"message\", \"must be a non-empty string\");\n }\n if (message.length > MAX_LOG_MESSAGE) {\n throw new ValidationError(\n \"message\",\n `must be at most ${MAX_LOG_MESSAGE} characters, got ${message.length}`\n );\n }\n}\n\nexport function validateUserId(id: unknown): void {\n if (typeof id !== \"string\" || id.length === 0) {\n throw new ValidationError(\"userId\", \"must be a non-empty string\");\n }\n}\n","export interface BatcherConfig<T> {\n size: number;\n interval: number; // ms\n maxQueueSize: number;\n send: (items: T[]) => Promise<void>;\n onOverflow?: () => void;\n}\n\nexport class Batcher<T> {\n private queue: T[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private closed = false;\n private flushing: Promise<void> | null = null;\n private config: BatcherConfig<T>;\n\n constructor(config: BatcherConfig<T>) {\n this.config = config;\n this.timer = setInterval(() => {\n if (this.queue.length > 0) {\n this.flush().catch(() => {});\n }\n }, config.interval);\n // Don't keep Node.js process alive just for flush timer\n if (this.timer && typeof (this.timer as any).unref === \"function\") {\n (this.timer as any).unref();\n }\n }\n\n add(item: T): void {\n if (this.closed) return;\n\n if (this.queue.length >= this.config.maxQueueSize) {\n this.queue.shift(); // drop oldest\n if (this.config.onOverflow) {\n this.config.onOverflow();\n }\n }\n\n this.queue.push(item);\n\n if (this.queue.length >= this.config.size) {\n this.flush().catch(() => {});\n }\n }\n\n async flush(): Promise<void> {\n // Prevent concurrent flushes\n if (this.flushing) {\n return this.flushing;\n }\n this.flushing = this.doFlush();\n try {\n await this.flushing;\n } finally {\n this.flushing = null;\n }\n }\n\n async close(): Promise<void> {\n this.closed = true;\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n drain(): T[] {\n const items = this.queue;\n this.queue = [];\n return items;\n }\n\n halveBatchSize(): void {\n this.config.size = Math.max(1, Math.floor(this.config.size / 2));\n }\n\n private async doFlush(): Promise<void> {\n while (this.queue.length > 0) {\n const batch = this.queue.slice(0, this.config.size);\n try {\n await this.config.send(batch);\n this.queue.splice(0, batch.length); // remove only on success\n } catch {\n return; // items stay in queue (e.g. 413 — batch size already halved)\n }\n }\n }\n}\n","/**\n * A function that transforms or drops an item before it is queued.\n * Return the (possibly modified) item, or null to drop it.\n */\nexport type BeforeSendFn<T> = (item: T) => T | null;\n\n/**\n * Run an item through a pipeline of beforeSend functions.\n * Returns the transformed item, or null if any function in the chain drops it.\n */\nexport function runBeforeSend<T>(\n item: T,\n fns: BeforeSendFn<T> | BeforeSendFn<T>[]\n): T | null {\n const pipeline = Array.isArray(fns) ? fns : [fns];\n let current: T | null = item;\n\n for (const fn of pipeline) {\n if (current === null) return null;\n current = fn(current);\n }\n\n return current;\n}\n","import type { BeforeSendFn } from \"./before-send.js\";\nimport type { JsonEvent, JsonLog, Properties } from \"./types.js\";\n\n/**\n * Common query-parameter names that often carry secrets or tokens.\n * Pass these (or a subset) to `stripParams` for quick sanitization.\n */\nexport const SENSITIVE_PARAMS: readonly string[] = [\n \"token\",\n \"api_key\",\n \"key\",\n \"secret\",\n \"password\",\n \"access_token\",\n \"refresh_token\",\n \"authorization\",\n] as const;\n\nexport interface RedactOptions {\n /** Query-parameter names to strip from URLs (context.url and URL-shaped property values). */\n stripParams?: string[];\n /** Property/trait keys whose values should be replaced with \"[REDACTED]\". */\n redactKeys?: string[];\n /** URL pathname prefixes — events whose context.url matches are dropped entirely. */\n dropRoutes?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction stripUrlParams(url: string, params: string[]): string {\n try {\n const u = new URL(url);\n for (const p of params) u.searchParams.delete(p);\n return u.toString();\n } catch {\n return url; // not a valid URL — leave as-is\n }\n}\n\nfunction stripParamsInProperties(\n props: Properties | undefined,\n params: string[],\n): Properties | undefined {\n if (!props) return props;\n const out: Properties = {};\n for (const [k, v] of Object.entries(props)) {\n if (typeof v === \"string\" && v.startsWith(\"http\")) {\n out[k] = stripUrlParams(v, params);\n } else {\n out[k] = v;\n }\n }\n return out;\n}\n\nfunction redactKeysInProperties(\n props: Properties | undefined,\n keys: string[],\n): Properties | undefined {\n if (!props) return props;\n const out: Properties = {};\n for (const [k, v] of Object.entries(props)) {\n out[k] = keys.includes(k) ? \"[REDACTED]\" : v;\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Factory that returns a `beforeSend` hook for events.\n *\n * - `dropRoutes` — drops events whose `context.url` pathname starts with a prefix.\n * - `stripParams` — removes query params from `context.url` and URL-shaped values\n * in `properties` and `traits`.\n * - `redactKeys` — replaces matching keys in `properties` and `traits` with `\"[REDACTED]\"`.\n *\n * The returned function never mutates the input event.\n */\nexport function redact(options: RedactOptions): BeforeSendFn<JsonEvent> {\n const { stripParams, redactKeys, dropRoutes } = options;\n\n return (event: JsonEvent): JsonEvent | null => {\n // --- dropRoutes ---\n if (dropRoutes && dropRoutes.length > 0 && event.context?.url) {\n try {\n const pathname = new URL(String(event.context.url)).pathname;\n for (const prefix of dropRoutes) {\n if (pathname.startsWith(prefix)) return null;\n }\n } catch {\n // not a valid URL — skip drop check\n }\n }\n\n let ctx = event.context;\n let props = event.properties;\n let traits = event.traits;\n\n // --- stripParams ---\n if (stripParams && stripParams.length > 0) {\n if (ctx?.url && typeof ctx.url === \"string\") {\n ctx = { ...ctx, url: stripUrlParams(ctx.url, stripParams) };\n }\n props = stripParamsInProperties(props, stripParams);\n traits = stripParamsInProperties(traits, stripParams);\n }\n\n // --- redactKeys ---\n if (redactKeys && redactKeys.length > 0) {\n props = redactKeysInProperties(props, redactKeys);\n traits = redactKeysInProperties(traits, redactKeys);\n }\n\n // Return a shallow copy if anything changed\n if (ctx !== event.context || props !== event.properties || traits !== event.traits) {\n return { ...event, context: ctx, properties: props, traits: traits };\n }\n\n return event;\n };\n}\n\n/**\n * Factory that returns a `beforeSend` hook for log entries.\n *\n * - `redactKeys` — replaces matching keys in `log.data` with `\"[REDACTED]\"`.\n *\n * The returned function never mutates the input log.\n */\nexport function redactLog(\n options: Pick<RedactOptions, \"redactKeys\">,\n): BeforeSendFn<JsonLog> {\n const { redactKeys } = options;\n\n return (log: JsonLog): JsonLog | null => {\n if (redactKeys && redactKeys.length > 0 && log.data) {\n const data = redactKeysInProperties(log.data, redactKeys);\n if (data !== log.data) {\n return { ...log, data };\n }\n }\n return log;\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/events.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/events.ts
|
|
21
|
+
var events_exports = {};
|
|
22
|
+
__export(events_exports, {
|
|
23
|
+
Events: () => Events
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(events_exports);
|
|
26
|
+
|
|
27
|
+
// ../core/src/constants.ts
|
|
28
|
+
var Events = {
|
|
29
|
+
// User Lifecycle
|
|
30
|
+
UserSignedUp: "User Signed Up",
|
|
31
|
+
UserSignedIn: "User Signed In",
|
|
32
|
+
UserSignedOut: "User Signed Out",
|
|
33
|
+
UserInvited: "User Invited",
|
|
34
|
+
UserOnboarded: "User Onboarded",
|
|
35
|
+
AuthenticationFailed: "Authentication Failed",
|
|
36
|
+
PasswordReset: "Password Reset",
|
|
37
|
+
TwoFactorEnabled: "Two Factor Enabled",
|
|
38
|
+
TwoFactorDisabled: "Two Factor Disabled",
|
|
39
|
+
// Revenue & Billing
|
|
40
|
+
OrderCompleted: "Order Completed",
|
|
41
|
+
OrderRefunded: "Order Refunded",
|
|
42
|
+
OrderCanceled: "Order Canceled",
|
|
43
|
+
PaymentFailed: "Payment Failed",
|
|
44
|
+
PaymentMethodAdded: "Payment Method Added",
|
|
45
|
+
PaymentMethodUpdated: "Payment Method Updated",
|
|
46
|
+
PaymentMethodRemoved: "Payment Method Removed",
|
|
47
|
+
// Subscription
|
|
48
|
+
SubscriptionStarted: "Subscription Started",
|
|
49
|
+
SubscriptionRenewed: "Subscription Renewed",
|
|
50
|
+
SubscriptionPaused: "Subscription Paused",
|
|
51
|
+
SubscriptionResumed: "Subscription Resumed",
|
|
52
|
+
SubscriptionChanged: "Subscription Changed",
|
|
53
|
+
SubscriptionCanceled: "Subscription Canceled",
|
|
54
|
+
// Trial
|
|
55
|
+
TrialStarted: "Trial Started",
|
|
56
|
+
TrialEndingSoon: "Trial Ending Soon",
|
|
57
|
+
TrialEnded: "Trial Ended",
|
|
58
|
+
TrialConverted: "Trial Converted",
|
|
59
|
+
// Shopping
|
|
60
|
+
CartViewed: "Cart Viewed",
|
|
61
|
+
CartUpdated: "Cart Updated",
|
|
62
|
+
CartAbandoned: "Cart Abandoned",
|
|
63
|
+
CheckoutStarted: "Checkout Started",
|
|
64
|
+
CheckoutCompleted: "Checkout Completed",
|
|
65
|
+
// Engagement
|
|
66
|
+
PageViewed: "Page Viewed",
|
|
67
|
+
FeatureUsed: "Feature Used",
|
|
68
|
+
SearchPerformed: "Search Performed",
|
|
69
|
+
FileUploaded: "File Uploaded",
|
|
70
|
+
NotificationSent: "Notification Sent",
|
|
71
|
+
NotificationClicked: "Notification Clicked",
|
|
72
|
+
// Communication
|
|
73
|
+
EmailSent: "Email Sent",
|
|
74
|
+
EmailOpened: "Email Opened",
|
|
75
|
+
EmailClicked: "Email Clicked",
|
|
76
|
+
EmailBounced: "Email Bounced",
|
|
77
|
+
EmailUnsubscribed: "Email Unsubscribed",
|
|
78
|
+
SupportTicketCreated: "Support Ticket Created",
|
|
79
|
+
SupportTicketResolved: "Support Ticket Resolved"
|
|
80
|
+
};
|
|
81
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
82
|
+
0 && (module.exports = {
|
|
83
|
+
Events
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=events.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/events.ts","../../core/src/constants.ts"],"sourcesContent":["export { Events, type EventName } from \"@tell-rs/core\";\n","// Standard event names — typed constants matching the spec appendix A\n\nexport const Events = {\n // User Lifecycle\n UserSignedUp: \"User Signed Up\",\n UserSignedIn: \"User Signed In\",\n UserSignedOut: \"User Signed Out\",\n UserInvited: \"User Invited\",\n UserOnboarded: \"User Onboarded\",\n AuthenticationFailed: \"Authentication Failed\",\n PasswordReset: \"Password Reset\",\n TwoFactorEnabled: \"Two Factor Enabled\",\n TwoFactorDisabled: \"Two Factor Disabled\",\n\n // Revenue & Billing\n OrderCompleted: \"Order Completed\",\n OrderRefunded: \"Order Refunded\",\n OrderCanceled: \"Order Canceled\",\n PaymentFailed: \"Payment Failed\",\n PaymentMethodAdded: \"Payment Method Added\",\n PaymentMethodUpdated: \"Payment Method Updated\",\n PaymentMethodRemoved: \"Payment Method Removed\",\n\n // Subscription\n SubscriptionStarted: \"Subscription Started\",\n SubscriptionRenewed: \"Subscription Renewed\",\n SubscriptionPaused: \"Subscription Paused\",\n SubscriptionResumed: \"Subscription Resumed\",\n SubscriptionChanged: \"Subscription Changed\",\n SubscriptionCanceled: \"Subscription Canceled\",\n\n // Trial\n TrialStarted: \"Trial Started\",\n TrialEndingSoon: \"Trial Ending Soon\",\n TrialEnded: \"Trial Ended\",\n TrialConverted: \"Trial Converted\",\n\n // Shopping\n CartViewed: \"Cart Viewed\",\n CartUpdated: \"Cart Updated\",\n CartAbandoned: \"Cart Abandoned\",\n CheckoutStarted: \"Checkout Started\",\n CheckoutCompleted: \"Checkout Completed\",\n\n // Engagement\n PageViewed: \"Page Viewed\",\n FeatureUsed: \"Feature Used\",\n SearchPerformed: \"Search Performed\",\n FileUploaded: \"File Uploaded\",\n NotificationSent: \"Notification Sent\",\n NotificationClicked: \"Notification Clicked\",\n\n // Communication\n EmailSent: \"Email Sent\",\n EmailOpened: \"Email Opened\",\n EmailClicked: \"Email Clicked\",\n EmailBounced: \"Email Bounced\",\n EmailUnsubscribed: \"Email Unsubscribed\",\n SupportTicketCreated: \"Support Ticket Created\",\n SupportTicketResolved: \"Support Ticket Resolved\",\n} as const;\n\nexport type EventName = (typeof Events)[keyof typeof Events];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,SAAS;AAAA;AAAA,EAEpB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,eAAe;AAAA,EACf,aAAa;AAAA,EACb,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,mBAAmB;AAAA;AAAA,EAGnB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,sBAAsB;AAAA;AAAA,EAGtB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA;AAAA,EAGtB,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,gBAAgB;AAAA;AAAA,EAGhB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,mBAAmB;AAAA;AAAA,EAGnB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,qBAAqB;AAAA;AAAA,EAGrB,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,uBAAuB;AACzB;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EventName, Events } from '@tell-rs/core';
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EventName, Events } from '@tell-rs/core';
|
package/dist/events.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|