@runtimescope/server-sdk 0.6.2 → 0.7.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.cts CHANGED
@@ -91,6 +91,12 @@ interface ServerSdkConfig {
91
91
  sampleRate?: number;
92
92
  maxEventsPerSecond?: number;
93
93
  maxQueueSize?: number;
94
+ /** Transport type: 'ws' (WebSocket, default) or 'http' (HTTP POST for serverless) */
95
+ transport?: 'ws' | 'http';
96
+ /** HTTP endpoint URL for HTTP transport (e.g., 'http://collector:9091/api/events') */
97
+ httpEndpoint?: string;
98
+ /** HTTP batch flush interval in ms (default: 1000) */
99
+ httpFlushIntervalMs?: number;
94
100
  }
95
101
 
96
102
  type EmitFn = (event: NetworkEvent) => void;
@@ -162,8 +168,40 @@ declare class Sampler {
162
168
  reset(): void;
163
169
  }
164
170
 
171
+ interface HttpTransportOptions {
172
+ url: string;
173
+ sessionId: string;
174
+ appName: string;
175
+ sdkVersion: string;
176
+ authToken?: string;
177
+ maxQueueSize?: number;
178
+ flushIntervalMs?: number;
179
+ maxRetries?: number;
180
+ retryDelayMs?: number;
181
+ }
182
+ declare class HttpTransport {
183
+ private queue;
184
+ private url;
185
+ private sessionId;
186
+ private appName;
187
+ private sdkVersion;
188
+ private authToken;
189
+ private maxQueueSize;
190
+ private maxRetries;
191
+ private retryDelayMs;
192
+ private flushTimer;
193
+ private _droppedCount;
194
+ private sessionRegistered;
195
+ constructor(options: HttpTransportOptions);
196
+ get droppedCount(): number;
197
+ sendEvent(event: ServerRuntimeEvent): void;
198
+ flush(): Promise<void>;
199
+ disconnect(): Promise<void>;
200
+ }
201
+
165
202
  declare class RuntimeScopeServer {
166
203
  private transport;
204
+ private httpTransport;
167
205
  private sessionId;
168
206
  private config;
169
207
  private sampler;
@@ -187,4 +225,4 @@ declare class RuntimeScopeServer {
187
225
  }
188
226
  declare const RuntimeScope: RuntimeScopeServer;
189
227
 
190
- export { type ConsoleEvent, type DatabaseEvent, type MetricUnit, type NetworkEvent, type PerformanceEvent, RuntimeScope, Sampler, type ServerMetricName, type ServerRuntimeEvent, type ServerSdkConfig, _log, generateId, generateSessionId, getRequestContext, getSessionId, normalizeQuery, parseOperation, parseTablesAccessed, redactParams, runWithContext, runtimeScopeMiddleware };
228
+ export { type ConsoleEvent, type DatabaseEvent, HttpTransport, type HttpTransportOptions, type MetricUnit, type NetworkEvent, type PerformanceEvent, RuntimeScope, Sampler, type ServerMetricName, type ServerRuntimeEvent, type ServerSdkConfig, _log, generateId, generateSessionId, getRequestContext, getSessionId, normalizeQuery, parseOperation, parseTablesAccessed, redactParams, runWithContext, runtimeScopeMiddleware };
package/dist/index.d.ts CHANGED
@@ -91,6 +91,12 @@ interface ServerSdkConfig {
91
91
  sampleRate?: number;
92
92
  maxEventsPerSecond?: number;
93
93
  maxQueueSize?: number;
94
+ /** Transport type: 'ws' (WebSocket, default) or 'http' (HTTP POST for serverless) */
95
+ transport?: 'ws' | 'http';
96
+ /** HTTP endpoint URL for HTTP transport (e.g., 'http://collector:9091/api/events') */
97
+ httpEndpoint?: string;
98
+ /** HTTP batch flush interval in ms (default: 1000) */
99
+ httpFlushIntervalMs?: number;
94
100
  }
95
101
 
96
102
  type EmitFn = (event: NetworkEvent) => void;
@@ -162,8 +168,40 @@ declare class Sampler {
162
168
  reset(): void;
163
169
  }
164
170
 
171
+ interface HttpTransportOptions {
172
+ url: string;
173
+ sessionId: string;
174
+ appName: string;
175
+ sdkVersion: string;
176
+ authToken?: string;
177
+ maxQueueSize?: number;
178
+ flushIntervalMs?: number;
179
+ maxRetries?: number;
180
+ retryDelayMs?: number;
181
+ }
182
+ declare class HttpTransport {
183
+ private queue;
184
+ private url;
185
+ private sessionId;
186
+ private appName;
187
+ private sdkVersion;
188
+ private authToken;
189
+ private maxQueueSize;
190
+ private maxRetries;
191
+ private retryDelayMs;
192
+ private flushTimer;
193
+ private _droppedCount;
194
+ private sessionRegistered;
195
+ constructor(options: HttpTransportOptions);
196
+ get droppedCount(): number;
197
+ sendEvent(event: ServerRuntimeEvent): void;
198
+ flush(): Promise<void>;
199
+ disconnect(): Promise<void>;
200
+ }
201
+
165
202
  declare class RuntimeScopeServer {
166
203
  private transport;
204
+ private httpTransport;
167
205
  private sessionId;
168
206
  private config;
169
207
  private sampler;
@@ -187,4 +225,4 @@ declare class RuntimeScopeServer {
187
225
  }
188
226
  declare const RuntimeScope: RuntimeScopeServer;
189
227
 
190
- export { type ConsoleEvent, type DatabaseEvent, type MetricUnit, type NetworkEvent, type PerformanceEvent, RuntimeScope, Sampler, type ServerMetricName, type ServerRuntimeEvent, type ServerSdkConfig, _log, generateId, generateSessionId, getRequestContext, getSessionId, normalizeQuery, parseOperation, parseTablesAccessed, redactParams, runWithContext, runtimeScopeMiddleware };
228
+ export { type ConsoleEvent, type DatabaseEvent, HttpTransport, type HttpTransportOptions, type MetricUnit, type NetworkEvent, type PerformanceEvent, RuntimeScope, Sampler, type ServerMetricName, type ServerRuntimeEvent, type ServerSdkConfig, _log, generateId, generateSessionId, getRequestContext, getSessionId, normalizeQuery, parseOperation, parseTablesAccessed, redactParams, runWithContext, runtimeScopeMiddleware };
package/dist/index.js CHANGED
@@ -128,6 +128,94 @@ var ServerTransport = class {
128
128
  }
129
129
  };
130
130
 
131
+ // src/http-transport.ts
132
+ var HttpTransport = class {
133
+ queue = [];
134
+ url;
135
+ sessionId;
136
+ appName;
137
+ sdkVersion;
138
+ authToken;
139
+ maxQueueSize;
140
+ maxRetries;
141
+ retryDelayMs;
142
+ flushTimer = null;
143
+ _droppedCount = 0;
144
+ sessionRegistered = false;
145
+ constructor(options) {
146
+ this.url = options.url;
147
+ this.sessionId = options.sessionId;
148
+ this.appName = options.appName;
149
+ this.sdkVersion = options.sdkVersion;
150
+ this.authToken = options.authToken;
151
+ this.maxQueueSize = options.maxQueueSize ?? 1e4;
152
+ this.maxRetries = options.maxRetries ?? 2;
153
+ this.retryDelayMs = options.retryDelayMs ?? 500;
154
+ const intervalMs = options.flushIntervalMs ?? 1e3;
155
+ this.flushTimer = setInterval(() => this.flush(), intervalMs);
156
+ if (this.flushTimer && typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
157
+ this.flushTimer.unref();
158
+ }
159
+ }
160
+ get droppedCount() {
161
+ return this._droppedCount;
162
+ }
163
+ sendEvent(event) {
164
+ if (this.queue.length >= this.maxQueueSize) {
165
+ this.queue.shift();
166
+ this._droppedCount++;
167
+ }
168
+ this.queue.push(event);
169
+ }
170
+ async flush() {
171
+ if (this.queue.length === 0) return;
172
+ const batch = this.queue.splice(0);
173
+ const payload = {
174
+ sessionId: this.sessionId,
175
+ events: batch
176
+ };
177
+ if (!this.sessionRegistered) {
178
+ payload.appName = this.appName;
179
+ payload.sdkVersion = this.sdkVersion;
180
+ }
181
+ const body = JSON.stringify(payload);
182
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
183
+ try {
184
+ const headers = {
185
+ "Content-Type": "application/json"
186
+ };
187
+ if (this.authToken) {
188
+ headers["Authorization"] = `Bearer ${this.authToken}`;
189
+ }
190
+ const response = await fetch(this.url, {
191
+ method: "POST",
192
+ headers,
193
+ body,
194
+ signal: AbortSignal.timeout(5e3)
195
+ });
196
+ if (response.ok) {
197
+ this.sessionRegistered = true;
198
+ return;
199
+ }
200
+ if (response.status === 401 || response.status === 400) {
201
+ return;
202
+ }
203
+ } catch {
204
+ }
205
+ if (attempt < this.maxRetries) {
206
+ await new Promise((r) => setTimeout(r, this.retryDelayMs));
207
+ }
208
+ }
209
+ }
210
+ async disconnect() {
211
+ if (this.flushTimer) {
212
+ clearInterval(this.flushTimer);
213
+ this.flushTimer = null;
214
+ }
215
+ await this.flush();
216
+ }
217
+ };
218
+
131
219
  // src/utils/id.ts
132
220
  import { randomBytes } from "crypto";
133
221
  function generateId() {
@@ -1351,9 +1439,10 @@ function runtimeScopeMiddleware(emit, sessionId, options) {
1351
1439
  }
1352
1440
 
1353
1441
  // src/index.ts
1354
- var SDK_VERSION = "0.6.2";
1442
+ var SDK_VERSION = "0.7.1";
1355
1443
  var RuntimeScopeServer = class {
1356
1444
  transport = null;
1445
+ httpTransport = null;
1357
1446
  sessionId = "";
1358
1447
  config = {};
1359
1448
  sampler = null;
@@ -1366,15 +1455,35 @@ var RuntimeScopeServer = class {
1366
1455
  this.config = config;
1367
1456
  this.sessionId = config.sessionId ?? generateSessionId();
1368
1457
  const serverUrl = config.serverUrl ?? config.endpoint ?? "ws://127.0.0.1:9090";
1369
- this.transport = new ServerTransport({
1370
- url: serverUrl,
1371
- sessionId: this.sessionId,
1372
- appName: config.appName ?? "server-app",
1373
- sdkVersion: SDK_VERSION,
1374
- authToken: config.authToken,
1375
- maxQueueSize: config.maxQueueSize
1376
- });
1377
- this.transport.connect();
1458
+ if (config.transport === "http") {
1459
+ let httpUrl = config.httpEndpoint;
1460
+ if (!httpUrl) {
1461
+ const wsUrl = new URL(serverUrl);
1462
+ wsUrl.protocol = wsUrl.protocol === "wss:" ? "https:" : "http:";
1463
+ wsUrl.port = "9091";
1464
+ wsUrl.pathname = "/api/events";
1465
+ httpUrl = wsUrl.toString();
1466
+ }
1467
+ this.httpTransport = new HttpTransport({
1468
+ url: httpUrl,
1469
+ sessionId: this.sessionId,
1470
+ appName: config.appName ?? "server-app",
1471
+ sdkVersion: SDK_VERSION,
1472
+ authToken: config.authToken,
1473
+ maxQueueSize: config.maxQueueSize,
1474
+ flushIntervalMs: config.httpFlushIntervalMs
1475
+ });
1476
+ } else {
1477
+ this.transport = new ServerTransport({
1478
+ url: serverUrl,
1479
+ sessionId: this.sessionId,
1480
+ appName: config.appName ?? "server-app",
1481
+ sdkVersion: SDK_VERSION,
1482
+ authToken: config.authToken,
1483
+ maxQueueSize: config.maxQueueSize
1484
+ });
1485
+ this.transport.connect();
1486
+ }
1378
1487
  if (config.sampleRate !== void 0 || config.maxEventsPerSecond !== void 0) {
1379
1488
  this.sampler = new Sampler({
1380
1489
  sampleRate: config.sampleRate,
@@ -1411,7 +1520,10 @@ var RuntimeScopeServer = class {
1411
1520
  maxBodySize: config.maxBodySize,
1412
1521
  redactHeaders: config.redactHeaders,
1413
1522
  // Auto-ignore the collector URL to prevent recursion
1414
- ignoreUrls: [serverUrl.replace("ws://", "").replace("wss://", "")],
1523
+ ignoreUrls: [
1524
+ serverUrl.replace("ws://", "").replace("wss://", ""),
1525
+ ...config.httpEndpoint ? [config.httpEndpoint.replace(/^https?:\/\//, "")] : []
1526
+ ],
1415
1527
  beforeSend: config.beforeSend
1416
1528
  })
1417
1529
  );
@@ -1439,6 +1551,10 @@ var RuntimeScopeServer = class {
1439
1551
  }
1440
1552
  this.restoreFunctions = [];
1441
1553
  this.sampler = null;
1554
+ if (this.httpTransport) {
1555
+ this.httpTransport.disconnect();
1556
+ this.httpTransport = null;
1557
+ }
1442
1558
  this.transport?.disconnect();
1443
1559
  this.transport = null;
1444
1560
  }
@@ -1447,12 +1563,12 @@ var RuntimeScopeServer = class {
1447
1563
  }
1448
1564
  emitEvent(event) {
1449
1565
  if (this.sampler && !this.sampler.shouldSample(event)) return;
1450
- if (this.config.beforeSend) {
1451
- const filtered = this.config.beforeSend(event);
1452
- if (!filtered) return;
1453
- this.transport?.sendEvent(filtered);
1566
+ const filtered = this.config.beforeSend ? this.config.beforeSend(event) : event;
1567
+ if (!filtered) return;
1568
+ if (this.httpTransport) {
1569
+ this.httpTransport.sendEvent(filtered);
1454
1570
  } else {
1455
- this.transport?.sendEvent(event);
1571
+ this.transport?.sendEvent(filtered);
1456
1572
  }
1457
1573
  }
1458
1574
  // --- Express/Connect Middleware ---
@@ -1573,6 +1689,7 @@ var RuntimeScopeServer = class {
1573
1689
  };
1574
1690
  var RuntimeScope = new RuntimeScopeServer();
1575
1691
  export {
1692
+ HttpTransport,
1576
1693
  RuntimeScope,
1577
1694
  Sampler,
1578
1695
  _log,