@terreno/api 0.13.3 → 0.14.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 (172) hide show
  1. package/dist/__tests__/versionCheckPlugin.test.js +53 -3
  2. package/dist/api.arrayOperations.test.js +1 -0
  3. package/dist/api.d.ts +15 -4
  4. package/dist/api.errors.test.js +1 -0
  5. package/dist/api.hooks.test.js +1 -0
  6. package/dist/api.js +153 -104
  7. package/dist/api.query.test.js +1 -0
  8. package/dist/api.test.js +174 -0
  9. package/dist/auth.d.ts +10 -5
  10. package/dist/auth.js +163 -90
  11. package/dist/auth.test.js +159 -0
  12. package/dist/betterAuthApp.test.js +1 -0
  13. package/dist/betterAuthSetup.d.ts +5 -6
  14. package/dist/betterAuthSetup.js +17 -14
  15. package/dist/betterAuthSetup.test.js +1 -0
  16. package/dist/config.d.ts +48 -0
  17. package/dist/config.js +248 -0
  18. package/dist/config.test.d.ts +1 -0
  19. package/dist/config.test.js +328 -0
  20. package/dist/configuration.test.js +1 -0
  21. package/dist/configurationApp.d.ts +1 -1
  22. package/dist/configurationApp.js +17 -13
  23. package/dist/configurationPlugin.test.js +1 -0
  24. package/dist/consentApp.test.js +1 -0
  25. package/dist/envConfigurationPlugin.d.ts +2 -0
  26. package/dist/envConfigurationPlugin.js +173 -0
  27. package/dist/envConfigurationPlugin.test.d.ts +1 -0
  28. package/dist/envConfigurationPlugin.test.js +322 -0
  29. package/dist/errors.d.ts +18 -7
  30. package/dist/errors.js +106 -10
  31. package/dist/errors.test.js +16 -1
  32. package/dist/example.js +16 -7
  33. package/dist/expressServer.d.ts +10 -9
  34. package/dist/expressServer.js +62 -53
  35. package/dist/expressServer.test.js +53 -2
  36. package/dist/githubAuth.d.ts +2 -1
  37. package/dist/githubAuth.js +41 -26
  38. package/dist/githubAuth.test.js +1 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +4 -0
  41. package/dist/logger.d.ts +1 -1
  42. package/dist/logger.js +42 -20
  43. package/dist/models/versionConfig.d.ts +2 -0
  44. package/dist/models/versionConfig.js +8 -0
  45. package/dist/notifiers/googleChatNotifier.js +14 -16
  46. package/dist/notifiers/googleChatNotifier.test.js +1 -0
  47. package/dist/notifiers/slackNotifier.js +16 -14
  48. package/dist/notifiers/slackNotifier.test.js +41 -3
  49. package/dist/notifiers/zoomNotifier.js +7 -10
  50. package/dist/notifiers/zoomNotifier.test.js +1 -0
  51. package/dist/openApi.d.ts +1 -1
  52. package/dist/openApi.test.js +1 -0
  53. package/dist/openApiBuilder.d.ts +39 -6
  54. package/dist/openApiBuilder.js +1 -31
  55. package/dist/openApiBuilder.test.js +1 -0
  56. package/dist/openApiValidator.js +1 -0
  57. package/dist/openApiValidator.test.js +1 -0
  58. package/dist/permissions.d.ts +4 -4
  59. package/dist/permissions.js +67 -65
  60. package/dist/permissions.middleware.test.js +1 -0
  61. package/dist/permissions.test.js +1 -0
  62. package/dist/plugins.d.ts +5 -5
  63. package/dist/plugins.js +18 -9
  64. package/dist/plugins.test.js +1 -1
  65. package/dist/populate.d.ts +15 -8
  66. package/dist/populate.js +23 -24
  67. package/dist/populate.test.js +1 -0
  68. package/dist/realtime/changeStreamWatcher.d.ts +73 -0
  69. package/dist/realtime/changeStreamWatcher.js +720 -0
  70. package/dist/realtime/index.d.ts +6 -0
  71. package/dist/realtime/index.js +27 -0
  72. package/dist/realtime/queryMatcher.d.ts +14 -0
  73. package/dist/realtime/queryMatcher.js +250 -0
  74. package/dist/realtime/queryStore.d.ts +37 -0
  75. package/dist/realtime/queryStore.js +195 -0
  76. package/dist/realtime/realtime.test.d.ts +10 -0
  77. package/dist/realtime/realtime.test.js +2158 -0
  78. package/dist/realtime/realtimeApp.d.ts +93 -0
  79. package/dist/realtime/realtimeApp.js +560 -0
  80. package/dist/realtime/registry.d.ts +40 -0
  81. package/dist/realtime/registry.js +38 -0
  82. package/dist/realtime/socketUser.d.ts +10 -0
  83. package/dist/realtime/socketUser.js +17 -0
  84. package/dist/realtime/types.d.ts +100 -0
  85. package/dist/realtime/types.js +2 -0
  86. package/dist/requestContext.d.ts +37 -0
  87. package/dist/requestContext.js +344 -0
  88. package/dist/requestContext.test.d.ts +1 -0
  89. package/dist/requestContext.test.js +241 -0
  90. package/dist/terrenoApp.d.ts +8 -0
  91. package/dist/terrenoApp.js +50 -13
  92. package/dist/terrenoApp.test.js +194 -21
  93. package/dist/terrenoPlugin.d.ts +11 -0
  94. package/dist/tests/bunSetup.js +1 -0
  95. package/dist/tests.js +1 -1
  96. package/dist/transformers.d.ts +2 -2
  97. package/dist/transformers.js +5 -3
  98. package/dist/transformers.test.js +90 -0
  99. package/dist/types/consentResponse.d.ts +6 -3
  100. package/dist/versionCheckPlugin.d.ts +2 -0
  101. package/dist/versionCheckPlugin.js +18 -12
  102. package/package.json +4 -2
  103. package/src/__tests__/versionCheckPlugin.test.ts +37 -3
  104. package/src/api.arrayOperations.test.ts +1 -0
  105. package/src/api.errors.test.ts +1 -0
  106. package/src/api.hooks.test.ts +1 -0
  107. package/src/api.query.test.ts +1 -0
  108. package/src/api.test.ts +132 -0
  109. package/src/api.ts +199 -84
  110. package/src/auth.test.ts +160 -0
  111. package/src/auth.ts +120 -50
  112. package/src/betterAuthApp.test.ts +1 -0
  113. package/src/betterAuthSetup.test.ts +1 -0
  114. package/src/betterAuthSetup.ts +46 -19
  115. package/src/config.test.ts +255 -0
  116. package/src/config.ts +206 -0
  117. package/src/configuration.test.ts +1 -0
  118. package/src/configurationApp.ts +59 -24
  119. package/src/configurationPlugin.test.ts +1 -0
  120. package/src/consentApp.test.ts +1 -0
  121. package/src/envConfigurationPlugin.test.ts +143 -0
  122. package/src/envConfigurationPlugin.ts +100 -0
  123. package/src/errors.test.ts +19 -1
  124. package/src/errors.ts +94 -20
  125. package/src/example.ts +46 -21
  126. package/src/express.d.ts +18 -1
  127. package/src/expressServer.test.ts +50 -2
  128. package/src/expressServer.ts +80 -50
  129. package/src/githubAuth.test.ts +1 -0
  130. package/src/githubAuth.ts +59 -38
  131. package/src/index.ts +4 -0
  132. package/src/logger.ts +47 -17
  133. package/src/models/versionConfig.ts +13 -2
  134. package/src/notifiers/googleChatNotifier.test.ts +1 -0
  135. package/src/notifiers/googleChatNotifier.ts +7 -9
  136. package/src/notifiers/slackNotifier.test.ts +29 -3
  137. package/src/notifiers/slackNotifier.ts +9 -7
  138. package/src/notifiers/zoomNotifier.test.ts +1 -0
  139. package/src/notifiers/zoomNotifier.ts +8 -11
  140. package/src/openApi.test.ts +1 -0
  141. package/src/openApi.ts +4 -4
  142. package/src/openApiBuilder.test.ts +1 -0
  143. package/src/openApiBuilder.ts +14 -11
  144. package/src/openApiValidator.test.ts +1 -0
  145. package/src/openApiValidator.ts +3 -2
  146. package/src/permissions.middleware.test.ts +1 -0
  147. package/src/permissions.test.ts +1 -0
  148. package/src/permissions.ts +30 -25
  149. package/src/plugins.test.ts +1 -1
  150. package/src/plugins.ts +21 -14
  151. package/src/populate.test.ts +1 -0
  152. package/src/populate.ts +44 -36
  153. package/src/realtime/changeStreamWatcher.ts +568 -0
  154. package/src/realtime/index.ts +34 -0
  155. package/src/realtime/queryMatcher.ts +179 -0
  156. package/src/realtime/queryStore.ts +132 -0
  157. package/src/realtime/realtime.test.ts +1755 -0
  158. package/src/realtime/realtimeApp.ts +478 -0
  159. package/src/realtime/registry.ts +64 -0
  160. package/src/realtime/socketUser.ts +25 -0
  161. package/src/realtime/types.ts +112 -0
  162. package/src/requestContext.test.ts +196 -0
  163. package/src/requestContext.ts +368 -0
  164. package/src/terrenoApp.test.ts +137 -11
  165. package/src/terrenoApp.ts +64 -17
  166. package/src/terrenoPlugin.ts +12 -0
  167. package/src/tests/bunSetup.ts +1 -0
  168. package/src/tests.ts +7 -2
  169. package/src/transformers.test.ts +70 -2
  170. package/src/transformers.ts +15 -7
  171. package/src/types/consentResponse.ts +8 -10
  172. package/src/versionCheckPlugin.ts +15 -7
@@ -0,0 +1,40 @@
1
+ import type { ModelRouterOptions } from "../api";
2
+ import type { RealtimeConfig } from "./types";
3
+ /**
4
+ * A registered model with real-time sync configuration.
5
+ */
6
+ export interface RealtimeRegistryEntry {
7
+ /** Mongoose model name (e.g. "Todo") */
8
+ modelName: string;
9
+ /** Route path (e.g. "/todos") */
10
+ routePath: string;
11
+ /** Collection name in MongoDB (e.g. "todos") */
12
+ collectionName: string;
13
+ /** Real-time configuration from modelRouter options */
14
+ config: RealtimeConfig;
15
+ /**
16
+ * Full modelRouter options (for responseHandler, permissions, etc.).
17
+ */
18
+ options: ModelRouterOptions<any>;
19
+ }
20
+ /**
21
+ * Register a model for real-time sync. Called automatically by modelRouter
22
+ * when the `realtime` option is provided.
23
+ */
24
+ export declare const registerRealtime: (entry: RealtimeRegistryEntry) => void;
25
+ /**
26
+ * Get all registered real-time models.
27
+ */
28
+ export declare const getRealtimeRegistry: () => RealtimeRegistryEntry[];
29
+ /**
30
+ * Find a registry entry by MongoDB collection name.
31
+ */
32
+ export declare const findRegistryEntryByCollection: (collectionName: string) => RealtimeRegistryEntry | undefined;
33
+ /**
34
+ * Find a registry entry by route path / collection tag (e.g. "todos").
35
+ */
36
+ export declare const findRegistryEntryByRoutePath: (collection: string) => RealtimeRegistryEntry | undefined;
37
+ /**
38
+ * Clear the registry (for testing).
39
+ */
40
+ export declare const clearRealtimeRegistry: () => void;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clearRealtimeRegistry = exports.findRegistryEntryByRoutePath = exports.findRegistryEntryByCollection = exports.getRealtimeRegistry = exports.registerRealtime = void 0;
4
+ var realtimeRegistry = [];
5
+ /**
6
+ * Register a model for real-time sync. Called automatically by modelRouter
7
+ * when the `realtime` option is provided.
8
+ */
9
+ var registerRealtime = function (entry) {
10
+ realtimeRegistry.push(entry);
11
+ };
12
+ exports.registerRealtime = registerRealtime;
13
+ /**
14
+ * Get all registered real-time models.
15
+ */
16
+ var getRealtimeRegistry = function () { return realtimeRegistry; };
17
+ exports.getRealtimeRegistry = getRealtimeRegistry;
18
+ /**
19
+ * Find a registry entry by MongoDB collection name.
20
+ */
21
+ var findRegistryEntryByCollection = function (collectionName) {
22
+ return realtimeRegistry.find(function (entry) { return entry.collectionName === collectionName; });
23
+ };
24
+ exports.findRegistryEntryByCollection = findRegistryEntryByCollection;
25
+ /**
26
+ * Find a registry entry by route path / collection tag (e.g. "todos").
27
+ */
28
+ var findRegistryEntryByRoutePath = function (collection) {
29
+ return realtimeRegistry.find(function (entry) { return entry.routePath === "/".concat(collection) || entry.routePath === collection; });
30
+ };
31
+ exports.findRegistryEntryByRoutePath = findRegistryEntryByRoutePath;
32
+ /**
33
+ * Clear the registry (for testing).
34
+ */
35
+ var clearRealtimeRegistry = function () {
36
+ realtimeRegistry.length = 0;
37
+ };
38
+ exports.clearRealtimeRegistry = clearRealtimeRegistry;
@@ -0,0 +1,10 @@
1
+ import type { User } from "../auth";
2
+ export interface DecodedRealtimeToken {
3
+ admin?: boolean;
4
+ id?: string;
5
+ isAnonymous?: boolean;
6
+ }
7
+ export interface SocketWithDecodedToken {
8
+ decodedToken?: DecodedRealtimeToken;
9
+ }
10
+ export declare const getSocketUser: (socket: SocketWithDecodedToken) => User | undefined;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSocketUser = void 0;
4
+ var getSocketUser = function (socket) {
5
+ var _a, _b, _c;
6
+ var userId = (_a = socket.decodedToken) === null || _a === void 0 ? void 0 : _a.id;
7
+ if (!userId) {
8
+ return undefined;
9
+ }
10
+ return {
11
+ _id: userId,
12
+ admin: ((_b = socket.decodedToken) === null || _b === void 0 ? void 0 : _b.admin) === true,
13
+ id: userId,
14
+ isAnonymous: (_c = socket.decodedToken) === null || _c === void 0 ? void 0 : _c.isAnonymous,
15
+ };
16
+ };
17
+ exports.getSocketUser = getSocketUser;
@@ -0,0 +1,100 @@
1
+ import type express from "express";
2
+ /**
3
+ * Configuration for real-time sync on a modelRouter.
4
+ * Determines which CRUD methods emit WebSocket events and how they are routed.
5
+ */
6
+ export interface RealtimeConfig {
7
+ /** Which CRUD methods should emit real-time sync events */
8
+ methods: Array<"create" | "update" | "delete">;
9
+ /**
10
+ * Strategy for determining which Socket.io rooms receive events.
11
+ * - 'owner': emit to `user:{doc.ownerId}` room
12
+ * - 'model': emit to `model:{modelName}` room (clients must subscribe)
13
+ * - 'broadcast': emit to all authenticated sockets
14
+ * - function: custom room resolver returning room name(s)
15
+ */
16
+ roomStrategy: "owner" | "model" | "broadcast" | ((doc: any, method: string, req: express.Request) => string[]);
17
+ /** Custom serializer for real-time events. Falls back to the modelRouter responseHandler. */
18
+ realtimeResponseHandler?: (doc: any, method: string) => any;
19
+ }
20
+ /**
21
+ * A real-time sync event emitted to clients via WebSocket.
22
+ */
23
+ export interface RealtimeEvent {
24
+ /** Mongoose model name (e.g. "Todo") */
25
+ model: string;
26
+ /** Route path used as tag type (e.g. "todos") */
27
+ collection: string;
28
+ /** The CRUD method that triggered this event */
29
+ method: "create" | "update" | "delete";
30
+ /** Document ID */
31
+ id: string;
32
+ /** Serialized document data (omitted for hard deletes) */
33
+ data?: any;
34
+ /** Fields that were updated (for update events from change streams) */
35
+ updatedFields?: string[];
36
+ /** Epoch milliseconds when the event was generated */
37
+ timestamp: number;
38
+ }
39
+ /**
40
+ * Configuration for the MongoDB change stream watcher.
41
+ */
42
+ export interface ChangeStreamConfig {
43
+ /** Collections to never watch (e.g. "socketio", "sessions") */
44
+ ignoredCollections?: string[];
45
+ /** Operation types to ignore */
46
+ ignoredOperations?: string[];
47
+ /** Non-modelRouter collections to watch (emits raw events) */
48
+ additionalCollections?: string[];
49
+ /** Change stream batch size (default: 50) */
50
+ batchSize?: number;
51
+ /** Full document mode (default: "updateLookup") */
52
+ fullDocument?: "updateLookup" | "whenAvailable";
53
+ }
54
+ /**
55
+ * Options for the RealtimeApp plugin.
56
+ */
57
+ export interface RealtimeAppOptions {
58
+ /** Change stream watcher configuration */
59
+ changeStream?: ChangeStreamConfig;
60
+ /** CORS configuration for Socket.io */
61
+ cors?: {
62
+ origin: string | string[];
63
+ methods?: string[];
64
+ };
65
+ /**
66
+ * Socket.io adapter for multi-instance deployments.
67
+ * - 'none': single-instance mode, no adapter (default)
68
+ * - 'redis': use Redis adapter (requires redisUrl or VALKEY_URL env var)
69
+ *
70
+ * For MongoDB adapter or custom adapters, configure the Socket.io instance
71
+ * directly via getIo() after server creation.
72
+ */
73
+ adapter?: "redis" | "none";
74
+ /** Redis URL for the Redis adapter */
75
+ redisUrl?: string;
76
+ /** JWT secret for socket authentication (default: process.env.TOKEN_SECRET) */
77
+ tokenSecret?: string;
78
+ /** Enable debug logging */
79
+ debug?: boolean;
80
+ }
81
+ /**
82
+ * Payload sent by the client to subscribe to a single document's changes.
83
+ */
84
+ export interface DocumentSubscription {
85
+ /** Collection tag (e.g. "todos") */
86
+ collection: string;
87
+ /** Document ID */
88
+ id: string;
89
+ }
90
+ /**
91
+ * Payload sent by the client to subscribe to a query-filtered list.
92
+ */
93
+ export interface QuerySubscription {
94
+ /** Collection tag (e.g. "todos") */
95
+ collection: string;
96
+ /** MongoDB-style query filter (e.g. {completed: false}) */
97
+ query: Record<string, any>;
98
+ /** Client-provided queryId (ignored — server computes a canonical ID) */
99
+ queryId?: string;
100
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,37 @@
1
+ import type express from "express";
2
+ import type { JwtPayload } from "jsonwebtoken";
3
+ export interface RequestContext {
4
+ jobId?: string;
5
+ requestId: string;
6
+ sessionId?: string;
7
+ spanId?: string;
8
+ traceId?: string;
9
+ traceSampled?: boolean;
10
+ userId?: string;
11
+ }
12
+ export type RequestContextAttributes = Record<string, string>;
13
+ export declare const REQUEST_CONTEXT_ATTRIBUTE_NAMES: {
14
+ readonly jobId: "x-job-id";
15
+ readonly requestId: "x-request-id";
16
+ readonly sessionId: "x-session-id";
17
+ readonly spanId: "x-span-id";
18
+ readonly traceId: "x-trace-id";
19
+ readonly traceParent: "traceparent";
20
+ readonly traceSampled: "x-trace-sampled";
21
+ readonly userId: "x-user-id";
22
+ };
23
+ export interface JwtSessionPayload extends JwtPayload {
24
+ sid?: string;
25
+ sessionId?: string;
26
+ }
27
+ export declare const getSessionIdFromJwtPayload: (payload?: JwtSessionPayload | null) => string | undefined;
28
+ export declare const getRequestContextFromAttributes: (attributes?: Record<string, string | undefined>) => RequestContext;
29
+ export declare const getCurrentRequestContext: () => RequestContext | undefined;
30
+ export declare const getCurrentLogContext: () => Partial<RequestContext>;
31
+ export declare const applyRequestContextToSentry: (context?: Partial<RequestContext>) => void;
32
+ export declare const setRequestContext: (updates: Partial<RequestContext>) => void;
33
+ export declare const getCurrentRequestContextAttributes: (overrides?: Partial<RequestContext>) => RequestContextAttributes;
34
+ export declare const runWithRequestContext: <T>(context: Partial<RequestContext>, callback: () => T) => T;
35
+ export declare const runWithRequestContextAttributes: <T>(attributes: Record<string, string | undefined> | undefined, callback: () => T) => T;
36
+ export declare const updateRequestContextFromRequest: (req: express.Request, res?: express.Response) => void;
37
+ export declare const requestContextMiddleware: (req: express.Request, res: express.Response, next: express.NextFunction) => void;
@@ -0,0 +1,344 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ var __read = (this && this.__read) || function (o, n) {
47
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
48
+ if (!m) return o;
49
+ var i = m.call(o), r, ar = [], e;
50
+ try {
51
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
52
+ }
53
+ catch (error) { e = { error: error }; }
54
+ finally {
55
+ try {
56
+ if (r && !r.done && (m = i["return"])) m.call(i);
57
+ }
58
+ finally { if (e) throw e.error; }
59
+ }
60
+ return ar;
61
+ };
62
+ var __values = (this && this.__values) || function(o) {
63
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
64
+ if (m) return m.call(o);
65
+ if (o && typeof o.length === "number") return {
66
+ next: function () {
67
+ if (o && i >= o.length) o = void 0;
68
+ return { value: o && o[i++], done: !o };
69
+ }
70
+ };
71
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
72
+ };
73
+ Object.defineProperty(exports, "__esModule", { value: true });
74
+ exports.requestContextMiddleware = exports.updateRequestContextFromRequest = exports.runWithRequestContextAttributes = exports.runWithRequestContext = exports.getCurrentRequestContextAttributes = exports.setRequestContext = exports.applyRequestContextToSentry = exports.getCurrentLogContext = exports.getCurrentRequestContext = exports.getRequestContextFromAttributes = exports.getSessionIdFromJwtPayload = exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES = void 0;
75
+ var node_async_hooks_1 = require("node:async_hooks");
76
+ var node_crypto_1 = require("node:crypto");
77
+ var Sentry = __importStar(require("@sentry/bun"));
78
+ var CLOUD_TRACE_CONTEXT_HEADER = "x-cloud-trace-context";
79
+ var JOB_ID_HEADER = "x-job-id";
80
+ var REQUEST_ID_HEADERS = ["x-request-id", "x-correlation-id", "x-transaction-id"];
81
+ var SESSION_ID_HEADER = "x-session-id";
82
+ var SPAN_ID_HEADER = "x-span-id";
83
+ var TRACE_ID_HEADER = "x-trace-id";
84
+ var TRACE_PARENT_HEADER = "traceparent";
85
+ var TRACE_SAMPLED_HEADER = "x-trace-sampled";
86
+ var USER_ID_HEADER = "x-user-id";
87
+ exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES = {
88
+ jobId: JOB_ID_HEADER,
89
+ requestId: "x-request-id",
90
+ sessionId: SESSION_ID_HEADER,
91
+ spanId: SPAN_ID_HEADER,
92
+ traceId: TRACE_ID_HEADER,
93
+ traceParent: TRACE_PARENT_HEADER,
94
+ traceSampled: TRACE_SAMPLED_HEADER,
95
+ userId: USER_ID_HEADER,
96
+ };
97
+ var requestContextStorage = new node_async_hooks_1.AsyncLocalStorage();
98
+ var getHeader = function (req, headerName) {
99
+ var value = req.header(headerName);
100
+ if (!Array.isArray(value)) {
101
+ return value;
102
+ }
103
+ return value[0];
104
+ };
105
+ var parseGoogleCloudTraceContext = function (headerValue) {
106
+ if (!headerValue) {
107
+ return undefined;
108
+ }
109
+ var _a = __read(headerValue.split(";"), 2), traceAndSpan = _a[0], options = _a[1];
110
+ var _b = __read(traceAndSpan.split("/"), 2), traceId = _b[0], spanId = _b[1];
111
+ if (!traceId) {
112
+ return undefined;
113
+ }
114
+ return {
115
+ spanId: spanId,
116
+ traceId: traceId,
117
+ traceSampled: options === "o=1",
118
+ };
119
+ };
120
+ var parseTraceParent = function (headerValue) {
121
+ if (!headerValue) {
122
+ return undefined;
123
+ }
124
+ var _a = __read(headerValue.split("-"), 4), _version = _a[0], traceId = _a[1], spanId = _a[2], flags = _a[3];
125
+ if (!traceId) {
126
+ return undefined;
127
+ }
128
+ return {
129
+ spanId: spanId,
130
+ traceId: traceId,
131
+ traceSampled: flags === "01",
132
+ };
133
+ };
134
+ var parseTraceSampled = function (value) {
135
+ if (typeof value === "boolean") {
136
+ return value;
137
+ }
138
+ if (value === "true" || value === "1") {
139
+ return true;
140
+ }
141
+ if (value === "false" || value === "0") {
142
+ return false;
143
+ }
144
+ return undefined;
145
+ };
146
+ var getIncomingRequestId = function (req, traceContext) {
147
+ var e_1, _a;
148
+ try {
149
+ for (var REQUEST_ID_HEADERS_1 = __values(REQUEST_ID_HEADERS), REQUEST_ID_HEADERS_1_1 = REQUEST_ID_HEADERS_1.next(); !REQUEST_ID_HEADERS_1_1.done; REQUEST_ID_HEADERS_1_1 = REQUEST_ID_HEADERS_1.next()) {
150
+ var headerName = REQUEST_ID_HEADERS_1_1.value;
151
+ var headerValue = getHeader(req, headerName);
152
+ if (headerValue) {
153
+ return headerValue;
154
+ }
155
+ }
156
+ }
157
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
158
+ finally {
159
+ try {
160
+ if (REQUEST_ID_HEADERS_1_1 && !REQUEST_ID_HEADERS_1_1.done && (_a = REQUEST_ID_HEADERS_1.return)) _a.call(REQUEST_ID_HEADERS_1);
161
+ }
162
+ finally { if (e_1) throw e_1.error; }
163
+ }
164
+ if (traceContext === null || traceContext === void 0 ? void 0 : traceContext.traceId) {
165
+ return traceContext.traceId;
166
+ }
167
+ return (0, node_crypto_1.randomUUID)();
168
+ };
169
+ var getSessionIdFromJwtPayload = function (payload) {
170
+ if (!payload) {
171
+ return undefined;
172
+ }
173
+ if (payload.sid) {
174
+ return payload.sid;
175
+ }
176
+ return payload.sessionId;
177
+ };
178
+ exports.getSessionIdFromJwtPayload = getSessionIdFromJwtPayload;
179
+ var getRequestContextFromAttributes = function (attributes) {
180
+ var _a, _b, _c, _d, _e, _f, _g;
181
+ if (attributes === void 0) { attributes = {}; }
182
+ var cloudTraceContext = parseGoogleCloudTraceContext(attributes[CLOUD_TRACE_CONTEXT_HEADER]);
183
+ var traceParentContext = parseTraceParent(attributes[TRACE_PARENT_HEADER]);
184
+ var traceContext = cloudTraceContext !== null && cloudTraceContext !== void 0 ? cloudTraceContext : traceParentContext;
185
+ return {
186
+ jobId: attributes[JOB_ID_HEADER],
187
+ requestId: (_d = (_c = (_b = (_a = attributes[exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.requestId]) !== null && _a !== void 0 ? _a : attributes["x-correlation-id"]) !== null && _b !== void 0 ? _b : attributes["x-transaction-id"]) !== null && _c !== void 0 ? _c : traceContext === null || traceContext === void 0 ? void 0 : traceContext.traceId) !== null && _d !== void 0 ? _d : (0, node_crypto_1.randomUUID)(),
188
+ sessionId: attributes[SESSION_ID_HEADER],
189
+ spanId: (_e = attributes[SPAN_ID_HEADER]) !== null && _e !== void 0 ? _e : traceContext === null || traceContext === void 0 ? void 0 : traceContext.spanId,
190
+ traceId: (_f = attributes[TRACE_ID_HEADER]) !== null && _f !== void 0 ? _f : traceContext === null || traceContext === void 0 ? void 0 : traceContext.traceId,
191
+ traceSampled: (_g = parseTraceSampled(attributes[TRACE_SAMPLED_HEADER])) !== null && _g !== void 0 ? _g : traceContext === null || traceContext === void 0 ? void 0 : traceContext.traceSampled,
192
+ userId: attributes[USER_ID_HEADER],
193
+ };
194
+ };
195
+ exports.getRequestContextFromAttributes = getRequestContextFromAttributes;
196
+ var getCurrentRequestContext = function () {
197
+ return requestContextStorage.getStore();
198
+ };
199
+ exports.getCurrentRequestContext = getCurrentRequestContext;
200
+ var getCurrentLogContext = function () {
201
+ var context = (0, exports.getCurrentRequestContext)();
202
+ if (!context) {
203
+ return {};
204
+ }
205
+ return {
206
+ jobId: context.jobId,
207
+ requestId: context.requestId,
208
+ sessionId: context.sessionId,
209
+ spanId: context.spanId,
210
+ traceId: context.traceId,
211
+ traceSampled: context.traceSampled,
212
+ userId: context.userId,
213
+ };
214
+ };
215
+ exports.getCurrentLogContext = getCurrentLogContext;
216
+ var setSentryTag = function (scope, name, value) {
217
+ if (typeof value === "undefined") {
218
+ return;
219
+ }
220
+ scope.setTag(name, String(value));
221
+ };
222
+ var setSentryContextValue = function (context, name, value) {
223
+ if (typeof value === "undefined") {
224
+ return;
225
+ }
226
+ context[name] = value;
227
+ };
228
+ var applyRequestContextToSentry = function (context) {
229
+ if (context === void 0) { context = (0, exports.getCurrentLogContext)(); }
230
+ var scope = Sentry.getCurrentScope();
231
+ setSentryTag(scope, "request_id", context.requestId);
232
+ setSentryTag(scope, "session_id", context.sessionId);
233
+ setSentryTag(scope, "job_id", context.jobId);
234
+ setSentryTag(scope, "user_id", context.userId);
235
+ setSentryTag(scope, "trace_id", context.traceId);
236
+ setSentryTag(scope, "span_id", context.spanId);
237
+ setSentryTag(scope, "trace_sampled", context.traceSampled);
238
+ if (context.userId) {
239
+ scope.setUser({ id: context.userId });
240
+ }
241
+ var sentryContext = {};
242
+ setSentryContextValue(sentryContext, "requestId", context.requestId);
243
+ setSentryContextValue(sentryContext, "sessionId", context.sessionId);
244
+ setSentryContextValue(sentryContext, "jobId", context.jobId);
245
+ setSentryContextValue(sentryContext, "userId", context.userId);
246
+ setSentryContextValue(sentryContext, "traceId", context.traceId);
247
+ setSentryContextValue(sentryContext, "spanId", context.spanId);
248
+ setSentryContextValue(sentryContext, "traceSampled", context.traceSampled);
249
+ if (Object.keys(sentryContext).length > 0) {
250
+ scope.setContext("request_context", sentryContext);
251
+ }
252
+ };
253
+ exports.applyRequestContextToSentry = applyRequestContextToSentry;
254
+ var setRequestContext = function (updates) {
255
+ var context = (0, exports.getCurrentRequestContext)();
256
+ if (!context) {
257
+ return;
258
+ }
259
+ Object.assign(context, updates);
260
+ (0, exports.applyRequestContextToSentry)(context);
261
+ };
262
+ exports.setRequestContext = setRequestContext;
263
+ var setAttribute = function (attributes, name, value) {
264
+ if (typeof value === "undefined") {
265
+ return;
266
+ }
267
+ attributes[name] = String(value);
268
+ };
269
+ var getCurrentRequestContextAttributes = function (overrides) {
270
+ if (overrides === void 0) { overrides = {}; }
271
+ var context = __assign(__assign({}, (0, exports.getCurrentLogContext)()), overrides);
272
+ var attributes = {};
273
+ setAttribute(attributes, exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.requestId, context.requestId);
274
+ setAttribute(attributes, exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.sessionId, context.sessionId);
275
+ setAttribute(attributes, exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.jobId, context.jobId);
276
+ setAttribute(attributes, exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.userId, context.userId);
277
+ setAttribute(attributes, exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.traceId, context.traceId);
278
+ setAttribute(attributes, exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.spanId, context.spanId);
279
+ setAttribute(attributes, exports.REQUEST_CONTEXT_ATTRIBUTE_NAMES.traceSampled, context.traceSampled);
280
+ return attributes;
281
+ };
282
+ exports.getCurrentRequestContextAttributes = getCurrentRequestContextAttributes;
283
+ var runWithRequestContext = function (context, callback) {
284
+ var _a;
285
+ var nextContext = __assign(__assign({}, context), { requestId: (_a = context.requestId) !== null && _a !== void 0 ? _a : (0, node_crypto_1.randomUUID)() });
286
+ return requestContextStorage.run(nextContext, function () {
287
+ (0, exports.applyRequestContextToSentry)(nextContext);
288
+ return callback();
289
+ });
290
+ };
291
+ exports.runWithRequestContext = runWithRequestContext;
292
+ var runWithRequestContextAttributes = function (attributes, callback) {
293
+ if (attributes === void 0) { attributes = {}; }
294
+ return (0, exports.runWithRequestContext)((0, exports.getRequestContextFromAttributes)(attributes), callback);
295
+ };
296
+ exports.runWithRequestContextAttributes = runWithRequestContextAttributes;
297
+ var updateRequestContextFromRequest = function (req, res) {
298
+ var _a, _b, _c, _d, _e, _f, _g;
299
+ var reqWithContext = req;
300
+ var jobId = (_a = reqWithContext.jobId) !== null && _a !== void 0 ? _a : getHeader(req, JOB_ID_HEADER);
301
+ var sessionId = (_f = (_e = (_b = (0, exports.getSessionIdFromJwtPayload)(reqWithContext.authTokenPayload)) !== null && _b !== void 0 ? _b : (_d = (_c = reqWithContext.betterAuthSession) === null || _c === void 0 ? void 0 : _c.session) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : reqWithContext.sessionId) !== null && _f !== void 0 ? _f : getHeader(req, SESSION_ID_HEADER);
302
+ var user = req.user;
303
+ var userId = (_g = user === null || user === void 0 ? void 0 : user.id) !== null && _g !== void 0 ? _g : ((user === null || user === void 0 ? void 0 : user._id) ? String(user._id) : undefined);
304
+ (0, exports.setRequestContext)({ jobId: jobId, sessionId: sessionId, userId: userId });
305
+ if (jobId) {
306
+ reqWithContext.jobId = jobId;
307
+ res === null || res === void 0 ? void 0 : res.setHeader("X-Job-ID", jobId);
308
+ }
309
+ if (sessionId) {
310
+ reqWithContext.sessionId = sessionId;
311
+ res === null || res === void 0 ? void 0 : res.setHeader("X-Session-ID", sessionId);
312
+ }
313
+ };
314
+ exports.updateRequestContextFromRequest = updateRequestContextFromRequest;
315
+ var requestContextMiddleware = function (req, res, next) {
316
+ var cloudTraceContext = parseGoogleCloudTraceContext(getHeader(req, CLOUD_TRACE_CONTEXT_HEADER));
317
+ var traceParentContext = parseTraceParent(getHeader(req, TRACE_PARENT_HEADER));
318
+ var traceContext = cloudTraceContext !== null && cloudTraceContext !== void 0 ? cloudTraceContext : traceParentContext;
319
+ var requestId = getIncomingRequestId(req, traceContext);
320
+ var jobId = getHeader(req, JOB_ID_HEADER);
321
+ var sessionId = getHeader(req, SESSION_ID_HEADER);
322
+ var context = {
323
+ jobId: jobId,
324
+ requestId: requestId,
325
+ sessionId: sessionId,
326
+ spanId: traceContext === null || traceContext === void 0 ? void 0 : traceContext.spanId,
327
+ traceId: traceContext === null || traceContext === void 0 ? void 0 : traceContext.traceId,
328
+ traceSampled: traceContext === null || traceContext === void 0 ? void 0 : traceContext.traceSampled,
329
+ };
330
+ var reqWithContext = req;
331
+ if (jobId) {
332
+ reqWithContext.jobId = jobId;
333
+ }
334
+ reqWithContext.requestId = requestId;
335
+ if (sessionId) {
336
+ reqWithContext.sessionId = sessionId;
337
+ }
338
+ res.setHeader("X-Request-ID", requestId);
339
+ requestContextStorage.run(context, function () {
340
+ (0, exports.updateRequestContextFromRequest)(req, res);
341
+ next();
342
+ });
343
+ };
344
+ exports.requestContextMiddleware = requestContextMiddleware;
@@ -0,0 +1 @@
1
+ export {};