@terreno/api 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +170 -0
  3. package/biome.jsonc +22 -0
  4. package/bunfig.toml +4 -0
  5. package/dist/api.d.ts +227 -0
  6. package/dist/api.js +1024 -0
  7. package/dist/api.test.d.ts +1 -0
  8. package/dist/api.test.js +2143 -0
  9. package/dist/auth.d.ts +50 -0
  10. package/dist/auth.js +512 -0
  11. package/dist/auth.test.d.ts +1 -0
  12. package/dist/auth.test.js +778 -0
  13. package/dist/errors.d.ts +75 -0
  14. package/dist/errors.js +216 -0
  15. package/dist/example.d.ts +1 -0
  16. package/dist/example.js +118 -0
  17. package/dist/expressServer.d.ts +35 -0
  18. package/dist/expressServer.js +436 -0
  19. package/dist/index.d.ts +14 -0
  20. package/dist/index.js +30 -0
  21. package/dist/logger.d.ts +23 -0
  22. package/dist/logger.js +249 -0
  23. package/dist/middleware.d.ts +10 -0
  24. package/dist/middleware.js +52 -0
  25. package/dist/notifiers/googleChatNotifier.d.ts +5 -0
  26. package/dist/notifiers/googleChatNotifier.js +130 -0
  27. package/dist/notifiers/googleChatNotifier.test.d.ts +1 -0
  28. package/dist/notifiers/googleChatNotifier.test.js +260 -0
  29. package/dist/notifiers/index.d.ts +3 -0
  30. package/dist/notifiers/index.js +19 -0
  31. package/dist/notifiers/slackNotifier.d.ts +5 -0
  32. package/dist/notifiers/slackNotifier.js +130 -0
  33. package/dist/notifiers/slackNotifier.test.d.ts +1 -0
  34. package/dist/notifiers/slackNotifier.test.js +259 -0
  35. package/dist/notifiers/zoomNotifier.d.ts +34 -0
  36. package/dist/notifiers/zoomNotifier.js +181 -0
  37. package/dist/notifiers/zoomNotifier.test.d.ts +1 -0
  38. package/dist/notifiers/zoomNotifier.test.js +370 -0
  39. package/dist/openApi.d.ts +60 -0
  40. package/dist/openApi.js +441 -0
  41. package/dist/openApi.test.d.ts +1 -0
  42. package/dist/openApi.test.js +445 -0
  43. package/dist/openApiBuilder.d.ts +419 -0
  44. package/dist/openApiBuilder.js +424 -0
  45. package/dist/openApiBuilder.test.d.ts +1 -0
  46. package/dist/openApiBuilder.test.js +509 -0
  47. package/dist/openApiEtag.d.ts +7 -0
  48. package/dist/openApiEtag.js +38 -0
  49. package/dist/permissions.d.ts +26 -0
  50. package/dist/permissions.js +331 -0
  51. package/dist/permissions.test.d.ts +1 -0
  52. package/dist/permissions.test.js +413 -0
  53. package/dist/plugins.d.ts +67 -0
  54. package/dist/plugins.js +315 -0
  55. package/dist/plugins.test.d.ts +1 -0
  56. package/dist/plugins.test.js +639 -0
  57. package/dist/populate.d.ts +14 -0
  58. package/dist/populate.js +315 -0
  59. package/dist/populate.test.d.ts +1 -0
  60. package/dist/populate.test.js +133 -0
  61. package/dist/response.d.ts +0 -0
  62. package/dist/response.js +1 -0
  63. package/dist/tests/bunSetup.d.ts +1 -0
  64. package/dist/tests/bunSetup.js +297 -0
  65. package/dist/tests/index.d.ts +1 -0
  66. package/dist/tests/index.js +17 -0
  67. package/dist/tests.d.ts +99 -0
  68. package/dist/tests.js +273 -0
  69. package/dist/transformers.d.ts +25 -0
  70. package/dist/transformers.js +217 -0
  71. package/dist/transformers.test.d.ts +1 -0
  72. package/dist/transformers.test.js +370 -0
  73. package/dist/utils.d.ts +11 -0
  74. package/dist/utils.js +143 -0
  75. package/dist/utils.test.d.ts +1 -0
  76. package/dist/utils.test.js +14 -0
  77. package/index.ts +1 -0
  78. package/package.json +88 -0
  79. package/src/__snapshots__/openApi.test.ts.snap +4814 -0
  80. package/src/__snapshots__/openApiBuilder.test.ts.snap +1485 -0
  81. package/src/api.test.ts +1661 -0
  82. package/src/api.ts +1036 -0
  83. package/src/auth.test.ts +550 -0
  84. package/src/auth.ts +408 -0
  85. package/src/errors.ts +225 -0
  86. package/src/example.ts +99 -0
  87. package/src/express.d.ts +5 -0
  88. package/src/expressServer.ts +387 -0
  89. package/src/index.ts +14 -0
  90. package/src/logger.ts +190 -0
  91. package/src/middleware.ts +18 -0
  92. package/src/notifiers/googleChatNotifier.test.ts +114 -0
  93. package/src/notifiers/googleChatNotifier.ts +47 -0
  94. package/src/notifiers/index.ts +3 -0
  95. package/src/notifiers/slackNotifier.test.ts +113 -0
  96. package/src/notifiers/slackNotifier.ts +55 -0
  97. package/src/notifiers/zoomNotifier.test.ts +207 -0
  98. package/src/notifiers/zoomNotifier.ts +111 -0
  99. package/src/openApi.test.ts +331 -0
  100. package/src/openApi.ts +494 -0
  101. package/src/openApiBuilder.test.ts +442 -0
  102. package/src/openApiBuilder.ts +636 -0
  103. package/src/openApiEtag.ts +40 -0
  104. package/src/permissions.test.ts +219 -0
  105. package/src/permissions.ts +228 -0
  106. package/src/plugins.test.ts +390 -0
  107. package/src/plugins.ts +289 -0
  108. package/src/populate.test.ts +65 -0
  109. package/src/populate.ts +258 -0
  110. package/src/response.ts +0 -0
  111. package/src/tests/bunSetup.ts +234 -0
  112. package/src/tests/index.ts +1 -0
  113. package/src/tests.ts +218 -0
  114. package/src/transformers.test.ts +202 -0
  115. package/src/transformers.ts +170 -0
  116. package/src/utils.test.ts +14 -0
  117. package/src/utils.ts +47 -0
  118. package/tsconfig.json +60 -0
  119. package/types.d.ts +17 -0
@@ -0,0 +1,65 @@
1
+ import {beforeEach, describe, expect, it} from "bun:test";
2
+
3
+ import {unpopulate} from "./populate";
4
+ import {FoodModel, setupDb} from "./tests";
5
+
6
+ describe("populate functions", () => {
7
+ let admin: any;
8
+ let notAdmin: any;
9
+
10
+ let spinach: any;
11
+
12
+ beforeEach(async () => {
13
+ [admin, notAdmin] = await setupDb();
14
+
15
+ [spinach] = await Promise.all([
16
+ FoodModel.create({
17
+ calories: 1,
18
+ created: new Date("2021-12-03T00:00:20.000Z"),
19
+ eatenBy: [admin._id],
20
+ hidden: false,
21
+ likesIds: [
22
+ {likes: true, userId: admin._id},
23
+ {likes: false, userId: notAdmin._id},
24
+ ],
25
+ name: "Spinach",
26
+ ownerId: admin._id,
27
+ source: {
28
+ name: "Brand",
29
+ },
30
+ }),
31
+ ]);
32
+ });
33
+
34
+ it("unpopulate", async () => {
35
+ let populated = await spinach.populate("ownerId");
36
+ populated = await populated.populate("eatenBy");
37
+ populated = await populated.populate("likesIds.userId");
38
+ expect(populated.ownerId.name).toBe("Admin");
39
+ expect(populated.eatenBy[0].id).toBe(admin.id);
40
+ expect(populated.eatenBy[0].name).toBe("Admin");
41
+ expect(populated.likesIds[0].userId.id).toBe(admin.id);
42
+ expect(populated.likesIds[0].userId.name).toBe("Admin");
43
+ expect(populated.likesIds[1].userId.id).toBe(notAdmin.id);
44
+ expect(populated.likesIds[1].userId.name).toBe("Not Admin");
45
+
46
+ let unpopulated: any = unpopulate(populated, "ownerId");
47
+ expect(spinach.ownerId.name).toBeUndefined();
48
+ expect(unpopulated.ownerId.toString()).toBe(admin.id);
49
+ // Ensure nothing else was touched.
50
+ expect(populated.likesIds[0].userId.id).toBe(admin.id);
51
+ expect(populated.likesIds[0].userId.name).toBe("Admin");
52
+ expect(populated.likesIds[1].userId.id).toBe(notAdmin.id);
53
+ expect(populated.likesIds[1].userId.name).toBe("Not Admin");
54
+
55
+ unpopulated = unpopulate(populated, "eatenBy");
56
+ expect(populated.eatenBy.toString()).toBe(admin.id);
57
+ expect(populated.eatenBy[0]?.name).toBeUndefined();
58
+
59
+ unpopulated = unpopulate(populated, "likesIds.userId");
60
+ expect(populated.likesIds[0].userId.toString()).toBe(admin.id);
61
+ expect(populated.likesIds[0].userId?.name).toBeUndefined();
62
+ expect(populated.likesIds[1].userId.toString()).toBe(notAdmin.id);
63
+ expect(populated.likesIds[1].userId.name).toBeUndefined();
64
+ });
65
+ });
@@ -0,0 +1,258 @@
1
+ import isArray from "lodash/isArray";
2
+ import type {Document} from "mongoose";
3
+ import m2s from "mongoose-to-swagger";
4
+
5
+ import {APIError} from "./errors";
6
+
7
+ const m2sOptions = {
8
+ props: ["readOnly", "required", "enum", "default"],
9
+ };
10
+
11
+ export type PopulatePath = {
12
+ // Mongoose style path population.
13
+ // "ownerId" // populates the User that matches `ownerId`
14
+ // "ownerId.organizationId" Nested. Populates the User that matches `ownerId`, as well as their organization.
15
+ path: string;
16
+ // If provided, type generation will use the already registered component.
17
+ // If not provided and path is provided, will use the path and optionally fields to
18
+ // automatically generate the types. If only generatePathFields is provided, the type will be
19
+ // any.
20
+ openApiComponent?: any;
21
+ // An array of strings to filter on the populated objects, following Mongoose's select
22
+ // rules. If each field starts a preceding "-", will act as a block list and only remove those
23
+ // fields. If each field does not start with a "-", will act as an allow list and only
24
+ // return those fields.
25
+ fields?: string[];
26
+ };
27
+
28
+ // This function filters an object to only include specified keys.
29
+ // It supports nested keys using dot notation (e.g., 'user.name').
30
+ // If no keys are provided, it returns the original object.
31
+ // The function recursively traverses the object structure to handle nested properties.
32
+ const filterKeys = (obj: Record<string, any>, keysToKeep?: string[]): Record<string, any> => {
33
+ if (!keysToKeep) {
34
+ return obj;
35
+ }
36
+
37
+ const result: Record<string, any> = {};
38
+
39
+ const filterNestedKeys = (
40
+ currentObj: Record<string, any>,
41
+ currentResult: Record<string, any>,
42
+ remainingKeys: string[]
43
+ ) => {
44
+ const currentKey = remainingKeys[0];
45
+ const nestedKeys = currentKey.split(".");
46
+
47
+ if (nestedKeys.length > 1) {
48
+ const [firstKey, ...rest] = nestedKeys;
49
+ if (firstKey === "__proto__" || firstKey === "constructor" || firstKey === "prototype") {
50
+ return;
51
+ }
52
+ if (!currentResult[firstKey]) {
53
+ currentResult[firstKey] = {};
54
+ }
55
+ filterNestedKeys(currentObj[firstKey], currentResult[firstKey], [
56
+ rest.join("."),
57
+ ...remainingKeys.slice(1),
58
+ ]);
59
+ } else {
60
+ // biome-ignore lint/suspicious/noPrototypeBuiltins: we need to use the prototype to check if the object has the property
61
+ if (Object.prototype.hasOwnProperty.call(currentObj, currentKey)) {
62
+ currentResult[currentKey] = currentObj[currentKey];
63
+ }
64
+ if (remainingKeys.length > 1) {
65
+ filterNestedKeys(currentObj, currentResult, remainingKeys.slice(1));
66
+ }
67
+ }
68
+ };
69
+
70
+ filterNestedKeys(obj, result, keysToKeep);
71
+ return result;
72
+ };
73
+
74
+ // Helper function to get the path in the OpenAPI schema, so we can swap out the type for the
75
+ // populated model component or generated type.
76
+ function getPathInSchema(schema: any, path: string): string {
77
+ const keys = path.split(".");
78
+ let currentSchema = schema;
79
+ let fullPath = "";
80
+
81
+ for (let i = 0; i < keys.length; i++) {
82
+ const key = keys[i];
83
+
84
+ if (currentSchema.properties?.[key]) {
85
+ fullPath += fullPath ? `.${key}` : key;
86
+ currentSchema = currentSchema.properties[key];
87
+
88
+ // If it's an array, add 'items' to the path
89
+ if (currentSchema.type === "array" && currentSchema.items) {
90
+ fullPath += ".items";
91
+ currentSchema = currentSchema.items;
92
+ }
93
+ } else if (i === keys.length - 1 && currentSchema.type === "array") {
94
+ // If we're at the last key and it's an array, we don't need to add anything
95
+ break;
96
+ } else {
97
+ throw new Error(`Path ${path} not found in schema at key ${key}`);
98
+ }
99
+ }
100
+
101
+ return fullPath;
102
+ }
103
+
104
+ // Replaces populated properties with the populated schema.
105
+ export function getOpenApiSpecForModel(
106
+ model: any,
107
+ {
108
+ populatePaths,
109
+ extraModelProperties,
110
+ }: {populatePaths?: PopulatePath[]; extraModelProperties?: any} = {}
111
+ ): {properties: any; required: string[]} {
112
+ const modelSwagger = m2s(model, {
113
+ props: ["required", "enum"],
114
+ });
115
+
116
+ if (populatePaths && isArray(populatePaths)) {
117
+ for (const populatePath of populatePaths) {
118
+ // Get the referenced populate model from the model schema
119
+ let populateModel = model.schema.path(populatePath.path)?.options?.ref;
120
+ const populatePathIsArray = Array.isArray(model.schema.path(populatePath.path).options.type);
121
+ if (populatePathIsArray) {
122
+ populateModel = model.schema.path(populatePath.path).options.type[0].ref;
123
+ }
124
+ if (!populateModel) {
125
+ continue;
126
+ }
127
+
128
+ // Get the properties of the referenced model
129
+ const properties = filterKeys(
130
+ m2s(model.db.model(populateModel), m2sOptions).properties,
131
+ populatePath.fields
132
+ );
133
+
134
+ // Get the OpenAPI path for the current populate path
135
+ const openApiPath = getPathInSchema(modelSwagger, populatePath.path);
136
+
137
+ // Determine the schema to set
138
+ let schemaToSet;
139
+ if (populatePath.openApiComponent) {
140
+ schemaToSet = {
141
+ $ref: `#/components/schemas/${populatePath.openApiComponent}`,
142
+ };
143
+ } else {
144
+ schemaToSet = {
145
+ properties,
146
+ type: "object",
147
+ };
148
+ }
149
+
150
+ // Navigate through the nested structure and set the schema
151
+ const pathParts = openApiPath.split(".");
152
+ let currentSchema = modelSwagger.properties;
153
+ for (let i = 0; i < pathParts.length; i++) {
154
+ const part = pathParts[i];
155
+ if (i === pathParts.length - 1) {
156
+ // We're at the last part, merge the schema
157
+ if (currentSchema[part]?.properties) {
158
+ currentSchema[part].properties = {
159
+ ...currentSchema[part].properties,
160
+ ...(schemaToSet.properties || {[part]: schemaToSet}),
161
+ };
162
+ } else {
163
+ currentSchema[part] = schemaToSet;
164
+ }
165
+ } else {
166
+ // We're still navigating, ensure the path exists
167
+ if (!currentSchema[part]) {
168
+ currentSchema[part] = {};
169
+ }
170
+ if (part === "items" && i < pathParts.length - 1) {
171
+ // If we're at 'items' and it's not the last part, it should be an object
172
+ if (!currentSchema[part].properties) {
173
+ currentSchema[part] = {properties: {}, type: "object"};
174
+ }
175
+ }
176
+ currentSchema = currentSchema[part].properties || currentSchema[part];
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ // Add virtuals to the modelSwagger property
183
+ for (const virtual of Object.keys(model.schema.virtuals)) {
184
+ // Skip Mongoose internals
185
+ if (virtual === "id" || virtual === "__v") {
186
+ continue;
187
+ }
188
+ modelSwagger.properties[virtual] = {
189
+ type: "any",
190
+ };
191
+ }
192
+
193
+ // Check subschemas for virtuals (one level deep)
194
+ if (model.schema.childSchemas.length > 0) {
195
+ for (const childSchema of model.schema.childSchemas) {
196
+ for (const virtual of Object.keys(childSchema.schema.virtuals)) {
197
+ if (virtual === "id" || virtual === "__v") {
198
+ continue;
199
+ }
200
+ modelSwagger.properties[childSchema.model.path].properties[virtual] = {
201
+ type: "any",
202
+ };
203
+ }
204
+ }
205
+ }
206
+
207
+ return {
208
+ properties: {...modelSwagger.properties, ...extraModelProperties},
209
+ required: modelSwagger.required ?? [],
210
+ };
211
+ }
212
+
213
+ // Helper function to unpopulate a document that has been populated.
214
+ // This is helpful for supporting backwards compatibility. E.g. you use populatePaths
215
+ // to populate a document but if the version header for the request is below the version
216
+ // that the populatePath was added, we remove the population and just return the _id.
217
+ export function unpopulate<T>(doc: Document<T>, path: string): Document<T> {
218
+ if (!path) {
219
+ throw new APIError({status: 500, title: "path is required for unpopulate"});
220
+ }
221
+ const pathParts = path.split(".");
222
+
223
+ // Recursive because we need to support nested paths.
224
+ const recursiveUnpopulate = (current: any, parts: string[]): any => {
225
+ const part = parts[0];
226
+
227
+ // If the path doesn't exist, return the original doc
228
+ if (!current[part]) {
229
+ return doc;
230
+ }
231
+
232
+ if (parts.length === 1) {
233
+ // Base case: we've reached the last part of the path
234
+ if (Array.isArray(current[part])) {
235
+ // If the field is an array, recursively unpopulate each element
236
+ current[part] = current[part].map((item: any) => {
237
+ return item?._id ? item._id : item;
238
+ });
239
+ } else if (current[part]?._id) {
240
+ // If the field is a populated document, revert to _id
241
+ current[part] = current[part]._id;
242
+ }
243
+ } else {
244
+ // Recursive case: continue down the path
245
+ if (Array.isArray(current[part])) {
246
+ for (const item of current[part]) {
247
+ recursiveUnpopulate(item, parts.slice(1)); // Recursively handle each item in the array
248
+ }
249
+ } else {
250
+ recursiveUnpopulate(current[part], parts.slice(1)); // Recursively handle the next part
251
+ }
252
+ }
253
+
254
+ return current;
255
+ };
256
+
257
+ return recursiveUnpopulate(doc, pathParts);
258
+ }
File without changes
@@ -0,0 +1,234 @@
1
+ import {afterAll, afterEach, beforeAll, beforeEach, mock} from "bun:test";
2
+ import {Writable} from "node:stream";
3
+ import mongoose from "mongoose";
4
+ import winston from "winston";
5
+
6
+ import {setupEnvironment} from "../expressServer";
7
+ import {logger, winstonLogger} from "../logger";
8
+
9
+ // Connect to MongoDB once for all tests
10
+ beforeAll(async () => {
11
+ await mongoose
12
+ .connect("mongodb://127.0.0.1/terreno?&connectTimeoutMS=360000")
13
+ .catch(logger.catch);
14
+ });
15
+
16
+ // Close MongoDB connection after all tests
17
+ afterAll(async () => {
18
+ await mongoose.connection.close();
19
+ });
20
+
21
+ let logs: string[] = [];
22
+
23
+ const SHOW_ALL_LOGS = process.env.SHOW_ALL_TEST_LOGS === "true";
24
+
25
+ // Create a custom stream that captures logs
26
+ const logStream = new Writable({
27
+ write(chunk: any, _encoding: any, callback: any) {
28
+ logs.push(chunk.toString());
29
+ if (SHOW_ALL_LOGS) {
30
+ process.stdout.write(chunk);
31
+ }
32
+ callback();
33
+ },
34
+ });
35
+
36
+ // Silence both winston loggers by replacing all transports with our capturing stream
37
+ const silentTransport = new winston.transports.Stream({
38
+ format: winston.format.simple(),
39
+ stream: logStream,
40
+ });
41
+
42
+ // Clear and silence the default winston logger
43
+ winston.clear();
44
+ winston.add(silentTransport);
45
+
46
+ // Clear and silence the custom winstonLogger
47
+ winstonLogger.clear();
48
+ winstonLogger.add(silentTransport);
49
+
50
+ // Capture and silence console methods
51
+ const originalConsole = {
52
+ debug: console.debug,
53
+ error: console.error,
54
+ info: console.info,
55
+ // biome-ignore lint/suspicious/noConsole: We keep the original reference.
56
+ log: console.log,
57
+ warn: console.warn,
58
+ };
59
+
60
+ const captureConsoleMethod = (method: keyof typeof originalConsole): void => {
61
+ (console as any)[method] = (...args: any[]) => {
62
+ const logMessage = `[console.${method}] ${args.map((arg) => (typeof arg === "object" ? JSON.stringify(arg) : String(arg))).join(" ")}`;
63
+ logs.push(logMessage);
64
+ if (SHOW_ALL_LOGS) {
65
+ originalConsole[method](...args);
66
+ }
67
+ };
68
+ };
69
+
70
+ captureConsoleMethod("log");
71
+ captureConsoleMethod("info");
72
+ captureConsoleMethod("warn");
73
+ captureConsoleMethod("error");
74
+ captureConsoleMethod("debug");
75
+
76
+ // Setup before each test
77
+ beforeEach(() => {
78
+ process.env.TOKEN_SECRET = "secret";
79
+ process.env.TOKEN_ISSUER = "terreno-api.test";
80
+ process.env.SESSION_SECRET = "sessionSecret";
81
+ process.env.REFRESH_TOKEN_SECRET = "refreshTokenSecret";
82
+ setupEnvironment();
83
+ // Re-silence loggers after setupEnvironment which may reconfigure them
84
+ winston.clear();
85
+ winston.add(silentTransport);
86
+ winstonLogger.clear();
87
+ winstonLogger.add(silentTransport);
88
+ logs = [];
89
+ });
90
+
91
+ // Clear logs after each test
92
+ afterEach(() => {
93
+ logs = [];
94
+ });
95
+
96
+ // Mock @sentry/node module
97
+ mock.module("@sentry/node", () => {
98
+ const mockFn = (): ReturnType<typeof mock> => mock(() => {});
99
+
100
+ // Mock Scope
101
+ const mockScope = {
102
+ addBreadcrumb: mockFn(),
103
+ clear: mockFn(),
104
+ getSpan: mockFn(),
105
+ setContext: mockFn(),
106
+ setFingerprint: mockFn(),
107
+ setLevel: mockFn(),
108
+ setSpan: mockFn(),
109
+ setTag: mockFn(),
110
+ setTags: mockFn(),
111
+ setTransactionName: mockFn(),
112
+ setUser: mockFn(),
113
+ };
114
+
115
+ // Mock Hub
116
+ const mockClient = {
117
+ captureException: mockFn(),
118
+ captureMessage: mockFn(),
119
+ close: mock(() => Promise.resolve(true)),
120
+ flush: mock(() => Promise.resolve(true)),
121
+ getOptions: mock(() => ({})),
122
+ };
123
+
124
+ const mockHub = {
125
+ addBreadcrumb: mockFn(),
126
+ captureException: mockFn(),
127
+ captureMessage: mockFn(),
128
+ configureScope: mockFn(),
129
+ getClient: mock(() => mockClient),
130
+ getScope: mock(() => mockScope),
131
+ popScope: mockFn(),
132
+ pushScope: mockFn(),
133
+ setContext: mockFn(),
134
+ setTag: mockFn(),
135
+ setTags: mockFn(),
136
+ setUser: mockFn(),
137
+ withScope: mockFn(),
138
+ };
139
+
140
+ const mockSpan: any = {
141
+ finish: mockFn(),
142
+ setData: mockFn(),
143
+ setStatus: mockFn(),
144
+ setTag: mockFn(),
145
+ startChild: mockFn(),
146
+ toTraceparent: mock(() => "mock-trace-parent"),
147
+ };
148
+ mockSpan.startChild = mock(() => mockSpan);
149
+
150
+ const mockTransaction = {
151
+ finish: mockFn(),
152
+ setData: mockFn(),
153
+ setName: mockFn(),
154
+ setStatus: mockFn(),
155
+ setTag: mockFn(),
156
+ startChild: mock(() => mockSpan),
157
+ toTraceparent: mock(() => "mock-trace-parent"),
158
+ };
159
+
160
+ return {
161
+ addBreadcrumb: mockFn(),
162
+ captureException: mockFn(),
163
+ captureMessage: mockFn(),
164
+ clearScope: mockFn(),
165
+ close: mock(() => Promise.resolve(true)),
166
+ configureScope: mockFn(),
167
+ default: {
168
+ addBreadcrumb: mockFn(),
169
+ captureException: mockFn(),
170
+ captureMessage: mockFn(),
171
+ clearScope: mockFn(),
172
+ close: mock(() => Promise.resolve(true)),
173
+ configureScope: mockFn(),
174
+ flush: mock(() => Promise.resolve(true)),
175
+ getClient: mock(() => mockClient),
176
+ getCurrentHub: mock(() => mockHub),
177
+ getCurrentScope: mock(() => mockScope),
178
+ Handlers: {
179
+ errorHandler: mock(() => (err: any, _req: any, _res: any, next: any) => next(err)),
180
+ requestHandler: mock(() => (_req: any, _res: any, next: any) => next()),
181
+ tracingHandler: mock(() => (_req: any, _res: any, next: any) => next()),
182
+ },
183
+ init: mockFn(),
184
+ isInitialized: mock(() => true),
185
+ popScope: mockFn(),
186
+ pushScope: mockFn(),
187
+ Severity: {
188
+ Debug: "debug",
189
+ Error: "error",
190
+ Fatal: "fatal",
191
+ Info: "info",
192
+ Warning: "warning",
193
+ } as const,
194
+ setContext: mockFn(),
195
+ setFingerprint: mockFn(),
196
+ setLevel: mockFn(),
197
+ setTag: mockFn(),
198
+ setTags: mockFn(),
199
+ setUser: mockFn(),
200
+ setupExpressErrorHandler: mockFn(),
201
+ startTransaction: mock(() => mockTransaction),
202
+ withScope: mock((callback: any) => callback(mockScope)),
203
+ },
204
+ flush: mock(() => Promise.resolve(true)),
205
+ getClient: mock(() => mockClient),
206
+ getCurrentHub: mock(() => mockHub),
207
+ getCurrentScope: mock(() => mockScope),
208
+ Handlers: {
209
+ errorHandler: mock(() => (err: any, _req: any, _res: any, next: any) => next(err)),
210
+ requestHandler: mock(() => (_req: any, _res: any, next: any) => next()),
211
+ tracingHandler: mock(() => (_req: any, _res: any, next: any) => next()),
212
+ },
213
+ init: mockFn(),
214
+ isInitialized: mock(() => true),
215
+ popScope: mockFn(),
216
+ pushScope: mockFn(),
217
+ Severity: {
218
+ Debug: "debug",
219
+ Error: "error",
220
+ Fatal: "fatal",
221
+ Info: "info",
222
+ Warning: "warning",
223
+ } as const,
224
+ setContext: mockFn(),
225
+ setFingerprint: mockFn(),
226
+ setLevel: mockFn(),
227
+ setTag: mockFn(),
228
+ setTags: mockFn(),
229
+ setUser: mockFn(),
230
+ setupExpressErrorHandler: mockFn(),
231
+ startTransaction: mock(() => mockTransaction),
232
+ withScope: mock((callback: any) => callback(mockScope)),
233
+ };
234
+ });
@@ -0,0 +1 @@
1
+ export * from "./bunSetup";