@terreno/api 0.11.6 → 0.11.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/configurationPlugin.d.ts +2 -1
- package/dist/configurationPlugin.js +16 -9
- package/dist/errors.d.ts +6 -6
- package/dist/errors.js +22 -22
- package/dist/errors.test.d.ts +1 -0
- package/dist/errors.test.js +280 -0
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +4 -3
- package/dist/notifiers/zoomNotifier.js +12 -11
- package/dist/openApiCompat.js +2 -1
- package/dist/openApiEtag.d.ts +1 -1
- package/dist/openApiEtag.js +4 -3
- package/dist/openApiValidator.d.ts +12 -12
- package/dist/openApiValidator.js +59 -58
- package/dist/plugins.test.js +22 -0
- package/dist/scriptRunner.d.ts +8 -7
- package/dist/secretProviders.js +17 -7
- package/package.json +1 -1
- package/src/configurationPlugin.ts +18 -9
- package/src/errors.test.ts +302 -0
- package/src/errors.ts +18 -13
- package/src/middleware.ts +6 -2
- package/src/notifiers/zoomNotifier.ts +4 -3
- package/src/openApiCompat.ts +2 -1
- package/src/openApiEtag.ts +2 -2
- package/src/openApiValidator.ts +46 -46
- package/src/plugins.test.ts +29 -0
- package/src/scriptRunner.ts +23 -27
- package/src/secretProviders.ts +27 -9
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import {beforeEach, describe, expect, it, mock} from "bun:test";
|
|
2
|
+
import * as Sentry from "@sentry/bun";
|
|
3
|
+
import type {NextFunction, Request, Response} from "express";
|
|
4
|
+
import {Schema} from "mongoose";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
APIError,
|
|
8
|
+
apiErrorMiddleware,
|
|
9
|
+
apiUnauthorizedMiddleware,
|
|
10
|
+
errorsPlugin,
|
|
11
|
+
getAPIErrorBody,
|
|
12
|
+
getDisableExternalErrorTracking,
|
|
13
|
+
isAPIError,
|
|
14
|
+
} from "./errors";
|
|
15
|
+
|
|
16
|
+
interface MockResponse {
|
|
17
|
+
status: ReturnType<typeof mock>;
|
|
18
|
+
json: ReturnType<typeof mock>;
|
|
19
|
+
send: ReturnType<typeof mock>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const buildResponse = (): MockResponse => {
|
|
23
|
+
const res: MockResponse = {
|
|
24
|
+
json: mock(() => res),
|
|
25
|
+
send: mock(() => res),
|
|
26
|
+
status: mock(() => res),
|
|
27
|
+
};
|
|
28
|
+
return res;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
describe("APIError", () => {
|
|
32
|
+
it("creates an error with the provided fields", () => {
|
|
33
|
+
const error = new APIError({
|
|
34
|
+
code: "validation-failed",
|
|
35
|
+
detail: "Email is invalid",
|
|
36
|
+
id: "abc-123",
|
|
37
|
+
links: {about: "https://example.com/help", type: "https://example.com/types/validation"},
|
|
38
|
+
meta: {requestId: "req-1"},
|
|
39
|
+
source: {header: "x-foo", parameter: "limit", pointer: "/data/email"},
|
|
40
|
+
status: 400,
|
|
41
|
+
title: "Validation failed",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(error).toBeInstanceOf(Error);
|
|
45
|
+
expect(error.name).toBe("APIError");
|
|
46
|
+
expect(error.title).toBe("Validation failed");
|
|
47
|
+
expect(error.detail).toBe("Email is invalid");
|
|
48
|
+
expect(error.code).toBe("validation-failed");
|
|
49
|
+
expect(error.status).toBe(400);
|
|
50
|
+
expect(error.id).toBe("abc-123");
|
|
51
|
+
expect(error.links).toEqual({
|
|
52
|
+
about: "https://example.com/help",
|
|
53
|
+
type: "https://example.com/types/validation",
|
|
54
|
+
});
|
|
55
|
+
expect(error.source).toEqual({
|
|
56
|
+
header: "x-foo",
|
|
57
|
+
parameter: "limit",
|
|
58
|
+
pointer: "/data/email",
|
|
59
|
+
});
|
|
60
|
+
expect(error.meta).toEqual({requestId: "req-1"});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("includes the title and detail in the error message", () => {
|
|
64
|
+
const error = new APIError({detail: "Something exploded", title: "Boom"});
|
|
65
|
+
expect(error.message).toBe("Boom: Something exploded");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("includes the wrapped error stack in the message", () => {
|
|
69
|
+
const wrapped = new Error("inner");
|
|
70
|
+
const error = new APIError({error: wrapped, title: "Outer"});
|
|
71
|
+
expect(error.message).toContain("Outer");
|
|
72
|
+
expect(error.message).toContain(wrapped.stack ?? "");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("defaults status to 500 when status is omitted", () => {
|
|
76
|
+
const error = new APIError({title: "No status"});
|
|
77
|
+
expect(error.status).toBe(500);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("forces status to 500 when below 400", () => {
|
|
81
|
+
const error = new APIError({status: 200, title: "Too low"});
|
|
82
|
+
expect(error.status).toBe(500);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("forces status to 500 when above 599", () => {
|
|
86
|
+
const error = new APIError({status: 600, title: "Too high"});
|
|
87
|
+
expect(error.status).toBe(500);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("defaults meta to an empty object when not provided", () => {
|
|
91
|
+
const error = new APIError({title: "No meta"});
|
|
92
|
+
expect(error.meta).toEqual({});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("merges fields into meta", () => {
|
|
96
|
+
const error = new APIError({
|
|
97
|
+
fields: {email: "Required", name: "Required"},
|
|
98
|
+
title: "Validation",
|
|
99
|
+
});
|
|
100
|
+
expect(error.meta?.fields).toEqual({email: "Required", name: "Required"});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("respects disableExternalErrorTracking", () => {
|
|
104
|
+
const trackedError = new APIError({title: "Tracked"});
|
|
105
|
+
const untrackedError = new APIError({
|
|
106
|
+
disableExternalErrorTracking: true,
|
|
107
|
+
title: "Untracked",
|
|
108
|
+
});
|
|
109
|
+
expect(trackedError.disableExternalErrorTracking).toBeUndefined();
|
|
110
|
+
expect(untrackedError.disableExternalErrorTracking).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("isAPIError", () => {
|
|
115
|
+
it("returns true for an APIError instance", () => {
|
|
116
|
+
expect(isAPIError(new APIError({title: "Boom"}))).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("returns false for a regular Error", () => {
|
|
120
|
+
expect(isAPIError(new Error("nope"))).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("returns true for any error whose name is APIError", () => {
|
|
124
|
+
const err = new Error("custom");
|
|
125
|
+
err.name = "APIError";
|
|
126
|
+
expect(isAPIError(err)).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("getDisableExternalErrorTracking", () => {
|
|
131
|
+
it("returns the flag from an APIError", () => {
|
|
132
|
+
const error = new APIError({disableExternalErrorTracking: true, title: "Test"});
|
|
133
|
+
expect(getDisableExternalErrorTracking(error)).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("returns undefined for a plain Error without the flag", () => {
|
|
137
|
+
expect(getDisableExternalErrorTracking(new Error("plain"))).toBeUndefined();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("returns the flag when attached to a non-APIError object", () => {
|
|
141
|
+
const error = {disableExternalErrorTracking: false};
|
|
142
|
+
expect(getDisableExternalErrorTracking(error)).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("returns undefined for primitives and null", () => {
|
|
146
|
+
expect(getDisableExternalErrorTracking(null)).toBeUndefined();
|
|
147
|
+
expect(getDisableExternalErrorTracking(undefined)).toBeUndefined();
|
|
148
|
+
expect(getDisableExternalErrorTracking("string")).toBeUndefined();
|
|
149
|
+
expect(getDisableExternalErrorTracking(42)).toBeUndefined();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("returns undefined for an object missing the property", () => {
|
|
153
|
+
expect(getDisableExternalErrorTracking({foo: "bar"})).toBeUndefined();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("getAPIErrorBody", () => {
|
|
158
|
+
it("returns title and status by default", () => {
|
|
159
|
+
const error = new APIError({status: 404, title: "Not Found"});
|
|
160
|
+
const body = getAPIErrorBody(error);
|
|
161
|
+
expect(body).toEqual({meta: {}, status: 404, title: "Not Found"});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("includes optional fields when set", () => {
|
|
165
|
+
const error = new APIError({
|
|
166
|
+
code: "not-found",
|
|
167
|
+
detail: "Could not find resource",
|
|
168
|
+
disableExternalErrorTracking: true,
|
|
169
|
+
id: "err-1",
|
|
170
|
+
links: {about: "https://example.com/help"},
|
|
171
|
+
source: {pointer: "/data/id"},
|
|
172
|
+
status: 404,
|
|
173
|
+
title: "Not Found",
|
|
174
|
+
});
|
|
175
|
+
const body = getAPIErrorBody(error);
|
|
176
|
+
expect(body).toEqual({
|
|
177
|
+
code: "not-found",
|
|
178
|
+
detail: "Could not find resource",
|
|
179
|
+
disableExternalErrorTracking: true,
|
|
180
|
+
id: "err-1",
|
|
181
|
+
links: {about: "https://example.com/help"},
|
|
182
|
+
meta: {},
|
|
183
|
+
source: {pointer: "/data/id"},
|
|
184
|
+
status: 404,
|
|
185
|
+
title: "Not Found",
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("omits empty meta and unset optional fields", () => {
|
|
190
|
+
const error = new APIError({status: 400, title: "Bad"});
|
|
191
|
+
// meta defaults to {} which is truthy, so it is included.
|
|
192
|
+
const body = getAPIErrorBody(error);
|
|
193
|
+
expect(body.meta).toEqual({});
|
|
194
|
+
expect(body.code).toBeUndefined();
|
|
195
|
+
expect(body.detail).toBeUndefined();
|
|
196
|
+
expect(body.id).toBeUndefined();
|
|
197
|
+
expect(body.links).toBeUndefined();
|
|
198
|
+
expect(body.source).toBeUndefined();
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
describe("errorsPlugin", () => {
|
|
203
|
+
it("adds an apiErrors array field to the schema", () => {
|
|
204
|
+
const schema = new Schema({name: String});
|
|
205
|
+
errorsPlugin(schema);
|
|
206
|
+
const path = schema.path("apiErrors");
|
|
207
|
+
expect(path).toBeDefined();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("requires title on each error subdocument", () => {
|
|
211
|
+
const schema = new Schema({name: String});
|
|
212
|
+
errorsPlugin(schema);
|
|
213
|
+
const path = schema.path("apiErrors");
|
|
214
|
+
// Inspect the embedded error schema for the title definition.
|
|
215
|
+
const embedded = path as unknown as {schema: Schema};
|
|
216
|
+
const titlePath = embedded.schema.path("title");
|
|
217
|
+
expect(titlePath).toBeDefined();
|
|
218
|
+
expect(titlePath.isRequired).toBe(true);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe("apiUnauthorizedMiddleware", () => {
|
|
223
|
+
let res: MockResponse;
|
|
224
|
+
let next: ReturnType<typeof mock>;
|
|
225
|
+
const req = {} as Request;
|
|
226
|
+
|
|
227
|
+
beforeEach(() => {
|
|
228
|
+
res = buildResponse();
|
|
229
|
+
next = mock(() => {});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("returns a 401 JSON response when the message is Unauthorized", () => {
|
|
233
|
+
apiUnauthorizedMiddleware(
|
|
234
|
+
new Error("Unauthorized"),
|
|
235
|
+
req,
|
|
236
|
+
res as unknown as Response,
|
|
237
|
+
next as unknown as NextFunction
|
|
238
|
+
);
|
|
239
|
+
expect(res.status).toHaveBeenCalledWith(401);
|
|
240
|
+
expect(res.json).toHaveBeenCalledWith({status: 401, title: "Unauthorized"});
|
|
241
|
+
expect(res.send).toHaveBeenCalled();
|
|
242
|
+
expect(next).not.toHaveBeenCalled();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("forwards other errors to next", () => {
|
|
246
|
+
const err = new Error("Something else");
|
|
247
|
+
apiUnauthorizedMiddleware(
|
|
248
|
+
err,
|
|
249
|
+
req,
|
|
250
|
+
res as unknown as Response,
|
|
251
|
+
next as unknown as NextFunction
|
|
252
|
+
);
|
|
253
|
+
expect(next).toHaveBeenCalledWith(err);
|
|
254
|
+
expect(res.status).not.toHaveBeenCalled();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
describe("apiErrorMiddleware", () => {
|
|
259
|
+
let res: MockResponse;
|
|
260
|
+
let next: ReturnType<typeof mock>;
|
|
261
|
+
const req = {} as Request;
|
|
262
|
+
const captureExceptionSpy = Sentry.captureException as unknown as ReturnType<typeof mock>;
|
|
263
|
+
|
|
264
|
+
beforeEach(() => {
|
|
265
|
+
res = buildResponse();
|
|
266
|
+
next = mock(() => {});
|
|
267
|
+
captureExceptionSpy.mockClear?.();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("responds with the APIError status and body", () => {
|
|
271
|
+
const err = new APIError({detail: "missing", status: 404, title: "Not Found"});
|
|
272
|
+
apiErrorMiddleware(err, req, res as unknown as Response, next as unknown as NextFunction);
|
|
273
|
+
expect(res.status).toHaveBeenCalledWith(404);
|
|
274
|
+
expect(res.json).toHaveBeenCalledWith(getAPIErrorBody(err));
|
|
275
|
+
expect(res.send).toHaveBeenCalled();
|
|
276
|
+
expect(next).not.toHaveBeenCalled();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("captures the exception with Sentry by default", () => {
|
|
280
|
+
const err = new APIError({status: 500, title: "Boom"});
|
|
281
|
+
apiErrorMiddleware(err, req, res as unknown as Response, next as unknown as NextFunction);
|
|
282
|
+
expect(captureExceptionSpy).toHaveBeenCalledWith(err);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("does not capture the exception when disableExternalErrorTracking is true", () => {
|
|
286
|
+
const err = new APIError({
|
|
287
|
+
disableExternalErrorTracking: true,
|
|
288
|
+
status: 500,
|
|
289
|
+
title: "Quiet",
|
|
290
|
+
});
|
|
291
|
+
apiErrorMiddleware(err, req, res as unknown as Response, next as unknown as NextFunction);
|
|
292
|
+
expect(captureExceptionSpy).not.toHaveBeenCalled();
|
|
293
|
+
expect(res.status).toHaveBeenCalledWith(500);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("forwards non-APIError errors to next", () => {
|
|
297
|
+
const err = new Error("not an api error");
|
|
298
|
+
apiErrorMiddleware(err, req, res as unknown as Response, next as unknown as NextFunction);
|
|
299
|
+
expect(next).toHaveBeenCalledWith(err);
|
|
300
|
+
expect(res.status).not.toHaveBeenCalled();
|
|
301
|
+
});
|
|
302
|
+
});
|
package/src/errors.ts
CHANGED
|
@@ -137,7 +137,7 @@ export class APIError extends Error {
|
|
|
137
137
|
|
|
138
138
|
// Create an errors field for storing error information in a JSONAPI compatible form directly on a
|
|
139
139
|
// model.
|
|
140
|
-
export
|
|
140
|
+
export const errorsPlugin = (schema: Schema): void => {
|
|
141
141
|
const errorSchema = new Schema({
|
|
142
142
|
code: {description: "Application-specific error code", type: String},
|
|
143
143
|
detail: {description: "Human-readable explanation of the error", type: String},
|
|
@@ -160,18 +160,18 @@ export function errorsPlugin(schema: Schema): void {
|
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
schema.add({apiErrors: errorSchema});
|
|
163
|
-
}
|
|
163
|
+
};
|
|
164
164
|
|
|
165
|
-
export
|
|
165
|
+
export const isAPIError = (error: Error): error is APIError => {
|
|
166
166
|
return error.name === "APIError";
|
|
167
|
-
}
|
|
167
|
+
};
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
170
|
* Safely extracts the disableExternalErrorTracking property from an error.
|
|
171
171
|
* Works with both APIError instances and regular Error objects that may have
|
|
172
172
|
* this property attached.
|
|
173
173
|
*/
|
|
174
|
-
export
|
|
174
|
+
export const getDisableExternalErrorTracking = (error: unknown): boolean | undefined => {
|
|
175
175
|
if (error instanceof Error) {
|
|
176
176
|
if (isAPIError(error)) {
|
|
177
177
|
return error.disableExternalErrorTracking;
|
|
@@ -181,12 +181,12 @@ export function getDisableExternalErrorTracking(error: unknown): boolean | undef
|
|
|
181
181
|
return (error as {disableExternalErrorTracking?: boolean}).disableExternalErrorTracking;
|
|
182
182
|
}
|
|
183
183
|
return undefined;
|
|
184
|
-
}
|
|
184
|
+
};
|
|
185
185
|
|
|
186
186
|
// Creates an APIError body to send to clients as JSON. Errors don't have a toJSON defined,
|
|
187
187
|
// and we want to strip out things like message, name, and stack for the client.
|
|
188
188
|
// There is almost certainly a more elegant solution to this.
|
|
189
|
-
export
|
|
189
|
+
export const getAPIErrorBody = (error: APIError): {[id: string]: any} => {
|
|
190
190
|
const errorData = {status: error.status, title: error.title};
|
|
191
191
|
for (const key of [
|
|
192
192
|
"id",
|
|
@@ -203,23 +203,28 @@ export function getAPIErrorBody(error: APIError): {[id: string]: any} {
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
return errorData;
|
|
206
|
-
}
|
|
206
|
+
};
|
|
207
207
|
|
|
208
|
-
export
|
|
208
|
+
export const apiUnauthorizedMiddleware = (
|
|
209
209
|
err: Error,
|
|
210
210
|
_req: Request,
|
|
211
211
|
res: Response,
|
|
212
212
|
next: NextFunction
|
|
213
|
-
) {
|
|
213
|
+
) => {
|
|
214
214
|
if (err.message === "Unauthorized") {
|
|
215
215
|
// not using the actual APIError class here because we don't want to log it as an error.
|
|
216
216
|
res.status(401).json({status: 401, title: "Unauthorized"}).send();
|
|
217
217
|
} else {
|
|
218
218
|
next(err);
|
|
219
219
|
}
|
|
220
|
-
}
|
|
220
|
+
};
|
|
221
221
|
|
|
222
|
-
export
|
|
222
|
+
export const apiErrorMiddleware = (
|
|
223
|
+
err: Error,
|
|
224
|
+
_req: Request,
|
|
225
|
+
res: Response,
|
|
226
|
+
next: NextFunction
|
|
227
|
+
) => {
|
|
223
228
|
if (isAPIError(err)) {
|
|
224
229
|
if (!err.disableExternalErrorTracking) {
|
|
225
230
|
Sentry.captureException(err);
|
|
@@ -228,4 +233,4 @@ export function apiErrorMiddleware(err: Error, _req: Request, res: Response, nex
|
|
|
228
233
|
} else {
|
|
229
234
|
next(err);
|
|
230
235
|
}
|
|
231
|
-
}
|
|
236
|
+
};
|
package/src/middleware.ts
CHANGED
|
@@ -9,10 +9,14 @@ import type {NextFunction, Request, Response} from "express";
|
|
|
9
9
|
*
|
|
10
10
|
* Expected header: `App-Version`
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
12
|
+
export const sentryAppVersionMiddleware = (
|
|
13
|
+
req: Request,
|
|
14
|
+
_res: Response,
|
|
15
|
+
next: NextFunction
|
|
16
|
+
): void => {
|
|
13
17
|
const appVersion = req.get("App-Version");
|
|
14
18
|
if (appVersion) {
|
|
15
19
|
Sentry.getCurrentScope().setTag("app_version", appVersion);
|
|
16
20
|
}
|
|
17
21
|
next();
|
|
18
|
-
}
|
|
22
|
+
};
|
|
@@ -95,13 +95,14 @@ export const sendToZoom = async (
|
|
|
95
95
|
},
|
|
96
96
|
}
|
|
97
97
|
);
|
|
98
|
-
} catch (error:
|
|
99
|
-
|
|
98
|
+
} catch (error: unknown) {
|
|
99
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
100
|
+
logger.error(`Error posting to Zoom: ${errorMessage}`);
|
|
100
101
|
Sentry.captureException(error);
|
|
101
102
|
if (shouldThrow) {
|
|
102
103
|
throw new APIError({
|
|
103
104
|
status: 500,
|
|
104
|
-
title: `Error posting to Zoom: ${
|
|
105
|
+
title: `Error posting to Zoom: ${errorMessage}`,
|
|
105
106
|
});
|
|
106
107
|
}
|
|
107
108
|
}
|
package/src/openApiCompat.ts
CHANGED
|
@@ -110,7 +110,7 @@ const patchRouterStack = (stack: any[]): void => {
|
|
|
110
110
|
*/
|
|
111
111
|
export const patchAppUse = (app: any): void => {
|
|
112
112
|
const originalUse = app.use.bind(app);
|
|
113
|
-
|
|
113
|
+
const patchedUse = (...args: any[]): unknown => {
|
|
114
114
|
// Track stack length before the call
|
|
115
115
|
const router = app._router || app.router;
|
|
116
116
|
const stackBefore = router?.stack?.length ?? 0;
|
|
@@ -132,6 +132,7 @@ export const patchAppUse = (app: any): void => {
|
|
|
132
132
|
|
|
133
133
|
return result;
|
|
134
134
|
};
|
|
135
|
+
app.use = patchedUse;
|
|
135
136
|
};
|
|
136
137
|
|
|
137
138
|
/**
|
package/src/openApiEtag.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type {NextFunction, Request, Response} from "express";
|
|
|
6
6
|
* This middleware should be added before the @wesleytodd/openapi middleware
|
|
7
7
|
* to intercept requests to /openapi.json and add conditional request support.
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export const openApiEtagMiddleware = (req: Request, res: Response, next: NextFunction): void => {
|
|
10
10
|
// Only handle GET requests to /openapi.json
|
|
11
11
|
if (req.method !== "GET" || req.path !== "/openapi.json") {
|
|
12
12
|
next();
|
|
@@ -37,4 +37,4 @@ export function openApiEtagMiddleware(req: Request, res: Response, next: NextFun
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
next();
|
|
40
|
-
}
|
|
40
|
+
};
|