fastify-txstate 3.2.5 → 3.2.7
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/lib/error.d.ts +6 -0
- package/lib/error.js +6 -1
- package/lib/index.js +28 -21
- package/lib/unified-auth.d.ts +2 -1
- package/lib/unified-auth.js +8 -1
- package/package.json +2 -2
package/lib/error.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FastifySchemaValidationError } from 'fastify/types/schema';
|
|
1
2
|
export declare class HttpError extends Error {
|
|
2
3
|
statusCode: number;
|
|
3
4
|
constructor(statusCode: number, message?: string);
|
|
@@ -7,4 +8,9 @@ export declare class FailedValidationError extends HttpError {
|
|
|
7
8
|
errors: ValidationErrors;
|
|
8
9
|
constructor(errors: ValidationErrors);
|
|
9
10
|
}
|
|
11
|
+
export declare function fstValidationToMessage(v: FastifySchemaValidationError): {
|
|
12
|
+
message: string | undefined;
|
|
13
|
+
path: string;
|
|
14
|
+
type: string;
|
|
15
|
+
};
|
|
10
16
|
export {};
|
package/lib/error.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FailedValidationError = exports.HttpError = void 0;
|
|
3
|
+
exports.fstValidationToMessage = exports.FailedValidationError = exports.HttpError = void 0;
|
|
4
4
|
const http_status_codes_1 = require("http-status-codes");
|
|
5
5
|
class HttpError extends Error {
|
|
6
6
|
constructor(statusCode, message) {
|
|
@@ -24,3 +24,8 @@ class FailedValidationError extends HttpError {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
exports.FailedValidationError = FailedValidationError;
|
|
27
|
+
function fstValidationToMessage(v) {
|
|
28
|
+
const instancePath = v.keyword === 'required' ? v.instancePath + '/' + v.params.missingProperty : v.instancePath;
|
|
29
|
+
return { message: v.message, path: instancePath.substring(1).replace(/\//g, '.'), type: 'error' };
|
|
30
|
+
}
|
|
31
|
+
exports.fstValidationToMessage = fstValidationToMessage;
|
package/lib/index.js
CHANGED
|
@@ -20,6 +20,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
20
20
|
exports.prodLogger = exports.devLogger = void 0;
|
|
21
21
|
const swagger_1 = __importDefault(require("@fastify/swagger"));
|
|
22
22
|
const swagger_ui_1 = __importDefault(require("@fastify/swagger-ui"));
|
|
23
|
+
const fastify_shared_1 = require("@txstate-mws/fastify-shared");
|
|
23
24
|
const ajv_errors_1 = __importDefault(require("ajv-errors"));
|
|
24
25
|
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
25
26
|
const fastify_1 = require("fastify");
|
|
@@ -108,25 +109,10 @@ class Server {
|
|
|
108
109
|
if (!((_a = route.schema) === null || _a === void 0 ? void 0 : _a.body))
|
|
109
110
|
return;
|
|
110
111
|
const missingResponse = ((_b = route.schema) === null || _b === void 0 ? void 0 : _b.response) == null;
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
errors: {
|
|
116
|
-
type: 'array',
|
|
117
|
-
items: {
|
|
118
|
-
type: 'object',
|
|
119
|
-
properties: {
|
|
120
|
-
type: { type: 'string', enum: ['error', 'warning', 'success', 'system'], example: 'error' },
|
|
121
|
-
message: { type: 'string', example: 'must be an integer' },
|
|
122
|
-
path: { type: 'string', example: 'cart.item.0.quantity', description: 'Dot-separated path to the field in the request body that caused the validation error.' }
|
|
123
|
-
},
|
|
124
|
-
required: ['type', 'message'],
|
|
125
|
-
additionalProperties: false
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
|
112
|
+
const response400 = (0, txstate_utils_1.set)(fastify_shared_1.validatedResponse.properties.messages, 'description', 'Basic validation failure. This means that the UI provided input that failed validation as defined in the openapi specification published by the API. The UI is at fault and should be re-coded to avoid sending invalid data.');
|
|
113
|
+
let newSchema = (0, txstate_utils_1.set)((_c = route.schema) !== null && _c !== void 0 ? _c : {}, 'response.400', response400);
|
|
114
|
+
const response422 = (0, txstate_utils_1.set)(fastify_shared_1.validatedResponse, 'description', 'Validation failure. This means that the user provided an invalid object. The user should be shown their error so that they can correct it.');
|
|
115
|
+
newSchema = (0, txstate_utils_1.set)(newSchema, 'response.422', response422);
|
|
130
116
|
if (missingResponse) {
|
|
131
117
|
newSchema.response['200'] = {
|
|
132
118
|
description: 'Success. Return type has not been specified.',
|
|
@@ -213,7 +199,7 @@ class Server {
|
|
|
213
199
|
});
|
|
214
200
|
this.app.setNotFoundHandler((req, res) => { void res.status(404).send('Not Found.'); });
|
|
215
201
|
this.app.setErrorHandler(async (err, req, res) => {
|
|
216
|
-
var _a
|
|
202
|
+
var _a;
|
|
217
203
|
req.log.warn(err);
|
|
218
204
|
for (const errorHandler of this.errorHandlers) {
|
|
219
205
|
if (!res.sent)
|
|
@@ -227,7 +213,28 @@ class Server {
|
|
|
227
213
|
await res.status(err.statusCode).send(err.message);
|
|
228
214
|
}
|
|
229
215
|
else if (err.code === 'FST_ERR_VALIDATION') {
|
|
230
|
-
|
|
216
|
+
const developerErrors = [];
|
|
217
|
+
const userErrors = [];
|
|
218
|
+
for (const v of (_a = err.validation) !== null && _a !== void 0 ? _a : []) {
|
|
219
|
+
if (v.keyword === 'errorMessage') {
|
|
220
|
+
for (const ov of v.params.errors) {
|
|
221
|
+
if (['type', 'additionalProperties'].includes(ov.keyword))
|
|
222
|
+
developerErrors.push({ ...ov, message: v.message });
|
|
223
|
+
else
|
|
224
|
+
userErrors.push({ ...ov, message: v.message });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
if (['type', 'additionalProperties'].includes(v.keyword))
|
|
229
|
+
developerErrors.push(v);
|
|
230
|
+
else
|
|
231
|
+
userErrors.push(v);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (userErrors.length)
|
|
235
|
+
await res.status(422).send({ success: false, messages: userErrors.map(error_1.fstValidationToMessage) });
|
|
236
|
+
else
|
|
237
|
+
await res.status(400).send(developerErrors.map(error_1.fstValidationToMessage));
|
|
231
238
|
}
|
|
232
239
|
else if (err.statusCode) {
|
|
233
240
|
await res.status(err.statusCode).send(new error_1.HttpError(err.statusCode).message);
|
package/lib/unified-auth.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ declare class Context<AuthType extends FastifyTxStateAuthInfo = FastifyTxStateAu
|
|
|
29
29
|
}>;
|
|
30
30
|
constructor(req?: FastifyRequest);
|
|
31
31
|
waitForAuth(): Promise<AuthType | undefined>;
|
|
32
|
+
protected static hasInitialized: boolean;
|
|
32
33
|
static init(): void;
|
|
33
34
|
/**
|
|
34
35
|
* If implemented, this method will be called on startup, once per configured issuer. It receives
|
|
@@ -58,5 +59,5 @@ declare class TxStateUAuthContext extends Context {
|
|
|
58
59
|
authFromPayload(payload: JWTPayload): Promise<FastifyTxStateAuthInfo>;
|
|
59
60
|
}
|
|
60
61
|
export declare function unifiedAuthenticate(req: FastifyRequest, ContextClass?: typeof TxStateUAuthContext): Promise<FastifyTxStateAuthInfo | undefined>;
|
|
61
|
-
export declare function unifiedAuthenticateAll(req: FastifyRequest, ContextClass?: typeof TxStateUAuthContext): Promise<FastifyTxStateAuthInfo>;
|
|
62
|
+
export declare function unifiedAuthenticateAll(req: FastifyRequest, ContextClass?: typeof TxStateUAuthContext): Promise<FastifyTxStateAuthInfo | undefined>;
|
|
62
63
|
export {};
|
package/lib/unified-auth.js
CHANGED
|
@@ -28,6 +28,9 @@ class Context extends MockContext {
|
|
|
28
28
|
}
|
|
29
29
|
static init() {
|
|
30
30
|
var _b;
|
|
31
|
+
if (this.hasInitialized)
|
|
32
|
+
return;
|
|
33
|
+
this.hasInitialized = true;
|
|
31
34
|
let secret = cleanPem(process.env.JWT_SECRET_VERIFY);
|
|
32
35
|
if (secret != null) {
|
|
33
36
|
_a.jwtVerifyKey = (0, crypto_1.createPublicKey)(secret);
|
|
@@ -102,6 +105,7 @@ Context.tokenCache = new txstate_utils_1.Cache(async (token, { req, ctx }) => {
|
|
|
102
105
|
return undefined;
|
|
103
106
|
}
|
|
104
107
|
}, { freshseconds: 10 });
|
|
108
|
+
Context.hasInitialized = false;
|
|
105
109
|
class TxStateUAuthContext extends Context {
|
|
106
110
|
static processIssuerConfig(config) {
|
|
107
111
|
var _b;
|
|
@@ -132,14 +136,17 @@ class TxStateUAuthContext extends Context {
|
|
|
132
136
|
}
|
|
133
137
|
}
|
|
134
138
|
async function unifiedAuthenticate(req, ContextClass = TxStateUAuthContext) {
|
|
139
|
+
ContextClass.init();
|
|
135
140
|
const ctx = new ContextClass(req);
|
|
136
141
|
return ctx.waitForAuth();
|
|
137
142
|
}
|
|
138
143
|
exports.unifiedAuthenticate = unifiedAuthenticate;
|
|
139
144
|
async function unifiedAuthenticateAll(req, ContextClass = TxStateUAuthContext) {
|
|
145
|
+
var _b;
|
|
146
|
+
ContextClass.init();
|
|
140
147
|
const ctx = new ContextClass(req);
|
|
141
148
|
const auth = await ctx.waitForAuth();
|
|
142
|
-
if (!(auth === null || auth === void 0 ? void 0 : auth.username.length))
|
|
149
|
+
if (!(auth === null || auth === void 0 ? void 0 : auth.username.length) && !((_b = req.routeOptions.url) === null || _b === void 0 ? void 0 : _b.startsWith('/docs')))
|
|
143
150
|
throw new Error('All requests require authentication.');
|
|
144
151
|
return auth;
|
|
145
152
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify-txstate",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.7",
|
|
4
4
|
"description": "A small wrapper for fastify providing a set of common conventions & utility functions we use.",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@fastify/swagger": "^8.14.0",
|
|
23
23
|
"@fastify/swagger-ui": "^3.0.0",
|
|
24
24
|
"@fastify/type-provider-json-schema-to-ts": "^3.0.0",
|
|
25
|
-
"@txstate-mws/fastify-shared": "^1.0.
|
|
25
|
+
"@txstate-mws/fastify-shared": "^1.0.9",
|
|
26
26
|
"ajv-errors": "^3.0.0",
|
|
27
27
|
"ajv-formats": "^2.1.1",
|
|
28
28
|
"fastify": "^4.9.2",
|