trusera-sdk 0.2.0 → 1.1.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 CHANGED
@@ -1,5 +1,7 @@
1
1
  # Trusera SDK for JavaScript/TypeScript
2
2
 
3
+ > **Beta** — This SDK is under active development. Expected GA: April 2026.
4
+
3
5
  [![npm version](https://badge.fury.io/js/trusera-sdk.svg)](https://www.npmjs.com/package/trusera-sdk)
4
6
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
7
 
package/dist/index.cjs CHANGED
@@ -42,6 +42,7 @@ __export(index_exports, {
42
42
  module.exports = __toCommonJS(index_exports);
43
43
 
44
44
  // src/client.ts
45
+ var SDK_VERSION = "1.0.0";
45
46
  var TruseraClient = class {
46
47
  apiKey;
47
48
  baseUrl;
@@ -52,6 +53,14 @@ var TruseraClient = class {
52
53
  eventQueue = [];
53
54
  flushTimer;
54
55
  isClosed = false;
56
+ // Fleet auto-registration
57
+ autoRegister;
58
+ agentName;
59
+ agentType;
60
+ environment;
61
+ heartbeatInterval;
62
+ fleetAgentId;
63
+ heartbeatTimer;
55
64
  constructor(options) {
56
65
  this.apiKey = options.apiKey;
57
66
  this.baseUrl = options.baseUrl ?? "https://api.trusera.io";
@@ -59,11 +68,28 @@ var TruseraClient = class {
59
68
  this.batchSize = options.batchSize ?? 100;
60
69
  this.flushInterval = options.flushInterval ?? 5e3;
61
70
  this.debug = options.debug ?? false;
71
+ const envAuto = (typeof process !== "undefined" ? process.env?.TRUSERA_AUTO_REGISTER : void 0) ?? "";
72
+ if (envAuto.toLowerCase() === "true" || envAuto === "1") {
73
+ this.autoRegister = true;
74
+ } else if (envAuto.toLowerCase() === "false" || envAuto === "0") {
75
+ this.autoRegister = false;
76
+ } else {
77
+ this.autoRegister = options.autoRegister ?? false;
78
+ }
79
+ const hostname = typeof process !== "undefined" && process.env?.HOSTNAME ? process.env.HOSTNAME : typeof globalThis !== "undefined" && "navigator" in globalThis ? "browser" : "unknown";
80
+ this.agentName = options.agentName ?? (typeof process !== "undefined" ? process.env?.TRUSERA_AGENT_NAME : void 0) ?? hostname;
81
+ this.agentType = options.agentType ?? (typeof process !== "undefined" ? process.env?.TRUSERA_AGENT_TYPE : void 0) ?? "";
82
+ this.environment = options.environment ?? (typeof process !== "undefined" ? process.env?.TRUSERA_ENVIRONMENT : void 0) ?? "";
83
+ const envHb = typeof process !== "undefined" ? process.env?.TRUSERA_HEARTBEAT_INTERVAL : void 0;
84
+ this.heartbeatInterval = envHb ? parseInt(envHb, 10) * 1e3 : options.heartbeatInterval ?? 6e4;
62
85
  if (!this.apiKey.startsWith("tsk_")) {
63
86
  throw new Error("Invalid API key format. Must start with 'tsk_'");
64
87
  }
65
88
  this.startFlushTimer();
66
- this.log("TruseraClient initialized", { baseUrl: this.baseUrl, batchSize: this.batchSize });
89
+ if (this.autoRegister) {
90
+ void this.registerWithFleet();
91
+ }
92
+ this.log("TruseraClient initialized", { baseUrl: this.baseUrl, batchSize: this.batchSize, autoRegister: this.autoRegister });
67
93
  }
68
94
  /**
69
95
  * Registers a new agent with Trusera backend.
@@ -167,6 +193,7 @@ var TruseraClient = class {
167
193
  this.log("Closing client");
168
194
  this.isClosed = true;
169
195
  this.stopFlushTimer();
196
+ this.stopHeartbeat();
170
197
  await this.flush();
171
198
  this.log("Client closed");
172
199
  }
@@ -182,6 +209,102 @@ var TruseraClient = class {
182
209
  getAgentId() {
183
210
  return this.agentId;
184
211
  }
212
+ // -- Fleet auto-registration --
213
+ getProcessInfo() {
214
+ if (typeof process === "undefined") return {};
215
+ return {
216
+ pid: process.pid,
217
+ argv: process.argv?.slice(0, 10),
218
+ node_version: process.version,
219
+ platform: process.platform,
220
+ arch: process.arch
221
+ };
222
+ }
223
+ getNetworkInfo() {
224
+ const info = {};
225
+ if (typeof process !== "undefined") {
226
+ try {
227
+ const os = require("os");
228
+ info.hostname = os.hostname?.();
229
+ } catch {
230
+ info.hostname = process.env?.HOSTNAME ?? "unknown";
231
+ }
232
+ }
233
+ return info;
234
+ }
235
+ async registerWithFleet() {
236
+ const payload = {
237
+ name: this.agentName,
238
+ discovery_method: "sdk",
239
+ sdk_version: SDK_VERSION,
240
+ hostname: this.agentName,
241
+ process_info: this.getProcessInfo(),
242
+ network_info: this.getNetworkInfo()
243
+ };
244
+ if (this.agentType) payload.framework = this.agentType;
245
+ if (this.environment) payload.environment = this.environment;
246
+ try {
247
+ const response = await fetch(`${this.baseUrl}/api/v1/fleet/register`, {
248
+ method: "POST",
249
+ headers: {
250
+ "Content-Type": "application/json",
251
+ Authorization: `Bearer ${this.apiKey}`
252
+ },
253
+ body: JSON.stringify(payload)
254
+ });
255
+ if (!response.ok) {
256
+ this.log("Fleet auto-register failed", { status: response.status });
257
+ return;
258
+ }
259
+ const data = await response.json();
260
+ const agentData = data.data ?? data;
261
+ const fleetId = agentData.id;
262
+ if (fleetId) {
263
+ this.fleetAgentId = String(fleetId);
264
+ this.startHeartbeat();
265
+ this.log("Fleet auto-register succeeded", { fleetAgentId: this.fleetAgentId });
266
+ }
267
+ } catch (err) {
268
+ this.log("Fleet auto-register error (continuing without)", { error: String(err) });
269
+ }
270
+ }
271
+ startHeartbeat() {
272
+ this.heartbeatTimer = setInterval(() => {
273
+ void this.sendHeartbeat();
274
+ }, this.heartbeatInterval);
275
+ if (this.heartbeatTimer.unref) {
276
+ this.heartbeatTimer.unref();
277
+ }
278
+ }
279
+ stopHeartbeat() {
280
+ if (this.heartbeatTimer) {
281
+ clearInterval(this.heartbeatTimer);
282
+ this.heartbeatTimer = void 0;
283
+ }
284
+ }
285
+ async sendHeartbeat() {
286
+ if (!this.fleetAgentId) return;
287
+ try {
288
+ const payload = {
289
+ process_info: this.getProcessInfo(),
290
+ network_info: this.getNetworkInfo()
291
+ };
292
+ const response = await fetch(`${this.baseUrl}/api/v1/fleet/${this.fleetAgentId}/heartbeat`, {
293
+ method: "POST",
294
+ headers: {
295
+ "Content-Type": "application/json",
296
+ Authorization: `Bearer ${this.apiKey}`
297
+ },
298
+ body: JSON.stringify(payload)
299
+ });
300
+ if (!response.ok) {
301
+ this.log("Fleet heartbeat failed", { status: response.status });
302
+ }
303
+ } catch (err) {
304
+ this.log("Fleet heartbeat error", { error: String(err) });
305
+ }
306
+ }
307
+ // -- Timers --
185
308
  startFlushTimer() {
186
309
  this.flushTimer = setInterval(() => {
187
310
  void this.flush();