@veridia/node-sdk 1.0.2

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.
@@ -0,0 +1,49 @@
1
+ name: Build & Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*.*.*' # triggers only for version tags (v1.0.0, v1.1.2, etc.)
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ name: Build and publish to npm
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write
14
+
15
+ steps:
16
+ - name: Checkout repository
17
+ uses: actions/checkout@v4
18
+
19
+ - name: Use Node.js 22
20
+ uses: actions/setup-node@v4
21
+ with:
22
+ node-version: 22
23
+ registry-url: 'https://registry.npmjs.org/'
24
+
25
+ - name: Install dependencies
26
+ run: npm ci
27
+
28
+ - name: Lint
29
+ run: npm run lint --if-present
30
+
31
+ - name: Run tests
32
+ run: npm test --if-present
33
+
34
+ - name: Build SDK (CJS + ESM)
35
+ run: npm run build
36
+
37
+ - name: Verify package contents
38
+ run: npm pack --dry-run
39
+
40
+ - name: Publish to npm
41
+ if: startsWith(github.ref, 'refs/tags/v')
42
+ env:
43
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
44
+ run: npm publish --access public
45
+
46
+ - name: Create GitHub Release
47
+ uses: softprops/action-gh-release@v2
48
+ with:
49
+ generate_release_notes: true
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 veridia-io
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # Veridia Node SDK
2
+
3
+ Official Node.js SDK for integrating with [Veridia Platform](https://veridia.io).
4
+ It provides an easy way to send user identification and tracking data, retrieve user segments, and integrate Veridia into your backend systems.
5
+
6
+ ---
7
+
8
+ ## 🚀 Installation
9
+
10
+ ```bash
11
+ npm install @veridia/node-sdk
12
+ ```
13
+
14
+ or with Yarn:
15
+
16
+ ```bash
17
+ yarn add @veridia/node-sdk
18
+ ```
19
+
20
+ ---
21
+
22
+ ## 📦 Usage
23
+
24
+ ### ESM
25
+
26
+ ```ts
27
+ import { VeridiaClient } from '@veridia/node-sdk';
28
+
29
+ const client = new VeridiaClient({
30
+ accessKeyId: 'your-access-key-id',
31
+ secretAccessKey: 'your-secret-access-key',
32
+ logger: {
33
+ error: (service, msg, ctx) => console.error(`[ERROR] ${service}: ${msg}`, ctx),
34
+ warn: (service, msg, ctx) => console.warn(`[WARN] ${service}: ${msg}`, ctx),
35
+ info: (service, msg, ctx) => console.log(`[INFO] ${service}: ${msg}`, ctx),
36
+ },
37
+ });
38
+ ```
39
+
40
+ ### CommonJS
41
+
42
+ ```js
43
+ const { VeridiaClient } = require('@veridia/node-sdk');
44
+
45
+ const client = new VeridiaClient({
46
+ accessKeyId: 'your-access-key-id',
47
+ secretAccessKey: 'your-secret-access-key',
48
+ logger: { error: console.error },
49
+ });
50
+ ```
51
+
52
+ ---
53
+
54
+ ## 🧠 API Reference
55
+
56
+ ### `identify(identifierType, identifierId, attributes)`
57
+
58
+ Identify a user and update their profile attributes. Provided attributes must match the Profile Attributes schema defined in the Veridia dashboard.
59
+
60
+ ```ts
61
+ await client.identify('userId', '123', {
62
+ email: 'user@example.com',
63
+ country: 'US',
64
+ plan: 'premium',
65
+ });
66
+ ```
67
+
68
+ | Parameter | Type | Description |
69
+ | ---------------- | ----------------------- | ---------------------------- |
70
+ | `identifierType` | `"userId"` \| `"email"` | How the user is identified. |
71
+ | `identifierId` | `string` | The unique identifier value. |
72
+ | `attributes` | `Record<string, any>` | Arbitrary user attributes. |
73
+
74
+ ---
75
+
76
+ ### `track(identifierType, identifierId, eventType, eventId, eventTime, properties)`
77
+
78
+ Track an event performed by a user. Provided attributes must match the event attributes schema defined in the Veridia dashboard.
79
+
80
+ ```ts
81
+ await client.track('userId', '123', 'purchase', 'evt-001', new Date().toISOString(), {
82
+ productId: 'A-1',
83
+ price: 49.99,
84
+ });
85
+ ```
86
+
87
+ | Parameter | Type | Description |
88
+ | ---------------- | ----------------------- | ----------------------------------- |
89
+ | `identifierType` | `"userId"` \| `"email"` | How the user is identified. |
90
+ | `identifierId` | `string` | Unique identifier for the user. |
91
+ | `eventType` | `string` | Event type as in Veridia dashboard. |
92
+ | `eventId` | `string` | Unique event ID for idempotency. |
93
+ | `eventTime` | `string` | ISO timestamp string. |
94
+ | `properties` | `Record<string, any>` | Optional event properties. |
95
+
96
+ ---
97
+
98
+ ### `getUserSegments(identifierType, identifierId)`
99
+
100
+ Fetches the list of segments the specified user currently belongs to.
101
+
102
+ ```ts
103
+ const segments = await client.getUserSegments('userId', '123');
104
+ console.log(segments); // ['617090ac-a1f6-4c70-a79e-40830a367324', '67f2c139-850f-469f-9ca4-a1c58e6d84ea']
105
+ ```
106
+
107
+ Returns:
108
+ `Promise<string[]>` — Array of segment identifiers.
109
+
110
+ ---
111
+
112
+ ### `flush()`
113
+
114
+ Immediately sends all queued identify and track data.
115
+
116
+ ```ts
117
+ await client.flush();
118
+ ```
119
+
120
+ ### `close()`
121
+
122
+ Flushes all pending data and prepares the client for shutdown.
123
+ Call this before process exit in background workers or serverless functions.
124
+
125
+ ```ts
126
+ await client.close();
127
+ ```
128
+
129
+ ---
130
+
131
+ ## ⚙️ Configuration Options
132
+
133
+ | Option | Type | Default | Description |
134
+ | -------------------------- | --------------- | --------------------------- | -------------------------------------- |
135
+ | `accessKeyId` | `string` | — | Veridia API access key ID |
136
+ | `secretAccessKey` | `string` | — | Veridia API secret |
137
+ | `endpoint` | `string` | `https://api.veridia.io/v1` | API base URL |
138
+ | `region` | `string` | `"default"` | API region |
139
+ | `maxBufferSize` | `number` | `500` | Max number of items before auto-flush |
140
+ | `maxBufferTimeMs` | `number` | `5000` | Max time before auto-flush |
141
+ | `retries` | `number` | `3` | Retry attempts on transient errors |
142
+ | `timeoutMsGetUserSegments` | `number` | `5000` | Timeout for `getUserSegments` requests |
143
+ | `timeoutMsFlush` | `number` | `30000` | Timeout for batch flush |
144
+ | `logger` | `VeridiaLogger` | — | Custom logger implementation |
145
+
146
+ ---
147
+
148
+ ## 🧾 Logger Interface
149
+
150
+ The SDK supports pluggable logging.
151
+ You can integrate your own logger (e.g. Pino, Winston, Bunyan) by providing the following interface:
152
+
153
+ ```ts
154
+ interface VeridiaLogger {
155
+ info(service: string, message: string, context?: unknown): void;
156
+ warn(service: string, message: string, context?: unknown): void;
157
+ error(service: string, message: string, context?: unknown): void;
158
+ }
159
+ ```
160
+
161
+ Example:
162
+
163
+ ```ts
164
+ import pino from 'pino';
165
+ const log = pino();
166
+
167
+ const client = new VeridiaClient({
168
+ accessKeyId: '...',
169
+ secretAccessKey: '...',
170
+ logger: {
171
+ info: (s, m, c) => log.info({ service: s, context: c }, m),
172
+ warn: (s, m, c) => log.warn({ service: s, context: c }, m),
173
+ error: (s, m, c) => log.error({ service: s, context: c }, m),
174
+ },
175
+ });
176
+ ```
177
+
178
+ ---
179
+
180
+ ## 🧩 TypeScript Support
181
+
182
+ The SDK ships with full `.d.ts` declarations and JSDoc for IntelliSense.
183
+ Hover over any method in VS Code to see inline documentation and parameter hints.
184
+
185
+ ---
186
+
187
+ ## 🧪 Example Usage
188
+
189
+ ```ts
190
+ import { VeridiaClient } from '@veridia/node-sdk';
191
+
192
+ const client = new VeridiaClient({
193
+ accessKeyId: 'test',
194
+ secretAccessKey: 'test',
195
+ logger: { error: console.error },
196
+ });
197
+
198
+ await client.identify('userId', '123', { plan: 'gold' });
199
+ await client.track('userId', '123', 'purchase', 'evt-123', new Date().toISOString());
200
+ await client.flush();
201
+ ```
202
+
203
+ ---
204
+
205
+ ## 🧱 License
206
+
207
+ [MIT](./LICENSE) © Veridia
@@ -0,0 +1,56 @@
1
+ import { IdentifierPayload, IdentifyPayload, TrackPayload, VeridiaClientOptions } from './types.js';
2
+ export declare class VeridiaClient {
3
+ private readonly options;
4
+ private trackBuffer;
5
+ private identifyBuffer;
6
+ private flushTimer?;
7
+ private readonly logger;
8
+ private readonly baseUrl;
9
+ private readonly region;
10
+ private readonly maxBufferSize;
11
+ private readonly maxBufferTimeMs;
12
+ private readonly retries;
13
+ private readonly retryBaseDelayMs;
14
+ private readonly timeoutMsGetUserSegments;
15
+ private readonly timeoutMsFlush;
16
+ constructor(options: VeridiaClientOptions);
17
+ /**
18
+ * Queues a user identification update to be flushed in batch.
19
+ *
20
+ * @param identifierType - The type of user identifier ("userId" | "email").
21
+ * @param identifierId - The unique ID or email.
22
+ * @param attributes - Key/value map of user attributes.
23
+ */
24
+ identify(identifierType: IdentifierPayload['type'], identifierId: IdentifierPayload['id'], attributes: IdentifyPayload['attributes']): void;
25
+ /**
26
+ * Sends a tracking event for the given user.
27
+ *
28
+ * @param identifierType - The type of user identifier ("userId" | "email").
29
+ * @param identifierId - The unique ID or email.
30
+ * @param eventType - Logical name of the event.
31
+ * @param eventId - Unique ID for idempotency.
32
+ * @param eventTime - ISO timestamp string.
33
+ * @param properties - Arbitrary event properties.
34
+ */
35
+ track(identifierType: IdentifierPayload['type'], identifierId: IdentifierPayload['id'], eventType: TrackPayload['eventType'], eventId: TrackPayload['eventId'], eventTime: TrackPayload['eventTime'], properties: TrackPayload['properties']): void;
36
+ /**
37
+ * Retrieves the current segments for the given user.
38
+ *
39
+ * @param identifierType - The type of user identifier ("userId" | "email").
40
+ * @param identifierId - The unique ID or email.
41
+ * @returns A list of segment identifiers the user currently belongs to.
42
+ */
43
+ getUserSegments(identifierType: IdentifierPayload['type'], identifierId: string): Promise<string[]>;
44
+ /**
45
+ * Sends all queued identify and track data to the Veridia API immediately.
46
+ * Automatically called when buffers reach their limit or after the configured time interval.
47
+ */
48
+ flush(): Promise<void>;
49
+ /**
50
+ * Flushes all pending data and prepares the client for shutdown.
51
+ * Should be called before application exit to ensure all data is sent.
52
+ */
53
+ close(): Promise<void>;
54
+ private scheduleFlushIfNeeded;
55
+ private flushBatch;
56
+ }
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.VeridiaClient = void 0;
37
+ const aws4 = __importStar(require("aws4"));
38
+ const http_js_1 = require("./http.js");
39
+ const version_js_1 = require("./version.js");
40
+ class VeridiaClient {
41
+ constructor(options) {
42
+ this.options = options;
43
+ this.trackBuffer = [];
44
+ this.identifyBuffer = [];
45
+ this.baseUrl = options.endpoint ?? 'https://api.veridia.io/v1';
46
+ this.region = options.region ?? 'default';
47
+ this.maxBufferSize = options.maxBufferSize ?? 500;
48
+ this.maxBufferTimeMs = options.maxBufferTimeMs ?? 5000;
49
+ this.retries = options.retries ?? 3;
50
+ this.retryBaseDelayMs = options.retryBaseDelayMs ?? 500;
51
+ this.timeoutMsGetUserSegments = options.timeoutMsGetUserSegments ?? 5_000;
52
+ this.timeoutMsFlush = options.timeoutMsFlush ?? 30_000;
53
+ this.logger = options.logger;
54
+ }
55
+ /**
56
+ * Queues a user identification update to be flushed in batch.
57
+ *
58
+ * @param identifierType - The type of user identifier ("userId" | "email").
59
+ * @param identifierId - The unique ID or email.
60
+ * @param attributes - Key/value map of user attributes.
61
+ */
62
+ identify(identifierType, identifierId, attributes) {
63
+ this.identifyBuffer.push({
64
+ identifier: {
65
+ type: identifierType,
66
+ id: identifierId,
67
+ },
68
+ attributes,
69
+ });
70
+ this.scheduleFlushIfNeeded(this.identifyBuffer);
71
+ }
72
+ /**
73
+ * Sends a tracking event for the given user.
74
+ *
75
+ * @param identifierType - The type of user identifier ("userId" | "email").
76
+ * @param identifierId - The unique ID or email.
77
+ * @param eventType - Logical name of the event.
78
+ * @param eventId - Unique ID for idempotency.
79
+ * @param eventTime - ISO timestamp string.
80
+ * @param properties - Arbitrary event properties.
81
+ */
82
+ track(identifierType, identifierId, eventType, eventId, eventTime, properties) {
83
+ this.trackBuffer.push({
84
+ identifier: { type: identifierType, id: identifierId },
85
+ eventId,
86
+ eventType,
87
+ eventTime,
88
+ properties,
89
+ });
90
+ this.scheduleFlushIfNeeded(this.trackBuffer);
91
+ }
92
+ /**
93
+ * Retrieves the current segments for the given user.
94
+ *
95
+ * @param identifierType - The type of user identifier ("userId" | "email").
96
+ * @param identifierId - The unique ID or email.
97
+ * @returns A list of segment identifiers the user currently belongs to.
98
+ */
99
+ async getUserSegments(identifierType, identifierId) {
100
+ try {
101
+ const path = `/segments/${identifierType}/${encodeURIComponent(identifierId)}`;
102
+ const url = `${this.baseUrl}${path}`;
103
+ const req = {
104
+ host: new URL(url).host,
105
+ path,
106
+ method: 'GET',
107
+ service: 'segments',
108
+ region: this.region,
109
+ headers: { 'User-Agent': `veridia-node-sdk/${version_js_1.SDK_VERSION}` },
110
+ };
111
+ aws4.sign(req, this.options);
112
+ const controller = new AbortController();
113
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMsGetUserSegments);
114
+ const res = await (0, http_js_1.httpFetch)(url, {
115
+ method: req.method,
116
+ headers: req.headers,
117
+ signal: controller.signal,
118
+ }).finally(() => clearTimeout(timeout));
119
+ if (!res.ok) {
120
+ this.logger?.error('segments', 'getUserSegments API call failed', { status: res.status });
121
+ return [];
122
+ }
123
+ const data = (await res.json());
124
+ if (data.status === 'success' && Array.isArray(data.data)) {
125
+ return data.data;
126
+ }
127
+ this.logger?.error('segments', 'getUserSegments API returned invalid response', {
128
+ data: data,
129
+ });
130
+ return [];
131
+ }
132
+ catch (err) {
133
+ this.logger?.error('segments', 'getUserSegments encountered an error', {
134
+ error: err,
135
+ });
136
+ return [];
137
+ }
138
+ }
139
+ /**
140
+ * Sends all queued identify and track data to the Veridia API immediately.
141
+ * Automatically called when buffers reach their limit or after the configured time interval.
142
+ */
143
+ async flush() {
144
+ if (this.flushTimer) {
145
+ clearTimeout(this.flushTimer);
146
+ this.flushTimer = undefined;
147
+ }
148
+ await Promise.all([
149
+ this.flushBatch('profiles', this.identifyBuffer),
150
+ this.flushBatch('events', this.trackBuffer),
151
+ ]);
152
+ }
153
+ /**
154
+ * Flushes all pending data and prepares the client for shutdown.
155
+ * Should be called before application exit to ensure all data is sent.
156
+ */
157
+ async close() {
158
+ await this.flush();
159
+ }
160
+ scheduleFlushIfNeeded(buffer) {
161
+ if (buffer.length >= this.maxBufferSize) {
162
+ void this.flush();
163
+ }
164
+ else if (!this.flushTimer) {
165
+ this.flushTimer = setTimeout(() => this.flush(), this.maxBufferTimeMs);
166
+ }
167
+ }
168
+ async flushBatch(service, buffer) {
169
+ if (buffer.length === 0)
170
+ return;
171
+ const batch = [...buffer];
172
+ buffer.length = 0; // clear buffer safely
173
+ const urlObj = new URL(this.baseUrl + '/' + service);
174
+ const opts = {
175
+ host: urlObj.host,
176
+ path: urlObj.pathname + urlObj.search,
177
+ method: 'POST',
178
+ headers: {
179
+ 'Content-Type': 'application/json',
180
+ 'User-Agent': `veridia-node-sdk/${version_js_1.SDK_VERSION}`,
181
+ },
182
+ body: JSON.stringify({ [service]: batch }),
183
+ service,
184
+ region: this.region,
185
+ };
186
+ aws4.sign(opts, this.options);
187
+ const signedOpts = {
188
+ method: opts.method,
189
+ headers: opts.headers,
190
+ body: opts.body,
191
+ };
192
+ for (let attempt = 1; attempt <= this.retries; attempt++) {
193
+ try {
194
+ const controller = new AbortController();
195
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMsFlush);
196
+ const res = await (0, http_js_1.httpFetch)(urlObj.toString(), {
197
+ ...signedOpts,
198
+ signal: controller.signal,
199
+ }).finally(() => clearTimeout(timeout));
200
+ if (!res.ok) {
201
+ throw new Error(`${service} flush failed: ${res.status}`);
202
+ }
203
+ if (this.logger?.info)
204
+ this.logger.info(service, 'flush completed', { batchSize: batch.length });
205
+ return;
206
+ }
207
+ catch (err) {
208
+ if (this.logger?.warn)
209
+ this.logger.warn(service, `flush attempt ${attempt} failed`, { error: err });
210
+ if (attempt === this.retries) {
211
+ this.logger?.error(service, `flush failed after max retries`, { error: err });
212
+ throw err;
213
+ }
214
+ await new Promise((r) => setTimeout(r, this.retryBaseDelayMs * 2 ** (attempt - 1))); // backoff
215
+ }
216
+ }
217
+ }
218
+ }
219
+ exports.VeridiaClient = VeridiaClient;
220
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ export declare function httpFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.httpFetch = httpFetch;
37
+ let _fetch;
38
+ async function getFetch() {
39
+ if (_fetch)
40
+ return _fetch;
41
+ if (typeof globalThis.fetch === 'function') {
42
+ _fetch = globalThis.fetch.bind(globalThis);
43
+ }
44
+ else {
45
+ const mod = await Promise.resolve().then(() => __importStar(require('node-fetch')));
46
+ _fetch = (mod.default ?? mod);
47
+ }
48
+ return _fetch;
49
+ }
50
+ async function httpFetch(input, init) {
51
+ const f = await getFetch();
52
+ return f(input, init);
53
+ }
54
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1,2 @@
1
+ export * from './types.js';
2
+ export * from './client.js';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types.js"), exports);
18
+ __exportStar(require("./client.js"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,57 @@
1
+ export interface VeridiaLogContext {
2
+ status?: number;
3
+ error?: unknown;
4
+ data?: unknown;
5
+ [key: string]: unknown;
6
+ }
7
+ export type VeridiaLogger = {
8
+ /**
9
+ * Logs informational messages.
10
+ * @param service - Service called the logger.
11
+ * @param message - Human-readable message.
12
+ * @param context - Optional structured data or additional info.
13
+ */
14
+ info?: (service: string, message: string, context?: VeridiaLogContext) => void;
15
+ /**
16
+ * Logs warnings.
17
+ * @param service - Service called the logger.
18
+ * @param message - Human-readable message.
19
+ * @param context - Optional structured data or additional info.
20
+ */
21
+ warn?: (service: string, message: string, context?: VeridiaLogContext) => void;
22
+ /**
23
+ * Logs errors.
24
+ * @param service - Service called the logger.
25
+ * @param message - Human-readable message.
26
+ * @param context - Optional structured data or additional info.
27
+ */
28
+ error: (service: string, message: string, context?: VeridiaLogContext) => void;
29
+ };
30
+ export type VeridiaClientOptions = {
31
+ accessKeyId: string;
32
+ secretAccessKey: string;
33
+ endpoint?: string;
34
+ region?: string;
35
+ maxBufferSize?: number;
36
+ maxBufferTimeMs?: number;
37
+ retries?: number;
38
+ retryBaseDelayMs?: number;
39
+ timeoutMsGetUserSegments?: number;
40
+ timeoutMsFlush?: number;
41
+ logger?: VeridiaLogger;
42
+ };
43
+ export type IdentifierPayload = {
44
+ type: 'userId' | 'email';
45
+ id: string;
46
+ };
47
+ export type IdentifyPayload = {
48
+ identifier: IdentifierPayload;
49
+ attributes: any;
50
+ };
51
+ export type TrackPayload = {
52
+ identifier: IdentifierPayload;
53
+ eventId: string;
54
+ eventType: string;
55
+ eventTime: string;
56
+ properties: any;
57
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ export declare const SDK_VERSION = "1.0.2";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SDK_VERSION = void 0;
4
+ exports.SDK_VERSION = '1.0.2';
5
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1,56 @@
1
+ import { IdentifierPayload, IdentifyPayload, TrackPayload, VeridiaClientOptions } from './types.js';
2
+ export declare class VeridiaClient {
3
+ private readonly options;
4
+ private trackBuffer;
5
+ private identifyBuffer;
6
+ private flushTimer?;
7
+ private readonly logger;
8
+ private readonly baseUrl;
9
+ private readonly region;
10
+ private readonly maxBufferSize;
11
+ private readonly maxBufferTimeMs;
12
+ private readonly retries;
13
+ private readonly retryBaseDelayMs;
14
+ private readonly timeoutMsGetUserSegments;
15
+ private readonly timeoutMsFlush;
16
+ constructor(options: VeridiaClientOptions);
17
+ /**
18
+ * Queues a user identification update to be flushed in batch.
19
+ *
20
+ * @param identifierType - The type of user identifier ("userId" | "email").
21
+ * @param identifierId - The unique ID or email.
22
+ * @param attributes - Key/value map of user attributes.
23
+ */
24
+ identify(identifierType: IdentifierPayload['type'], identifierId: IdentifierPayload['id'], attributes: IdentifyPayload['attributes']): void;
25
+ /**
26
+ * Sends a tracking event for the given user.
27
+ *
28
+ * @param identifierType - The type of user identifier ("userId" | "email").
29
+ * @param identifierId - The unique ID or email.
30
+ * @param eventType - Logical name of the event.
31
+ * @param eventId - Unique ID for idempotency.
32
+ * @param eventTime - ISO timestamp string.
33
+ * @param properties - Arbitrary event properties.
34
+ */
35
+ track(identifierType: IdentifierPayload['type'], identifierId: IdentifierPayload['id'], eventType: TrackPayload['eventType'], eventId: TrackPayload['eventId'], eventTime: TrackPayload['eventTime'], properties: TrackPayload['properties']): void;
36
+ /**
37
+ * Retrieves the current segments for the given user.
38
+ *
39
+ * @param identifierType - The type of user identifier ("userId" | "email").
40
+ * @param identifierId - The unique ID or email.
41
+ * @returns A list of segment identifiers the user currently belongs to.
42
+ */
43
+ getUserSegments(identifierType: IdentifierPayload['type'], identifierId: string): Promise<string[]>;
44
+ /**
45
+ * Sends all queued identify and track data to the Veridia API immediately.
46
+ * Automatically called when buffers reach their limit or after the configured time interval.
47
+ */
48
+ flush(): Promise<void>;
49
+ /**
50
+ * Flushes all pending data and prepares the client for shutdown.
51
+ * Should be called before application exit to ensure all data is sent.
52
+ */
53
+ close(): Promise<void>;
54
+ private scheduleFlushIfNeeded;
55
+ private flushBatch;
56
+ }
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.VeridiaClient = void 0;
37
+ const aws4 = __importStar(require("aws4"));
38
+ const http_js_1 = require("./http.js");
39
+ const version_js_1 = require("./version.js");
40
+ class VeridiaClient {
41
+ constructor(options) {
42
+ this.options = options;
43
+ this.trackBuffer = [];
44
+ this.identifyBuffer = [];
45
+ this.baseUrl = options.endpoint ?? 'https://api.veridia.io/v1';
46
+ this.region = options.region ?? 'default';
47
+ this.maxBufferSize = options.maxBufferSize ?? 500;
48
+ this.maxBufferTimeMs = options.maxBufferTimeMs ?? 5000;
49
+ this.retries = options.retries ?? 3;
50
+ this.retryBaseDelayMs = options.retryBaseDelayMs ?? 500;
51
+ this.timeoutMsGetUserSegments = options.timeoutMsGetUserSegments ?? 5_000;
52
+ this.timeoutMsFlush = options.timeoutMsFlush ?? 30_000;
53
+ this.logger = options.logger;
54
+ }
55
+ /**
56
+ * Queues a user identification update to be flushed in batch.
57
+ *
58
+ * @param identifierType - The type of user identifier ("userId" | "email").
59
+ * @param identifierId - The unique ID or email.
60
+ * @param attributes - Key/value map of user attributes.
61
+ */
62
+ identify(identifierType, identifierId, attributes) {
63
+ this.identifyBuffer.push({
64
+ identifier: {
65
+ type: identifierType,
66
+ id: identifierId,
67
+ },
68
+ attributes,
69
+ });
70
+ this.scheduleFlushIfNeeded(this.identifyBuffer);
71
+ }
72
+ /**
73
+ * Sends a tracking event for the given user.
74
+ *
75
+ * @param identifierType - The type of user identifier ("userId" | "email").
76
+ * @param identifierId - The unique ID or email.
77
+ * @param eventType - Logical name of the event.
78
+ * @param eventId - Unique ID for idempotency.
79
+ * @param eventTime - ISO timestamp string.
80
+ * @param properties - Arbitrary event properties.
81
+ */
82
+ track(identifierType, identifierId, eventType, eventId, eventTime, properties) {
83
+ this.trackBuffer.push({
84
+ identifier: { type: identifierType, id: identifierId },
85
+ eventId,
86
+ eventType,
87
+ eventTime,
88
+ properties,
89
+ });
90
+ this.scheduleFlushIfNeeded(this.trackBuffer);
91
+ }
92
+ /**
93
+ * Retrieves the current segments for the given user.
94
+ *
95
+ * @param identifierType - The type of user identifier ("userId" | "email").
96
+ * @param identifierId - The unique ID or email.
97
+ * @returns A list of segment identifiers the user currently belongs to.
98
+ */
99
+ async getUserSegments(identifierType, identifierId) {
100
+ try {
101
+ const path = `/segments/${identifierType}/${encodeURIComponent(identifierId)}`;
102
+ const url = `${this.baseUrl}${path}`;
103
+ const req = {
104
+ host: new URL(url).host,
105
+ path,
106
+ method: 'GET',
107
+ service: 'segments',
108
+ region: this.region,
109
+ headers: { 'User-Agent': `veridia-node-sdk/${version_js_1.SDK_VERSION}` },
110
+ };
111
+ aws4.sign(req, this.options);
112
+ const controller = new AbortController();
113
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMsGetUserSegments);
114
+ const res = await (0, http_js_1.httpFetch)(url, {
115
+ method: req.method,
116
+ headers: req.headers,
117
+ signal: controller.signal,
118
+ }).finally(() => clearTimeout(timeout));
119
+ if (!res.ok) {
120
+ this.logger?.error('segments', 'getUserSegments API call failed', { status: res.status });
121
+ return [];
122
+ }
123
+ const data = (await res.json());
124
+ if (data.status === 'success' && Array.isArray(data.data)) {
125
+ return data.data;
126
+ }
127
+ this.logger?.error('segments', 'getUserSegments API returned invalid response', {
128
+ data: data,
129
+ });
130
+ return [];
131
+ }
132
+ catch (err) {
133
+ this.logger?.error('segments', 'getUserSegments encountered an error', {
134
+ error: err,
135
+ });
136
+ return [];
137
+ }
138
+ }
139
+ /**
140
+ * Sends all queued identify and track data to the Veridia API immediately.
141
+ * Automatically called when buffers reach their limit or after the configured time interval.
142
+ */
143
+ async flush() {
144
+ if (this.flushTimer) {
145
+ clearTimeout(this.flushTimer);
146
+ this.flushTimer = undefined;
147
+ }
148
+ await Promise.all([
149
+ this.flushBatch('profiles', this.identifyBuffer),
150
+ this.flushBatch('events', this.trackBuffer),
151
+ ]);
152
+ }
153
+ /**
154
+ * Flushes all pending data and prepares the client for shutdown.
155
+ * Should be called before application exit to ensure all data is sent.
156
+ */
157
+ async close() {
158
+ await this.flush();
159
+ }
160
+ scheduleFlushIfNeeded(buffer) {
161
+ if (buffer.length >= this.maxBufferSize) {
162
+ void this.flush();
163
+ }
164
+ else if (!this.flushTimer) {
165
+ this.flushTimer = setTimeout(() => this.flush(), this.maxBufferTimeMs);
166
+ }
167
+ }
168
+ async flushBatch(service, buffer) {
169
+ if (buffer.length === 0)
170
+ return;
171
+ const batch = [...buffer];
172
+ buffer.length = 0; // clear buffer safely
173
+ const urlObj = new URL(this.baseUrl + '/' + service);
174
+ const opts = {
175
+ host: urlObj.host,
176
+ path: urlObj.pathname + urlObj.search,
177
+ method: 'POST',
178
+ headers: {
179
+ 'Content-Type': 'application/json',
180
+ 'User-Agent': `veridia-node-sdk/${version_js_1.SDK_VERSION}`,
181
+ },
182
+ body: JSON.stringify({ [service]: batch }),
183
+ service,
184
+ region: this.region,
185
+ };
186
+ aws4.sign(opts, this.options);
187
+ const signedOpts = {
188
+ method: opts.method,
189
+ headers: opts.headers,
190
+ body: opts.body,
191
+ };
192
+ for (let attempt = 1; attempt <= this.retries; attempt++) {
193
+ try {
194
+ const controller = new AbortController();
195
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMsFlush);
196
+ const res = await (0, http_js_1.httpFetch)(urlObj.toString(), {
197
+ ...signedOpts,
198
+ signal: controller.signal,
199
+ }).finally(() => clearTimeout(timeout));
200
+ if (!res.ok) {
201
+ throw new Error(`${service} flush failed: ${res.status}`);
202
+ }
203
+ if (this.logger?.info)
204
+ this.logger.info(service, 'flush completed', { batchSize: batch.length });
205
+ return;
206
+ }
207
+ catch (err) {
208
+ if (this.logger?.warn)
209
+ this.logger.warn(service, `flush attempt ${attempt} failed`, { error: err });
210
+ if (attempt === this.retries) {
211
+ this.logger?.error(service, `flush failed after max retries`, { error: err });
212
+ throw err;
213
+ }
214
+ await new Promise((r) => setTimeout(r, this.retryBaseDelayMs * 2 ** (attempt - 1))); // backoff
215
+ }
216
+ }
217
+ }
218
+ }
219
+ exports.VeridiaClient = VeridiaClient;
220
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ export declare function httpFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.httpFetch = httpFetch;
4
+ let _fetch;
5
+ async function getFetch() {
6
+ if (_fetch)
7
+ return _fetch;
8
+ if (typeof globalThis.fetch === 'function') {
9
+ _fetch = globalThis.fetch.bind(globalThis);
10
+ }
11
+ else {
12
+ const mod = await import('node-fetch');
13
+ _fetch = (mod.default ?? mod);
14
+ }
15
+ return _fetch;
16
+ }
17
+ async function httpFetch(input, init) {
18
+ const f = await getFetch();
19
+ return f(input, init);
20
+ }
21
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1,2 @@
1
+ export * from './types.js';
2
+ export * from './client.js';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types.js"), exports);
18
+ __exportStar(require("./client.js"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,57 @@
1
+ export interface VeridiaLogContext {
2
+ status?: number;
3
+ error?: unknown;
4
+ data?: unknown;
5
+ [key: string]: unknown;
6
+ }
7
+ export type VeridiaLogger = {
8
+ /**
9
+ * Logs informational messages.
10
+ * @param service - Service called the logger.
11
+ * @param message - Human-readable message.
12
+ * @param context - Optional structured data or additional info.
13
+ */
14
+ info?: (service: string, message: string, context?: VeridiaLogContext) => void;
15
+ /**
16
+ * Logs warnings.
17
+ * @param service - Service called the logger.
18
+ * @param message - Human-readable message.
19
+ * @param context - Optional structured data or additional info.
20
+ */
21
+ warn?: (service: string, message: string, context?: VeridiaLogContext) => void;
22
+ /**
23
+ * Logs errors.
24
+ * @param service - Service called the logger.
25
+ * @param message - Human-readable message.
26
+ * @param context - Optional structured data or additional info.
27
+ */
28
+ error: (service: string, message: string, context?: VeridiaLogContext) => void;
29
+ };
30
+ export type VeridiaClientOptions = {
31
+ accessKeyId: string;
32
+ secretAccessKey: string;
33
+ endpoint?: string;
34
+ region?: string;
35
+ maxBufferSize?: number;
36
+ maxBufferTimeMs?: number;
37
+ retries?: number;
38
+ retryBaseDelayMs?: number;
39
+ timeoutMsGetUserSegments?: number;
40
+ timeoutMsFlush?: number;
41
+ logger?: VeridiaLogger;
42
+ };
43
+ export type IdentifierPayload = {
44
+ type: 'userId' | 'email';
45
+ id: string;
46
+ };
47
+ export type IdentifyPayload = {
48
+ identifier: IdentifierPayload;
49
+ attributes: any;
50
+ };
51
+ export type TrackPayload = {
52
+ identifier: IdentifierPayload;
53
+ eventId: string;
54
+ eventType: string;
55
+ eventTime: string;
56
+ properties: any;
57
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ export declare const SDK_VERSION = "1.0.2";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SDK_VERSION = void 0;
4
+ exports.SDK_VERSION = '1.0.2';
5
+ //# sourceMappingURL=version.js.map
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@veridia/node-sdk",
3
+ "version": "1.0.2",
4
+ "description": "",
5
+ "main": "./dist/cjs/index.js",
6
+ "module": "./dist/esm/index.js",
7
+ "types": "./dist/esm/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/esm/index.d.ts",
11
+ "import": "./dist/esm/index.js",
12
+ "require": "./dist/cjs/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "npm pkg get version | xargs -I {} sh -c \"sed -i.bak -e 's/__SDK_VERSION__/{}/g' src/version.ts && rm -f src/version.ts.bak\" && npm run build:cjs && npm run build:esm",
17
+ "build:cjs": "tsc -p tsconfig.cjs.json",
18
+ "build:esm": "tsc -p tsconfig.esm.json",
19
+ "clean": "rm -rf dist",
20
+ "test": "vitest",
21
+ "lint": "eslint . --ext .ts",
22
+ "format": "prettier --write .",
23
+ "prepare": "husky install"
24
+ },
25
+ "dependencies": {
26
+ "aws4": "1.13.2",
27
+ "node-fetch": "^3.3.2"
28
+ },
29
+ "devDependencies": {
30
+ "@types/aws4": "^1.11.6",
31
+ "@types/node": "^24.9.2",
32
+ "@typescript-eslint/eslint-plugin": "^8.46.2",
33
+ "@typescript-eslint/parser": "^8.46.2",
34
+ "eslint": "^9.38.0",
35
+ "eslint-plugin-prettier": "^5.5.4",
36
+ "husky": "^8.0.0",
37
+ "prettier": "^3.6.2",
38
+ "typescript": "^5.9.3",
39
+ "vitest": "^4.0.6"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/veridia-io/veridia-node-sdk.git"
44
+ }
45
+ }