luchy 0.0.1 → 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 +373 -0
- package/dist/api/index.d.ts +112 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +125 -0
- package/dist/api/schema.d.ts +457 -0
- package/dist/client.d.ts +23 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +314 -0
- package/dist/react-router.d.ts +164 -0
- package/dist/react-router.d.ts.map +1 -0
- package/dist/react-router.js +107 -0
- package/dist/script/luchy.js +357 -0
- package/dist/script/luchy.js.br +0 -0
- package/dist/script/luchy.js.gz +0 -0
- package/dist/script/luchy.min.js +357 -0
- package/dist/script/luchy.min.js.br +0 -0
- package/dist/script/luchy.min.js.gz +0 -0
- package/dist/server.d.ts +71 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +40 -0
- package/package.json +69 -9
- package/index.js +0 -1
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
var __async = (__this, __arguments, generator) => {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
var fulfilled = (value) => {
|
|
20
|
+
try {
|
|
21
|
+
step(generator.next(value));
|
|
22
|
+
} catch (e) {
|
|
23
|
+
reject(e);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var rejected = (value) => {
|
|
27
|
+
try {
|
|
28
|
+
step(generator.throw(value));
|
|
29
|
+
} catch (e) {
|
|
30
|
+
reject(e);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
34
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
(function(exports) {
|
|
38
|
+
"use strict";
|
|
39
|
+
function sendEvent(options) {
|
|
40
|
+
return __async(this, null, function* () {
|
|
41
|
+
const { endpoint, apiKey, data, onError } = options;
|
|
42
|
+
try {
|
|
43
|
+
yield fetch(endpoint, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
Authorization: `Bearer ${apiKey}`
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify(data),
|
|
50
|
+
keepalive: true
|
|
51
|
+
// Important for page unload events
|
|
52
|
+
});
|
|
53
|
+
} catch (error) {
|
|
54
|
+
onError == null ? void 0 : onError(error);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function collectBrowserData() {
|
|
59
|
+
var _a;
|
|
60
|
+
return {
|
|
61
|
+
userAgent: navigator.userAgent,
|
|
62
|
+
language: navigator.language || ((_a = navigator.languages) == null ? void 0 : _a[0]) || "en"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function luchy(options) {
|
|
66
|
+
const endpoint = options.endpoint || "https://api.luchy.app/ingest";
|
|
67
|
+
const { apiKey, trackLocalhost = false } = options;
|
|
68
|
+
const shouldTrack = () => {
|
|
69
|
+
if (trackLocalhost) return true;
|
|
70
|
+
return location.hostname !== "localhost" && location.hostname !== "127.0.0.1";
|
|
71
|
+
};
|
|
72
|
+
function trackPageview(data) {
|
|
73
|
+
return __async(this, null, function* () {
|
|
74
|
+
if (!shouldTrack()) return;
|
|
75
|
+
const browserData = collectBrowserData();
|
|
76
|
+
const pathname = (data == null ? void 0 : data.pathname) || location.pathname;
|
|
77
|
+
const referrer = (data == null ? void 0 : data.referrer) || document.referrer || void 0;
|
|
78
|
+
yield sendEvent({
|
|
79
|
+
endpoint: `${endpoint}/pageview`,
|
|
80
|
+
apiKey,
|
|
81
|
+
data: __spreadValues({
|
|
82
|
+
pathname,
|
|
83
|
+
referrer
|
|
84
|
+
}, browserData)
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function trackEvent(name, payload, options2) {
|
|
89
|
+
return __async(this, null, function* () {
|
|
90
|
+
if (!shouldTrack()) return;
|
|
91
|
+
const browserData = collectBrowserData();
|
|
92
|
+
const pathname = location.pathname;
|
|
93
|
+
yield sendEvent({
|
|
94
|
+
endpoint: `${endpoint}/event`,
|
|
95
|
+
apiKey,
|
|
96
|
+
data: __spreadValues({
|
|
97
|
+
name,
|
|
98
|
+
type: options2 == null ? void 0 : options2.type,
|
|
99
|
+
pathname,
|
|
100
|
+
// `payload`, NOT `props`. The ingest endpoint validates with a
|
|
101
|
+
// non-passthrough zod object, so an unknown key is stripped and the
|
|
102
|
+
// event is stored with no properties at all — 200, success, no data.
|
|
103
|
+
payload
|
|
104
|
+
}, browserData)
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
let autoPageviewsEnabled = false;
|
|
109
|
+
let autoOutboundEnabled = false;
|
|
110
|
+
let autoEventsEnabled = false;
|
|
111
|
+
let hashRoutingEnabled = false;
|
|
112
|
+
let pageEnteredAt = 0;
|
|
113
|
+
let currentPathname = "";
|
|
114
|
+
let pageleaveSent = false;
|
|
115
|
+
let trackedLocation = "";
|
|
116
|
+
function locationKey() {
|
|
117
|
+
return `${location.pathname}${location.search || ""}${location.hash || ""}`;
|
|
118
|
+
}
|
|
119
|
+
function trackNavigation() {
|
|
120
|
+
const next = locationKey();
|
|
121
|
+
if (next === trackedLocation) return;
|
|
122
|
+
sendPageleave();
|
|
123
|
+
trackedLocation = next;
|
|
124
|
+
trackPageview();
|
|
125
|
+
resetPageTiming();
|
|
126
|
+
}
|
|
127
|
+
function sendPageleave() {
|
|
128
|
+
if (pageleaveSent || !currentPathname || !pageEnteredAt) return;
|
|
129
|
+
pageleaveSent = true;
|
|
130
|
+
const duration = Date.now() - pageEnteredAt;
|
|
131
|
+
trackEvent(
|
|
132
|
+
"__pageleave",
|
|
133
|
+
{ duration, pathname: currentPathname },
|
|
134
|
+
{ type: "__internal" }
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
function resetPageTiming() {
|
|
138
|
+
pageEnteredAt = Date.now();
|
|
139
|
+
currentPathname = location.pathname;
|
|
140
|
+
pageleaveSent = false;
|
|
141
|
+
}
|
|
142
|
+
let visibilityListener = null;
|
|
143
|
+
let pagehideListener = null;
|
|
144
|
+
let originalPushState = null;
|
|
145
|
+
let originalReplaceState = null;
|
|
146
|
+
let popstateListener = null;
|
|
147
|
+
let hashchangeListener = null;
|
|
148
|
+
let clickListener = null;
|
|
149
|
+
let dataEventClickListener = null;
|
|
150
|
+
function enableAutoPageviews() {
|
|
151
|
+
if (autoPageviewsEnabled) return;
|
|
152
|
+
autoPageviewsEnabled = true;
|
|
153
|
+
trackedLocation = locationKey();
|
|
154
|
+
trackPageview();
|
|
155
|
+
resetPageTiming();
|
|
156
|
+
if (!originalPushState) {
|
|
157
|
+
originalPushState = history.pushState.bind(history);
|
|
158
|
+
}
|
|
159
|
+
if (!originalReplaceState) {
|
|
160
|
+
originalReplaceState = history.replaceState.bind(history);
|
|
161
|
+
}
|
|
162
|
+
history.pushState = function(data, unused, url) {
|
|
163
|
+
originalPushState.apply(this, [data, unused, url]);
|
|
164
|
+
trackNavigation();
|
|
165
|
+
};
|
|
166
|
+
history.replaceState = function(data, unused, url) {
|
|
167
|
+
originalReplaceState.apply(this, [data, unused, url]);
|
|
168
|
+
trackNavigation();
|
|
169
|
+
};
|
|
170
|
+
popstateListener = () => {
|
|
171
|
+
trackNavigation();
|
|
172
|
+
};
|
|
173
|
+
window.addEventListener("popstate", popstateListener);
|
|
174
|
+
visibilityListener = () => {
|
|
175
|
+
if (document.visibilityState === "hidden") {
|
|
176
|
+
sendPageleave();
|
|
177
|
+
} else if (document.visibilityState === "visible") {
|
|
178
|
+
resetPageTiming();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
document.addEventListener("visibilitychange", visibilityListener);
|
|
182
|
+
pagehideListener = () => sendPageleave();
|
|
183
|
+
window.addEventListener("pagehide", pagehideListener);
|
|
184
|
+
}
|
|
185
|
+
function disableAutoPageviews() {
|
|
186
|
+
if (!autoPageviewsEnabled) return;
|
|
187
|
+
autoPageviewsEnabled = false;
|
|
188
|
+
if (originalPushState) {
|
|
189
|
+
history.pushState = originalPushState;
|
|
190
|
+
}
|
|
191
|
+
if (originalReplaceState) {
|
|
192
|
+
history.replaceState = originalReplaceState;
|
|
193
|
+
}
|
|
194
|
+
if (popstateListener) {
|
|
195
|
+
window.removeEventListener("popstate", popstateListener);
|
|
196
|
+
popstateListener = null;
|
|
197
|
+
}
|
|
198
|
+
if (visibilityListener) {
|
|
199
|
+
document.removeEventListener("visibilitychange", visibilityListener);
|
|
200
|
+
visibilityListener = null;
|
|
201
|
+
}
|
|
202
|
+
if (pagehideListener) {
|
|
203
|
+
window.removeEventListener("pagehide", pagehideListener);
|
|
204
|
+
pagehideListener = null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function enableHashRouting() {
|
|
208
|
+
if (hashRoutingEnabled) return;
|
|
209
|
+
hashRoutingEnabled = true;
|
|
210
|
+
hashchangeListener = () => trackNavigation();
|
|
211
|
+
window.addEventListener("hashchange", hashchangeListener);
|
|
212
|
+
}
|
|
213
|
+
function disableHashRouting() {
|
|
214
|
+
if (!hashRoutingEnabled) return;
|
|
215
|
+
hashRoutingEnabled = false;
|
|
216
|
+
if (hashchangeListener) {
|
|
217
|
+
window.removeEventListener("hashchange", hashchangeListener);
|
|
218
|
+
hashchangeListener = null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function enableAutoOutboundTracking() {
|
|
222
|
+
if (autoOutboundEnabled) return;
|
|
223
|
+
autoOutboundEnabled = true;
|
|
224
|
+
clickListener = (event) => {
|
|
225
|
+
var _a;
|
|
226
|
+
const link = (_a = event.target) == null ? void 0 : _a.closest("a");
|
|
227
|
+
if (!link) return;
|
|
228
|
+
if (link.closest("[data-luchy-event]")) return;
|
|
229
|
+
const href = link.href;
|
|
230
|
+
if (!href) return;
|
|
231
|
+
try {
|
|
232
|
+
const url = new URL(href);
|
|
233
|
+
if (url.hostname !== location.hostname) {
|
|
234
|
+
trackEvent("Outbound Link", { url: href }, { type: "click" });
|
|
235
|
+
}
|
|
236
|
+
} catch (e) {
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
document.addEventListener("click", clickListener);
|
|
240
|
+
}
|
|
241
|
+
function disableAutoOutboundTracking() {
|
|
242
|
+
if (!autoOutboundEnabled) return;
|
|
243
|
+
autoOutboundEnabled = false;
|
|
244
|
+
if (clickListener) {
|
|
245
|
+
document.removeEventListener("click", clickListener);
|
|
246
|
+
clickListener = null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function enableAutoEvents() {
|
|
250
|
+
if (autoEventsEnabled) return;
|
|
251
|
+
autoEventsEnabled = true;
|
|
252
|
+
dataEventClickListener = (event) => {
|
|
253
|
+
var _a;
|
|
254
|
+
const target = (_a = event.target) == null ? void 0 : _a.closest(
|
|
255
|
+
"[data-luchy-event]"
|
|
256
|
+
);
|
|
257
|
+
if (!target) return;
|
|
258
|
+
const name = target.getAttribute("data-luchy-event");
|
|
259
|
+
if (!name) return;
|
|
260
|
+
const payload = {};
|
|
261
|
+
for (const attr of Array.from(target.attributes)) {
|
|
262
|
+
const prefix = attr.name.startsWith("data-luchy-payload-") ? "data-luchy-payload-" : attr.name.startsWith("data-luchy-prop-") ? "data-luchy-prop-" : null;
|
|
263
|
+
if (!prefix) continue;
|
|
264
|
+
const key = attr.name.slice(prefix.length).replace(/-/g, "_");
|
|
265
|
+
payload[key] = attr.value;
|
|
266
|
+
}
|
|
267
|
+
trackEvent(
|
|
268
|
+
name,
|
|
269
|
+
Object.keys(payload).length > 0 ? payload : void 0,
|
|
270
|
+
{ type: "click" }
|
|
271
|
+
);
|
|
272
|
+
};
|
|
273
|
+
document.addEventListener("click", dataEventClickListener);
|
|
274
|
+
}
|
|
275
|
+
function disableAutoEvents() {
|
|
276
|
+
if (!autoEventsEnabled) return;
|
|
277
|
+
autoEventsEnabled = false;
|
|
278
|
+
if (dataEventClickListener) {
|
|
279
|
+
document.removeEventListener("click", dataEventClickListener);
|
|
280
|
+
dataEventClickListener = null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function setOptions(options2) {
|
|
284
|
+
if (options2.autoPageviews !== void 0) {
|
|
285
|
+
if (options2.autoPageviews) {
|
|
286
|
+
enableAutoPageviews();
|
|
287
|
+
} else {
|
|
288
|
+
disableAutoPageviews();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (options2.autoOutbound !== void 0) {
|
|
292
|
+
if (options2.autoOutbound) {
|
|
293
|
+
enableAutoOutboundTracking();
|
|
294
|
+
} else {
|
|
295
|
+
disableAutoOutboundTracking();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (options2.autoEvents !== void 0) {
|
|
299
|
+
if (options2.autoEvents) {
|
|
300
|
+
enableAutoEvents();
|
|
301
|
+
} else {
|
|
302
|
+
disableAutoEvents();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (options2.hashRouting !== void 0) {
|
|
306
|
+
if (options2.hashRouting) {
|
|
307
|
+
enableHashRouting();
|
|
308
|
+
} else {
|
|
309
|
+
disableHashRouting();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
trackPageview,
|
|
315
|
+
trackEvent,
|
|
316
|
+
setOptions
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
if (typeof document !== "undefined" && document.currentScript) {
|
|
320
|
+
const script = document.currentScript;
|
|
321
|
+
const apiKey = script.getAttribute("data-api-key");
|
|
322
|
+
const endpoint = script.getAttribute("data-endpoint") || void 0;
|
|
323
|
+
const trackLocalhost = script.hasAttribute("data-track-localhost");
|
|
324
|
+
if (apiKey) {
|
|
325
|
+
const tracker = luchy({
|
|
326
|
+
apiKey,
|
|
327
|
+
endpoint,
|
|
328
|
+
trackLocalhost
|
|
329
|
+
});
|
|
330
|
+
const autoPageviewsAttr = script.getAttribute("data-auto-pageviews");
|
|
331
|
+
const autoOutboundAttr = script.getAttribute("data-auto-outbound");
|
|
332
|
+
const autoEventsAttr = script.getAttribute("data-auto-events");
|
|
333
|
+
const hashRoutingAttr = script.getAttribute("data-hash-routing");
|
|
334
|
+
const options = {};
|
|
335
|
+
if (autoPageviewsAttr !== null) {
|
|
336
|
+
options.autoPageviews = autoPageviewsAttr !== "false";
|
|
337
|
+
}
|
|
338
|
+
if (autoOutboundAttr !== null) {
|
|
339
|
+
options.autoOutbound = autoOutboundAttr !== "false";
|
|
340
|
+
}
|
|
341
|
+
if (autoEventsAttr !== null) {
|
|
342
|
+
options.autoEvents = autoEventsAttr !== "false";
|
|
343
|
+
}
|
|
344
|
+
if (hashRoutingAttr !== null) {
|
|
345
|
+
options.hashRouting = hashRoutingAttr !== "false";
|
|
346
|
+
}
|
|
347
|
+
tracker.setOptions(__spreadValues({
|
|
348
|
+
autoPageviews: true,
|
|
349
|
+
autoOutbound: true,
|
|
350
|
+
autoEvents: true,
|
|
351
|
+
hashRouting: true
|
|
352
|
+
}, options));
|
|
353
|
+
window.luchy = tracker;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
exports.luchy = luchy;
|
|
357
|
+
})(this.luchy = this.luchy || {});
|
|
Binary file
|
|
Binary file
|