@snapback/cli 1.6.0 → 3.0.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.
Files changed (57) hide show
  1. package/README.md +120 -21
  2. package/dist/SkippedTestDetector-AXTMWWHC.js +5 -0
  3. package/dist/SkippedTestDetector-QLSQV7K7.js +5 -0
  4. package/dist/analysis-6WTBZJH3.js +6 -0
  5. package/dist/analysis-C472LUGW.js +2475 -0
  6. package/dist/auth-TDIHGKKL.js +1446 -0
  7. package/dist/auto-provision-organization-CXHL46P3.js +161 -0
  8. package/dist/{chunk-FVIYXFCL.js → chunk-4YTE4JEW.js} +2 -3
  9. package/dist/chunk-5EOPYJ4Y.js +12 -0
  10. package/dist/{chunk-ARVV3F4K.js → chunk-5SQA44V7.js} +1085 -18
  11. package/dist/{chunk-RB7H4UQJ.js → chunk-7ADPL4Q3.js} +10 -3
  12. package/dist/chunk-CBGOC6RV.js +293 -0
  13. package/dist/chunk-CPZWXRP2.js +4432 -0
  14. package/dist/{chunk-7JX6Y4TL.js → chunk-DPWFZNMY.js} +21 -34
  15. package/dist/{chunk-R7CUQ7CU.js → chunk-E6V6QKS7.js} +317 -33
  16. package/dist/chunk-FMWCFAY7.js +111 -0
  17. package/dist/chunk-GQ73B37K.js +314 -0
  18. package/dist/chunk-LIBBDBW5.js +6136 -0
  19. package/dist/chunk-O7HMAZ7L.js +3497 -0
  20. package/dist/chunk-PL4HF4M2.js +593 -0
  21. package/dist/chunk-Q4VC7GND.js +2300 -0
  22. package/dist/chunk-WS36HDEU.js +3735 -0
  23. package/dist/chunk-ZBQDE6WJ.js +108 -0
  24. package/dist/client-62E3L6DW.js +8 -0
  25. package/dist/dist-5LR7APG5.js +5 -0
  26. package/dist/dist-NFU5UJEW.js +9 -0
  27. package/dist/dist-OO5LJHL6.js +12 -0
  28. package/dist/index.js +61644 -37198
  29. package/dist/local-service-adapter-AB3UYRUK.js +6 -0
  30. package/dist/pioneer-oauth-hook-V2JKEXM7.js +12 -0
  31. package/dist/{secure-credentials-IWQB6KU4.js → secure-credentials-UEPG7GWW.js} +2 -3
  32. package/dist/snapback-dir-MG7DTRMF.js +6 -0
  33. package/package.json +12 -11
  34. package/scripts/postinstall.mjs +2 -3
  35. package/dist/SkippedTestDetector-5WJZKZQ3.js +0 -5
  36. package/dist/SkippedTestDetector-5WJZKZQ3.js.map +0 -1
  37. package/dist/analysis-YI4UNUCM.js +0 -6
  38. package/dist/analysis-YI4UNUCM.js.map +0 -1
  39. package/dist/chunk-7JX6Y4TL.js.map +0 -1
  40. package/dist/chunk-ARVV3F4K.js.map +0 -1
  41. package/dist/chunk-EU2IZPOK.js +0 -13002
  42. package/dist/chunk-EU2IZPOK.js.map +0 -1
  43. package/dist/chunk-FVIYXFCL.js.map +0 -1
  44. package/dist/chunk-R7CUQ7CU.js.map +0 -1
  45. package/dist/chunk-RB7H4UQJ.js.map +0 -1
  46. package/dist/chunk-SOABQWAU.js +0 -385
  47. package/dist/chunk-SOABQWAU.js.map +0 -1
  48. package/dist/dist-O6EBXLN6.js +0 -5
  49. package/dist/dist-O6EBXLN6.js.map +0 -1
  50. package/dist/dist-PJVBBZTF.js +0 -5
  51. package/dist/dist-PJVBBZTF.js.map +0 -1
  52. package/dist/index.js.map +0 -1
  53. package/dist/learning-pruner-QC4CTJDX.js +0 -5
  54. package/dist/learning-pruner-QC4CTJDX.js.map +0 -1
  55. package/dist/secure-credentials-IWQB6KU4.js.map +0 -1
  56. package/dist/snapback-dir-V6MWXIW4.js +0 -5
  57. package/dist/snapback-dir-V6MWXIW4.js.map +0 -1
@@ -0,0 +1,2300 @@
1
+ #!/usr/bin/env node --no-warnings=ExperimentalWarning
2
+ import { logger } from './chunk-PL4HF4M2.js';
3
+ import { FEATURE_FLAGS, validateTelemetryEvent, FeatureManager } from './chunk-WS36HDEU.js';
4
+ import { __commonJS, __name, __export } from './chunk-7ADPL4Q3.js';
5
+ import { neonConfig, neon } from '@neondatabase/serverless';
6
+ import { readFileSync } from 'fs';
7
+ import { dirname, join } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import { PostHog } from 'posthog-node';
10
+ import client from 'prom-client';
11
+ import { trace, metrics, context, SpanStatusCode, propagation, ROOT_CONTEXT } from '@opentelemetry/api';
12
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
13
+ import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
14
+ import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino';
15
+ import { resourceFromAttributes } from '@opentelemetry/resources';
16
+ import { BatchSpanProcessor, ConsoleSpanExporter, TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base';
17
+ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
18
+ import { ATTR_SERVICE_VERSION, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
19
+
20
+ process.env.SNAPBACK_CLI='true';
21
+
22
+ // ../../packages/infrastructure/package.json
23
+ var require_package = __commonJS({
24
+ "../../packages/infrastructure/package.json"(exports$1, module) {
25
+ module.exports = {
26
+ name: "@snapback/infrastructure",
27
+ version: "0.2.0",
28
+ license: "Apache-2.0",
29
+ author: "SnapBack Team",
30
+ repository: {
31
+ type: "git",
32
+ url: "https://github.com/snapback-dev.git",
33
+ directory: "packages/infrastructure"
34
+ },
35
+ files: [
36
+ "dist"
37
+ ],
38
+ dependencies: {
39
+ "@neondatabase/serverless": "catalog:",
40
+ "@opentelemetry/api": "catalog:",
41
+ "@opentelemetry/exporter-trace-otlp-http": "catalog:",
42
+ "@opentelemetry/instrumentation-pg": "catalog:",
43
+ "@opentelemetry/instrumentation-pino": "catalog:",
44
+ "@opentelemetry/resources": "catalog:",
45
+ "@opentelemetry/sdk-trace-base": "catalog:",
46
+ "@opentelemetry/sdk-trace-node": "catalog:",
47
+ "@opentelemetry/semantic-conventions": "catalog:",
48
+ "@snapback/contracts": "workspace:*",
49
+ bullmq: "catalog:",
50
+ nanoid: "catalog:",
51
+ pino: "catalog:",
52
+ "posthog-node": "catalog:",
53
+ opossum: "catalog:",
54
+ "p-queue": "catalog:",
55
+ "p-retry": "catalog:",
56
+ "lru-cache": "catalog:",
57
+ chokidar: "catalog:",
58
+ "prom-client": "catalog:"
59
+ },
60
+ optionalDependencies: {
61
+ "@sentry/node": "catalog:",
62
+ "@sentry/profiling-node": "catalog:"
63
+ },
64
+ devDependencies: {
65
+ "@snapback/tsconfig": "workspace:*",
66
+ "@types/node": "catalog:",
67
+ "posthog-js": "catalog:",
68
+ tsup: "catalog:",
69
+ typescript: "catalog:",
70
+ vitest: "catalog:"
71
+ },
72
+ exports: {
73
+ ".": {
74
+ types: "./dist/index.d.ts",
75
+ default: "./dist/index.js"
76
+ },
77
+ "./logging/logger": {
78
+ types: "./dist/logging/logger.d.ts",
79
+ default: "./dist/logging/logger.js"
80
+ },
81
+ "./metrics": {
82
+ types: "./dist/metrics/index.d.ts",
83
+ default: "./dist/metrics/index.js"
84
+ },
85
+ "./tracing": {
86
+ types: "./dist/tracing/index.d.ts",
87
+ default: "./dist/tracing/index.js"
88
+ },
89
+ "./health": {
90
+ types: "./dist/health/index.d.ts",
91
+ default: "./dist/health/index.js"
92
+ },
93
+ "./resiliency": {
94
+ types: "./dist/resiliency/index.d.ts",
95
+ default: "./dist/resiliency/index.js"
96
+ },
97
+ "./cache": {
98
+ types: "./dist/cache/index.d.ts",
99
+ default: "./dist/cache/index.js"
100
+ },
101
+ "./files": {
102
+ types: "./dist/files/watcher.d.ts",
103
+ default: "./dist/files/watcher.js"
104
+ },
105
+ "./sqlite": {
106
+ types: "./dist/sqlite/index.d.ts",
107
+ default: "./dist/sqlite/index.js"
108
+ },
109
+ "./neon": {
110
+ types: "./dist/neon/index.d.ts",
111
+ default: "./dist/neon/index.js"
112
+ },
113
+ "./prometheus": {
114
+ types: "./dist/prometheus/index.d.ts",
115
+ default: "./dist/prometheus/index.js"
116
+ }
117
+ },
118
+ publishConfig: {
119
+ exports: {
120
+ ".": {
121
+ types: "./dist/logging/logger.d.ts",
122
+ default: "./dist/logging/logger.js"
123
+ },
124
+ "./logging/logger": {
125
+ types: "./dist/logging/logger.d.ts",
126
+ default: "./dist/logging/logger.js"
127
+ },
128
+ "./health": {
129
+ types: "./dist/health/index.d.ts",
130
+ default: "./dist/health/index.js"
131
+ },
132
+ "./tracing": {
133
+ types: "./dist/tracing/index.d.ts",
134
+ default: "./dist/tracing/index.js"
135
+ },
136
+ "./metrics": {
137
+ types: "./dist/metrics/index.d.ts",
138
+ default: "./dist/metrics/index.js"
139
+ },
140
+ "./resiliency": {
141
+ types: "./dist/resiliency/index.d.ts",
142
+ default: "./dist/resiliency/index.js"
143
+ },
144
+ "./cache": {
145
+ types: "./dist/cache/index.d.ts",
146
+ default: "./dist/cache/index.js"
147
+ },
148
+ "./files": {
149
+ types: "./dist/files/watcher.d.ts",
150
+ default: "./dist/files/watcher.js"
151
+ },
152
+ "./sqlite": {
153
+ types: "./dist/sqlite/index.d.ts",
154
+ default: "./dist/sqlite/index.js"
155
+ },
156
+ "./neon": {
157
+ types: "./dist/neon/index.d.ts",
158
+ default: "./dist/neon/index.js"
159
+ }
160
+ }
161
+ },
162
+ main: "dist/index.js",
163
+ private: true,
164
+ scripts: {
165
+ build: "tsup && tsc --build tsconfig.build.json --force && node ../../scripts/build-utils/add-js-extensions.mjs",
166
+ "build:docker": "tsup --no-dts && node ../../scripts/build-utils/add-js-extensions.mjs",
167
+ dev: "tsup --watch",
168
+ check: "biome check .",
169
+ format: "biome format --write .",
170
+ lint: "biome lint .",
171
+ "lint:fix": "biome lint --fix .",
172
+ postbuild: "test -f dist/index.d.ts && node scripts/patch-dts.cjs || echo 'Warning: Type declarations not fully generated'",
173
+ test: "vitest run",
174
+ "test:coverage": "vitest run --coverage",
175
+ "test:watch": "vitest",
176
+ "type-check": "tsc --noEmit"
177
+ },
178
+ type: "module",
179
+ types: "dist/index.d.ts"
180
+ };
181
+ }
182
+ });
183
+
184
+ // ../../packages/infrastructure/dist/environment/index.js
185
+ function isDevelopment() {
186
+ return getDeploymentEnv() === "development";
187
+ }
188
+ __name(isDevelopment, "isDevelopment");
189
+ function isProduction() {
190
+ return getDeploymentEnv() === "production";
191
+ }
192
+ __name(isProduction, "isProduction");
193
+ function getDeploymentEnv() {
194
+ const explicitEnv = process.env.DEPLOYMENT_ENV;
195
+ if (explicitEnv === "development" || explicitEnv === "staging" || explicitEnv === "production") {
196
+ return explicitEnv;
197
+ }
198
+ if (process.env.VERCEL || process.env.VERCEL_ENV || process.env.FLY_ALLOC_ID) {
199
+ return "production";
200
+ }
201
+ const authUrl = process.env.BETTER_AUTH_URL || process.env.APP_URL || "";
202
+ if (authUrl.includes("localhost") || authUrl.includes("127.0.0.1")) {
203
+ return "development";
204
+ }
205
+ if (typeof window !== "undefined") {
206
+ const hostname = window.location.hostname;
207
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname.endsWith(".local") || hostname.endsWith(".test")) {
208
+ return "development";
209
+ }
210
+ }
211
+ if (process.env.CI) {
212
+ return "production";
213
+ }
214
+ return "production";
215
+ }
216
+ __name(getDeploymentEnv, "getDeploymentEnv");
217
+ function getAnalyticsEnv() {
218
+ return getDeploymentEnv() === "development" ? "dev" : "prod";
219
+ }
220
+ __name(getAnalyticsEnv, "getAnalyticsEnv");
221
+ function getEnvironmentInfo() {
222
+ const deployment = getDeploymentEnv();
223
+ return {
224
+ deployment,
225
+ analytics: deployment === "development" ? "dev" : "prod",
226
+ nodeEnv: process.env.NODE_ENV,
227
+ isCi: !!process.env.CI,
228
+ isVercel: !!(process.env.VERCEL || process.env.VERCEL_ENV),
229
+ isFly: !!process.env.FLY_ALLOC_ID,
230
+ isLocalhost: (process.env.BETTER_AUTH_URL?.includes("localhost") ?? false) || typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1")
231
+ };
232
+ }
233
+ __name(getEnvironmentInfo, "getEnvironmentInfo");
234
+ function detectSurface() {
235
+ if (process.env.VSCODE_EXTENSION || typeof process.env.VSCODE_PID !== "undefined") {
236
+ return "vscode";
237
+ }
238
+ if (process.env.SNAPBACK_CLI || process.argv[1]?.includes("cli")) {
239
+ return "cli";
240
+ }
241
+ if (process.env.MCP_SERVER || process.env.MCP_MODE) {
242
+ return "mcp";
243
+ }
244
+ if (process.env.DAEMON_MODE || process.env.LOCAL_SERVICE) {
245
+ return "daemon";
246
+ }
247
+ if (process.env.API_SERVER || typeof process.env.PORT !== "undefined") {
248
+ return "api";
249
+ }
250
+ if (typeof window !== "undefined") {
251
+ return "web";
252
+ }
253
+ return "api";
254
+ }
255
+ __name(detectSurface, "detectSurface");
256
+ function getAnalyticsSuperProperties(surface) {
257
+ return {
258
+ env: getAnalyticsEnv(),
259
+ surface: surface ?? detectSurface()
260
+ };
261
+ }
262
+ __name(getAnalyticsSuperProperties, "getAnalyticsSuperProperties");
263
+
264
+ // ../../packages/infrastructure/dist/graceful-shutdown/index.js
265
+ function createGracefulShutdown(options) {
266
+ const { logger: logger2, timeoutMs = 25e3, healthMarkerPath } = options;
267
+ const cleanupHandlers = [];
268
+ let isShuttingDown = false;
269
+ let isReady = false;
270
+ function updateReadiness(ready) {
271
+ isReady = ready;
272
+ if (healthMarkerPath) {
273
+ try {
274
+ if (ready) {
275
+ globalThis.Bun?.write?.(healthMarkerPath, process.pid.toString());
276
+ } else {
277
+ globalThis.Bun?.write?.(healthMarkerPath, "");
278
+ }
279
+ } catch (error) {
280
+ logger2.debug("Health marker file operation failed", {
281
+ error
282
+ });
283
+ }
284
+ }
285
+ }
286
+ __name(updateReadiness, "updateReadiness");
287
+ async function shutdown(signal) {
288
+ if (isShuttingDown) {
289
+ logger2.warn("Shutdown already in progress, ignoring signal", {
290
+ signal
291
+ });
292
+ return;
293
+ }
294
+ isShuttingDown = true;
295
+ logger2.info("Shutdown initiated", {
296
+ signal,
297
+ pid: process.pid
298
+ });
299
+ updateReadiness(false);
300
+ logger2.info("Service marked as not ready, stopping new traffic");
301
+ const drainTimeout = Math.min(5e3, timeoutMs / 5);
302
+ logger2.info("Waiting for in-flight requests to complete", {
303
+ drainTimeoutMs: drainTimeout
304
+ });
305
+ await new Promise((resolve) => setTimeout(resolve, drainTimeout));
306
+ logger2.info("Running cleanup handlers", {
307
+ count: cleanupHandlers.length
308
+ });
309
+ const cleanupTimeout = timeoutMs - drainTimeout - 2e3;
310
+ const cleanupStart = Date.now();
311
+ for (let i = cleanupHandlers.length - 1; i >= 0; i--) {
312
+ const remainingTime = cleanupTimeout - (Date.now() - cleanupStart);
313
+ if (remainingTime <= 0) {
314
+ logger2.warn("Cleanup timeout reached, some handlers may not have completed");
315
+ break;
316
+ }
317
+ try {
318
+ const handler = cleanupHandlers[i];
319
+ const handlerTimeout = Math.min(remainingTime, 5e3);
320
+ await Promise.race([
321
+ handler(),
322
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Handler timeout")), handlerTimeout))
323
+ ]);
324
+ } catch (error) {
325
+ logger2.error("Cleanup handler error", {
326
+ error,
327
+ handlerIndex: i
328
+ });
329
+ }
330
+ }
331
+ logger2.info("Shutdown complete", {
332
+ durationMs: Date.now() - cleanupStart + drainTimeout
333
+ });
334
+ process.exit(0);
335
+ }
336
+ __name(shutdown, "shutdown");
337
+ const forceExit = /* @__PURE__ */ __name(() => {
338
+ logger2.error("Forced exit due to timeout", {
339
+ timeoutMs
340
+ });
341
+ process.exit(1);
342
+ }, "forceExit");
343
+ return {
344
+ register(handler) {
345
+ cleanupHandlers.push(handler);
346
+ },
347
+ setReady() {
348
+ updateReadiness(true);
349
+ },
350
+ setNotReady() {
351
+ updateReadiness(false);
352
+ },
353
+ init() {
354
+ const handleShutdown = /* @__PURE__ */ __name((signal) => {
355
+ shutdown(signal).catch((error) => {
356
+ logger2.error("Shutdown error", {
357
+ error
358
+ });
359
+ process.exit(1);
360
+ });
361
+ setTimeout(forceExit, timeoutMs);
362
+ }, "handleShutdown");
363
+ process.on("SIGTERM", () => handleShutdown("SIGTERM"));
364
+ process.on("SIGINT", () => handleShutdown("SIGINT"));
365
+ process.on("uncaughtException", (error) => {
366
+ logger2.error("Uncaught exception, initiating shutdown", {
367
+ error
368
+ });
369
+ handleShutdown("uncaughtException");
370
+ });
371
+ process.on("unhandledRejection", (reason) => {
372
+ logger2.error("Unhandled rejection, initiating shutdown", {
373
+ reason
374
+ });
375
+ if (process.env.NODE_ENV !== "production") {
376
+ handleShutdown("unhandledRejection");
377
+ }
378
+ });
379
+ logger2.info("Graceful shutdown handler initialized", {
380
+ timeoutMs
381
+ });
382
+ },
383
+ isReady() {
384
+ return isReady;
385
+ },
386
+ isShuttingDown() {
387
+ return isShuttingDown;
388
+ }
389
+ };
390
+ }
391
+ __name(createGracefulShutdown, "createGracefulShutdown");
392
+ async function drainAndCloseServer(server, logger2) {
393
+ logger2.info("Closing server...");
394
+ const closePromise = server.close();
395
+ if (server.closeIdleConnections) {
396
+ logger2.info("Closing idle connections...");
397
+ server.closeIdleConnections();
398
+ }
399
+ const timeout = 1e4;
400
+ await Promise.race([
401
+ closePromise,
402
+ new Promise((resolve) => setTimeout(resolve, timeout))
403
+ ]);
404
+ if (server.closeAllConnections) {
405
+ logger2.info("Force closing remaining connections...");
406
+ server.closeAllConnections();
407
+ }
408
+ logger2.info("Server closed");
409
+ }
410
+ __name(drainAndCloseServer, "drainAndCloseServer");
411
+ async function preStopDelay(ms = 5e3) {
412
+ await new Promise((resolve) => setTimeout(resolve, ms));
413
+ }
414
+ __name(preStopDelay, "preStopDelay");
415
+
416
+ // ../../packages/infrastructure/dist/health/index.js
417
+ function createHealthCheck(options) {
418
+ return async () => {
419
+ const checks = {};
420
+ checks.system = {
421
+ status: "healthy",
422
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
423
+ latency: 0
424
+ };
425
+ const memoryUsage = process.memoryUsage();
426
+ checks.memory = {
427
+ status: memoryUsage.heapUsed < 0.8 * memoryUsage.heapTotal ? "healthy" : "degraded",
428
+ message: `Memory usage: ${Math.round(memoryUsage.heapUsed / 1024 / 1024 * 100) / 100} MB`,
429
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
430
+ };
431
+ const uptime = process.uptime();
432
+ if (options.dependencies) {
433
+ for (const dep of options.dependencies) {
434
+ try {
435
+ const depStartTime = Date.now();
436
+ const result = await dep.check();
437
+ const latency = Date.now() - depStartTime;
438
+ checks[dep.name] = {
439
+ status: result.status,
440
+ message: result.message,
441
+ latency,
442
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
443
+ };
444
+ } catch (error) {
445
+ checks[dep.name] = {
446
+ status: "unhealthy",
447
+ message: error instanceof Error ? error.message : "Unknown error",
448
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
449
+ };
450
+ }
451
+ }
452
+ }
453
+ let overallStatus = "healthy";
454
+ for (const check of Object.values(checks)) {
455
+ if (check.status === "unhealthy") {
456
+ overallStatus = "unhealthy";
457
+ break;
458
+ }
459
+ if (check.status === "degraded" && overallStatus === "healthy") {
460
+ overallStatus = "degraded";
461
+ }
462
+ }
463
+ const response = {
464
+ status: overallStatus,
465
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
466
+ service: options.service,
467
+ checks,
468
+ uptime,
469
+ memoryUsage: {
470
+ heapUsed: memoryUsage.heapUsed,
471
+ heapTotal: memoryUsage.heapTotal,
472
+ rss: memoryUsage.rss
473
+ }
474
+ };
475
+ if (options.version) {
476
+ response.version = options.version;
477
+ }
478
+ return response;
479
+ };
480
+ }
481
+ __name(createHealthCheck, "createHealthCheck");
482
+ async function checkDatabaseConnection(_connectionString) {
483
+ try {
484
+ const startTime = Date.now();
485
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 50));
486
+ const latency = Date.now() - startTime;
487
+ if (latency > 1e3) {
488
+ return {
489
+ status: "degraded",
490
+ message: `Database connection is slow (${latency}ms)`
491
+ };
492
+ }
493
+ return {
494
+ status: "healthy",
495
+ message: `Database connection successful (${latency}ms)`
496
+ };
497
+ } catch (error) {
498
+ return {
499
+ status: "unhealthy",
500
+ message: error instanceof Error ? error.message : "Database connection failed"
501
+ };
502
+ }
503
+ }
504
+ __name(checkDatabaseConnection, "checkDatabaseConnection");
505
+ async function checkRedisConnection(_redisUrl) {
506
+ try {
507
+ const startTime = Date.now();
508
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 30));
509
+ const latency = Date.now() - startTime;
510
+ if (latency > 200) {
511
+ return {
512
+ status: "degraded",
513
+ message: `Redis connection is slow (${latency}ms)`
514
+ };
515
+ }
516
+ return {
517
+ status: "healthy",
518
+ message: `Redis connection successful (${latency}ms)`
519
+ };
520
+ } catch (error) {
521
+ return {
522
+ status: "unhealthy",
523
+ message: error instanceof Error ? error.message : "Redis connection failed"
524
+ };
525
+ }
526
+ }
527
+ __name(checkRedisConnection, "checkRedisConnection");
528
+ async function checkHttpService(_url) {
529
+ try {
530
+ const startTime = Date.now();
531
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 100));
532
+ const latency = Date.now() - startTime;
533
+ if (latency > 1e3) {
534
+ return {
535
+ status: "degraded",
536
+ message: `HTTP service is slow (${latency}ms)`
537
+ };
538
+ }
539
+ return {
540
+ status: "healthy",
541
+ message: `HTTP service check successful (${latency}ms)`
542
+ };
543
+ } catch (error) {
544
+ return {
545
+ status: "unhealthy",
546
+ message: error instanceof Error ? error.message : "HTTP service check failed"
547
+ };
548
+ }
549
+ }
550
+ __name(checkHttpService, "checkHttpService");
551
+
552
+ // ../../packages/infrastructure/dist/metrics/core/events.js
553
+ var AnalyticsEvents = {
554
+ // ===== Authentication Events (6) =====
555
+ AUTH_SIGNUP_COMPLETED: "auth_signup_completed",
556
+ AUTH_LOGIN_COMPLETED: "auth_login_completed",
557
+ AUTH_LOGOUT_COMPLETED: "auth_logout_completed",
558
+ AUTH_EMAIL_VERIFIED: "auth_email_verified",
559
+ AUTH_PASSWORD_RESET_REQUESTED: "auth_password_reset_requested",
560
+ AUTH_PASSWORD_RESET_COMPLETED: "auth_password_reset_completed",
561
+ // ===== Snapshot Events (20) =====
562
+ SNAPSHOT_CREATED: "snapshot_created",
563
+ SNAPSHOT_RESTORED: "snapshot_restored",
564
+ SNAPSHOT_DELETED: "snapshot_deleted",
565
+ SNAPSHOT_SEARCHED: "snapshot_searched",
566
+ SNAPSHOT_LIMIT_HIT: "snapshot_limit_hit",
567
+ SNAPSHOT_AUTO_CREATED: "snapshot_auto_created",
568
+ SNAPSHOT_SHARED: "snapshot_shared",
569
+ SNAPSHOT_EXPORTED: "snapshot_exported",
570
+ SNAPSHOT_VIEWED: "snapshot_viewed",
571
+ SNAPSHOT_DIFF_VIEWED: "snapshot_diff_viewed",
572
+ // Removed duplicate snapshot_checkpoint_* events to maintain consistent terminology
573
+ // ===== Billing/Monetization Events (12) =====
574
+ BILLING_UPGRADE_PROMPT_SHOWN: "billing_upgrade_prompt_shown",
575
+ BILLING_UPGRADE_PROMPT_CLICKED: "billing_upgrade_prompt_clicked",
576
+ BILLING_PRICING_VIEWED: "billing_pricing_viewed",
577
+ BILLING_CHECKOUT_STARTED: "billing_checkout_started",
578
+ BILLING_CHECKOUT_COMPLETED: "billing_checkout_completed",
579
+ BILLING_CHECKOUT_ABANDONED: "billing_checkout_abandoned",
580
+ BILLING_SUBSCRIPTION_UPGRADED: "billing_subscription_upgraded",
581
+ BILLING_SUBSCRIPTION_DOWNGRADED: "billing_subscription_downgraded",
582
+ BILLING_SUBSCRIPTION_CANCELLED: "billing_subscription_cancelled",
583
+ BILLING_PAYMENT_FAILED: "billing_payment_failed",
584
+ BILLING_COUPON_APPLIED: "billing_coupon_applied",
585
+ BILLING_INVOICE_VIEWED: "billing_invoice_viewed",
586
+ // ===== Extension Events (8) =====
587
+ EXTENSION_INSTALLED: "extension_installed",
588
+ EXTENSION_ACTIVATED: "extension_activated",
589
+ EXTENSION_COMMAND_USED: "extension_command_used",
590
+ EXTENSION_SETTINGS_CHANGED: "extension_settings_changed",
591
+ EXTENSION_ERROR_OCCURRED: "extension_error_occurred",
592
+ EXTENSION_UPDATED: "extension_updated",
593
+ EXTENSION_UNINSTALLED: "extension_uninstalled",
594
+ EXTENSION_FEEDBACK_SUBMITTED: "extension_feedback_submitted",
595
+ // ===== Dashboard Events (8) =====
596
+ DASHBOARD_VIEWED: "dashboard_viewed",
597
+ DASHBOARD_API_KEY_CREATED: "dashboard_api_key_created",
598
+ DASHBOARD_API_KEY_REVOKED: "dashboard_api_key_revoked",
599
+ DASHBOARD_USAGE_CHART_VIEWED: "dashboard_usage_chart_viewed",
600
+ DASHBOARD_SETTINGS_UPDATED: "dashboard_settings_updated",
601
+ DASHBOARD_SEARCH_PERFORMED: "dashboard_search_performed",
602
+ DASHBOARD_EXPORT_TRIGGERED: "dashboard_export_triggered",
603
+ DASHBOARD_HELP_ACCESSED: "dashboard_help_accessed",
604
+ // ===== Team Collaboration Events (6) =====
605
+ TEAM_CREATED: "team_created",
606
+ TEAM_MEMBER_INVITED: "team_member_invited",
607
+ TEAM_MEMBER_JOINED: "team_member_joined",
608
+ TEAM_SNAPSHOT_SHARED: "team_snapshot_shared",
609
+ TEAM_SETTINGS_CHANGED: "team_settings_changed",
610
+ TEAM_MEMBER_REMOVED: "team_member_removed",
611
+ // ===== AI Features Events (5) =====
612
+ AI_SUGGESTION_SHOWN: "ai_suggestion_shown",
613
+ AI_SUGGESTION_ACCEPTED: "ai_suggestion_accepted",
614
+ AI_SUGGESTION_REJECTED: "ai_suggestion_rejected",
615
+ AI_RISK_DETECTED: "ai_risk_detected",
616
+ AI_RISK_PREVENTED: "ai_risk_prevented",
617
+ // ===== API Usage Events (5) =====
618
+ API_CALL_MADE: "api_call_made",
619
+ API_RATE_LIMIT_HIT: "api_rate_limit_hit",
620
+ API_ERROR_OCCURRED: "api_error_occurred",
621
+ API_KEY_ROTATED: "api_key_rotated",
622
+ API_WEBHOOK_CONFIGURED: "api_webhook_configured",
623
+ // ===== Intelligence Layer: Prediction & Learning (6) =====
624
+ PREDICTION_MADE: "prediction_made",
625
+ PREDICTION_OUTCOME_RECORDED: "prediction_outcome_recorded",
626
+ TRUST_SCORE_UPDATED: "trust_score_updated",
627
+ PATTERN_DETECTED: "pattern_detected",
628
+ PATTERN_CONFIRMED: "pattern_confirmed",
629
+ MODEL_CALIBRATION_TRIGGERED: "model_calibration_triggered",
630
+ // ===== Intelligence Layer: Cross-Repo Intelligence (4) =====
631
+ WORKSPACE_CONNECTED: "workspace_connected",
632
+ CROSS_REPO_PATTERN_DETECTED: "cross_repo_pattern_detected",
633
+ REPO_PERSONALITY_UPDATED: "repo_personality_updated",
634
+ GLOBAL_INSIGHT_APPLIED: "global_insight_applied",
635
+ // ===== Intelligence Layer: GitHub Integration (5) =====
636
+ GITHUB_REPO_CONNECTED: "github_repo_connected",
637
+ GITHUB_PR_ANALYZED: "github_pr_analyzed",
638
+ GITHUB_COMMIT_SCANNED: "github_commit_scanned",
639
+ GITHUB_AI_CONTRIBUTION_DETECTED: "github_ai_contribution_detected",
640
+ GITHUB_CHECK_POSTED: "github_check_posted",
641
+ // ===== Intelligence Layer: MCP Tools (3) =====
642
+ MCP_TOOL_CALLED: "mcp_tool_called",
643
+ MCP_CONTEXT_PROVIDED: "mcp_context_provided",
644
+ MCP_AGENT_SELF_CHECK: "mcp_agent_self_check",
645
+ // ===== Intelligence Layer: Community & Engagement (6) =====
646
+ DISASTER_STORY_SHARED: "disaster_story_shared",
647
+ FEEDBACK_SUBMITTED: "feedback_submitted",
648
+ COMMUNITY_ACTION_COMPLETED: "community_action_completed",
649
+ BETA_ELIGIBILITY_CALCULATED: "beta_eligibility_calculated",
650
+ REFERRAL_LINK_GENERATED: "referral_link_generated",
651
+ REFERRAL_CONVERTED: "referral_converted",
652
+ // ===== Activation Funnel Events (2) =====
653
+ AUTH_COMPLETED: "auth_completed",
654
+ FIRST_SNAPSHOT_CREATED: "first_snapshot_created"
655
+ };
656
+
657
+ // ../../packages/infrastructure/dist/neon/index.js
658
+ var neon_exports = {};
659
+ __export(neon_exports, {
660
+ NeonDocClient: () => NeonDocClient,
661
+ runMigration: () => runMigration,
662
+ verifySchema: () => verifySchema
663
+ });
664
+ var NeonDocClient = class {
665
+ static {
666
+ __name(this, "NeonDocClient");
667
+ }
668
+ sql;
669
+ constructor(config) {
670
+ if (config.enableCache !== false) {
671
+ neonConfig.fetchConnectionCache = true;
672
+ }
673
+ this.sql = neon(config.connectionString);
674
+ }
675
+ /**
676
+ * Execute hybrid search against doc_embeddings
677
+ *
678
+ * @param queryEmbedding - 768-dim vector from text-embedding-3-small
679
+ * @param options - Search filters and limits
680
+ * @returns Ranked search results with similarity scores
681
+ */
682
+ async hybridSearch(queryEmbedding, options = {}) {
683
+ if (queryEmbedding.length !== 768) {
684
+ throw new Error(`Expected 768-dim embedding, got ${queryEmbedding.length}`);
685
+ }
686
+ const { library = null, version = null, limit = 5, similarityThreshold = 0.75 } = options;
687
+ const embeddingStr = `[${queryEmbedding.join(",")}]`;
688
+ const results = await this.sql`
689
+ SELECT * FROM hybrid_search(
690
+ ${embeddingStr}::vector(768),
691
+ ${library},
692
+ ${version},
693
+ ${limit},
694
+ ${similarityThreshold}
695
+ )
696
+ `;
697
+ return results;
698
+ }
699
+ /**
700
+ * Insert a single doc embedding
701
+ *
702
+ * @param doc - Document embedding record
703
+ * @returns Inserted record ID
704
+ */
705
+ async insertDoc(doc) {
706
+ if (doc.embedding.length !== 768) {
707
+ throw new Error(`Expected 768-dim embedding, got ${doc.embedding.length}`);
708
+ }
709
+ const embeddingStr = `[${doc.embedding.join(",")}]`;
710
+ const result = await this.sql`
711
+ INSERT INTO doc_embeddings (library, version, doc_type, chunk_text, embedding, metadata, source_url)
712
+ VALUES (
713
+ ${doc.library},
714
+ ${doc.version},
715
+ ${doc.doc_type},
716
+ ${doc.chunk_text},
717
+ ${embeddingStr}::vector(768),
718
+ ${JSON.stringify(doc.metadata)},
719
+ ${doc.source_url}
720
+ )
721
+ ON CONFLICT (library, version, chunk_text)
722
+ DO UPDATE SET
723
+ embedding = EXCLUDED.embedding,
724
+ metadata = EXCLUDED.metadata,
725
+ indexed_at = NOW()
726
+ RETURNING id
727
+ `;
728
+ return result[0]?.id ?? "";
729
+ }
730
+ /**
731
+ * Batch insert doc embeddings (optimized for bulk ingestion)
732
+ *
733
+ * @param docs - Array of document embeddings
734
+ * @returns Count of inserted/updated records
735
+ */
736
+ async batchInsertDocs(docs) {
737
+ if (docs.length === 0) {
738
+ return 0;
739
+ }
740
+ for (const doc of docs) {
741
+ if (doc.embedding.length !== 768) {
742
+ throw new Error(`Expected 768-dim embedding, got ${doc.embedding.length}`);
743
+ }
744
+ }
745
+ let count = 0;
746
+ for (const doc of docs) {
747
+ await this.insertDoc(doc);
748
+ count++;
749
+ }
750
+ return count;
751
+ }
752
+ /**
753
+ * Get embedding stats (total chunks, by library, etc.)
754
+ */
755
+ async getStats() {
756
+ const totalResult = await this.sql`SELECT COUNT(*) as count FROM doc_embeddings`;
757
+ const total = Number(totalResult[0]?.count ?? 0);
758
+ const byLibraryResult = await this.sql`
759
+ SELECT library, COUNT(*) as count
760
+ FROM doc_embeddings
761
+ GROUP BY library
762
+ `;
763
+ const byDocTypeResult = await this.sql`
764
+ SELECT doc_type, COUNT(*) as count
765
+ FROM doc_embeddings
766
+ GROUP BY doc_type
767
+ `;
768
+ return {
769
+ total,
770
+ byLibrary: Object.fromEntries(byLibraryResult.map((r) => [
771
+ r.library,
772
+ Number(r.count)
773
+ ])),
774
+ byDocType: Object.fromEntries(byDocTypeResult.map((r) => [
775
+ r.doc_type,
776
+ Number(r.count)
777
+ ]))
778
+ };
779
+ }
780
+ };
781
+ var __filename$1 = fileURLToPath(import.meta.url);
782
+ var __dirname$1 = dirname(__filename$1);
783
+ async function runMigration(connectionString) {
784
+ try {
785
+ const sql = neon(connectionString);
786
+ const schemaPath = join(__dirname$1, "schema.sql");
787
+ const schemaSql = readFileSync(schemaPath, "utf-8");
788
+ await sql(schemaSql);
789
+ return {
790
+ success: true
791
+ };
792
+ } catch (error) {
793
+ return {
794
+ success: false,
795
+ error: error instanceof Error ? error.message : String(error)
796
+ };
797
+ }
798
+ }
799
+ __name(runMigration, "runMigration");
800
+ async function verifySchema(connectionString) {
801
+ try {
802
+ const sql = neon(connectionString);
803
+ const tableCheck = await sql`
804
+ SELECT EXISTS (
805
+ SELECT FROM information_schema.tables
806
+ WHERE table_name = 'doc_embeddings'
807
+ ) as exists
808
+ `;
809
+ const tableExists = tableCheck[0]?.exists === true;
810
+ const indexCheck = await sql`
811
+ SELECT EXISTS (
812
+ SELECT FROM pg_indexes
813
+ WHERE indexname = 'doc_embeddings_hnsw_idx'
814
+ ) as exists
815
+ `;
816
+ const hnswIndexExists = indexCheck[0]?.exists === true;
817
+ const functionCheck = await sql`
818
+ SELECT EXISTS (
819
+ SELECT FROM pg_proc
820
+ WHERE proname = 'hybrid_search'
821
+ ) as exists
822
+ `;
823
+ const hybridSearchFunctionExists = functionCheck[0]?.exists === true;
824
+ const valid = tableExists && hnswIndexExists && hybridSearchFunctionExists;
825
+ return {
826
+ valid,
827
+ checks: {
828
+ tableExists,
829
+ hnswIndexExists,
830
+ hybridSearchFunctionExists
831
+ }
832
+ };
833
+ } catch (error) {
834
+ return {
835
+ valid: false,
836
+ checks: {
837
+ tableExists: false,
838
+ hnswIndexExists: false,
839
+ hybridSearchFunctionExists: false
840
+ },
841
+ error: error instanceof Error ? error.message : String(error)
842
+ };
843
+ }
844
+ }
845
+ __name(verifySchema, "verifySchema");
846
+ async function createAlert(config) {
847
+ try {
848
+ logger.info({
849
+ alert: config
850
+ }, "PostHog Alert Configuration (Manual Setup Required)");
851
+ return `alert_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
852
+ } catch (error) {
853
+ logger.error({
854
+ error,
855
+ config
856
+ }, "Failed to create PostHog alert");
857
+ throw new Error("Failed to create PostHog alert");
858
+ }
859
+ }
860
+ __name(createAlert, "createAlert");
861
+ async function getAlerts() {
862
+ try {
863
+ return [];
864
+ } catch (error) {
865
+ logger.error({
866
+ error
867
+ }, "Failed to fetch PostHog alerts");
868
+ throw new Error("Failed to fetch PostHog alerts");
869
+ }
870
+ }
871
+ __name(getAlerts, "getAlerts");
872
+ async function toggleAlert(alertId, enabled) {
873
+ try {
874
+ logger.info({
875
+ alertId,
876
+ enabled
877
+ }, "Toggling PostHog alert");
878
+ return true;
879
+ } catch (error) {
880
+ logger.error({
881
+ error,
882
+ alertId,
883
+ enabled
884
+ }, "Failed to toggle PostHog alert");
885
+ throw new Error("Failed to toggle PostHog alert");
886
+ }
887
+ }
888
+ __name(toggleAlert, "toggleAlert");
889
+ async function deleteAlert(alertId) {
890
+ try {
891
+ logger.info({
892
+ alertId
893
+ }, "Deleting PostHog alert");
894
+ return true;
895
+ } catch (error) {
896
+ logger.error({
897
+ error,
898
+ alertId
899
+ }, "Failed to delete PostHog alert");
900
+ throw new Error("Failed to delete PostHog alert");
901
+ }
902
+ }
903
+ __name(deleteAlert, "deleteAlert");
904
+ async function registerKeyMetricAlerts() {
905
+ const posthogKey = process.env.POSTHOG_PERSONAL_API_KEY;
906
+ const environmentId = process.env.POSTHOG_ENVIRONMENT_ID;
907
+ if (!posthogKey) {
908
+ logger.warn("POSTHOG_PERSONAL_API_KEY not set - skipping PostHog alerts registration");
909
+ return;
910
+ }
911
+ if (!environmentId) {
912
+ logger.warn("POSTHOG_ENVIRONMENT_ID not set - skipping PostHog alerts registration");
913
+ return;
914
+ }
915
+ try {
916
+ logger.info({
917
+ count: KEY_METRIC_ALERTS.length
918
+ }, "Registering PostHog key metric alerts");
919
+ for (const alertConfig of KEY_METRIC_ALERTS) {
920
+ await createAlert(alertConfig);
921
+ }
922
+ logger.info("Successfully registered all PostHog key metric alerts");
923
+ } catch (error) {
924
+ logger.error({
925
+ error
926
+ }, "Failed to register PostHog alerts");
927
+ }
928
+ }
929
+ __name(registerKeyMetricAlerts, "registerKeyMetricAlerts");
930
+ var KEY_METRIC_ALERTS = [
931
+ {
932
+ name: "TTFV p75 Alert",
933
+ insightId: "ttfv_insight",
934
+ series: "ttfv_p75",
935
+ type: "value",
936
+ threshold: 7,
937
+ thresholdType: "absolute",
938
+ frequency: "daily",
939
+ recipients: [
940
+ "engineering-team@snapback.ai"
941
+ ]
942
+ },
943
+ {
944
+ name: "Onboarding Completion Rate Alert",
945
+ insightId: "onboarding_insight",
946
+ series: "completion_rate",
947
+ type: "value",
948
+ threshold: 60,
949
+ thresholdType: "absolute",
950
+ frequency: "daily",
951
+ recipients: [
952
+ "product-team@snapback.ai"
953
+ ]
954
+ },
955
+ {
956
+ name: "Crash-free Sessions Alert",
957
+ insightId: "crash_insight",
958
+ series: "crash_free_rate",
959
+ type: "value",
960
+ threshold: 95,
961
+ thresholdType: "absolute",
962
+ frequency: "daily",
963
+ recipients: [
964
+ "engineering-team@snapback.ai"
965
+ ]
966
+ },
967
+ {
968
+ name: "Replay Budget Alert",
969
+ insightId: "replay_insight",
970
+ series: "replay_budget",
971
+ type: "value",
972
+ threshold: 80,
973
+ thresholdType: "percentage",
974
+ frequency: "weekly",
975
+ recipients: [
976
+ "analytics-team@snapback.ai"
977
+ ]
978
+ },
979
+ {
980
+ name: "D7 Retention Alert",
981
+ insightId: "retention_insight",
982
+ series: "d7_retention",
983
+ type: "decrease",
984
+ threshold: 5,
985
+ thresholdType: "percentage",
986
+ frequency: "weekly",
987
+ recipients: [
988
+ "growth-team@snapback.ai"
989
+ ]
990
+ }
991
+ ];
992
+ var posthogClient = null;
993
+ var posthogApiKey = null;
994
+ var posthogHost = null;
995
+ function getPostHog() {
996
+ if (!posthogClient) {
997
+ const posthogKey = process.env.POSTHOG_PERSONAL_API_KEY;
998
+ if (!posthogKey) {
999
+ throw new Error("PostHog personal API key not configured");
1000
+ }
1001
+ const host = process.env.POSTHOG_HOST || "https://app.posthog.com";
1002
+ posthogClient = new PostHog(posthogKey, {
1003
+ host
1004
+ });
1005
+ posthogApiKey = posthogKey;
1006
+ posthogHost = host;
1007
+ }
1008
+ return posthogClient;
1009
+ }
1010
+ __name(getPostHog, "getPostHog");
1011
+ function getPostHogConfig() {
1012
+ if (!posthogApiKey || !posthogHost) {
1013
+ getPostHog();
1014
+ }
1015
+ if (!posthogApiKey || !posthogHost) {
1016
+ throw new Error("PostHog configuration not initialized");
1017
+ }
1018
+ return {
1019
+ apiKey: posthogApiKey,
1020
+ host: posthogHost
1021
+ };
1022
+ }
1023
+ __name(getPostHogConfig, "getPostHogConfig");
1024
+ async function createCohort(config) {
1025
+ try {
1026
+ getPostHog();
1027
+ const phConfig = getPostHogConfig();
1028
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/`, {
1029
+ method: "POST",
1030
+ headers: {
1031
+ Authorization: `Bearer ${phConfig.apiKey}`,
1032
+ "Content-Type": "application/json"
1033
+ },
1034
+ body: JSON.stringify({
1035
+ name: config.name,
1036
+ description: config.description,
1037
+ filters: config.filters,
1038
+ is_static: config.is_static
1039
+ })
1040
+ });
1041
+ if (!response.ok) {
1042
+ throw new Error(`Failed to create cohort: ${response.statusText}`);
1043
+ }
1044
+ const cohort = await response.json();
1045
+ logger.info({
1046
+ cohort
1047
+ }, "Created PostHog cohort");
1048
+ return cohort;
1049
+ } catch (error) {
1050
+ logger.error({
1051
+ error,
1052
+ config
1053
+ }, "Failed to create PostHog cohort");
1054
+ throw new Error(`Failed to create PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1055
+ }
1056
+ }
1057
+ __name(createCohort, "createCohort");
1058
+ async function getCohorts() {
1059
+ try {
1060
+ getPostHog();
1061
+ const phConfig = getPostHogConfig();
1062
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/`, {
1063
+ method: "GET",
1064
+ headers: {
1065
+ Authorization: `Bearer ${phConfig.apiKey}`,
1066
+ "Content-Type": "application/json"
1067
+ }
1068
+ });
1069
+ if (!response.ok) {
1070
+ throw new Error(`Failed to fetch cohorts: ${response.statusText}`);
1071
+ }
1072
+ const data = await response.json();
1073
+ return data.results || [];
1074
+ } catch (error) {
1075
+ logger.error({
1076
+ error
1077
+ }, "Failed to fetch PostHog cohorts");
1078
+ throw new Error(`Failed to fetch PostHog cohorts: ${error instanceof Error ? error.message : "Unknown error"}`);
1079
+ }
1080
+ }
1081
+ __name(getCohorts, "getCohorts");
1082
+ async function getCohort(cohortId) {
1083
+ try {
1084
+ getPostHog();
1085
+ const phConfig = getPostHogConfig();
1086
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/`, {
1087
+ method: "GET",
1088
+ headers: {
1089
+ Authorization: `Bearer ${phConfig.apiKey}`,
1090
+ "Content-Type": "application/json"
1091
+ }
1092
+ });
1093
+ if (!response.ok) {
1094
+ throw new Error(`Failed to fetch cohort: ${response.statusText}`);
1095
+ }
1096
+ const cohort = await response.json();
1097
+ return cohort;
1098
+ } catch (error) {
1099
+ logger.error({
1100
+ error,
1101
+ cohortId
1102
+ }, "Failed to fetch PostHog cohort");
1103
+ throw new Error(`Failed to fetch PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1104
+ }
1105
+ }
1106
+ __name(getCohort, "getCohort");
1107
+ async function updateCohort(cohortId, config) {
1108
+ try {
1109
+ getPostHog();
1110
+ const phConfig = getPostHogConfig();
1111
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/`, {
1112
+ method: "PATCH",
1113
+ headers: {
1114
+ Authorization: `Bearer ${phConfig.apiKey}`,
1115
+ "Content-Type": "application/json"
1116
+ },
1117
+ body: JSON.stringify(config)
1118
+ });
1119
+ if (!response.ok) {
1120
+ throw new Error(`Failed to update cohort: ${response.statusText}`);
1121
+ }
1122
+ const cohort = await response.json();
1123
+ logger.info({
1124
+ cohort
1125
+ }, "Updated PostHog cohort");
1126
+ return cohort;
1127
+ } catch (error) {
1128
+ logger.error({
1129
+ error,
1130
+ cohortId,
1131
+ config
1132
+ }, "Failed to update PostHog cohort");
1133
+ throw new Error(`Failed to update PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1134
+ }
1135
+ }
1136
+ __name(updateCohort, "updateCohort");
1137
+ async function deleteCohort(cohortId) {
1138
+ try {
1139
+ getPostHog();
1140
+ const phConfig = getPostHogConfig();
1141
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/`, {
1142
+ method: "DELETE",
1143
+ headers: {
1144
+ Authorization: `Bearer ${phConfig.apiKey}`,
1145
+ "Content-Type": "application/json"
1146
+ }
1147
+ });
1148
+ if (!response.ok) {
1149
+ throw new Error(`Failed to delete cohort: ${response.statusText}`);
1150
+ }
1151
+ logger.info({
1152
+ cohortId
1153
+ }, "Deleted PostHog cohort");
1154
+ } catch (error) {
1155
+ logger.error({
1156
+ error,
1157
+ cohortId
1158
+ }, "Failed to delete PostHog cohort");
1159
+ throw new Error(`Failed to delete PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1160
+ }
1161
+ }
1162
+ __name(deleteCohort, "deleteCohort");
1163
+ async function getCohortMembers(cohortId) {
1164
+ try {
1165
+ getPostHog();
1166
+ const phConfig = getPostHogConfig();
1167
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/persons/`, {
1168
+ method: "GET",
1169
+ headers: {
1170
+ Authorization: `Bearer ${phConfig.apiKey}`,
1171
+ "Content-Type": "application/json"
1172
+ }
1173
+ });
1174
+ if (!response.ok) {
1175
+ throw new Error(`Failed to fetch cohort members: ${response.statusText}`);
1176
+ }
1177
+ const data = await response.json();
1178
+ return data.results || [];
1179
+ } catch (error) {
1180
+ logger.error({
1181
+ error,
1182
+ cohortId
1183
+ }, "Failed to fetch PostHog cohort members");
1184
+ throw new Error(`Failed to fetch PostHog cohort members: ${error instanceof Error ? error.message : "Unknown error"}`);
1185
+ }
1186
+ }
1187
+ __name(getCohortMembers, "getCohortMembers");
1188
+ var RETENTION_COHORTS = [
1189
+ {
1190
+ name: "D7 Retention",
1191
+ description: "Users who return within 7 days of their first activity",
1192
+ filters: {
1193
+ properties: [
1194
+ {
1195
+ key: "first_seen",
1196
+ value: "7 days",
1197
+ operator: "within",
1198
+ type: "event"
1199
+ }
1200
+ ]
1201
+ }
1202
+ },
1203
+ {
1204
+ name: "D30 Retention",
1205
+ description: "Users who return within 30 days of their first activity",
1206
+ filters: {
1207
+ properties: [
1208
+ {
1209
+ key: "first_seen",
1210
+ value: "30 days",
1211
+ operator: "within",
1212
+ type: "event"
1213
+ }
1214
+ ]
1215
+ }
1216
+ },
1217
+ {
1218
+ name: "Onboarding Completion Cohort",
1219
+ description: "Users who completed the onboarding process",
1220
+ filters: {
1221
+ properties: [
1222
+ {
1223
+ key: "onboarding_completed",
1224
+ value: true,
1225
+ operator: "exact",
1226
+ type: "event"
1227
+ }
1228
+ ]
1229
+ }
1230
+ },
1231
+ {
1232
+ name: "High Engagement Users",
1233
+ description: "Users with high engagement (5+ sessions in 7 days)",
1234
+ filters: {
1235
+ properties: [
1236
+ {
1237
+ key: "session_count",
1238
+ value: 5,
1239
+ operator: "gt",
1240
+ type: "event"
1241
+ },
1242
+ {
1243
+ key: "activity_period",
1244
+ value: "7 days",
1245
+ operator: "within",
1246
+ type: "event"
1247
+ }
1248
+ ]
1249
+ }
1250
+ }
1251
+ ];
1252
+ var CORRELATION_COHORTS = [
1253
+ {
1254
+ name: "Feature Power Users",
1255
+ description: "Users who use advanced features regularly",
1256
+ filters: {
1257
+ properties: [
1258
+ {
1259
+ key: "advanced_feature_usage",
1260
+ value: true,
1261
+ operator: "exact",
1262
+ type: "event"
1263
+ }
1264
+ ]
1265
+ }
1266
+ },
1267
+ {
1268
+ name: "At-Risk Churn",
1269
+ description: "Users showing signs of disengagement",
1270
+ filters: {
1271
+ properties: [
1272
+ {
1273
+ key: "days_since_last_activity",
1274
+ value: 14,
1275
+ operator: "gt",
1276
+ type: "event"
1277
+ }
1278
+ ]
1279
+ }
1280
+ },
1281
+ {
1282
+ name: "Free to Paid Converters",
1283
+ description: "Users who upgraded from free to paid plan",
1284
+ filters: {
1285
+ properties: [
1286
+ {
1287
+ key: "plan_upgrade",
1288
+ value: "free_to_paid",
1289
+ operator: "exact",
1290
+ type: "event"
1291
+ }
1292
+ ]
1293
+ }
1294
+ }
1295
+ ];
1296
+ var posthogClient2 = null;
1297
+ function getPostHog2() {
1298
+ if (!posthogClient2) {
1299
+ const posthogKey = process.env.POSTHOG_PERSONAL_API_KEY;
1300
+ if (!posthogKey) {
1301
+ throw new Error("PostHog personal API key not configured");
1302
+ }
1303
+ const posthogHost2 = process.env.POSTHOG_HOST || "https://app.posthog.com";
1304
+ posthogClient2 = new PostHog(posthogKey, {
1305
+ host: posthogHost2
1306
+ });
1307
+ }
1308
+ return posthogClient2;
1309
+ }
1310
+ __name(getPostHog2, "getPostHog");
1311
+ async function performCorrelationAnalysis(config) {
1312
+ try {
1313
+ const _posthog = getPostHog2();
1314
+ logger.info({
1315
+ config
1316
+ }, "Performing correlation analysis");
1317
+ const results = config.propertyNames.map((property, _index) => ({
1318
+ property,
1319
+ correlation: Math.random() * 2 - 1,
1320
+ count: Math.floor(Math.random() * 1e3) + 100,
1321
+ relativeFrequency: Math.random()
1322
+ }));
1323
+ results.sort((a, b) => Math.abs(b.correlation) - Math.abs(a.correlation));
1324
+ const analysis = {
1325
+ id: `correlation_${Date.now()}`,
1326
+ name: config.name,
1327
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1328
+ results: results.slice(0, 10)
1329
+ };
1330
+ logger.info({
1331
+ analysis
1332
+ }, "Correlation analysis completed");
1333
+ return analysis;
1334
+ } catch (error) {
1335
+ logger.error({
1336
+ error,
1337
+ config
1338
+ }, "Failed to perform correlation analysis");
1339
+ throw new Error(`Failed to perform correlation analysis: ${error instanceof Error ? error.message : "Unknown error"}`);
1340
+ }
1341
+ }
1342
+ __name(performCorrelationAnalysis, "performCorrelationAnalysis");
1343
+ async function getCorrelationAnalysis(analysisId) {
1344
+ try {
1345
+ throw new Error("Correlation analysis persistence not implemented");
1346
+ } catch (error) {
1347
+ logger.error({
1348
+ error,
1349
+ analysisId
1350
+ }, "Failed to fetch correlation analysis");
1351
+ throw new Error(`Failed to fetch correlation analysis: ${error instanceof Error ? error.message : "Unknown error"}`);
1352
+ }
1353
+ }
1354
+ __name(getCorrelationAnalysis, "getCorrelationAnalysis");
1355
+ var CORRELATION_ANALYSES = [
1356
+ {
1357
+ name: "Onboarding Completion Factors",
1358
+ eventName: "onboarding_completed",
1359
+ propertyNames: [
1360
+ "signup_source",
1361
+ "device_type",
1362
+ "browser",
1363
+ "utm_campaign",
1364
+ "time_to_complete",
1365
+ "steps_completed",
1366
+ "help_articles_viewed"
1367
+ ]
1368
+ },
1369
+ {
1370
+ name: "Feature Adoption Correlations",
1371
+ eventName: "feature_used",
1372
+ propertyNames: [
1373
+ "user_plan",
1374
+ "account_age_days",
1375
+ "session_frequency",
1376
+ "support_tickets",
1377
+ "documentation_views",
1378
+ "community_posts"
1379
+ ]
1380
+ },
1381
+ {
1382
+ name: "Churn Risk Indicators",
1383
+ eventName: "account_deactivated",
1384
+ propertyNames: [
1385
+ "days_since_last_activity",
1386
+ "feature_usage_count",
1387
+ "support_ticket_count",
1388
+ "billing_issues",
1389
+ "plan_downgrade",
1390
+ "session_duration_avg"
1391
+ ]
1392
+ },
1393
+ {
1394
+ name: "High Value User Characteristics",
1395
+ eventName: "plan_upgraded",
1396
+ propertyNames: [
1397
+ "initial_plan",
1398
+ "signup_source",
1399
+ "feature_discovery_rate",
1400
+ "engagement_score",
1401
+ "referral_count",
1402
+ "content_creation"
1403
+ ]
1404
+ }
1405
+ ];
1406
+
1407
+ // ../../packages/infrastructure/dist/prometheus/index.js
1408
+ var prometheus_exports = {};
1409
+ __export(prometheus_exports, {
1410
+ client: () => client,
1411
+ dbConnections: () => dbConnections,
1412
+ dbQueryDurationSeconds: () => dbQueryDurationSeconds,
1413
+ getContentType: () => getContentType,
1414
+ getMetrics: () => getMetrics,
1415
+ healthCheckDurationSeconds: () => healthCheckDurationSeconds,
1416
+ healthCheckFailuresTotal: () => healthCheckFailuresTotal,
1417
+ healthCheckLastSuccessTimestamp: () => healthCheckLastSuccessTimestamp,
1418
+ healthCheckStatus: () => healthCheckStatus,
1419
+ httpRequestDurationSeconds: () => httpRequestDurationSeconds,
1420
+ httpRequestsTotal: () => httpRequestsTotal,
1421
+ mcpActiveSessions: () => mcpActiveSessions,
1422
+ mcpProxyErrorsTotal: () => mcpProxyErrorsTotal,
1423
+ readinessProbeLastSuccessTimestamp: () => readinessProbeLastSuccessTimestamp,
1424
+ readinessProbeStatus: () => readinessProbeStatus,
1425
+ recordHealthCheck: () => recordHealthCheck,
1426
+ recordReadinessProbe: () => recordReadinessProbe,
1427
+ recordStartupComplete: () => recordStartupComplete,
1428
+ registry: () => registry,
1429
+ sseConnectionsTotal: () => sseConnectionsTotal,
1430
+ startupProbeDurationSeconds: () => startupProbeDurationSeconds,
1431
+ startupProbeFailuresTotal: () => startupProbeFailuresTotal
1432
+ });
1433
+ var registry = new client.Registry();
1434
+ var defaultMetrics = client.collectDefaultMetrics;
1435
+ defaultMetrics({
1436
+ register: registry
1437
+ });
1438
+ var healthCheckStatus = new client.Gauge({
1439
+ name: "health_check_status",
1440
+ help: "Current health check status (1=healthy, 0=unhealthy)",
1441
+ labelNames: [
1442
+ "service",
1443
+ "check"
1444
+ ],
1445
+ registers: [
1446
+ registry
1447
+ ]
1448
+ });
1449
+ var healthCheckFailuresTotal = new client.Counter({
1450
+ name: "health_check_failures_total",
1451
+ help: "Total number of health check failures",
1452
+ labelNames: [
1453
+ "service",
1454
+ "check",
1455
+ "reason"
1456
+ ],
1457
+ registers: [
1458
+ registry
1459
+ ]
1460
+ });
1461
+ var healthCheckDurationSeconds = new client.Histogram({
1462
+ name: "health_check_duration_seconds",
1463
+ help: "Duration of health check execution in seconds",
1464
+ labelNames: [
1465
+ "service",
1466
+ "check"
1467
+ ],
1468
+ buckets: [
1469
+ 1e-3,
1470
+ 5e-3,
1471
+ 0.01,
1472
+ 0.025,
1473
+ 0.05,
1474
+ 0.1,
1475
+ 0.25,
1476
+ 0.5,
1477
+ 1,
1478
+ 2.5,
1479
+ 5,
1480
+ 10
1481
+ ],
1482
+ registers: [
1483
+ registry
1484
+ ]
1485
+ });
1486
+ var healthCheckLastSuccessTimestamp = new client.Gauge({
1487
+ name: "health_check_last_success_timestamp_seconds",
1488
+ help: "Unix timestamp of the last successful health check",
1489
+ labelNames: [
1490
+ "service",
1491
+ "check"
1492
+ ],
1493
+ registers: [
1494
+ registry
1495
+ ]
1496
+ });
1497
+ var startupProbeFailuresTotal = new client.Counter({
1498
+ name: "startup_probe_failures_total",
1499
+ help: "Total number of startup probe failures",
1500
+ labelNames: [
1501
+ "service"
1502
+ ],
1503
+ registers: [
1504
+ registry
1505
+ ]
1506
+ });
1507
+ var startupProbeDurationSeconds = new client.Gauge({
1508
+ name: "startup_probe_duration_seconds",
1509
+ help: "Time taken for service startup in seconds",
1510
+ labelNames: [
1511
+ "service"
1512
+ ],
1513
+ registers: [
1514
+ registry
1515
+ ]
1516
+ });
1517
+ var readinessProbeStatus = new client.Gauge({
1518
+ name: "readiness_probe_status",
1519
+ help: "Current readiness probe status (1=ready, 0=not_ready)",
1520
+ labelNames: [
1521
+ "service"
1522
+ ],
1523
+ registers: [
1524
+ registry
1525
+ ]
1526
+ });
1527
+ var readinessProbeLastSuccessTimestamp = new client.Gauge({
1528
+ name: "readiness_probe_last_success_timestamp_seconds",
1529
+ help: "Unix timestamp of the last successful readiness probe",
1530
+ labelNames: [
1531
+ "service"
1532
+ ],
1533
+ registers: [
1534
+ registry
1535
+ ]
1536
+ });
1537
+ var httpRequestDurationSeconds = new client.Histogram({
1538
+ name: "http_request_duration_seconds",
1539
+ help: "Duration of HTTP requests in seconds",
1540
+ labelNames: [
1541
+ "method",
1542
+ "path",
1543
+ "status"
1544
+ ],
1545
+ buckets: [
1546
+ 1e-3,
1547
+ 5e-3,
1548
+ 0.01,
1549
+ 0.025,
1550
+ 0.05,
1551
+ 0.1,
1552
+ 0.25,
1553
+ 0.5,
1554
+ 1,
1555
+ 2.5,
1556
+ 5
1557
+ ],
1558
+ registers: [
1559
+ registry
1560
+ ]
1561
+ });
1562
+ var httpRequestsTotal = new client.Counter({
1563
+ name: "http_requests_total",
1564
+ help: "Total number of HTTP requests",
1565
+ labelNames: [
1566
+ "method",
1567
+ "path",
1568
+ "status"
1569
+ ],
1570
+ registers: [
1571
+ registry
1572
+ ]
1573
+ });
1574
+ var dbConnections = new client.Gauge({
1575
+ name: "db_connections",
1576
+ help: "Current number of database connections",
1577
+ labelNames: [
1578
+ "pool",
1579
+ "state"
1580
+ ],
1581
+ registers: [
1582
+ registry
1583
+ ]
1584
+ });
1585
+ var dbQueryDurationSeconds = new client.Histogram({
1586
+ name: "db_query_duration_seconds",
1587
+ help: "Duration of database queries in seconds",
1588
+ labelNames: [
1589
+ "operation",
1590
+ "table"
1591
+ ],
1592
+ buckets: [
1593
+ 1e-3,
1594
+ 5e-3,
1595
+ 0.01,
1596
+ 0.025,
1597
+ 0.05,
1598
+ 0.1,
1599
+ 0.25,
1600
+ 0.5,
1601
+ 1
1602
+ ],
1603
+ registers: [
1604
+ registry
1605
+ ]
1606
+ });
1607
+ var mcpActiveSessions = new client.Gauge({
1608
+ name: "mcp_active_sessions",
1609
+ help: "Current number of active MCP sessions",
1610
+ registers: [
1611
+ registry
1612
+ ]
1613
+ });
1614
+ var mcpProxyErrorsTotal = new client.Counter({
1615
+ name: "mcp_proxy_errors_total",
1616
+ help: "Total number of MCP proxy errors",
1617
+ labelNames: [
1618
+ "endpoint",
1619
+ "error_type"
1620
+ ],
1621
+ registers: [
1622
+ registry
1623
+ ]
1624
+ });
1625
+ var sseConnectionsTotal = new client.Gauge({
1626
+ name: "sse_connections_total",
1627
+ help: "Current number of SSE connections",
1628
+ labelNames: [
1629
+ "service"
1630
+ ],
1631
+ registers: [
1632
+ registry
1633
+ ]
1634
+ });
1635
+ function recordHealthCheck(service, check, status, durationMs) {
1636
+ const isHealthy = status === "healthy" ? 1 : 0;
1637
+ healthCheckStatus.set({
1638
+ service,
1639
+ check
1640
+ }, isHealthy);
1641
+ healthCheckDurationSeconds.observe({
1642
+ service,
1643
+ check
1644
+ }, durationMs / 1e3);
1645
+ if (status === "healthy") {
1646
+ healthCheckLastSuccessTimestamp.set({
1647
+ service,
1648
+ check
1649
+ }, Date.now() / 1e3);
1650
+ }
1651
+ if (status === "unhealthy") {
1652
+ healthCheckFailuresTotal.inc({
1653
+ service,
1654
+ check,
1655
+ reason: "check_failed"
1656
+ });
1657
+ }
1658
+ }
1659
+ __name(recordHealthCheck, "recordHealthCheck");
1660
+ function recordReadinessProbe(service, isReady) {
1661
+ readinessProbeStatus.set({
1662
+ service
1663
+ }, isReady ? 1 : 0);
1664
+ if (isReady) {
1665
+ readinessProbeLastSuccessTimestamp.set({
1666
+ service
1667
+ }, Date.now() / 1e3);
1668
+ }
1669
+ }
1670
+ __name(recordReadinessProbe, "recordReadinessProbe");
1671
+ function recordStartupComplete(service, durationSeconds) {
1672
+ startupProbeDurationSeconds.set({
1673
+ service
1674
+ }, durationSeconds);
1675
+ }
1676
+ __name(recordStartupComplete, "recordStartupComplete");
1677
+ async function getMetrics() {
1678
+ return registry.metrics();
1679
+ }
1680
+ __name(getMetrics, "getMetrics");
1681
+ function getContentType() {
1682
+ return registry.contentType;
1683
+ }
1684
+ __name(getContentType, "getContentType");
1685
+
1686
+ // ../../packages/infrastructure/dist/sentry/index.js
1687
+ var Sentry = null;
1688
+ var ProfilingIntegration = null;
1689
+ async function loadSentry() {
1690
+ if (Sentry) {
1691
+ return {
1692
+ Sentry,
1693
+ ProfilingIntegration
1694
+ };
1695
+ }
1696
+ if (process.env.DISABLE_SENTRY === "true") {
1697
+ return null;
1698
+ }
1699
+ try {
1700
+ Sentry = await import('@sentry/node');
1701
+ ProfilingIntegration = await import('@sentry/profiling-node');
1702
+ return {
1703
+ Sentry,
1704
+ ProfilingIntegration
1705
+ };
1706
+ } catch (error) {
1707
+ console.warn("\u26A0\uFE0F Failed to load Sentry:", error instanceof Error ? error.message : String(error));
1708
+ return null;
1709
+ }
1710
+ }
1711
+ __name(loadSentry, "loadSentry");
1712
+ async function initSentry(options) {
1713
+ if (process.env.DISABLE_SENTRY === "true" || options?.enabled === false) {
1714
+ console.log("\u2139\uFE0F Sentry is disabled");
1715
+ return;
1716
+ }
1717
+ const dsn = options?.dsn || process.env.SENTRY_DSN;
1718
+ if (!dsn) {
1719
+ console.warn("\u26A0\uFE0F SENTRY_DSN not configured. Error tracking disabled.");
1720
+ return;
1721
+ }
1722
+ const modules = await loadSentry();
1723
+ if (!modules) {
1724
+ return;
1725
+ }
1726
+ const { Sentry: SentryModule, ProfilingIntegration: ProfilingIntegration2 } = modules;
1727
+ SentryModule.init({
1728
+ dsn,
1729
+ environment: options?.environment || process.env.NODE_ENV || "development",
1730
+ release: options?.release || process.env.GIT_SHA || process.env.RELEASE || void 0,
1731
+ tracesSampleRate: options?.tracesSampleRate ?? (process.env.NODE_ENV === "production" ? 0.1 : 1),
1732
+ profilesSampleRate: options?.profilesSampleRate ?? 0.1,
1733
+ debug: options?.debug || process.env.DEBUG_SENTRY === "true",
1734
+ integrations: [
1735
+ new SentryModule.HttpIntegration({
1736
+ tracing: true,
1737
+ request: true
1738
+ }),
1739
+ ...ProfilingIntegration2 ? [
1740
+ ProfilingIntegration2.nodeProfilingIntegration()
1741
+ ] : []
1742
+ ],
1743
+ // Filter out sensitive data
1744
+ beforeSend: /* @__PURE__ */ __name((event) => {
1745
+ if (event?.exception?.values?.[0]?.value?.includes?.("404") || event?.request?.url?.includes?.("/favicon.ico")) {
1746
+ return null;
1747
+ }
1748
+ if (event?.request?.headers) {
1749
+ delete event.request.headers.authorization;
1750
+ delete event.request.headers.cookie;
1751
+ }
1752
+ return event;
1753
+ }, "beforeSend")
1754
+ });
1755
+ console.log("\u2705 Sentry initialized for error tracking");
1756
+ }
1757
+ __name(initSentry, "initSentry");
1758
+ function createSentryMiddleware() {
1759
+ if (!Sentry) {
1760
+ return {
1761
+ requestHandler: /* @__PURE__ */ __name((_c, next) => next(), "requestHandler"),
1762
+ errorHandler: /* @__PURE__ */ __name((_c, next) => next(), "errorHandler")
1763
+ };
1764
+ }
1765
+ return {
1766
+ requestHandler: Sentry.Handlers?.requestHandler?.() || ((_c, next) => next()),
1767
+ errorHandler: Sentry.Handlers?.errorHandler?.() || ((_c, next) => next())
1768
+ };
1769
+ }
1770
+ __name(createSentryMiddleware, "createSentryMiddleware");
1771
+ function captureError(error, context2) {
1772
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1773
+ return;
1774
+ }
1775
+ Sentry.withScope((scope) => {
1776
+ if (context2) {
1777
+ if (context2.userId) {
1778
+ scope.setUser({
1779
+ id: context2.userId
1780
+ });
1781
+ }
1782
+ if (context2.organizationId) {
1783
+ scope.setTag("organization_id", context2.organizationId);
1784
+ }
1785
+ if (context2.tags) {
1786
+ Object.entries(context2.tags).forEach(([key, value]) => {
1787
+ scope.setTag(key, value);
1788
+ });
1789
+ }
1790
+ if (context2.extra) {
1791
+ scope.setContext("extra", context2.extra);
1792
+ }
1793
+ }
1794
+ if (Sentry) {
1795
+ Sentry.captureException(typeof error === "string" ? new Error(error) : error);
1796
+ }
1797
+ });
1798
+ }
1799
+ __name(captureError, "captureError");
1800
+ function captureMessage(message, level = "info", context2) {
1801
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1802
+ return;
1803
+ }
1804
+ Sentry.captureMessage(message, level);
1805
+ if (context2) {
1806
+ Sentry.withScope((scope) => {
1807
+ if (context2.userId) {
1808
+ scope.setUser({
1809
+ id: context2.userId
1810
+ });
1811
+ }
1812
+ if (context2.tags) {
1813
+ Object.entries(context2.tags).forEach(([key, value]) => {
1814
+ scope.setTag(key, value);
1815
+ });
1816
+ }
1817
+ if (context2.extra) {
1818
+ scope.setContext("extra", context2.extra);
1819
+ }
1820
+ });
1821
+ }
1822
+ }
1823
+ __name(captureMessage, "captureMessage");
1824
+ function setSentryUser(userId, userInfo) {
1825
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1826
+ return;
1827
+ }
1828
+ Sentry.setUser({
1829
+ id: userId,
1830
+ email: userInfo?.email,
1831
+ username: userInfo?.username,
1832
+ organization_id: userInfo?.organizationId
1833
+ });
1834
+ }
1835
+ __name(setSentryUser, "setSentryUser");
1836
+ function clearSentryUser() {
1837
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1838
+ return;
1839
+ }
1840
+ Sentry.setUser(null);
1841
+ }
1842
+ __name(clearSentryUser, "clearSentryUser");
1843
+ function addSentryBreadcrumb(message, data, level = "info") {
1844
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1845
+ return;
1846
+ }
1847
+ Sentry.addBreadcrumb({
1848
+ message,
1849
+ level,
1850
+ data,
1851
+ timestamp: Date.now() / 1e3
1852
+ });
1853
+ }
1854
+ __name(addSentryBreadcrumb, "addSentryBreadcrumb");
1855
+ function startSentryTransaction(name, op) {
1856
+ if (process.env.DISABLE_SENTRY === "true") {
1857
+ return null;
1858
+ }
1859
+ return Sentry.startTransaction?.({
1860
+ name,
1861
+ op: op || "operation"
1862
+ }) || null;
1863
+ }
1864
+ __name(startSentryTransaction, "startSentryTransaction");
1865
+ async function flushSentry(timeout = 2e3) {
1866
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1867
+ return true;
1868
+ }
1869
+ return await Sentry.close(timeout);
1870
+ }
1871
+ __name(flushSentry, "flushSentry");
1872
+
1873
+ // ../../packages/infrastructure/dist/tracing/error-budget.js
1874
+ var ERROR_BUDGET = 0.01;
1875
+ var ALERT_THRESHOLD = 5e-3;
1876
+ var errorMetrics = {
1877
+ totalRequests: 0,
1878
+ errorCount: 0,
1879
+ lastAlertTime: 0
1880
+ };
1881
+ function recordSuccess() {
1882
+ errorMetrics.totalRequests++;
1883
+ }
1884
+ __name(recordSuccess, "recordSuccess");
1885
+ function recordError() {
1886
+ errorMetrics.totalRequests++;
1887
+ errorMetrics.errorCount++;
1888
+ }
1889
+ __name(recordError, "recordError");
1890
+ function getErrorRate() {
1891
+ if (errorMetrics.totalRequests === 0) {
1892
+ return 0;
1893
+ }
1894
+ return errorMetrics.errorCount / errorMetrics.totalRequests;
1895
+ }
1896
+ __name(getErrorRate, "getErrorRate");
1897
+ async function checkErrorBudget() {
1898
+ const errorRate = getErrorRate();
1899
+ if (errorRate > ALERT_THRESHOLD && Date.now() - errorMetrics.lastAlertTime > 6e4) {
1900
+ logger.warn({
1901
+ errorRate: `${(errorRate * 100).toFixed(2)}%`,
1902
+ threshold: `${(ALERT_THRESHOLD * 100).toFixed(2)}%`,
1903
+ errorCount: errorMetrics.errorCount,
1904
+ totalRequests: errorMetrics.totalRequests
1905
+ }, "Error rate approaching budget threshold");
1906
+ errorMetrics.lastAlertTime = Date.now();
1907
+ }
1908
+ if (errorRate > ERROR_BUDGET) {
1909
+ logger.error({
1910
+ errorRate: `${(errorRate * 100).toFixed(2)}%`,
1911
+ budget: `${(ERROR_BUDGET * 100).toFixed(2)}%`,
1912
+ errorCount: errorMetrics.errorCount,
1913
+ totalRequests: errorMetrics.totalRequests,
1914
+ recommendation: "Investigate root cause immediately and consider rolling back"
1915
+ }, "\u{1F6A8} Error budget exceeded!");
1916
+ await sendAlert({
1917
+ channel: "#alerts",
1918
+ message: `\u{1F6A8} Error budget exceeded! Current error rate: ${(errorRate * 100).toFixed(2)}% (Budget: ${(ERROR_BUDGET * 100).toFixed(2)}%)`
1919
+ });
1920
+ }
1921
+ }
1922
+ __name(checkErrorBudget, "checkErrorBudget");
1923
+ async function sendAlert(alert) {
1924
+ logger.info(alert, "Alert sent");
1925
+ }
1926
+ __name(sendAlert, "sendAlert");
1927
+ function resetMetrics() {
1928
+ errorMetrics.totalRequests = 0;
1929
+ errorMetrics.errorCount = 0;
1930
+ errorMetrics.lastAlertTime = 0;
1931
+ }
1932
+ __name(resetMetrics, "resetMetrics");
1933
+ function getMetrics2() {
1934
+ return {
1935
+ ...errorMetrics,
1936
+ errorRate: getErrorRate()
1937
+ };
1938
+ }
1939
+ __name(getMetrics2, "getMetrics");
1940
+ var OTelSpanAdapter = class OTelSpanAdapter2 {
1941
+ static {
1942
+ __name(this, "OTelSpanAdapter");
1943
+ }
1944
+ otelSpan;
1945
+ constructor(otelSpan) {
1946
+ this.otelSpan = otelSpan;
1947
+ }
1948
+ setAttribute(key, value) {
1949
+ this.otelSpan.setAttribute(key, value);
1950
+ }
1951
+ setAttributes(attributes) {
1952
+ this.otelSpan.setAttributes(attributes);
1953
+ }
1954
+ addEvent(name, attributes) {
1955
+ this.otelSpan.addEvent(name, attributes);
1956
+ }
1957
+ setStatus(status) {
1958
+ this.otelSpan.setStatus({
1959
+ code: status.code,
1960
+ message: status.message
1961
+ });
1962
+ }
1963
+ recordException(error) {
1964
+ this.otelSpan.recordException(error);
1965
+ }
1966
+ end() {
1967
+ this.otelSpan.end();
1968
+ }
1969
+ isRecording() {
1970
+ return this.otelSpan.isRecording();
1971
+ }
1972
+ };
1973
+ var OTelInstrumentationProvider = class {
1974
+ static {
1975
+ __name(this, "OTelInstrumentationProvider");
1976
+ }
1977
+ tracer;
1978
+ provider;
1979
+ meter;
1980
+ constructor(config) {
1981
+ const resource = resourceFromAttributes({
1982
+ [ATTR_SERVICE_NAME]: config.serviceName,
1983
+ [ATTR_SERVICE_VERSION]: config.serviceVersion || "unknown",
1984
+ "deployment.environment": config.environment || "development",
1985
+ "service.instance.id": process.pid.toString(),
1986
+ "host.name": process.env.HOSTNAME || "unknown",
1987
+ "process.pid": process.pid
1988
+ });
1989
+ const spanProcessors = [];
1990
+ if (config.collectorUrl) {
1991
+ const otlpExporter = new OTLPTraceExporter({
1992
+ url: config.collectorUrl
1993
+ });
1994
+ spanProcessors.push(new BatchSpanProcessor(otlpExporter));
1995
+ }
1996
+ if (config.enableConsole) {
1997
+ const consoleExporter = new ConsoleSpanExporter();
1998
+ spanProcessors.push(new BatchSpanProcessor(consoleExporter));
1999
+ }
2000
+ const samplingRate = config.sampleRate ?? 1;
2001
+ const sampler = new TraceIdRatioBasedSampler(samplingRate);
2002
+ this.provider = new NodeTracerProvider({
2003
+ resource,
2004
+ sampler,
2005
+ spanProcessors
2006
+ });
2007
+ this.provider.register();
2008
+ const pinoInstrumentation = new PinoInstrumentation({
2009
+ // Keep default log keys: trace_id, span_id, trace_flags
2010
+ // These match standard OTel semantic conventions
2011
+ disableLogSending: true,
2012
+ disableLogCorrelation: false
2013
+ });
2014
+ const pgInstrumentation = new PgInstrumentation({
2015
+ // Add database query attributes to spans
2016
+ requireParentSpan: false,
2017
+ enhancedDatabaseReporting: true
2018
+ });
2019
+ try {
2020
+ pinoInstrumentation.enable();
2021
+ pgInstrumentation.enable();
2022
+ } catch {
2023
+ }
2024
+ this.tracer = trace.getTracer(config.serviceName, config.serviceVersion);
2025
+ this.meter = metrics.getMeter(config.serviceName, config.serviceVersion || "unknown");
2026
+ }
2027
+ startSpan(name, options) {
2028
+ const otelSpan = this.tracer.startSpan(name, {
2029
+ kind: options?.kind,
2030
+ attributes: options?.attributes,
2031
+ startTime: options?.startTime
2032
+ });
2033
+ return new OTelSpanAdapter(otelSpan);
2034
+ }
2035
+ async withSpan(name, fn, options) {
2036
+ const parentCtx = options?.parent ? options.parent : context.active();
2037
+ return await this.tracer.startActiveSpan(name, {
2038
+ kind: options?.kind,
2039
+ attributes: options?.attributes,
2040
+ startTime: options?.startTime
2041
+ }, parentCtx, async (otelSpan) => {
2042
+ const span = new OTelSpanAdapter(otelSpan);
2043
+ try {
2044
+ const result = await fn(span);
2045
+ otelSpan.setStatus({
2046
+ code: SpanStatusCode.OK
2047
+ });
2048
+ return result;
2049
+ } catch (error) {
2050
+ otelSpan.recordException(error);
2051
+ otelSpan.setStatus({
2052
+ code: SpanStatusCode.ERROR,
2053
+ message: error instanceof Error ? error.message : String(error)
2054
+ });
2055
+ throw error;
2056
+ } finally {
2057
+ otelSpan.end();
2058
+ }
2059
+ });
2060
+ }
2061
+ injectContext(carrier) {
2062
+ propagation.inject(context.active(), carrier);
2063
+ }
2064
+ extractContext(carrier) {
2065
+ const extractedContext = propagation.extract(ROOT_CONTEXT, carrier);
2066
+ const span = trace.getSpan(extractedContext);
2067
+ if (span?.spanContext().traceId) {
2068
+ return extractedContext;
2069
+ }
2070
+ return null;
2071
+ }
2072
+ recordMetric(_name, _value, _attributes) {
2073
+ }
2074
+ recordEvent(_name, _attributes) {
2075
+ }
2076
+ async shutdown() {
2077
+ await this.provider.shutdown();
2078
+ }
2079
+ };
2080
+
2081
+ // ../../packages/infrastructure/dist/tracing/telemetry-client.js
2082
+ var TelemetryClient = class {
2083
+ static {
2084
+ __name(this, "TelemetryClient");
2085
+ }
2086
+ environment;
2087
+ flags = /* @__PURE__ */ new Map();
2088
+ eventQueue = [];
2089
+ flushInterval = 5e3;
2090
+ maxQueueSize = 100;
2091
+ rateLimitWindow = 6e4;
2092
+ eventCounts = /* @__PURE__ */ new Map();
2093
+ lastRateLimitReset = Date.now();
2094
+ proxyUrl;
2095
+ offlineMode = false;
2096
+ anonymousId;
2097
+ constructor(_apiKey, proxyHost, environment) {
2098
+ this.environment = environment;
2099
+ this.proxyUrl = `${proxyHost}/api/telemetry/events`;
2100
+ this.anonymousId = this.generateAnonymousId();
2101
+ setInterval(() => this.flush(), this.flushInterval);
2102
+ }
2103
+ async initialize() {
2104
+ console.warn("Feature flags not supported in proxy mode");
2105
+ }
2106
+ /**
2107
+ * Set offline mode
2108
+ * @param enabled Whether offline mode is enabled
2109
+ */
2110
+ setOfflineMode(enabled) {
2111
+ this.offlineMode = enabled;
2112
+ }
2113
+ /**
2114
+ * Check if offline mode is enabled
2115
+ * @returns Whether offline mode is enabled
2116
+ */
2117
+ isOfflineMode() {
2118
+ return this.offlineMode;
2119
+ }
2120
+ isEnabled(flag) {
2121
+ const value = this.flags.get(flag) ?? FEATURE_FLAGS[flag];
2122
+ return Boolean(value);
2123
+ }
2124
+ async reloadFlags() {
2125
+ console.warn("Feature flags not supported in proxy mode");
2126
+ }
2127
+ /**
2128
+ * Track a telemetry event with strict typing and validation
2129
+ * @param event The event name (must be from the whitelist)
2130
+ * @param properties The event properties (validated at runtime)
2131
+ */
2132
+ trackEvent(event) {
2133
+ if (!validateTelemetryEvent(event)) {
2134
+ console.warn("Invalid telemetry event, skipping:", event);
2135
+ return;
2136
+ }
2137
+ if (this.offlineMode) {
2138
+ return;
2139
+ }
2140
+ const featureManager = FeatureManager.getInstance();
2141
+ if (!featureManager.isEnabled("telemetry.detailed_events")) {
2142
+ if (![
2143
+ "checkpoint.created",
2144
+ "risk.high",
2145
+ "error"
2146
+ ].includes(event.event)) {
2147
+ return;
2148
+ }
2149
+ }
2150
+ const samplingRate = featureManager.getValue("telemetry.sampling_rate") ?? 1;
2151
+ if (Math.random() > samplingRate) {
2152
+ return;
2153
+ }
2154
+ if (this.isRateLimited(event.event)) {
2155
+ return;
2156
+ }
2157
+ this.eventQueue.push({
2158
+ event: event.event,
2159
+ properties: {
2160
+ ...this.sanitizeProperties(event.properties || {}),
2161
+ environment: this.environment,
2162
+ timestamp: event.timestamp
2163
+ },
2164
+ timestamp: event.timestamp
2165
+ });
2166
+ if (this.eventQueue.length >= this.maxQueueSize) {
2167
+ this.flush();
2168
+ }
2169
+ }
2170
+ /**
2171
+ * Track a telemetry event with string-based event name (legacy compatibility)
2172
+ * @param event The event name
2173
+ * @param properties The event properties
2174
+ */
2175
+ track(event, properties) {
2176
+ const typedEvent = {
2177
+ event,
2178
+ properties,
2179
+ timestamp: Date.now()
2180
+ };
2181
+ this.trackEvent(typedEvent);
2182
+ }
2183
+ isRateLimited(event) {
2184
+ const now = Date.now();
2185
+ if (now - this.lastRateLimitReset > this.rateLimitWindow) {
2186
+ this.eventCounts.clear();
2187
+ this.lastRateLimitReset = now;
2188
+ }
2189
+ const count = this.eventCounts.get(event) || 0;
2190
+ const maxEventsPerWindow = 10;
2191
+ if (count >= maxEventsPerWindow) {
2192
+ return true;
2193
+ }
2194
+ this.eventCounts.set(event, count + 1);
2195
+ return false;
2196
+ }
2197
+ /**
2198
+ * Sanitize properties to remove PII before sending
2199
+ */
2200
+ sanitizeProperties(properties) {
2201
+ const sanitized = {};
2202
+ if (!properties) {
2203
+ return sanitized;
2204
+ }
2205
+ const allowedProps = [
2206
+ "version",
2207
+ "platform",
2208
+ "duration",
2209
+ "success",
2210
+ "filesCount",
2211
+ "method",
2212
+ "trigger",
2213
+ "feature",
2214
+ "viewId",
2215
+ "command"
2216
+ ];
2217
+ for (const key of allowedProps) {
2218
+ if (key in properties) {
2219
+ sanitized[key] = properties[key];
2220
+ }
2221
+ }
2222
+ return sanitized;
2223
+ }
2224
+ /**
2225
+ * Get the anonymous ID for this client instance
2226
+ * @returns The stored anonymous ID
2227
+ */
2228
+ getAnonymousId() {
2229
+ return this.anonymousId;
2230
+ }
2231
+ generateAnonymousId() {
2232
+ return `${this.environment}_${Math.random().toString(36).substr(2, 9)}`;
2233
+ }
2234
+ /**
2235
+ * Get current package version
2236
+ * @returns The current version string
2237
+ */
2238
+ getVersion() {
2239
+ try {
2240
+ const packageJson = require_package();
2241
+ return packageJson.version || "unknown";
2242
+ } catch (_error) {
2243
+ return process.env.SNAPBACK_VERSION || "1.0.0";
2244
+ }
2245
+ }
2246
+ /**
2247
+ * Custom transport layer - routes all events through proxy
2248
+ */
2249
+ async customTransport(batch) {
2250
+ if (this.offlineMode) {
2251
+ return;
2252
+ }
2253
+ try {
2254
+ const response = await fetch(this.proxyUrl, {
2255
+ method: "POST",
2256
+ headers: {
2257
+ "Content-Type": "application/json",
2258
+ "X-SnapBack-Platform": this.environment,
2259
+ "X-SnapBack-Version": this.getVersion()
2260
+ },
2261
+ body: JSON.stringify({
2262
+ events: batch.map((event) => ({
2263
+ event: event.event,
2264
+ properties: this.sanitizeProperties(event.properties || {}),
2265
+ timestamp: event.timestamp
2266
+ }))
2267
+ })
2268
+ });
2269
+ if (!response.ok) {
2270
+ const error = await response.text();
2271
+ console.warn("Telemetry proxy rejected events", {
2272
+ status: response.status,
2273
+ error
2274
+ });
2275
+ }
2276
+ } catch (error) {
2277
+ console.error("Failed to send telemetry through proxy", error);
2278
+ }
2279
+ }
2280
+ async flush() {
2281
+ if (this.offlineMode) {
2282
+ return;
2283
+ }
2284
+ if (this.eventQueue.length === 0) {
2285
+ return;
2286
+ }
2287
+ const eventsToFlush = [
2288
+ ...this.eventQueue
2289
+ ];
2290
+ this.eventQueue = [];
2291
+ try {
2292
+ await this.customTransport(eventsToFlush);
2293
+ } catch (error) {
2294
+ console.warn("Failed to send telemetry events:", error);
2295
+ this.eventQueue.unshift(...eventsToFlush);
2296
+ }
2297
+ }
2298
+ };
2299
+
2300
+ export { AnalyticsEvents, CORRELATION_ANALYSES, CORRELATION_COHORTS, KEY_METRIC_ALERTS, OTelInstrumentationProvider, RETENTION_COHORTS, TelemetryClient, addSentryBreadcrumb, captureError, captureMessage, checkDatabaseConnection, checkErrorBudget, checkHttpService, checkRedisConnection, clearSentryUser, createAlert, createCohort, createGracefulShutdown, createHealthCheck, createSentryMiddleware, deleteAlert, deleteCohort, detectSurface, drainAndCloseServer, flushSentry, getAlerts, getAnalyticsEnv, getAnalyticsSuperProperties, getCohort, getCohortMembers, getCohorts, getCorrelationAnalysis, getDeploymentEnv, getEnvironmentInfo, getErrorRate, getMetrics2 as getMetrics, initSentry, isDevelopment, isProduction, neon_exports, performCorrelationAnalysis, preStopDelay, prometheus_exports, recordError, recordSuccess, registerKeyMetricAlerts, resetMetrics, setSentryUser, startSentryTransaction, toggleAlert, updateCohort };