@inslytic/sdk-node 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +156 -0
- package/dist/index.mjs +129 -0
- package/package.json +57 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
type InslyticNodeConfig = {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
flushInterval?: number;
|
|
5
|
+
maxBatchSize?: number;
|
|
6
|
+
maxRetries?: number;
|
|
7
|
+
};
|
|
8
|
+
type NodeEventPayload = {
|
|
9
|
+
eventName: string;
|
|
10
|
+
userId?: string | null;
|
|
11
|
+
anonymousId: string;
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
properties?: Record<string, string>;
|
|
14
|
+
timestamp?: string;
|
|
15
|
+
consentGiven?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
declare class InslyticNode {
|
|
19
|
+
private queue;
|
|
20
|
+
private timer;
|
|
21
|
+
private endpoint;
|
|
22
|
+
private apiKey;
|
|
23
|
+
private maxBatchSize;
|
|
24
|
+
private maxRetries;
|
|
25
|
+
private flushing;
|
|
26
|
+
private shutdownRequested;
|
|
27
|
+
private shutdownHandlers;
|
|
28
|
+
constructor(config: InslyticNodeConfig);
|
|
29
|
+
track(event: NodeEventPayload): void;
|
|
30
|
+
identify(userId: string, _traits?: Record<string, string>): void;
|
|
31
|
+
flush(): Promise<void>;
|
|
32
|
+
shutdown(): Promise<void>;
|
|
33
|
+
get pending(): number;
|
|
34
|
+
private sendWithRetry;
|
|
35
|
+
private backoffMs;
|
|
36
|
+
private sleep;
|
|
37
|
+
private setupShutdownHandlers;
|
|
38
|
+
private removeShutdownHandlers;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { InslyticNode, type InslyticNodeConfig, type NodeEventPayload };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
type InslyticNodeConfig = {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
flushInterval?: number;
|
|
5
|
+
maxBatchSize?: number;
|
|
6
|
+
maxRetries?: number;
|
|
7
|
+
};
|
|
8
|
+
type NodeEventPayload = {
|
|
9
|
+
eventName: string;
|
|
10
|
+
userId?: string | null;
|
|
11
|
+
anonymousId: string;
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
properties?: Record<string, string>;
|
|
14
|
+
timestamp?: string;
|
|
15
|
+
consentGiven?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
declare class InslyticNode {
|
|
19
|
+
private queue;
|
|
20
|
+
private timer;
|
|
21
|
+
private endpoint;
|
|
22
|
+
private apiKey;
|
|
23
|
+
private maxBatchSize;
|
|
24
|
+
private maxRetries;
|
|
25
|
+
private flushing;
|
|
26
|
+
private shutdownRequested;
|
|
27
|
+
private shutdownHandlers;
|
|
28
|
+
constructor(config: InslyticNodeConfig);
|
|
29
|
+
track(event: NodeEventPayload): void;
|
|
30
|
+
identify(userId: string, _traits?: Record<string, string>): void;
|
|
31
|
+
flush(): Promise<void>;
|
|
32
|
+
shutdown(): Promise<void>;
|
|
33
|
+
get pending(): number;
|
|
34
|
+
private sendWithRetry;
|
|
35
|
+
private backoffMs;
|
|
36
|
+
private sleep;
|
|
37
|
+
private setupShutdownHandlers;
|
|
38
|
+
private removeShutdownHandlers;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { InslyticNode, type InslyticNodeConfig, type NodeEventPayload };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
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/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
InslyticNode: () => InslyticNode
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/client.ts
|
|
28
|
+
var DEFAULT_ENDPOINT = "https://api.inslytic.com";
|
|
29
|
+
var DEFAULT_FLUSH_INTERVAL = 1e4;
|
|
30
|
+
var DEFAULT_MAX_BATCH_SIZE = 20;
|
|
31
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
32
|
+
var InslyticNode = class {
|
|
33
|
+
queue = [];
|
|
34
|
+
timer = null;
|
|
35
|
+
endpoint;
|
|
36
|
+
apiKey;
|
|
37
|
+
maxBatchSize;
|
|
38
|
+
maxRetries;
|
|
39
|
+
flushing = false;
|
|
40
|
+
shutdownRequested = false;
|
|
41
|
+
shutdownHandlers = [];
|
|
42
|
+
constructor(config) {
|
|
43
|
+
this.endpoint = config.endpoint ?? DEFAULT_ENDPOINT;
|
|
44
|
+
this.apiKey = config.apiKey;
|
|
45
|
+
this.maxBatchSize = config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE;
|
|
46
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
47
|
+
const interval = config.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
|
|
48
|
+
this.timer = setInterval(() => this.flush(), interval);
|
|
49
|
+
this.setupShutdownHandlers();
|
|
50
|
+
}
|
|
51
|
+
track(event) {
|
|
52
|
+
if (this.shutdownRequested) return;
|
|
53
|
+
this.queue.push({
|
|
54
|
+
eventName: event.eventName,
|
|
55
|
+
timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
56
|
+
userId: event.userId ?? null,
|
|
57
|
+
anonymousId: event.anonymousId,
|
|
58
|
+
sessionId: event.sessionId ?? "",
|
|
59
|
+
consentGiven: event.consentGiven ?? true,
|
|
60
|
+
properties: event.properties ?? {},
|
|
61
|
+
pageUrl: "",
|
|
62
|
+
pageTitle: "",
|
|
63
|
+
referrer: "",
|
|
64
|
+
utmSource: null,
|
|
65
|
+
utmMedium: null,
|
|
66
|
+
utmCampaign: null
|
|
67
|
+
});
|
|
68
|
+
if (this.queue.length >= this.maxBatchSize) {
|
|
69
|
+
this.flush();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
identify(userId, _traits) {
|
|
73
|
+
this.track({
|
|
74
|
+
eventName: "$identify",
|
|
75
|
+
userId,
|
|
76
|
+
anonymousId: userId,
|
|
77
|
+
consentGiven: true
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async flush() {
|
|
81
|
+
if (this.queue.length === 0 || this.flushing) return;
|
|
82
|
+
this.flushing = true;
|
|
83
|
+
try {
|
|
84
|
+
while (this.queue.length > 0) {
|
|
85
|
+
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
86
|
+
await this.sendWithRetry(batch);
|
|
87
|
+
}
|
|
88
|
+
} finally {
|
|
89
|
+
this.flushing = false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async shutdown() {
|
|
93
|
+
this.shutdownRequested = true;
|
|
94
|
+
if (this.timer) {
|
|
95
|
+
clearInterval(this.timer);
|
|
96
|
+
this.timer = null;
|
|
97
|
+
}
|
|
98
|
+
this.removeShutdownHandlers();
|
|
99
|
+
await this.flush();
|
|
100
|
+
}
|
|
101
|
+
get pending() {
|
|
102
|
+
return this.queue.length;
|
|
103
|
+
}
|
|
104
|
+
async sendWithRetry(batch) {
|
|
105
|
+
const url = `${this.endpoint}/v1/ingest`;
|
|
106
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(url, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: {
|
|
111
|
+
"Content-Type": "application/json",
|
|
112
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
113
|
+
},
|
|
114
|
+
body: JSON.stringify({ events: batch })
|
|
115
|
+
});
|
|
116
|
+
if (response.ok || response.status < 500) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (attempt < this.maxRetries) {
|
|
120
|
+
await this.sleep(this.backoffMs(attempt));
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
if (attempt < this.maxRetries) {
|
|
124
|
+
await this.sleep(this.backoffMs(attempt));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
this.queue.unshift(...batch);
|
|
129
|
+
}
|
|
130
|
+
backoffMs(attempt) {
|
|
131
|
+
return Math.min(1e3 * 2 ** attempt, 3e4);
|
|
132
|
+
}
|
|
133
|
+
sleep(ms) {
|
|
134
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
135
|
+
}
|
|
136
|
+
setupShutdownHandlers() {
|
|
137
|
+
if (typeof process === "undefined") return;
|
|
138
|
+
const handler = () => {
|
|
139
|
+
this.shutdown();
|
|
140
|
+
};
|
|
141
|
+
for (const signal of ["SIGTERM", "SIGINT"]) {
|
|
142
|
+
process.on(signal, handler);
|
|
143
|
+
this.shutdownHandlers.push(() => process.removeListener(signal, handler));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
removeShutdownHandlers() {
|
|
147
|
+
for (const remove of this.shutdownHandlers) {
|
|
148
|
+
remove();
|
|
149
|
+
}
|
|
150
|
+
this.shutdownHandlers = [];
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
154
|
+
0 && (module.exports = {
|
|
155
|
+
InslyticNode
|
|
156
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
var DEFAULT_ENDPOINT = "https://api.inslytic.com";
|
|
3
|
+
var DEFAULT_FLUSH_INTERVAL = 1e4;
|
|
4
|
+
var DEFAULT_MAX_BATCH_SIZE = 20;
|
|
5
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
6
|
+
var InslyticNode = class {
|
|
7
|
+
queue = [];
|
|
8
|
+
timer = null;
|
|
9
|
+
endpoint;
|
|
10
|
+
apiKey;
|
|
11
|
+
maxBatchSize;
|
|
12
|
+
maxRetries;
|
|
13
|
+
flushing = false;
|
|
14
|
+
shutdownRequested = false;
|
|
15
|
+
shutdownHandlers = [];
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.endpoint = config.endpoint ?? DEFAULT_ENDPOINT;
|
|
18
|
+
this.apiKey = config.apiKey;
|
|
19
|
+
this.maxBatchSize = config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE;
|
|
20
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
21
|
+
const interval = config.flushInterval ?? DEFAULT_FLUSH_INTERVAL;
|
|
22
|
+
this.timer = setInterval(() => this.flush(), interval);
|
|
23
|
+
this.setupShutdownHandlers();
|
|
24
|
+
}
|
|
25
|
+
track(event) {
|
|
26
|
+
if (this.shutdownRequested) return;
|
|
27
|
+
this.queue.push({
|
|
28
|
+
eventName: event.eventName,
|
|
29
|
+
timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
30
|
+
userId: event.userId ?? null,
|
|
31
|
+
anonymousId: event.anonymousId,
|
|
32
|
+
sessionId: event.sessionId ?? "",
|
|
33
|
+
consentGiven: event.consentGiven ?? true,
|
|
34
|
+
properties: event.properties ?? {},
|
|
35
|
+
pageUrl: "",
|
|
36
|
+
pageTitle: "",
|
|
37
|
+
referrer: "",
|
|
38
|
+
utmSource: null,
|
|
39
|
+
utmMedium: null,
|
|
40
|
+
utmCampaign: null
|
|
41
|
+
});
|
|
42
|
+
if (this.queue.length >= this.maxBatchSize) {
|
|
43
|
+
this.flush();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
identify(userId, _traits) {
|
|
47
|
+
this.track({
|
|
48
|
+
eventName: "$identify",
|
|
49
|
+
userId,
|
|
50
|
+
anonymousId: userId,
|
|
51
|
+
consentGiven: true
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async flush() {
|
|
55
|
+
if (this.queue.length === 0 || this.flushing) return;
|
|
56
|
+
this.flushing = true;
|
|
57
|
+
try {
|
|
58
|
+
while (this.queue.length > 0) {
|
|
59
|
+
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
60
|
+
await this.sendWithRetry(batch);
|
|
61
|
+
}
|
|
62
|
+
} finally {
|
|
63
|
+
this.flushing = false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async shutdown() {
|
|
67
|
+
this.shutdownRequested = true;
|
|
68
|
+
if (this.timer) {
|
|
69
|
+
clearInterval(this.timer);
|
|
70
|
+
this.timer = null;
|
|
71
|
+
}
|
|
72
|
+
this.removeShutdownHandlers();
|
|
73
|
+
await this.flush();
|
|
74
|
+
}
|
|
75
|
+
get pending() {
|
|
76
|
+
return this.queue.length;
|
|
77
|
+
}
|
|
78
|
+
async sendWithRetry(batch) {
|
|
79
|
+
const url = `${this.endpoint}/v1/ingest`;
|
|
80
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: {
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
87
|
+
},
|
|
88
|
+
body: JSON.stringify({ events: batch })
|
|
89
|
+
});
|
|
90
|
+
if (response.ok || response.status < 500) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (attempt < this.maxRetries) {
|
|
94
|
+
await this.sleep(this.backoffMs(attempt));
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
if (attempt < this.maxRetries) {
|
|
98
|
+
await this.sleep(this.backoffMs(attempt));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
this.queue.unshift(...batch);
|
|
103
|
+
}
|
|
104
|
+
backoffMs(attempt) {
|
|
105
|
+
return Math.min(1e3 * 2 ** attempt, 3e4);
|
|
106
|
+
}
|
|
107
|
+
sleep(ms) {
|
|
108
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
109
|
+
}
|
|
110
|
+
setupShutdownHandlers() {
|
|
111
|
+
if (typeof process === "undefined") return;
|
|
112
|
+
const handler = () => {
|
|
113
|
+
this.shutdown();
|
|
114
|
+
};
|
|
115
|
+
for (const signal of ["SIGTERM", "SIGINT"]) {
|
|
116
|
+
process.on(signal, handler);
|
|
117
|
+
this.shutdownHandlers.push(() => process.removeListener(signal, handler));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
removeShutdownHandlers() {
|
|
121
|
+
for (const remove of this.shutdownHandlers) {
|
|
122
|
+
remove();
|
|
123
|
+
}
|
|
124
|
+
this.shutdownHandlers = [];
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
export {
|
|
128
|
+
InslyticNode
|
|
129
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inslytic/sdk-node",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Node.js server-side SDK for Inslytic — AI-powered product analytics",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/inslytic/inslytic",
|
|
9
|
+
"directory": "packages/sdk-node"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"analytics",
|
|
13
|
+
"tracking",
|
|
14
|
+
"product-analytics",
|
|
15
|
+
"node",
|
|
16
|
+
"server-side",
|
|
17
|
+
"inslytic"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"module": "./dist/index.mjs",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"import": {
|
|
26
|
+
"types": "./dist/index.d.mts",
|
|
27
|
+
"default": "./dist/index.mjs"
|
|
28
|
+
},
|
|
29
|
+
"require": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^25.2.3",
|
|
46
|
+
"tsup": "^8.0.0",
|
|
47
|
+
"typescript": "^5.7.0",
|
|
48
|
+
"vitest": "^3.0.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
52
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --watch",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"clean": "rm -rf dist .turbo node_modules"
|
|
56
|
+
}
|
|
57
|
+
}
|