@snapback/cli 1.1.12 → 1.1.15

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 (59) hide show
  1. package/README.md +79 -18
  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-HFJRXXG2.js +1446 -0
  7. package/dist/auto-provision-organization-SF6XM7X4.js +161 -0
  8. package/dist/chunk-23G5VYA3.js +4259 -0
  9. package/dist/{chunk-QAKFE3NE.js → chunk-4YTE4JEW.js} +3 -4
  10. package/dist/chunk-5EOPYJ4Y.js +12 -0
  11. package/dist/{chunk-G7QXHNGB.js → chunk-5SQA44V7.js} +1125 -32
  12. package/dist/{chunk-BW7RALUZ.js → chunk-7ADPL4Q3.js} +11 -4
  13. package/dist/chunk-CBGOC6RV.js +293 -0
  14. package/dist/chunk-DNEADD2G.js +3499 -0
  15. package/dist/{chunk-NKBZIXCN.js → chunk-DPWFZNMY.js} +122 -15
  16. package/dist/chunk-GQ73B37K.js +314 -0
  17. package/dist/chunk-HR34NJP7.js +6133 -0
  18. package/dist/chunk-ICKSHS3A.js +2264 -0
  19. package/dist/{chunk-KPETDXQO.js → chunk-OI2HNNT6.js} +565 -50
  20. package/dist/chunk-PL4HF4M2.js +593 -0
  21. package/dist/chunk-WS36HDEU.js +3735 -0
  22. package/dist/chunk-XYU5FFE3.js +111 -0
  23. package/dist/chunk-ZBQDE6WJ.js +108 -0
  24. package/dist/client-WIO6W447.js +8 -0
  25. package/dist/dist-E7E2T3DQ.js +9 -0
  26. package/dist/dist-TEWNOZYS.js +5 -0
  27. package/dist/dist-YZBJAYEJ.js +12 -0
  28. package/dist/index.js +65215 -26627
  29. package/dist/local-service-adapter-3JHN6G4O.js +6 -0
  30. package/dist/pioneer-oauth-hook-V2JKEXM7.js +12 -0
  31. package/dist/{secure-credentials-6UMEU22H.js → secure-credentials-UEPG7GWW.js} +15 -8
  32. package/dist/snapback-dir-MG7DTRMF.js +6 -0
  33. package/package.json +8 -42
  34. package/scripts/postinstall.mjs +2 -3
  35. package/dist/SkippedTestDetector-B3JZUE5G.js +0 -5
  36. package/dist/SkippedTestDetector-B3JZUE5G.js.map +0 -1
  37. package/dist/analysis-Z53F5FT2.js +0 -6
  38. package/dist/analysis-Z53F5FT2.js.map +0 -1
  39. package/dist/chunk-6MR2TINI.js +0 -27
  40. package/dist/chunk-6MR2TINI.js.map +0 -1
  41. package/dist/chunk-BW7RALUZ.js.map +0 -1
  42. package/dist/chunk-G7QXHNGB.js.map +0 -1
  43. package/dist/chunk-ISVRGBWT.js +0 -16223
  44. package/dist/chunk-ISVRGBWT.js.map +0 -1
  45. package/dist/chunk-KPETDXQO.js.map +0 -1
  46. package/dist/chunk-NKBZIXCN.js.map +0 -1
  47. package/dist/chunk-QAKFE3NE.js.map +0 -1
  48. package/dist/chunk-YOVA65PS.js +0 -12745
  49. package/dist/chunk-YOVA65PS.js.map +0 -1
  50. package/dist/dist-7UKXVKH3.js +0 -5
  51. package/dist/dist-7UKXVKH3.js.map +0 -1
  52. package/dist/dist-VDK7WEF4.js +0 -5
  53. package/dist/dist-VDK7WEF4.js.map +0 -1
  54. package/dist/dist-WKLJSPJT.js +0 -8
  55. package/dist/dist-WKLJSPJT.js.map +0 -1
  56. package/dist/index.js.map +0 -1
  57. package/dist/secure-credentials-6UMEU22H.js.map +0 -1
  58. package/dist/snapback-dir-T3CRQRY6.js +0 -6
  59. package/dist/snapback-dir-T3CRQRY6.js.map +0 -1
@@ -0,0 +1,2264 @@
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, 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
+ var KEY_METRIC_ALERTS = [
905
+ {
906
+ name: "TTFV p75 Alert",
907
+ insightId: "ttfv_insight",
908
+ series: "ttfv_p75",
909
+ type: "value",
910
+ threshold: 7,
911
+ thresholdType: "absolute",
912
+ frequency: "daily",
913
+ recipients: [
914
+ "engineering-team@snapback.ai"
915
+ ]
916
+ },
917
+ {
918
+ name: "Onboarding Completion Rate Alert",
919
+ insightId: "onboarding_insight",
920
+ series: "completion_rate",
921
+ type: "value",
922
+ threshold: 60,
923
+ thresholdType: "absolute",
924
+ frequency: "daily",
925
+ recipients: [
926
+ "product-team@snapback.ai"
927
+ ]
928
+ },
929
+ {
930
+ name: "Crash-free Sessions Alert",
931
+ insightId: "crash_insight",
932
+ series: "crash_free_rate",
933
+ type: "value",
934
+ threshold: 95,
935
+ thresholdType: "absolute",
936
+ frequency: "daily",
937
+ recipients: [
938
+ "engineering-team@snapback.ai"
939
+ ]
940
+ },
941
+ {
942
+ name: "Replay Budget Alert",
943
+ insightId: "replay_insight",
944
+ series: "replay_budget",
945
+ type: "value",
946
+ threshold: 80,
947
+ thresholdType: "percentage",
948
+ frequency: "weekly",
949
+ recipients: [
950
+ "analytics-team@snapback.ai"
951
+ ]
952
+ },
953
+ {
954
+ name: "D7 Retention Alert",
955
+ insightId: "retention_insight",
956
+ series: "d7_retention",
957
+ type: "decrease",
958
+ threshold: 5,
959
+ thresholdType: "percentage",
960
+ frequency: "weekly",
961
+ recipients: [
962
+ "growth-team@snapback.ai"
963
+ ]
964
+ }
965
+ ];
966
+ var posthogClient = null;
967
+ var posthogApiKey = null;
968
+ var posthogHost = null;
969
+ function getPostHog() {
970
+ if (!posthogClient) {
971
+ const posthogKey = process.env.POSTHOG_PERSONAL_API_KEY;
972
+ if (!posthogKey) {
973
+ throw new Error("PostHog personal API key not configured");
974
+ }
975
+ const host = process.env.POSTHOG_HOST || "https://app.posthog.com";
976
+ posthogClient = new PostHog(posthogKey, {
977
+ host
978
+ });
979
+ posthogApiKey = posthogKey;
980
+ posthogHost = host;
981
+ }
982
+ return posthogClient;
983
+ }
984
+ __name(getPostHog, "getPostHog");
985
+ function getPostHogConfig() {
986
+ if (!posthogApiKey || !posthogHost) {
987
+ getPostHog();
988
+ }
989
+ if (!posthogApiKey || !posthogHost) {
990
+ throw new Error("PostHog configuration not initialized");
991
+ }
992
+ return {
993
+ apiKey: posthogApiKey,
994
+ host: posthogHost
995
+ };
996
+ }
997
+ __name(getPostHogConfig, "getPostHogConfig");
998
+ async function createCohort(config) {
999
+ try {
1000
+ getPostHog();
1001
+ const phConfig = getPostHogConfig();
1002
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/`, {
1003
+ method: "POST",
1004
+ headers: {
1005
+ Authorization: `Bearer ${phConfig.apiKey}`,
1006
+ "Content-Type": "application/json"
1007
+ },
1008
+ body: JSON.stringify({
1009
+ name: config.name,
1010
+ description: config.description,
1011
+ filters: config.filters,
1012
+ is_static: config.is_static
1013
+ })
1014
+ });
1015
+ if (!response.ok) {
1016
+ throw new Error(`Failed to create cohort: ${response.statusText}`);
1017
+ }
1018
+ const cohort = await response.json();
1019
+ logger.info({
1020
+ cohort
1021
+ }, "Created PostHog cohort");
1022
+ return cohort;
1023
+ } catch (error) {
1024
+ logger.error({
1025
+ error,
1026
+ config
1027
+ }, "Failed to create PostHog cohort");
1028
+ throw new Error(`Failed to create PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1029
+ }
1030
+ }
1031
+ __name(createCohort, "createCohort");
1032
+ async function getCohorts() {
1033
+ try {
1034
+ getPostHog();
1035
+ const phConfig = getPostHogConfig();
1036
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/`, {
1037
+ method: "GET",
1038
+ headers: {
1039
+ Authorization: `Bearer ${phConfig.apiKey}`,
1040
+ "Content-Type": "application/json"
1041
+ }
1042
+ });
1043
+ if (!response.ok) {
1044
+ throw new Error(`Failed to fetch cohorts: ${response.statusText}`);
1045
+ }
1046
+ const data = await response.json();
1047
+ return data.results || [];
1048
+ } catch (error) {
1049
+ logger.error({
1050
+ error
1051
+ }, "Failed to fetch PostHog cohorts");
1052
+ throw new Error(`Failed to fetch PostHog cohorts: ${error instanceof Error ? error.message : "Unknown error"}`);
1053
+ }
1054
+ }
1055
+ __name(getCohorts, "getCohorts");
1056
+ async function getCohort(cohortId) {
1057
+ try {
1058
+ getPostHog();
1059
+ const phConfig = getPostHogConfig();
1060
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/`, {
1061
+ method: "GET",
1062
+ headers: {
1063
+ Authorization: `Bearer ${phConfig.apiKey}`,
1064
+ "Content-Type": "application/json"
1065
+ }
1066
+ });
1067
+ if (!response.ok) {
1068
+ throw new Error(`Failed to fetch cohort: ${response.statusText}`);
1069
+ }
1070
+ const cohort = await response.json();
1071
+ return cohort;
1072
+ } catch (error) {
1073
+ logger.error({
1074
+ error,
1075
+ cohortId
1076
+ }, "Failed to fetch PostHog cohort");
1077
+ throw new Error(`Failed to fetch PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1078
+ }
1079
+ }
1080
+ __name(getCohort, "getCohort");
1081
+ async function updateCohort(cohortId, config) {
1082
+ try {
1083
+ getPostHog();
1084
+ const phConfig = getPostHogConfig();
1085
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/`, {
1086
+ method: "PATCH",
1087
+ headers: {
1088
+ Authorization: `Bearer ${phConfig.apiKey}`,
1089
+ "Content-Type": "application/json"
1090
+ },
1091
+ body: JSON.stringify(config)
1092
+ });
1093
+ if (!response.ok) {
1094
+ throw new Error(`Failed to update cohort: ${response.statusText}`);
1095
+ }
1096
+ const cohort = await response.json();
1097
+ logger.info({
1098
+ cohort
1099
+ }, "Updated PostHog cohort");
1100
+ return cohort;
1101
+ } catch (error) {
1102
+ logger.error({
1103
+ error,
1104
+ cohortId,
1105
+ config
1106
+ }, "Failed to update PostHog cohort");
1107
+ throw new Error(`Failed to update PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1108
+ }
1109
+ }
1110
+ __name(updateCohort, "updateCohort");
1111
+ async function deleteCohort(cohortId) {
1112
+ try {
1113
+ getPostHog();
1114
+ const phConfig = getPostHogConfig();
1115
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/`, {
1116
+ method: "DELETE",
1117
+ headers: {
1118
+ Authorization: `Bearer ${phConfig.apiKey}`,
1119
+ "Content-Type": "application/json"
1120
+ }
1121
+ });
1122
+ if (!response.ok) {
1123
+ throw new Error(`Failed to delete cohort: ${response.statusText}`);
1124
+ }
1125
+ logger.info({
1126
+ cohortId
1127
+ }, "Deleted PostHog cohort");
1128
+ } catch (error) {
1129
+ logger.error({
1130
+ error,
1131
+ cohortId
1132
+ }, "Failed to delete PostHog cohort");
1133
+ throw new Error(`Failed to delete PostHog cohort: ${error instanceof Error ? error.message : "Unknown error"}`);
1134
+ }
1135
+ }
1136
+ __name(deleteCohort, "deleteCohort");
1137
+ async function getCohortMembers(cohortId) {
1138
+ try {
1139
+ getPostHog();
1140
+ const phConfig = getPostHogConfig();
1141
+ const response = await fetch(`${phConfig.host}/api/projects/@current/cohorts/${cohortId}/persons/`, {
1142
+ method: "GET",
1143
+ headers: {
1144
+ Authorization: `Bearer ${phConfig.apiKey}`,
1145
+ "Content-Type": "application/json"
1146
+ }
1147
+ });
1148
+ if (!response.ok) {
1149
+ throw new Error(`Failed to fetch cohort members: ${response.statusText}`);
1150
+ }
1151
+ const data = await response.json();
1152
+ return data.results || [];
1153
+ } catch (error) {
1154
+ logger.error({
1155
+ error,
1156
+ cohortId
1157
+ }, "Failed to fetch PostHog cohort members");
1158
+ throw new Error(`Failed to fetch PostHog cohort members: ${error instanceof Error ? error.message : "Unknown error"}`);
1159
+ }
1160
+ }
1161
+ __name(getCohortMembers, "getCohortMembers");
1162
+ var RETENTION_COHORTS = [
1163
+ {
1164
+ name: "D7 Retention",
1165
+ description: "Users who return within 7 days of their first activity",
1166
+ filters: {
1167
+ properties: [
1168
+ {
1169
+ key: "first_seen",
1170
+ value: "7 days",
1171
+ operator: "within",
1172
+ type: "event"
1173
+ }
1174
+ ]
1175
+ }
1176
+ },
1177
+ {
1178
+ name: "D30 Retention",
1179
+ description: "Users who return within 30 days of their first activity",
1180
+ filters: {
1181
+ properties: [
1182
+ {
1183
+ key: "first_seen",
1184
+ value: "30 days",
1185
+ operator: "within",
1186
+ type: "event"
1187
+ }
1188
+ ]
1189
+ }
1190
+ },
1191
+ {
1192
+ name: "Onboarding Completion Cohort",
1193
+ description: "Users who completed the onboarding process",
1194
+ filters: {
1195
+ properties: [
1196
+ {
1197
+ key: "onboarding_completed",
1198
+ value: true,
1199
+ operator: "exact",
1200
+ type: "event"
1201
+ }
1202
+ ]
1203
+ }
1204
+ },
1205
+ {
1206
+ name: "High Engagement Users",
1207
+ description: "Users with high engagement (5+ sessions in 7 days)",
1208
+ filters: {
1209
+ properties: [
1210
+ {
1211
+ key: "session_count",
1212
+ value: 5,
1213
+ operator: "gt",
1214
+ type: "event"
1215
+ },
1216
+ {
1217
+ key: "activity_period",
1218
+ value: "7 days",
1219
+ operator: "within",
1220
+ type: "event"
1221
+ }
1222
+ ]
1223
+ }
1224
+ }
1225
+ ];
1226
+ var CORRELATION_COHORTS = [
1227
+ {
1228
+ name: "Feature Power Users",
1229
+ description: "Users who use advanced features regularly",
1230
+ filters: {
1231
+ properties: [
1232
+ {
1233
+ key: "advanced_feature_usage",
1234
+ value: true,
1235
+ operator: "exact",
1236
+ type: "event"
1237
+ }
1238
+ ]
1239
+ }
1240
+ },
1241
+ {
1242
+ name: "At-Risk Churn",
1243
+ description: "Users showing signs of disengagement",
1244
+ filters: {
1245
+ properties: [
1246
+ {
1247
+ key: "days_since_last_activity",
1248
+ value: 14,
1249
+ operator: "gt",
1250
+ type: "event"
1251
+ }
1252
+ ]
1253
+ }
1254
+ },
1255
+ {
1256
+ name: "Free to Paid Converters",
1257
+ description: "Users who upgraded from free to paid plan",
1258
+ filters: {
1259
+ properties: [
1260
+ {
1261
+ key: "plan_upgrade",
1262
+ value: "free_to_paid",
1263
+ operator: "exact",
1264
+ type: "event"
1265
+ }
1266
+ ]
1267
+ }
1268
+ }
1269
+ ];
1270
+ var posthogClient2 = null;
1271
+ function getPostHog2() {
1272
+ if (!posthogClient2) {
1273
+ const posthogKey = process.env.POSTHOG_PERSONAL_API_KEY;
1274
+ if (!posthogKey) {
1275
+ throw new Error("PostHog personal API key not configured");
1276
+ }
1277
+ const posthogHost2 = process.env.POSTHOG_HOST || "https://app.posthog.com";
1278
+ posthogClient2 = new PostHog(posthogKey, {
1279
+ host: posthogHost2
1280
+ });
1281
+ }
1282
+ return posthogClient2;
1283
+ }
1284
+ __name(getPostHog2, "getPostHog");
1285
+ async function performCorrelationAnalysis(config) {
1286
+ try {
1287
+ const _posthog = getPostHog2();
1288
+ logger.info({
1289
+ config
1290
+ }, "Performing correlation analysis");
1291
+ const results = config.propertyNames.map((property, _index) => ({
1292
+ property,
1293
+ correlation: Math.random() * 2 - 1,
1294
+ count: Math.floor(Math.random() * 1e3) + 100,
1295
+ relativeFrequency: Math.random()
1296
+ }));
1297
+ results.sort((a, b) => Math.abs(b.correlation) - Math.abs(a.correlation));
1298
+ const analysis = {
1299
+ id: `correlation_${Date.now()}`,
1300
+ name: config.name,
1301
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1302
+ results: results.slice(0, 10)
1303
+ };
1304
+ logger.info({
1305
+ analysis
1306
+ }, "Correlation analysis completed");
1307
+ return analysis;
1308
+ } catch (error) {
1309
+ logger.error({
1310
+ error,
1311
+ config
1312
+ }, "Failed to perform correlation analysis");
1313
+ throw new Error(`Failed to perform correlation analysis: ${error instanceof Error ? error.message : "Unknown error"}`);
1314
+ }
1315
+ }
1316
+ __name(performCorrelationAnalysis, "performCorrelationAnalysis");
1317
+ async function getCorrelationAnalysis(analysisId) {
1318
+ try {
1319
+ throw new Error("Correlation analysis persistence not implemented");
1320
+ } catch (error) {
1321
+ logger.error({
1322
+ error,
1323
+ analysisId
1324
+ }, "Failed to fetch correlation analysis");
1325
+ throw new Error(`Failed to fetch correlation analysis: ${error instanceof Error ? error.message : "Unknown error"}`);
1326
+ }
1327
+ }
1328
+ __name(getCorrelationAnalysis, "getCorrelationAnalysis");
1329
+ var CORRELATION_ANALYSES = [
1330
+ {
1331
+ name: "Onboarding Completion Factors",
1332
+ eventName: "onboarding_completed",
1333
+ propertyNames: [
1334
+ "signup_source",
1335
+ "device_type",
1336
+ "browser",
1337
+ "utm_campaign",
1338
+ "time_to_complete",
1339
+ "steps_completed",
1340
+ "help_articles_viewed"
1341
+ ]
1342
+ },
1343
+ {
1344
+ name: "Feature Adoption Correlations",
1345
+ eventName: "feature_used",
1346
+ propertyNames: [
1347
+ "user_plan",
1348
+ "account_age_days",
1349
+ "session_frequency",
1350
+ "support_tickets",
1351
+ "documentation_views",
1352
+ "community_posts"
1353
+ ]
1354
+ },
1355
+ {
1356
+ name: "Churn Risk Indicators",
1357
+ eventName: "account_deactivated",
1358
+ propertyNames: [
1359
+ "days_since_last_activity",
1360
+ "feature_usage_count",
1361
+ "support_ticket_count",
1362
+ "billing_issues",
1363
+ "plan_downgrade",
1364
+ "session_duration_avg"
1365
+ ]
1366
+ },
1367
+ {
1368
+ name: "High Value User Characteristics",
1369
+ eventName: "plan_upgraded",
1370
+ propertyNames: [
1371
+ "initial_plan",
1372
+ "signup_source",
1373
+ "feature_discovery_rate",
1374
+ "engagement_score",
1375
+ "referral_count",
1376
+ "content_creation"
1377
+ ]
1378
+ }
1379
+ ];
1380
+
1381
+ // ../../packages/infrastructure/dist/prometheus/index.js
1382
+ var prometheus_exports = {};
1383
+ __export(prometheus_exports, {
1384
+ client: () => client,
1385
+ dbConnections: () => dbConnections,
1386
+ dbQueryDurationSeconds: () => dbQueryDurationSeconds,
1387
+ getContentType: () => getContentType,
1388
+ getMetrics: () => getMetrics,
1389
+ healthCheckDurationSeconds: () => healthCheckDurationSeconds,
1390
+ healthCheckFailuresTotal: () => healthCheckFailuresTotal,
1391
+ healthCheckLastSuccessTimestamp: () => healthCheckLastSuccessTimestamp,
1392
+ healthCheckStatus: () => healthCheckStatus,
1393
+ httpRequestDurationSeconds: () => httpRequestDurationSeconds,
1394
+ httpRequestsTotal: () => httpRequestsTotal,
1395
+ mcpActiveSessions: () => mcpActiveSessions,
1396
+ mcpProxyErrorsTotal: () => mcpProxyErrorsTotal,
1397
+ readinessProbeLastSuccessTimestamp: () => readinessProbeLastSuccessTimestamp,
1398
+ readinessProbeStatus: () => readinessProbeStatus,
1399
+ recordHealthCheck: () => recordHealthCheck,
1400
+ recordReadinessProbe: () => recordReadinessProbe,
1401
+ recordStartupComplete: () => recordStartupComplete,
1402
+ registry: () => registry,
1403
+ sseConnectionsTotal: () => sseConnectionsTotal,
1404
+ startupProbeDurationSeconds: () => startupProbeDurationSeconds,
1405
+ startupProbeFailuresTotal: () => startupProbeFailuresTotal
1406
+ });
1407
+ var registry = new client.Registry();
1408
+ var defaultMetrics = client.collectDefaultMetrics;
1409
+ defaultMetrics({
1410
+ register: registry
1411
+ });
1412
+ var healthCheckStatus = new client.Gauge({
1413
+ name: "health_check_status",
1414
+ help: "Current health check status (1=healthy, 0=unhealthy)",
1415
+ labelNames: [
1416
+ "service",
1417
+ "check"
1418
+ ],
1419
+ registers: [
1420
+ registry
1421
+ ]
1422
+ });
1423
+ var healthCheckFailuresTotal = new client.Counter({
1424
+ name: "health_check_failures_total",
1425
+ help: "Total number of health check failures",
1426
+ labelNames: [
1427
+ "service",
1428
+ "check",
1429
+ "reason"
1430
+ ],
1431
+ registers: [
1432
+ registry
1433
+ ]
1434
+ });
1435
+ var healthCheckDurationSeconds = new client.Histogram({
1436
+ name: "health_check_duration_seconds",
1437
+ help: "Duration of health check execution in seconds",
1438
+ labelNames: [
1439
+ "service",
1440
+ "check"
1441
+ ],
1442
+ buckets: [
1443
+ 1e-3,
1444
+ 5e-3,
1445
+ 0.01,
1446
+ 0.025,
1447
+ 0.05,
1448
+ 0.1,
1449
+ 0.25,
1450
+ 0.5,
1451
+ 1,
1452
+ 2.5,
1453
+ 5,
1454
+ 10
1455
+ ],
1456
+ registers: [
1457
+ registry
1458
+ ]
1459
+ });
1460
+ var healthCheckLastSuccessTimestamp = new client.Gauge({
1461
+ name: "health_check_last_success_timestamp_seconds",
1462
+ help: "Unix timestamp of the last successful health check",
1463
+ labelNames: [
1464
+ "service",
1465
+ "check"
1466
+ ],
1467
+ registers: [
1468
+ registry
1469
+ ]
1470
+ });
1471
+ var startupProbeFailuresTotal = new client.Counter({
1472
+ name: "startup_probe_failures_total",
1473
+ help: "Total number of startup probe failures",
1474
+ labelNames: [
1475
+ "service"
1476
+ ],
1477
+ registers: [
1478
+ registry
1479
+ ]
1480
+ });
1481
+ var startupProbeDurationSeconds = new client.Gauge({
1482
+ name: "startup_probe_duration_seconds",
1483
+ help: "Time taken for service startup in seconds",
1484
+ labelNames: [
1485
+ "service"
1486
+ ],
1487
+ registers: [
1488
+ registry
1489
+ ]
1490
+ });
1491
+ var readinessProbeStatus = new client.Gauge({
1492
+ name: "readiness_probe_status",
1493
+ help: "Current readiness probe status (1=ready, 0=not_ready)",
1494
+ labelNames: [
1495
+ "service"
1496
+ ],
1497
+ registers: [
1498
+ registry
1499
+ ]
1500
+ });
1501
+ var readinessProbeLastSuccessTimestamp = new client.Gauge({
1502
+ name: "readiness_probe_last_success_timestamp_seconds",
1503
+ help: "Unix timestamp of the last successful readiness probe",
1504
+ labelNames: [
1505
+ "service"
1506
+ ],
1507
+ registers: [
1508
+ registry
1509
+ ]
1510
+ });
1511
+ var httpRequestDurationSeconds = new client.Histogram({
1512
+ name: "http_request_duration_seconds",
1513
+ help: "Duration of HTTP requests in seconds",
1514
+ labelNames: [
1515
+ "method",
1516
+ "path",
1517
+ "status"
1518
+ ],
1519
+ buckets: [
1520
+ 1e-3,
1521
+ 5e-3,
1522
+ 0.01,
1523
+ 0.025,
1524
+ 0.05,
1525
+ 0.1,
1526
+ 0.25,
1527
+ 0.5,
1528
+ 1,
1529
+ 2.5,
1530
+ 5
1531
+ ],
1532
+ registers: [
1533
+ registry
1534
+ ]
1535
+ });
1536
+ var httpRequestsTotal = new client.Counter({
1537
+ name: "http_requests_total",
1538
+ help: "Total number of HTTP requests",
1539
+ labelNames: [
1540
+ "method",
1541
+ "path",
1542
+ "status"
1543
+ ],
1544
+ registers: [
1545
+ registry
1546
+ ]
1547
+ });
1548
+ var dbConnections = new client.Gauge({
1549
+ name: "db_connections",
1550
+ help: "Current number of database connections",
1551
+ labelNames: [
1552
+ "pool",
1553
+ "state"
1554
+ ],
1555
+ registers: [
1556
+ registry
1557
+ ]
1558
+ });
1559
+ var dbQueryDurationSeconds = new client.Histogram({
1560
+ name: "db_query_duration_seconds",
1561
+ help: "Duration of database queries in seconds",
1562
+ labelNames: [
1563
+ "operation",
1564
+ "table"
1565
+ ],
1566
+ buckets: [
1567
+ 1e-3,
1568
+ 5e-3,
1569
+ 0.01,
1570
+ 0.025,
1571
+ 0.05,
1572
+ 0.1,
1573
+ 0.25,
1574
+ 0.5,
1575
+ 1
1576
+ ],
1577
+ registers: [
1578
+ registry
1579
+ ]
1580
+ });
1581
+ var mcpActiveSessions = new client.Gauge({
1582
+ name: "mcp_active_sessions",
1583
+ help: "Current number of active MCP sessions",
1584
+ registers: [
1585
+ registry
1586
+ ]
1587
+ });
1588
+ var mcpProxyErrorsTotal = new client.Counter({
1589
+ name: "mcp_proxy_errors_total",
1590
+ help: "Total number of MCP proxy errors",
1591
+ labelNames: [
1592
+ "endpoint",
1593
+ "error_type"
1594
+ ],
1595
+ registers: [
1596
+ registry
1597
+ ]
1598
+ });
1599
+ var sseConnectionsTotal = new client.Gauge({
1600
+ name: "sse_connections_total",
1601
+ help: "Current number of SSE connections",
1602
+ labelNames: [
1603
+ "service"
1604
+ ],
1605
+ registers: [
1606
+ registry
1607
+ ]
1608
+ });
1609
+ function recordHealthCheck(service, check, status, durationMs) {
1610
+ const isHealthy = status === "healthy" ? 1 : 0;
1611
+ healthCheckStatus.set({
1612
+ service,
1613
+ check
1614
+ }, isHealthy);
1615
+ healthCheckDurationSeconds.observe({
1616
+ service,
1617
+ check
1618
+ }, durationMs / 1e3);
1619
+ if (status === "healthy") {
1620
+ healthCheckLastSuccessTimestamp.set({
1621
+ service,
1622
+ check
1623
+ }, Date.now() / 1e3);
1624
+ }
1625
+ if (status === "unhealthy") {
1626
+ healthCheckFailuresTotal.inc({
1627
+ service,
1628
+ check,
1629
+ reason: "check_failed"
1630
+ });
1631
+ }
1632
+ }
1633
+ __name(recordHealthCheck, "recordHealthCheck");
1634
+ function recordReadinessProbe(service, isReady) {
1635
+ readinessProbeStatus.set({
1636
+ service
1637
+ }, isReady ? 1 : 0);
1638
+ if (isReady) {
1639
+ readinessProbeLastSuccessTimestamp.set({
1640
+ service
1641
+ }, Date.now() / 1e3);
1642
+ }
1643
+ }
1644
+ __name(recordReadinessProbe, "recordReadinessProbe");
1645
+ function recordStartupComplete(service, durationSeconds) {
1646
+ startupProbeDurationSeconds.set({
1647
+ service
1648
+ }, durationSeconds);
1649
+ }
1650
+ __name(recordStartupComplete, "recordStartupComplete");
1651
+ async function getMetrics() {
1652
+ return registry.metrics();
1653
+ }
1654
+ __name(getMetrics, "getMetrics");
1655
+ function getContentType() {
1656
+ return registry.contentType;
1657
+ }
1658
+ __name(getContentType, "getContentType");
1659
+
1660
+ // ../../packages/infrastructure/dist/sentry/index.js
1661
+ var Sentry = null;
1662
+ var ProfilingIntegration = null;
1663
+ async function loadSentry() {
1664
+ if (Sentry) {
1665
+ return {
1666
+ Sentry,
1667
+ ProfilingIntegration
1668
+ };
1669
+ }
1670
+ if (process.env.DISABLE_SENTRY === "true") {
1671
+ return null;
1672
+ }
1673
+ try {
1674
+ Sentry = await import('@sentry/node');
1675
+ ProfilingIntegration = await import('@sentry/profiling-node');
1676
+ return {
1677
+ Sentry,
1678
+ ProfilingIntegration
1679
+ };
1680
+ } catch (error) {
1681
+ console.warn("\u26A0\uFE0F Failed to load Sentry:", error instanceof Error ? error.message : String(error));
1682
+ return null;
1683
+ }
1684
+ }
1685
+ __name(loadSentry, "loadSentry");
1686
+ async function initSentry(options) {
1687
+ if (process.env.DISABLE_SENTRY === "true" || options?.enabled === false) {
1688
+ console.log("\u2139\uFE0F Sentry is disabled");
1689
+ return;
1690
+ }
1691
+ const dsn = options?.dsn || process.env.SENTRY_DSN;
1692
+ if (!dsn) {
1693
+ console.warn("\u26A0\uFE0F SENTRY_DSN not configured. Error tracking disabled.");
1694
+ return;
1695
+ }
1696
+ const modules = await loadSentry();
1697
+ if (!modules) {
1698
+ return;
1699
+ }
1700
+ const { Sentry: SentryModule, ProfilingIntegration: ProfilingIntegration2 } = modules;
1701
+ SentryModule.init({
1702
+ dsn,
1703
+ environment: options?.environment || process.env.NODE_ENV || "development",
1704
+ release: options?.release || process.env.GIT_SHA || process.env.RELEASE || void 0,
1705
+ tracesSampleRate: options?.tracesSampleRate ?? (process.env.NODE_ENV === "production" ? 0.1 : 1),
1706
+ profilesSampleRate: options?.profilesSampleRate ?? 0.1,
1707
+ debug: options?.debug || process.env.DEBUG_SENTRY === "true",
1708
+ integrations: [
1709
+ new SentryModule.HttpIntegration({
1710
+ tracing: true,
1711
+ request: true
1712
+ }),
1713
+ ...ProfilingIntegration2 ? [
1714
+ ProfilingIntegration2.nodeProfilingIntegration()
1715
+ ] : []
1716
+ ],
1717
+ // Filter out sensitive data
1718
+ beforeSend: /* @__PURE__ */ __name((event) => {
1719
+ if (event?.exception?.values?.[0]?.value?.includes?.("404") || event?.request?.url?.includes?.("/favicon.ico")) {
1720
+ return null;
1721
+ }
1722
+ if (event?.request?.headers) {
1723
+ delete event.request.headers.authorization;
1724
+ delete event.request.headers.cookie;
1725
+ }
1726
+ return event;
1727
+ }, "beforeSend")
1728
+ });
1729
+ console.log("\u2705 Sentry initialized for error tracking");
1730
+ }
1731
+ __name(initSentry, "initSentry");
1732
+ function createSentryMiddleware() {
1733
+ if (!Sentry) {
1734
+ return {
1735
+ requestHandler: /* @__PURE__ */ __name((_c, next) => next(), "requestHandler"),
1736
+ errorHandler: /* @__PURE__ */ __name((_c, next) => next(), "errorHandler")
1737
+ };
1738
+ }
1739
+ return {
1740
+ requestHandler: Sentry.Handlers?.requestHandler?.() || ((_c, next) => next()),
1741
+ errorHandler: Sentry.Handlers?.errorHandler?.() || ((_c, next) => next())
1742
+ };
1743
+ }
1744
+ __name(createSentryMiddleware, "createSentryMiddleware");
1745
+ function captureError(error, context2) {
1746
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1747
+ return;
1748
+ }
1749
+ Sentry.withScope((scope) => {
1750
+ if (context2) {
1751
+ if (context2.userId) {
1752
+ scope.setUser({
1753
+ id: context2.userId
1754
+ });
1755
+ }
1756
+ if (context2.organizationId) {
1757
+ scope.setTag("organization_id", context2.organizationId);
1758
+ }
1759
+ if (context2.tags) {
1760
+ Object.entries(context2.tags).forEach(([key, value]) => {
1761
+ scope.setTag(key, value);
1762
+ });
1763
+ }
1764
+ if (context2.extra) {
1765
+ scope.setContext("extra", context2.extra);
1766
+ }
1767
+ }
1768
+ if (Sentry) {
1769
+ Sentry.captureException(typeof error === "string" ? new Error(error) : error);
1770
+ }
1771
+ });
1772
+ }
1773
+ __name(captureError, "captureError");
1774
+ function captureMessage(message, level = "info", context2) {
1775
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1776
+ return;
1777
+ }
1778
+ Sentry.captureMessage(message, level);
1779
+ if (context2) {
1780
+ Sentry.withScope((scope) => {
1781
+ if (context2.userId) {
1782
+ scope.setUser({
1783
+ id: context2.userId
1784
+ });
1785
+ }
1786
+ if (context2.tags) {
1787
+ Object.entries(context2.tags).forEach(([key, value]) => {
1788
+ scope.setTag(key, value);
1789
+ });
1790
+ }
1791
+ if (context2.extra) {
1792
+ scope.setContext("extra", context2.extra);
1793
+ }
1794
+ });
1795
+ }
1796
+ }
1797
+ __name(captureMessage, "captureMessage");
1798
+ function setSentryUser(userId, userInfo) {
1799
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1800
+ return;
1801
+ }
1802
+ Sentry.setUser({
1803
+ id: userId,
1804
+ email: userInfo?.email,
1805
+ username: userInfo?.username,
1806
+ organization_id: userInfo?.organizationId
1807
+ });
1808
+ }
1809
+ __name(setSentryUser, "setSentryUser");
1810
+ function clearSentryUser() {
1811
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1812
+ return;
1813
+ }
1814
+ Sentry.setUser(null);
1815
+ }
1816
+ __name(clearSentryUser, "clearSentryUser");
1817
+ function addSentryBreadcrumb(message, data, level = "info") {
1818
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1819
+ return;
1820
+ }
1821
+ Sentry.addBreadcrumb({
1822
+ message,
1823
+ level,
1824
+ data,
1825
+ timestamp: Date.now() / 1e3
1826
+ });
1827
+ }
1828
+ __name(addSentryBreadcrumb, "addSentryBreadcrumb");
1829
+ function startSentryTransaction(name, op) {
1830
+ if (process.env.DISABLE_SENTRY === "true") {
1831
+ return null;
1832
+ }
1833
+ return Sentry.startTransaction?.({
1834
+ name,
1835
+ op: op || "operation"
1836
+ }) || null;
1837
+ }
1838
+ __name(startSentryTransaction, "startSentryTransaction");
1839
+ async function flushSentry(timeout = 2e3) {
1840
+ if (process.env.DISABLE_SENTRY === "true" || !Sentry) {
1841
+ return true;
1842
+ }
1843
+ return await Sentry.close(timeout);
1844
+ }
1845
+ __name(flushSentry, "flushSentry");
1846
+
1847
+ // ../../packages/infrastructure/dist/tracing/error-budget.js
1848
+ var ERROR_BUDGET = 0.01;
1849
+ var ALERT_THRESHOLD = 5e-3;
1850
+ var errorMetrics = {
1851
+ totalRequests: 0,
1852
+ errorCount: 0,
1853
+ lastAlertTime: 0
1854
+ };
1855
+ function recordSuccess() {
1856
+ errorMetrics.totalRequests++;
1857
+ }
1858
+ __name(recordSuccess, "recordSuccess");
1859
+ function recordError() {
1860
+ errorMetrics.totalRequests++;
1861
+ errorMetrics.errorCount++;
1862
+ }
1863
+ __name(recordError, "recordError");
1864
+ function getErrorRate() {
1865
+ if (errorMetrics.totalRequests === 0) {
1866
+ return 0;
1867
+ }
1868
+ return errorMetrics.errorCount / errorMetrics.totalRequests;
1869
+ }
1870
+ __name(getErrorRate, "getErrorRate");
1871
+ async function checkErrorBudget() {
1872
+ const errorRate = getErrorRate();
1873
+ if (errorRate > ALERT_THRESHOLD && Date.now() - errorMetrics.lastAlertTime > 6e4) {
1874
+ logger.warn({
1875
+ errorRate: `${(errorRate * 100).toFixed(2)}%`,
1876
+ threshold: `${(ALERT_THRESHOLD * 100).toFixed(2)}%`,
1877
+ errorCount: errorMetrics.errorCount,
1878
+ totalRequests: errorMetrics.totalRequests
1879
+ }, "Error rate approaching budget threshold");
1880
+ errorMetrics.lastAlertTime = Date.now();
1881
+ }
1882
+ if (errorRate > ERROR_BUDGET) {
1883
+ logger.error({
1884
+ errorRate: `${(errorRate * 100).toFixed(2)}%`,
1885
+ budget: `${(ERROR_BUDGET * 100).toFixed(2)}%`,
1886
+ errorCount: errorMetrics.errorCount,
1887
+ totalRequests: errorMetrics.totalRequests,
1888
+ recommendation: "Investigate root cause immediately and consider rolling back"
1889
+ }, "\u{1F6A8} Error budget exceeded!");
1890
+ await sendAlert({
1891
+ channel: "#alerts",
1892
+ message: `\u{1F6A8} Error budget exceeded! Current error rate: ${(errorRate * 100).toFixed(2)}% (Budget: ${(ERROR_BUDGET * 100).toFixed(2)}%)`
1893
+ });
1894
+ }
1895
+ }
1896
+ __name(checkErrorBudget, "checkErrorBudget");
1897
+ async function sendAlert(alert) {
1898
+ logger.info(alert, "Alert sent");
1899
+ }
1900
+ __name(sendAlert, "sendAlert");
1901
+ function resetMetrics() {
1902
+ errorMetrics.totalRequests = 0;
1903
+ errorMetrics.errorCount = 0;
1904
+ errorMetrics.lastAlertTime = 0;
1905
+ }
1906
+ __name(resetMetrics, "resetMetrics");
1907
+ function getMetrics2() {
1908
+ return {
1909
+ ...errorMetrics,
1910
+ errorRate: getErrorRate()
1911
+ };
1912
+ }
1913
+ __name(getMetrics2, "getMetrics");
1914
+ var OTelSpanAdapter = class OTelSpanAdapter2 {
1915
+ static {
1916
+ __name(this, "OTelSpanAdapter");
1917
+ }
1918
+ otelSpan;
1919
+ constructor(otelSpan) {
1920
+ this.otelSpan = otelSpan;
1921
+ }
1922
+ setAttribute(key, value) {
1923
+ this.otelSpan.setAttribute(key, value);
1924
+ }
1925
+ setAttributes(attributes) {
1926
+ this.otelSpan.setAttributes(attributes);
1927
+ }
1928
+ addEvent(name, attributes) {
1929
+ this.otelSpan.addEvent(name, attributes);
1930
+ }
1931
+ setStatus(status) {
1932
+ this.otelSpan.setStatus({
1933
+ code: status.code,
1934
+ message: status.message
1935
+ });
1936
+ }
1937
+ recordException(error) {
1938
+ this.otelSpan.recordException(error);
1939
+ }
1940
+ end() {
1941
+ this.otelSpan.end();
1942
+ }
1943
+ isRecording() {
1944
+ return this.otelSpan.isRecording();
1945
+ }
1946
+ };
1947
+ var OTelInstrumentationProvider = class {
1948
+ static {
1949
+ __name(this, "OTelInstrumentationProvider");
1950
+ }
1951
+ tracer;
1952
+ provider;
1953
+ constructor(config) {
1954
+ const resource = resourceFromAttributes({
1955
+ [ATTR_SERVICE_NAME]: config.serviceName,
1956
+ [ATTR_SERVICE_VERSION]: config.serviceVersion || "unknown",
1957
+ "deployment.environment": config.environment || "development",
1958
+ "service.instance.id": process.pid.toString(),
1959
+ "host.name": process.env.HOSTNAME || "unknown",
1960
+ "process.pid": process.pid
1961
+ });
1962
+ const spanProcessors = [];
1963
+ if (config.collectorUrl) {
1964
+ const otlpExporter = new OTLPTraceExporter({
1965
+ url: config.collectorUrl
1966
+ });
1967
+ spanProcessors.push(new BatchSpanProcessor(otlpExporter));
1968
+ }
1969
+ if (config.enableConsole) {
1970
+ const consoleExporter = new ConsoleSpanExporter();
1971
+ spanProcessors.push(new BatchSpanProcessor(consoleExporter));
1972
+ }
1973
+ const samplingRate = config.sampleRate ?? 1;
1974
+ const sampler = new TraceIdRatioBasedSampler(samplingRate);
1975
+ this.provider = new NodeTracerProvider({
1976
+ resource,
1977
+ sampler,
1978
+ spanProcessors
1979
+ });
1980
+ this.provider.register();
1981
+ const pinoInstrumentation = new PinoInstrumentation({
1982
+ // Keep default log keys: trace_id, span_id, trace_flags
1983
+ // These match standard OTel semantic conventions
1984
+ disableLogSending: true,
1985
+ disableLogCorrelation: false
1986
+ });
1987
+ const pgInstrumentation = new PgInstrumentation({
1988
+ // Add database query attributes to spans
1989
+ requireParentSpan: false,
1990
+ enhancedDatabaseReporting: true
1991
+ });
1992
+ try {
1993
+ pinoInstrumentation.enable();
1994
+ pgInstrumentation.enable();
1995
+ } catch {
1996
+ }
1997
+ this.tracer = trace.getTracer(config.serviceName, config.serviceVersion);
1998
+ }
1999
+ startSpan(name, options) {
2000
+ const otelSpan = this.tracer.startSpan(name, {
2001
+ kind: options?.kind,
2002
+ attributes: options?.attributes,
2003
+ startTime: options?.startTime
2004
+ });
2005
+ return new OTelSpanAdapter(otelSpan);
2006
+ }
2007
+ async withSpan(name, fn, options) {
2008
+ const parentCtx = options?.parent ? options.parent : context.active();
2009
+ return await this.tracer.startActiveSpan(name, {
2010
+ kind: options?.kind,
2011
+ attributes: options?.attributes,
2012
+ startTime: options?.startTime
2013
+ }, parentCtx, async (otelSpan) => {
2014
+ const span = new OTelSpanAdapter(otelSpan);
2015
+ try {
2016
+ const result = await fn(span);
2017
+ otelSpan.setStatus({
2018
+ code: SpanStatusCode.OK
2019
+ });
2020
+ return result;
2021
+ } catch (error) {
2022
+ otelSpan.recordException(error);
2023
+ otelSpan.setStatus({
2024
+ code: SpanStatusCode.ERROR,
2025
+ message: error instanceof Error ? error.message : String(error)
2026
+ });
2027
+ throw error;
2028
+ } finally {
2029
+ otelSpan.end();
2030
+ }
2031
+ });
2032
+ }
2033
+ injectContext(carrier) {
2034
+ propagation.inject(context.active(), carrier);
2035
+ }
2036
+ extractContext(carrier) {
2037
+ const extractedContext = propagation.extract(ROOT_CONTEXT, carrier);
2038
+ const span = trace.getSpan(extractedContext);
2039
+ if (span?.spanContext().traceId) {
2040
+ return extractedContext;
2041
+ }
2042
+ return null;
2043
+ }
2044
+ recordMetric(_name, _value, _attributes) {
2045
+ }
2046
+ recordEvent(_name, _attributes) {
2047
+ }
2048
+ async shutdown() {
2049
+ await this.provider.shutdown();
2050
+ }
2051
+ };
2052
+
2053
+ // ../../packages/infrastructure/dist/tracing/telemetry-client.js
2054
+ var TelemetryClient = class {
2055
+ static {
2056
+ __name(this, "TelemetryClient");
2057
+ }
2058
+ environment;
2059
+ flags = /* @__PURE__ */ new Map();
2060
+ eventQueue = [];
2061
+ flushInterval = 5e3;
2062
+ maxQueueSize = 100;
2063
+ rateLimitWindow = 6e4;
2064
+ eventCounts = /* @__PURE__ */ new Map();
2065
+ lastRateLimitReset = Date.now();
2066
+ proxyUrl;
2067
+ offlineMode = false;
2068
+ constructor(_apiKey, proxyHost, environment) {
2069
+ this.environment = environment;
2070
+ this.proxyUrl = `${proxyHost}/api/telemetry/events`;
2071
+ this.generateAnonymousId();
2072
+ setInterval(() => this.flush(), this.flushInterval);
2073
+ }
2074
+ async initialize() {
2075
+ console.warn("Feature flags not supported in proxy mode");
2076
+ }
2077
+ /**
2078
+ * Set offline mode
2079
+ * @param enabled Whether offline mode is enabled
2080
+ */
2081
+ setOfflineMode(enabled) {
2082
+ this.offlineMode = enabled;
2083
+ }
2084
+ /**
2085
+ * Check if offline mode is enabled
2086
+ * @returns Whether offline mode is enabled
2087
+ */
2088
+ isOfflineMode() {
2089
+ return this.offlineMode;
2090
+ }
2091
+ isEnabled(flag) {
2092
+ const value = this.flags.get(flag) ?? FEATURE_FLAGS[flag];
2093
+ return Boolean(value);
2094
+ }
2095
+ async reloadFlags() {
2096
+ console.warn("Feature flags not supported in proxy mode");
2097
+ }
2098
+ /**
2099
+ * Track a telemetry event with strict typing and validation
2100
+ * @param event The event name (must be from the whitelist)
2101
+ * @param properties The event properties (validated at runtime)
2102
+ */
2103
+ trackEvent(event) {
2104
+ if (!validateTelemetryEvent(event)) {
2105
+ console.warn("Invalid telemetry event, skipping:", event);
2106
+ return;
2107
+ }
2108
+ if (this.offlineMode) {
2109
+ return;
2110
+ }
2111
+ const featureManager = FeatureManager.getInstance();
2112
+ if (!featureManager.isEnabled("telemetry.detailed_events")) {
2113
+ if (![
2114
+ "checkpoint.created",
2115
+ "risk.high",
2116
+ "error"
2117
+ ].includes(event.event)) {
2118
+ return;
2119
+ }
2120
+ }
2121
+ const samplingRate = featureManager.getValue("telemetry.sampling_rate") ?? 1;
2122
+ if (Math.random() > samplingRate) {
2123
+ return;
2124
+ }
2125
+ if (this.isRateLimited(event.event)) {
2126
+ return;
2127
+ }
2128
+ this.eventQueue.push({
2129
+ event: event.event,
2130
+ properties: {
2131
+ ...this.sanitizeProperties(event.properties || {}),
2132
+ environment: this.environment,
2133
+ timestamp: event.timestamp
2134
+ },
2135
+ timestamp: event.timestamp
2136
+ });
2137
+ if (this.eventQueue.length >= this.maxQueueSize) {
2138
+ this.flush();
2139
+ }
2140
+ }
2141
+ /**
2142
+ * Track a telemetry event with string-based event name (legacy compatibility)
2143
+ * @param event The event name
2144
+ * @param properties The event properties
2145
+ */
2146
+ track(event, properties) {
2147
+ const typedEvent = {
2148
+ event,
2149
+ properties,
2150
+ timestamp: Date.now()
2151
+ };
2152
+ this.trackEvent(typedEvent);
2153
+ }
2154
+ isRateLimited(event) {
2155
+ const now = Date.now();
2156
+ if (now - this.lastRateLimitReset > this.rateLimitWindow) {
2157
+ this.eventCounts.clear();
2158
+ this.lastRateLimitReset = now;
2159
+ }
2160
+ const count = this.eventCounts.get(event) || 0;
2161
+ const maxEventsPerWindow = 10;
2162
+ if (count >= maxEventsPerWindow) {
2163
+ return true;
2164
+ }
2165
+ this.eventCounts.set(event, count + 1);
2166
+ return false;
2167
+ }
2168
+ /**
2169
+ * Sanitize properties to remove PII before sending
2170
+ */
2171
+ sanitizeProperties(properties) {
2172
+ const sanitized = {};
2173
+ if (!properties) {
2174
+ return sanitized;
2175
+ }
2176
+ const allowedProps = [
2177
+ "version",
2178
+ "platform",
2179
+ "duration",
2180
+ "success",
2181
+ "filesCount",
2182
+ "method",
2183
+ "trigger",
2184
+ "feature",
2185
+ "viewId",
2186
+ "command"
2187
+ ];
2188
+ for (const key of allowedProps) {
2189
+ if (key in properties) {
2190
+ sanitized[key] = properties[key];
2191
+ }
2192
+ }
2193
+ return sanitized;
2194
+ }
2195
+ generateAnonymousId() {
2196
+ return `${this.environment}_${Math.random().toString(36).substr(2, 9)}`;
2197
+ }
2198
+ /**
2199
+ * Get current package version
2200
+ * @returns The current version string
2201
+ */
2202
+ getVersion() {
2203
+ try {
2204
+ const packageJson = require_package();
2205
+ return packageJson.version || "unknown";
2206
+ } catch (_error) {
2207
+ return process.env.SNAPBACK_VERSION || "1.0.0";
2208
+ }
2209
+ }
2210
+ /**
2211
+ * Custom transport layer - routes all events through proxy
2212
+ */
2213
+ async customTransport(batch) {
2214
+ if (this.offlineMode) {
2215
+ return;
2216
+ }
2217
+ try {
2218
+ const response = await fetch(this.proxyUrl, {
2219
+ method: "POST",
2220
+ headers: {
2221
+ "Content-Type": "application/json",
2222
+ "X-SnapBack-Platform": this.environment,
2223
+ "X-SnapBack-Version": this.getVersion()
2224
+ },
2225
+ body: JSON.stringify({
2226
+ events: batch.map((event) => ({
2227
+ event: event.event,
2228
+ properties: this.sanitizeProperties(event.properties || {}),
2229
+ timestamp: event.timestamp
2230
+ }))
2231
+ })
2232
+ });
2233
+ if (!response.ok) {
2234
+ const error = await response.text();
2235
+ console.warn("Telemetry proxy rejected events", {
2236
+ status: response.status,
2237
+ error
2238
+ });
2239
+ }
2240
+ } catch (error) {
2241
+ console.error("Failed to send telemetry through proxy", error);
2242
+ }
2243
+ }
2244
+ async flush() {
2245
+ if (this.offlineMode) {
2246
+ return;
2247
+ }
2248
+ if (this.eventQueue.length === 0) {
2249
+ return;
2250
+ }
2251
+ const eventsToFlush = [
2252
+ ...this.eventQueue
2253
+ ];
2254
+ this.eventQueue = [];
2255
+ try {
2256
+ await this.customTransport(eventsToFlush);
2257
+ } catch (error) {
2258
+ console.warn("Failed to send telemetry events:", error);
2259
+ this.eventQueue.unshift(...eventsToFlush);
2260
+ }
2261
+ }
2262
+ };
2263
+
2264
+ 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, resetMetrics, setSentryUser, startSentryTransaction, toggleAlert, updateCohort };