@runtimescope/server-sdk 0.6.2 → 0.7.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/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ HttpTransport: () => HttpTransport,
33
34
  RuntimeScope: () => RuntimeScope,
34
35
  Sampler: () => Sampler,
35
36
  _log: () => _log,
@@ -176,6 +177,94 @@ var ServerTransport = class {
176
177
  }
177
178
  };
178
179
 
180
+ // src/http-transport.ts
181
+ var HttpTransport = class {
182
+ queue = [];
183
+ url;
184
+ sessionId;
185
+ appName;
186
+ sdkVersion;
187
+ authToken;
188
+ maxQueueSize;
189
+ maxRetries;
190
+ retryDelayMs;
191
+ flushTimer = null;
192
+ _droppedCount = 0;
193
+ sessionRegistered = false;
194
+ constructor(options) {
195
+ this.url = options.url;
196
+ this.sessionId = options.sessionId;
197
+ this.appName = options.appName;
198
+ this.sdkVersion = options.sdkVersion;
199
+ this.authToken = options.authToken;
200
+ this.maxQueueSize = options.maxQueueSize ?? 1e4;
201
+ this.maxRetries = options.maxRetries ?? 2;
202
+ this.retryDelayMs = options.retryDelayMs ?? 500;
203
+ const intervalMs = options.flushIntervalMs ?? 1e3;
204
+ this.flushTimer = setInterval(() => this.flush(), intervalMs);
205
+ if (this.flushTimer && typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
206
+ this.flushTimer.unref();
207
+ }
208
+ }
209
+ get droppedCount() {
210
+ return this._droppedCount;
211
+ }
212
+ sendEvent(event) {
213
+ if (this.queue.length >= this.maxQueueSize) {
214
+ this.queue.shift();
215
+ this._droppedCount++;
216
+ }
217
+ this.queue.push(event);
218
+ }
219
+ async flush() {
220
+ if (this.queue.length === 0) return;
221
+ const batch = this.queue.splice(0);
222
+ const payload = {
223
+ sessionId: this.sessionId,
224
+ events: batch
225
+ };
226
+ if (!this.sessionRegistered) {
227
+ payload.appName = this.appName;
228
+ payload.sdkVersion = this.sdkVersion;
229
+ }
230
+ const body = JSON.stringify(payload);
231
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
232
+ try {
233
+ const headers = {
234
+ "Content-Type": "application/json"
235
+ };
236
+ if (this.authToken) {
237
+ headers["Authorization"] = `Bearer ${this.authToken}`;
238
+ }
239
+ const response = await fetch(this.url, {
240
+ method: "POST",
241
+ headers,
242
+ body,
243
+ signal: AbortSignal.timeout(5e3)
244
+ });
245
+ if (response.ok) {
246
+ this.sessionRegistered = true;
247
+ return;
248
+ }
249
+ if (response.status === 401 || response.status === 400) {
250
+ return;
251
+ }
252
+ } catch {
253
+ }
254
+ if (attempt < this.maxRetries) {
255
+ await new Promise((r) => setTimeout(r, this.retryDelayMs));
256
+ }
257
+ }
258
+ }
259
+ async disconnect() {
260
+ if (this.flushTimer) {
261
+ clearInterval(this.flushTimer);
262
+ this.flushTimer = null;
263
+ }
264
+ await this.flush();
265
+ }
266
+ };
267
+
179
268
  // src/utils/id.ts
180
269
  var import_node_crypto = require("crypto");
181
270
  function generateId() {
@@ -1399,9 +1488,10 @@ function runtimeScopeMiddleware(emit, sessionId, options) {
1399
1488
  }
1400
1489
 
1401
1490
  // src/index.ts
1402
- var SDK_VERSION = "0.6.2";
1491
+ var SDK_VERSION = "0.7.0";
1403
1492
  var RuntimeScopeServer = class {
1404
1493
  transport = null;
1494
+ httpTransport = null;
1405
1495
  sessionId = "";
1406
1496
  config = {};
1407
1497
  sampler = null;
@@ -1414,15 +1504,35 @@ var RuntimeScopeServer = class {
1414
1504
  this.config = config;
1415
1505
  this.sessionId = config.sessionId ?? generateSessionId();
1416
1506
  const serverUrl = config.serverUrl ?? config.endpoint ?? "ws://127.0.0.1:9090";
1417
- this.transport = new ServerTransport({
1418
- url: serverUrl,
1419
- sessionId: this.sessionId,
1420
- appName: config.appName ?? "server-app",
1421
- sdkVersion: SDK_VERSION,
1422
- authToken: config.authToken,
1423
- maxQueueSize: config.maxQueueSize
1424
- });
1425
- this.transport.connect();
1507
+ if (config.transport === "http") {
1508
+ let httpUrl = config.httpEndpoint;
1509
+ if (!httpUrl) {
1510
+ const wsUrl = new URL(serverUrl);
1511
+ wsUrl.protocol = wsUrl.protocol === "wss:" ? "https:" : "http:";
1512
+ wsUrl.port = "9091";
1513
+ wsUrl.pathname = "/api/events";
1514
+ httpUrl = wsUrl.toString();
1515
+ }
1516
+ this.httpTransport = new HttpTransport({
1517
+ url: httpUrl,
1518
+ sessionId: this.sessionId,
1519
+ appName: config.appName ?? "server-app",
1520
+ sdkVersion: SDK_VERSION,
1521
+ authToken: config.authToken,
1522
+ maxQueueSize: config.maxQueueSize,
1523
+ flushIntervalMs: config.httpFlushIntervalMs
1524
+ });
1525
+ } else {
1526
+ this.transport = new ServerTransport({
1527
+ url: serverUrl,
1528
+ sessionId: this.sessionId,
1529
+ appName: config.appName ?? "server-app",
1530
+ sdkVersion: SDK_VERSION,
1531
+ authToken: config.authToken,
1532
+ maxQueueSize: config.maxQueueSize
1533
+ });
1534
+ this.transport.connect();
1535
+ }
1426
1536
  if (config.sampleRate !== void 0 || config.maxEventsPerSecond !== void 0) {
1427
1537
  this.sampler = new Sampler({
1428
1538
  sampleRate: config.sampleRate,
@@ -1459,7 +1569,10 @@ var RuntimeScopeServer = class {
1459
1569
  maxBodySize: config.maxBodySize,
1460
1570
  redactHeaders: config.redactHeaders,
1461
1571
  // Auto-ignore the collector URL to prevent recursion
1462
- ignoreUrls: [serverUrl.replace("ws://", "").replace("wss://", "")],
1572
+ ignoreUrls: [
1573
+ serverUrl.replace("ws://", "").replace("wss://", ""),
1574
+ ...config.httpEndpoint ? [config.httpEndpoint.replace(/^https?:\/\//, "")] : []
1575
+ ],
1463
1576
  beforeSend: config.beforeSend
1464
1577
  })
1465
1578
  );
@@ -1487,6 +1600,10 @@ var RuntimeScopeServer = class {
1487
1600
  }
1488
1601
  this.restoreFunctions = [];
1489
1602
  this.sampler = null;
1603
+ if (this.httpTransport) {
1604
+ this.httpTransport.disconnect();
1605
+ this.httpTransport = null;
1606
+ }
1490
1607
  this.transport?.disconnect();
1491
1608
  this.transport = null;
1492
1609
  }
@@ -1495,12 +1612,12 @@ var RuntimeScopeServer = class {
1495
1612
  }
1496
1613
  emitEvent(event) {
1497
1614
  if (this.sampler && !this.sampler.shouldSample(event)) return;
1498
- if (this.config.beforeSend) {
1499
- const filtered = this.config.beforeSend(event);
1500
- if (!filtered) return;
1501
- this.transport?.sendEvent(filtered);
1615
+ const filtered = this.config.beforeSend ? this.config.beforeSend(event) : event;
1616
+ if (!filtered) return;
1617
+ if (this.httpTransport) {
1618
+ this.httpTransport.sendEvent(filtered);
1502
1619
  } else {
1503
- this.transport?.sendEvent(event);
1620
+ this.transport?.sendEvent(filtered);
1504
1621
  }
1505
1622
  }
1506
1623
  // --- Express/Connect Middleware ---
@@ -1622,6 +1739,7 @@ var RuntimeScopeServer = class {
1622
1739
  var RuntimeScope = new RuntimeScopeServer();
1623
1740
  // Annotate the CommonJS export names for ESM import in node:
1624
1741
  0 && (module.exports = {
1742
+ HttpTransport,
1625
1743
  RuntimeScope,
1626
1744
  Sampler,
1627
1745
  _log,