@devmoods/express-extras 0.72.5 → 0.73.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.
- package/dist/auth.js +4 -15
- package/dist/errors.d.ts +0 -2
- package/dist/errors.js +0 -11
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/listen.d.ts +1 -0
- package/dist/listen.js +1 -0
- package/dist/logger.d.ts +3 -9
- package/dist/logger.js +14 -26
- package/dist/vite/ssr.js +9 -1
- package/package.json +7 -10
- package/dist/sentry.d.ts +0 -5
- package/dist/sentry.js +0 -38
package/dist/auth.js
CHANGED
|
@@ -5,7 +5,7 @@ import { InvalidToken, PermissionDenied } from './auth/errors.js';
|
|
|
5
5
|
import { createAccessToken, decodeAccessToken, extractAccessTokenFromRequest, setAccessTokenCookie, tokenSchema, } from './auth/token.js';
|
|
6
6
|
import {} from './auth/types.js';
|
|
7
7
|
import { setRequestContext, useRequestContext } from './context.js';
|
|
8
|
-
import { Forbidden,
|
|
8
|
+
import { Forbidden, Unauthorized } from './errors.js';
|
|
9
9
|
import { getLogger } from './logger.js';
|
|
10
10
|
import { createRouter } from './router.js';
|
|
11
11
|
import { jsonSchema } from './validate.js';
|
|
@@ -77,29 +77,18 @@ export function createAuth({ getUserById, filterUser, tokenStorage, providers, l
|
|
|
77
77
|
const user = useCurrentUser();
|
|
78
78
|
return filterUser(user);
|
|
79
79
|
});
|
|
80
|
-
router.
|
|
80
|
+
router.post('/logout', {}, async (req, res) => {
|
|
81
81
|
await logout(req, res);
|
|
82
82
|
res.redirect(loginUrl);
|
|
83
83
|
});
|
|
84
|
-
/**
|
|
85
|
-
* Check that a reset token is valid.
|
|
86
|
-
*/
|
|
87
84
|
router.get('/reset/:token', {
|
|
88
85
|
params: jsonSchema({
|
|
89
86
|
type: 'object',
|
|
90
87
|
properties: { token: tokenSchema },
|
|
91
88
|
required: ['token'],
|
|
92
89
|
}),
|
|
93
|
-
}, async (
|
|
94
|
-
|
|
95
|
-
const value = await tokenStorage.get(token);
|
|
96
|
-
if (!value) {
|
|
97
|
-
logger.info('invalid reset token', { token });
|
|
98
|
-
throw NotFound();
|
|
99
|
-
}
|
|
100
|
-
return 200;
|
|
101
|
-
});
|
|
102
|
-
router.get('/token/refresh', {}, middleware(false), async (req, res) => {
|
|
90
|
+
}, async () => 200);
|
|
91
|
+
router.post('/token/refresh', {}, middleware(false), async (req, res) => {
|
|
103
92
|
const user = useCurrentUser();
|
|
104
93
|
if (!user) {
|
|
105
94
|
setAccessTokenCookie(res, null);
|
package/dist/errors.d.ts
CHANGED
|
@@ -35,8 +35,6 @@ export interface ErrorHandlerOptions {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Generic error handler for JSON-based apps.
|
|
38
|
-
*
|
|
39
|
-
* Composed together with the Sentry error handler.
|
|
40
38
|
*/
|
|
41
39
|
export declare function errorHandler({ onError }?: ErrorHandlerOptions): ErrorHandler<any, any, void>;
|
|
42
40
|
export {};
|
package/dist/errors.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { STATUS_CODES } from 'node:http';
|
|
2
2
|
import { DoesNotExistError, IntegrityError } from '@devmoods/postgres';
|
|
3
|
-
import * as Sentry from '@sentry/node';
|
|
4
3
|
import {} from 'express';
|
|
5
4
|
import { InvalidToken } from './auth/errors.js';
|
|
6
5
|
import { errors } from './composeMiddleware.js';
|
|
@@ -66,8 +65,6 @@ function _errorHandler({ onError }) {
|
|
|
66
65
|
}
|
|
67
66
|
/**
|
|
68
67
|
* Generic error handler for JSON-based apps.
|
|
69
|
-
*
|
|
70
|
-
* Composed together with the Sentry error handler.
|
|
71
68
|
*/
|
|
72
69
|
export function errorHandler({ onError } = {}) {
|
|
73
70
|
const logger = getLogger();
|
|
@@ -82,14 +79,6 @@ export function errorHandler({ onError } = {}) {
|
|
|
82
79
|
}
|
|
83
80
|
};
|
|
84
81
|
return errors([
|
|
85
|
-
Sentry.expressErrorHandler({
|
|
86
|
-
shouldHandleError(error) {
|
|
87
|
-
if (error instanceof ApiError && error.status < 500) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
return process.env.NODE_ENV === 'production';
|
|
91
|
-
},
|
|
92
|
-
}),
|
|
93
82
|
_errorHandler({
|
|
94
83
|
onError: onError || _defaultErrorHandler,
|
|
95
84
|
}),
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/listen.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface ExpressServerOptions {
|
|
|
14
14
|
onStart?(): Promise<void> | void;
|
|
15
15
|
onShutdown?(): Promise<void> | void;
|
|
16
16
|
beforeShutdown?(): Promise<void> | void;
|
|
17
|
+
afterShutdown?(): Promise<void> | void;
|
|
17
18
|
healthCheck?(type?: 'live' | 'ready'): Promise<unknown>;
|
|
18
19
|
gracePeriodMs?: number;
|
|
19
20
|
}
|
package/dist/listen.js
CHANGED
package/dist/logger.d.ts
CHANGED
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
import { type Writable } from 'node:stream';
|
|
2
|
+
import { type LoggerAdapter } from '@devmoods/observability';
|
|
2
3
|
export type LoggerContext = Record<string, any>;
|
|
3
|
-
export interface LoggerAdapter {
|
|
4
|
-
captureError(error: Error | null, attributes?: Record<string, any>): void;
|
|
5
|
-
write(chunk: Record<string, any>): boolean;
|
|
6
|
-
}
|
|
7
4
|
export declare class JsonStreamAdapter implements LoggerAdapter {
|
|
8
5
|
#private;
|
|
9
6
|
constructor(stream: Writable);
|
|
10
7
|
captureError(error: Error, attributes?: Record<string, any>): void;
|
|
11
8
|
write(log: Record<string, any>): boolean;
|
|
12
9
|
}
|
|
13
|
-
export declare class SentryLoggerAdapter implements LoggerAdapter {
|
|
14
|
-
constructor();
|
|
15
|
-
captureError(error: Error | null, attributes?: Record<string, any>): void;
|
|
16
|
-
write(log: Record<string, any>): boolean;
|
|
17
|
-
}
|
|
18
10
|
export interface LoggerOptions {
|
|
19
11
|
/**
|
|
20
12
|
* Name of the logger
|
|
@@ -36,6 +28,8 @@ export interface LoggerOptions {
|
|
|
36
28
|
export declare function setGlobalLoggerContext(getContext: () => LoggerContext): void;
|
|
37
29
|
export declare function clearGlobalLoggerContext(): void;
|
|
38
30
|
export type Logger = ReturnType<typeof createLogger>;
|
|
31
|
+
export declare function addDefaultLoggerOutput(output: LoggerAdapter): void;
|
|
32
|
+
export declare function clearDefaultLoggerOutputs(): void;
|
|
39
33
|
export declare function createLogger({ name, getContext, level, outputs }: LoggerOptions): {
|
|
40
34
|
debug(message: string, context?: LoggerContext): void;
|
|
41
35
|
info(message: string, context?: LoggerContext): void;
|
package/dist/logger.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as os from 'node:os';
|
|
2
2
|
import {} from 'node:stream';
|
|
3
3
|
import { config } from '@devmoods/config';
|
|
4
|
-
import
|
|
4
|
+
import {} from '@devmoods/observability';
|
|
5
5
|
export class JsonStreamAdapter {
|
|
6
6
|
#stream;
|
|
7
7
|
constructor(stream) {
|
|
@@ -14,30 +14,6 @@ export class JsonStreamAdapter {
|
|
|
14
14
|
return this.#stream.write(chunk);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
export class SentryLoggerAdapter {
|
|
18
|
-
constructor() { }
|
|
19
|
-
captureError(error, attributes) {
|
|
20
|
-
/* v8 ignore next -- @preserve */
|
|
21
|
-
if (error == null) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
/* v8 ignore next -- @preserve */
|
|
25
|
-
if (Sentry.isInitialized()) {
|
|
26
|
-
Sentry.captureException(error, {
|
|
27
|
-
tags: attributes,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
write(log) {
|
|
32
|
-
const { message, ...attributes } = log;
|
|
33
|
-
/* v8 ignore next -- @preserve */
|
|
34
|
-
if (Sentry.isInitialized()) {
|
|
35
|
-
const fn = log.level;
|
|
36
|
-
Sentry.logger[fn](message, attributes);
|
|
37
|
-
}
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
17
|
const LEVELS = {
|
|
42
18
|
TRACE: 10,
|
|
43
19
|
DEBUG: 20,
|
|
@@ -73,7 +49,19 @@ function baseContext() {
|
|
|
73
49
|
}
|
|
74
50
|
return globalContext;
|
|
75
51
|
}
|
|
76
|
-
|
|
52
|
+
const defaultLoggerOutputs = [
|
|
53
|
+
new JsonStreamAdapter(process.stdout),
|
|
54
|
+
];
|
|
55
|
+
export function addDefaultLoggerOutput(output) {
|
|
56
|
+
if (defaultLoggerOutputs.includes(output)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
defaultLoggerOutputs.push(output);
|
|
60
|
+
}
|
|
61
|
+
export function clearDefaultLoggerOutputs() {
|
|
62
|
+
defaultLoggerOutputs.length = 0;
|
|
63
|
+
}
|
|
64
|
+
export function createLogger({ name, getContext, level = config.LOG_LEVEL, outputs = defaultLoggerOutputs, }) {
|
|
77
65
|
if (_loggers.has(name)) {
|
|
78
66
|
throw new Error(`A logger named ${name} already exists`);
|
|
79
67
|
}
|
package/dist/vite/ssr.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
1
9
|
import * as fs from 'node:fs/promises';
|
|
2
10
|
import * as path from 'node:path';
|
|
3
11
|
import { config } from '@devmoods/config';
|
|
@@ -38,7 +46,7 @@ export async function createSsrMiddleware({ root = process.cwd(), getInitialData
|
|
|
38
46
|
render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render;
|
|
39
47
|
}
|
|
40
48
|
else {
|
|
41
|
-
render = (await import(path.join(root, 'dist/server/entry-server.js'))).render;
|
|
49
|
+
render = (await import(__rewriteRelativeImportExtension(path.join(root, 'dist/server/entry-server.js')))).render;
|
|
42
50
|
}
|
|
43
51
|
const rendered = await render(createFetchRequest(req, res), {
|
|
44
52
|
useDevServer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devmoods/express-extras",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.73.0",
|
|
4
4
|
"description": "Kubernetes-ready utilities for rapid Node.js application development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -70,13 +70,10 @@
|
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@devmoods/config": "0.2.3",
|
|
72
72
|
"@devmoods/fetch": "^4.3.0",
|
|
73
|
-
"@devmoods/observability": "0.
|
|
74
|
-
"@devmoods/postgres": "0.
|
|
75
|
-
"@hey-api/openapi-ts": "^0.
|
|
76
|
-
"@rolldown/plugin-babel": "^0.2.
|
|
77
|
-
"@sentry/node": "^10.48.0",
|
|
78
|
-
"@sentry/node-native": "^10.48.0",
|
|
79
|
-
"@sentry/profiling-node": "^10.48.0",
|
|
73
|
+
"@devmoods/observability": "0.2.0",
|
|
74
|
+
"@devmoods/postgres": "0.5.0",
|
|
75
|
+
"@hey-api/openapi-ts": "^0.96.0",
|
|
76
|
+
"@rolldown/plugin-babel": "^0.2.3",
|
|
80
77
|
"@standard-schema/spec": "^1.1.0",
|
|
81
78
|
"@types/bcrypt": "^6.0.0",
|
|
82
79
|
"@types/cookie-parser": "^1.4.10",
|
|
@@ -91,7 +88,7 @@
|
|
|
91
88
|
"chalk": "^5.6.2",
|
|
92
89
|
"commander": "^14.0.3",
|
|
93
90
|
"cookie-parser": "^1.4.7",
|
|
94
|
-
"dotenv": "^17.4.
|
|
91
|
+
"dotenv": "^17.4.2",
|
|
95
92
|
"express": "^4.21.2",
|
|
96
93
|
"google-auth-library": "^10.6.2",
|
|
97
94
|
"helmet": "^8.1.0",
|
|
@@ -113,5 +110,5 @@
|
|
|
113
110
|
"engines": {
|
|
114
111
|
"node": ">=20 <26"
|
|
115
112
|
},
|
|
116
|
-
"gitHead": "
|
|
113
|
+
"gitHead": "ea4f51756aca98bd050cf98128bf4d4b3da1bf38"
|
|
117
114
|
}
|
package/dist/sentry.d.ts
DELETED
package/dist/sentry.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { config } from '@devmoods/config';
|
|
2
|
-
/**
|
|
3
|
-
* Safely imports native Sentry integrations if available.
|
|
4
|
-
* Returns null if native modules are not available (e.g., on unsupported Node.js versions).
|
|
5
|
-
*/
|
|
6
|
-
async function getNativeIntegrations() {
|
|
7
|
-
const integrations = [];
|
|
8
|
-
/* v8 ignore next -- @preserve */
|
|
9
|
-
try {
|
|
10
|
-
const { nodeProfilingIntegration } = await import('@sentry/profiling-node');
|
|
11
|
-
integrations.push(nodeProfilingIntegration());
|
|
12
|
-
}
|
|
13
|
-
catch {
|
|
14
|
-
// Native profiling integration not available
|
|
15
|
-
}
|
|
16
|
-
/* v8 ignore next -- @preserve */
|
|
17
|
-
try {
|
|
18
|
-
const { eventLoopBlockIntegration } = await import('@sentry/node-native');
|
|
19
|
-
integrations.push(eventLoopBlockIntegration({
|
|
20
|
-
threshold: config.SENTRY_EVENT_LOOP_THRESHOLD,
|
|
21
|
-
}));
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// Native event loop integration not available
|
|
25
|
-
}
|
|
26
|
-
return integrations;
|
|
27
|
-
}
|
|
28
|
-
export async function sentryOptions(options = {}) {
|
|
29
|
-
const nativeIntegrations = await getNativeIntegrations();
|
|
30
|
-
return {
|
|
31
|
-
dsn: config.SENTRY_DSN,
|
|
32
|
-
tracesSampleRate: config.SENTRY_TRACES_SAMPLE_RATE,
|
|
33
|
-
profileSessionSampleRate: config.SENTRY_PROFILES_SAMPLE_RATE,
|
|
34
|
-
integrations: nativeIntegrations,
|
|
35
|
-
enableLogs: true,
|
|
36
|
-
...options,
|
|
37
|
-
};
|
|
38
|
-
}
|