@zintrust/core 0.4.19 → 0.4.21
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/package.json +1 -1
- package/src/functions/cloudflare.d.ts.map +1 -1
- package/src/functions/cloudflare.js +55 -12
- package/src/http/Kernel.d.ts.map +1 -1
- package/src/http/Kernel.js +28 -2
- package/src/index.js +3 -3
- package/src/middleware/AuthMiddleware.d.ts.map +1 -1
- package/src/middleware/AuthMiddleware.js +7 -1
- package/src/middleware/JwtAuthMiddleware.d.ts.map +1 -1
- package/src/middleware/JwtAuthMiddleware.js +63 -69
- package/src/middleware/MiddlewareFailureBody.d.ts +12 -0
- package/src/middleware/MiddlewareFailureBody.d.ts.map +1 -0
- package/src/middleware/MiddlewareFailureBody.js +8 -0
- package/src/middleware/MiddlewareFailureResponder.d.ts +1 -0
- package/src/middleware/MiddlewareFailureResponder.d.ts.map +1 -1
- package/src/middleware/MiddlewareFailureResponder.js +1 -0
- package/src/middleware/SecurityMiddleware.d.ts +1 -1
- package/src/middleware/SecurityMiddleware.d.ts.map +1 -1
- package/src/middleware/SecurityMiddleware.js +42 -7
- package/src/middleware/index.d.ts +1 -0
- package/src/middleware/index.d.ts.map +1 -1
- package/src/middleware/index.js +1 -0
- package/src/runtime/RuntimeAdapter.d.ts.map +1 -1
- package/src/runtime/RuntimeAdapter.js +50 -30
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/functions/cloudflare.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/functions/cloudflare.ts"],"names":[],"mappings":";mBAwNuB,OAAO,QAAQ,OAAO,QAAQ,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;;AADhF,wBAoCE"}
|
|
@@ -1,53 +1,93 @@
|
|
|
1
1
|
import { Logger } from '../config/logger.js';
|
|
2
|
+
import { clearMiddlewareConfigCache } from '../config/middleware.js';
|
|
2
3
|
import { CloudflareAdapter } from '../runtime/adapters/CloudflareAdapter.js';
|
|
3
4
|
import mergeOverrideValues from '../runtime/OverrideValueMerge.js';
|
|
4
5
|
import { ProjectRuntime } from '../runtime/ProjectRuntime.js';
|
|
5
|
-
import { StartupConfigFile } from '../runtime/StartupConfigFileRegistry.js';
|
|
6
|
+
import { StartupConfigFile, StartupConfigFileRegistry, } from '../runtime/StartupConfigFileRegistry.js';
|
|
6
7
|
import { WorkerAdapterImports } from '../runtime/WorkerAdapterImports.js';
|
|
7
8
|
import { getKernel } from '../runtime/getKernel.js';
|
|
8
9
|
const startupConfigModules = Object.freeze([
|
|
9
10
|
{
|
|
10
11
|
file: StartupConfigFile.Broadcast,
|
|
11
|
-
rootModuleId: '@runtime-config/' + 'broadcast.ts',
|
|
12
12
|
serviceModuleId: '@service-runtime-config/' + 'broadcast.ts',
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
file: StartupConfigFile.Cache,
|
|
16
|
-
rootModuleId: '@runtime-config/' + 'cache.ts',
|
|
17
16
|
serviceModuleId: '@service-runtime-config/' + 'cache.ts',
|
|
18
17
|
},
|
|
19
18
|
{
|
|
20
19
|
file: StartupConfigFile.Database,
|
|
21
|
-
rootModuleId: '@runtime-config/' + 'database.ts',
|
|
22
20
|
serviceModuleId: '@service-runtime-config/' + 'database.ts',
|
|
23
21
|
},
|
|
24
22
|
{
|
|
25
23
|
file: StartupConfigFile.Mail,
|
|
26
|
-
rootModuleId: '@runtime-config/' + 'mail.ts',
|
|
27
24
|
serviceModuleId: '@service-runtime-config/' + 'mail.ts',
|
|
28
25
|
},
|
|
29
26
|
{
|
|
30
27
|
file: StartupConfigFile.Middleware,
|
|
31
|
-
rootModuleId: '@runtime-config/' + 'middleware.ts',
|
|
32
28
|
serviceModuleId: '@service-runtime-config/' + 'middleware.ts',
|
|
33
29
|
},
|
|
34
30
|
{
|
|
35
31
|
file: StartupConfigFile.Notification,
|
|
36
|
-
rootModuleId: '@runtime-config/' + 'notification.ts',
|
|
37
32
|
serviceModuleId: '@service-runtime-config/' + 'notification.ts',
|
|
38
33
|
},
|
|
39
34
|
{
|
|
40
35
|
file: StartupConfigFile.Queue,
|
|
41
|
-
rootModuleId: '@runtime-config/' + 'queue.ts',
|
|
42
36
|
serviceModuleId: '@service-runtime-config/' + 'queue.ts',
|
|
43
37
|
},
|
|
44
38
|
{
|
|
45
39
|
file: StartupConfigFile.Storage,
|
|
46
|
-
rootModuleId: '@runtime-config/' + 'storage.ts',
|
|
47
40
|
serviceModuleId: '@service-runtime-config/' + 'storage.ts',
|
|
48
41
|
},
|
|
49
42
|
]);
|
|
50
|
-
const
|
|
43
|
+
const importRootBroadcastModule = async () => {
|
|
44
|
+
return (await import('@runtime-config/' + 'broadcast.ts'));
|
|
45
|
+
};
|
|
46
|
+
const importRootCacheModule = async () => {
|
|
47
|
+
return (await import('@runtime-config/' + 'cache.ts'));
|
|
48
|
+
};
|
|
49
|
+
const importRootDatabaseModule = async () => {
|
|
50
|
+
return (await import('@runtime-config/' + 'database.ts'));
|
|
51
|
+
};
|
|
52
|
+
const importRootMailModule = async () => {
|
|
53
|
+
return (await import('@runtime-config/' + 'mail.ts'));
|
|
54
|
+
};
|
|
55
|
+
const importRootMiddlewareModule = async () => {
|
|
56
|
+
return (await import('@runtime-config/' + 'middleware.ts'));
|
|
57
|
+
};
|
|
58
|
+
const importRootNotificationModule = async () => {
|
|
59
|
+
return (await import('@runtime-config/' + 'notification.ts'));
|
|
60
|
+
};
|
|
61
|
+
const importRootQueueModule = async () => {
|
|
62
|
+
return (await import('@runtime-config/' + 'queue.ts'));
|
|
63
|
+
};
|
|
64
|
+
const importRootStorageModule = async () => {
|
|
65
|
+
return (await import('@runtime-config/' + 'storage.ts'));
|
|
66
|
+
};
|
|
67
|
+
const importRootWorkersModule = async () => {
|
|
68
|
+
return (await import('@runtime-config/' + 'workers.ts'));
|
|
69
|
+
};
|
|
70
|
+
const rootStartupImporters = Object.freeze({
|
|
71
|
+
[StartupConfigFile.Broadcast]: importRootBroadcastModule,
|
|
72
|
+
[StartupConfigFile.Cache]: importRootCacheModule,
|
|
73
|
+
[StartupConfigFile.Database]: importRootDatabaseModule,
|
|
74
|
+
[StartupConfigFile.Mail]: importRootMailModule,
|
|
75
|
+
[StartupConfigFile.Middleware]: importRootMiddlewareModule,
|
|
76
|
+
[StartupConfigFile.Notification]: importRootNotificationModule,
|
|
77
|
+
[StartupConfigFile.Queue]: importRootQueueModule,
|
|
78
|
+
[StartupConfigFile.Storage]: importRootStorageModule,
|
|
79
|
+
[StartupConfigFile.Workers]: importRootWorkersModule,
|
|
80
|
+
});
|
|
81
|
+
const importOptionalDefault = async (importer) => {
|
|
82
|
+
try {
|
|
83
|
+
const module = await importer();
|
|
84
|
+
return module.default;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const importOptionalDefaultById = async (moduleId) => {
|
|
51
91
|
try {
|
|
52
92
|
const module = (await import(moduleId));
|
|
53
93
|
return module.default;
|
|
@@ -57,10 +97,10 @@ const importOptionalDefault = async (moduleId) => {
|
|
|
57
97
|
}
|
|
58
98
|
};
|
|
59
99
|
const resolveStartupOverrideValue = async (entry) => {
|
|
60
|
-
const rootOverride = await importOptionalDefault(entry.
|
|
100
|
+
const rootOverride = await importOptionalDefault(rootStartupImporters[entry.file]);
|
|
61
101
|
const serviceOverride = ProjectRuntime.getActiveService() === undefined
|
|
62
102
|
? undefined
|
|
63
|
-
: await
|
|
103
|
+
: await importOptionalDefaultById(entry.serviceModuleId);
|
|
64
104
|
if (rootOverride === undefined)
|
|
65
105
|
return serviceOverride;
|
|
66
106
|
if (serviceOverride === undefined)
|
|
@@ -82,6 +122,9 @@ const applyStartupConfigOverrides = async () => {
|
|
|
82
122
|
}
|
|
83
123
|
globalAny.__zintrustStartupConfigOverrides.set(entry.file, entry.value);
|
|
84
124
|
}
|
|
125
|
+
StartupConfigFileRegistry.clear();
|
|
126
|
+
clearMiddlewareConfigCache();
|
|
127
|
+
await StartupConfigFileRegistry.preload(startupConfigModules.map((entry) => entry.file));
|
|
85
128
|
}
|
|
86
129
|
catch (error) {
|
|
87
130
|
Logger.error('Error applying startup config overrides:', error);
|
package/src/http/Kernel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Kernel.d.ts","sourceRoot":"","sources":["../../../src/http/Kernel.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,OAAO,KAAK,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"Kernel.d.ts","sourceRoot":"","sources":["../../../src/http/Kernel.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,OAAO,KAAK,EAAE,OAAO,EAAc,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK7E,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAGpE,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/C,wBAAwB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAC5D,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IACpE,SAAS,IAAI,OAAO,CAAC;IACrB,YAAY,IAAI,iBAAiB,CAAC;IAClC,kBAAkB,IAAI,gBAAgB,CAAC;IAGvC,gBAAgB,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5C,cAAc,IAAI,IAAI,CAAC;IACvB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AA6VD,eAAO,MAAM,MAAM;qBA1DK,OAAO,aAAa,iBAAiB,KAAG,OAAO;EA4DrE,CAAC;AAEH,eAAe,MAAM,CAAC"}
|
package/src/http/Kernel.js
CHANGED
|
@@ -60,6 +60,32 @@ const resolveMiddlewareForRoute = (route, globalMiddleware, routeMiddleware) =>
|
|
|
60
60
|
.filter((mw) => typeof mw === 'function');
|
|
61
61
|
return [...globalMiddleware, ...resolvedRouteMiddleware];
|
|
62
62
|
};
|
|
63
|
+
const PREFLIGHT_FALLBACK_METHODS = Object.freeze([
|
|
64
|
+
'GET',
|
|
65
|
+
'HEAD',
|
|
66
|
+
'POST',
|
|
67
|
+
'PUT',
|
|
68
|
+
'PATCH',
|
|
69
|
+
'DELETE',
|
|
70
|
+
'*',
|
|
71
|
+
]);
|
|
72
|
+
const resolveRouteWithPreflightFallback = (router, method, path) => {
|
|
73
|
+
const direct = Router.match(router, method, path);
|
|
74
|
+
if (direct !== null || method !== 'OPTIONS')
|
|
75
|
+
return direct;
|
|
76
|
+
for (const fallbackMethod of PREFLIGHT_FALLBACK_METHODS) {
|
|
77
|
+
const matched = Router.match(router, fallbackMethod, path);
|
|
78
|
+
if (matched === null)
|
|
79
|
+
continue;
|
|
80
|
+
return {
|
|
81
|
+
...matched,
|
|
82
|
+
handler: async () => {
|
|
83
|
+
await Promise.resolve();
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
};
|
|
63
89
|
const maybeStartKernelTraceSpan = (req, context) => {
|
|
64
90
|
if (OpenTelemetry.isEnabled() === false)
|
|
65
91
|
return undefined;
|
|
@@ -85,8 +111,8 @@ const maybeSetKernelTraceRoute = (traceSpan, method, routeLabel) => {
|
|
|
85
111
|
};
|
|
86
112
|
const runKernelPipeline = async (router, globalMiddleware, routeMiddleware, req, res, context, traceSpan) => {
|
|
87
113
|
Logger.info(`[${req.getMethod()}] ${req.getPath()}`);
|
|
88
|
-
const route =
|
|
89
|
-
if (
|
|
114
|
+
const route = resolveRouteWithPreflightFallback(router, req.getMethod(), req.getPath());
|
|
115
|
+
if (route === null) {
|
|
90
116
|
const routeLabel = 'not_found';
|
|
91
117
|
maybeSetKernelTraceRoute(traceSpan, context.method, routeLabel);
|
|
92
118
|
const handleNotFound = ErrorRouting.handleNotFound;
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v0.4.
|
|
2
|
+
* @zintrust/core v0.4.21
|
|
3
3
|
*
|
|
4
4
|
* ZinTrust Framework - Production-Grade TypeScript Backend
|
|
5
5
|
* Built for performance, type safety, and exceptional developer experience
|
|
6
6
|
*
|
|
7
7
|
* Build Information:
|
|
8
|
-
* Built: 2026-03-
|
|
8
|
+
* Built: 2026-03-26T13:55:52.794Z
|
|
9
9
|
* Node: >=20.0.0
|
|
10
10
|
* License: MIT
|
|
11
11
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* Available at runtime for debugging and health checks
|
|
22
22
|
*/
|
|
23
23
|
export const ZINTRUST_VERSION = '0.1.41';
|
|
24
|
-
export const ZINTRUST_BUILD_DATE = '2026-03-
|
|
24
|
+
export const ZINTRUST_BUILD_DATE = '2026-03-26T13:55:52.759Z'; // Replaced during build
|
|
25
25
|
export { Application } from './boot/Application.js';
|
|
26
26
|
export { AwsSigV4 } from './common/index.js';
|
|
27
27
|
export { SignedRequest } from './security/SignedRequest.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/AuthMiddleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/AuthMiddleware.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAS9D,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,0BAA0B,CAAC;CAC7C;AAED,eAAO,MAAM,cAAc;qBACT,WAAW,GAAQ,UAAU;EAsB7C,CAAC;AAEH,eAAe,cAAc,CAAC"}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
|
|
2
|
+
const createAuthFailureBody = (reason, message) => ({
|
|
3
|
+
error: {
|
|
4
|
+
code: reason,
|
|
5
|
+
message,
|
|
6
|
+
},
|
|
7
|
+
});
|
|
2
8
|
export const AuthMiddleware = Object.freeze({
|
|
3
9
|
create(options = {}) {
|
|
4
10
|
const headerName = (options.headerName ?? 'authorization').toLowerCase();
|
|
@@ -12,7 +18,7 @@ export const AuthMiddleware = Object.freeze({
|
|
|
12
18
|
reason: 'missing_authorization_header',
|
|
13
19
|
statusCode: 401,
|
|
14
20
|
message,
|
|
15
|
-
body:
|
|
21
|
+
body: createAuthFailureBody('missing_authorization_header', message),
|
|
16
22
|
});
|
|
17
23
|
return;
|
|
18
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JwtAuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/JwtAuthMiddleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"JwtAuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/JwtAuthMiddleware.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAItE,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,0BAA0B,CAAC;CAC7C;AAqJD,eAAO,MAAM,iBAAiB;qBACZ,cAAc,GAAQ,UAAU;EAWhD,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
|
|
@@ -38,6 +38,68 @@ const getOptionalStringOrNumberClaim = (payload, key) => {
|
|
|
38
38
|
return String(value);
|
|
39
39
|
return undefined;
|
|
40
40
|
};
|
|
41
|
+
const createJwtFailureBody = (reason, message) => ({
|
|
42
|
+
error: {
|
|
43
|
+
code: reason,
|
|
44
|
+
message,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
const respondJwtUnauthorized = async (req, res, onUnauthorized, reason, message, error) => {
|
|
48
|
+
await respondWithMiddlewareFailure(req, res, onUnauthorized, {
|
|
49
|
+
middleware: 'jwt',
|
|
50
|
+
reason,
|
|
51
|
+
statusCode: 401,
|
|
52
|
+
message,
|
|
53
|
+
body: createJwtFailureBody(reason, message),
|
|
54
|
+
error,
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const hydrateJwtRequestContext = (req, payload) => {
|
|
58
|
+
req.user = payload;
|
|
59
|
+
const subject = payload['sub'];
|
|
60
|
+
if (typeof subject === 'string' && subject.trim() !== '') {
|
|
61
|
+
RequestContext.setUserId(req, subject);
|
|
62
|
+
}
|
|
63
|
+
const tenantId = getOptionalStringOrNumberClaim(payload, 'tenantId') ??
|
|
64
|
+
getOptionalStringOrNumberClaim(payload, 'tenant_id');
|
|
65
|
+
if (tenantId !== undefined && tenantId.trim() !== '') {
|
|
66
|
+
RequestContext.setTenantId(req, tenantId);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const createJwtMiddlewareHandler = (jwt, algorithm, onUnauthorized) => {
|
|
70
|
+
return async (req, res, next) => {
|
|
71
|
+
if (req.context?.['authStrategy'] === 'bulletproof' && req.user !== undefined) {
|
|
72
|
+
await next();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const authorizationHeader = getHeaderValue(req.getHeader('authorization'));
|
|
76
|
+
if (authorizationHeader === '') {
|
|
77
|
+
await respondJwtUnauthorized(req, res, onUnauthorized, 'missing_authorization_header', 'Missing authorization header');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const token = getBearerToken(authorizationHeader);
|
|
81
|
+
if (token === null) {
|
|
82
|
+
await respondJwtUnauthorized(req, res, onUnauthorized, 'invalid_authorization_header_format', 'Invalid authorization header format');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const payload = jwt.verify(token, algorithm);
|
|
87
|
+
if (!(await JwtSessions.isActive(token))) {
|
|
88
|
+
await respondJwtUnauthorized(req, res, onUnauthorized, 'inactive_session', 'Invalid or expired token');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
hydrateJwtRequestContext(req, payload);
|
|
92
|
+
await next();
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
Logger.debug('JWT verification failed', {
|
|
96
|
+
algorithm,
|
|
97
|
+
error: error instanceof Error ? error.message : String(error),
|
|
98
|
+
});
|
|
99
|
+
await respondJwtUnauthorized(req, res, onUnauthorized, getJwtFailureReason(error), 'Invalid or expired token', error);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
};
|
|
41
103
|
export const JwtAuthMiddleware = Object.freeze({
|
|
42
104
|
create(options = {}) {
|
|
43
105
|
const algorithm = options.algorithm ?? securityConfig.jwt.algorithm;
|
|
@@ -46,75 +108,7 @@ export const JwtAuthMiddleware = Object.freeze({
|
|
|
46
108
|
if (algorithm === 'HS256' || algorithm === 'HS512') {
|
|
47
109
|
jwt.setHmacSecret(secret);
|
|
48
110
|
}
|
|
49
|
-
return
|
|
50
|
-
// If a stronger auth strategy already authenticated this request, do not re-verify.
|
|
51
|
-
if (req.context?.['authStrategy'] === 'bulletproof' && req.user !== undefined) {
|
|
52
|
-
await next();
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const authorizationHeader = getHeaderValue(req.getHeader('authorization'));
|
|
56
|
-
if (authorizationHeader === '') {
|
|
57
|
-
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
58
|
-
middleware: 'jwt',
|
|
59
|
-
reason: 'missing_authorization_header',
|
|
60
|
-
statusCode: 401,
|
|
61
|
-
message: 'Missing authorization header',
|
|
62
|
-
body: { error: 'Missing authorization header' },
|
|
63
|
-
});
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const token = getBearerToken(authorizationHeader);
|
|
67
|
-
if (token === null) {
|
|
68
|
-
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
69
|
-
middleware: 'jwt',
|
|
70
|
-
reason: 'invalid_authorization_header_format',
|
|
71
|
-
statusCode: 401,
|
|
72
|
-
message: 'Invalid authorization header format',
|
|
73
|
-
body: { error: 'Invalid authorization header format' },
|
|
74
|
-
});
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
const payload = jwt.verify(token, algorithm);
|
|
79
|
-
// Session allowlist: token must exist in the session store to be accepted.
|
|
80
|
-
if (!(await JwtSessions.isActive(token))) {
|
|
81
|
-
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
82
|
-
middleware: 'jwt',
|
|
83
|
-
reason: 'inactive_session',
|
|
84
|
-
statusCode: 401,
|
|
85
|
-
message: 'Invalid or expired token',
|
|
86
|
-
body: { error: 'Invalid or expired token' },
|
|
87
|
-
});
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
req.user = payload;
|
|
91
|
-
// Standardize request-scoped context fields.
|
|
92
|
-
if (typeof payload.sub === 'string' && payload.sub.trim() !== '') {
|
|
93
|
-
RequestContext.setUserId(req, payload.sub);
|
|
94
|
-
}
|
|
95
|
-
// Optional: if a tenant claim exists, attach it. (Apps may use a different claim name.)
|
|
96
|
-
const tenantId = getOptionalStringOrNumberClaim(payload, 'tenantId') ??
|
|
97
|
-
getOptionalStringOrNumberClaim(payload, 'tenant_id');
|
|
98
|
-
if (tenantId !== undefined && tenantId.trim() !== '') {
|
|
99
|
-
RequestContext.setTenantId(req, tenantId);
|
|
100
|
-
}
|
|
101
|
-
await next();
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
Logger.debug('JWT verification failed', {
|
|
105
|
-
algorithm,
|
|
106
|
-
error: error instanceof Error ? error.message : String(error),
|
|
107
|
-
});
|
|
108
|
-
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
109
|
-
middleware: 'jwt',
|
|
110
|
-
reason: getJwtFailureReason(error),
|
|
111
|
-
statusCode: 401,
|
|
112
|
-
message: 'Invalid or expired token',
|
|
113
|
-
body: { error: 'Invalid or expired token' },
|
|
114
|
-
error,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
};
|
|
111
|
+
return createJwtMiddlewareHandler(jwt, algorithm, options.onUnauthorized);
|
|
118
112
|
},
|
|
119
113
|
});
|
|
120
114
|
export default JwtAuthMiddleware;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type MiddlewareFailureBodyInput = Readonly<{
|
|
2
|
+
reason: string;
|
|
3
|
+
message: string;
|
|
4
|
+
}>;
|
|
5
|
+
export type DefaultMiddlewareFailureBody = Readonly<{
|
|
6
|
+
error: Readonly<{
|
|
7
|
+
code: string;
|
|
8
|
+
message: string;
|
|
9
|
+
}>;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function createDefaultMiddlewareFailureBody(context: MiddlewareFailureBodyInput): DefaultMiddlewareFailureBody;
|
|
12
|
+
//# sourceMappingURL=MiddlewareFailureBody.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MiddlewareFailureBody.d.ts","sourceRoot":"","sources":["../../../src/middleware/MiddlewareFailureBody.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,KAAK,EAAE,QAAQ,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ,CAAC,CAAC;AAEH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,0BAA0B,GAClC,4BAA4B,CAO9B"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IRequest } from '../http/Request';
|
|
2
2
|
import type { IResponse } from '../http/Response';
|
|
3
|
+
export { createDefaultMiddlewareFailureBody, type DefaultMiddlewareFailureBody, type MiddlewareFailureBodyInput, } from './MiddlewareFailureBody';
|
|
3
4
|
export type MiddlewareFailureContext = Readonly<{
|
|
4
5
|
middleware: string;
|
|
5
6
|
reason: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiddlewareFailureResponder.d.ts","sourceRoot":"","sources":["../../../src/middleware/MiddlewareFailureResponder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CACvC,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,wBAAwB,KAC9B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,eAAO,MAAM,iCAAiC,EAAE,0BAgB/C,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,WAAW,0BAA0B,GAAG,SAAS,EACjD,SAAS,wBAAwB,KAChC,OAAO,CAAC,IAAI,CAEd,CAAC"}
|
|
1
|
+
{"version":3,"file":"MiddlewareFailureResponder.d.ts","sourceRoot":"","sources":["../../../src/middleware/MiddlewareFailureResponder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EACL,kCAAkC,EAClC,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,GAChC,MAAM,mCAAmC,CAAC;AAE3C,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CACvC,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,wBAAwB,KAC9B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,eAAO,MAAM,iCAAiC,EAAE,0BAgB/C,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,WAAW,0BAA0B,GAAG,SAAS,EACjD,SAAS,wBAAwB,KAChC,OAAO,CAAC,IAAI,CAEd,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isObject } from '../helper/index.js';
|
|
2
|
+
export { createDefaultMiddlewareFailureBody, } from './MiddlewareFailureBody.js';
|
|
2
3
|
export const defaultMiddlewareFailureResponder = (_req, res, context) => {
|
|
3
4
|
const statusTarget = res.setStatus(context.statusCode);
|
|
4
5
|
const responseTarget = isObject(statusTarget) ? statusTarget : res;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecurityMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/SecurityMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"SecurityMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/SecurityMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;KAChC,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;KACvC,CAAC;CACH;AAwID,eAAO,MAAM,kBAAkB;IAC7B;;OAEG;qBACa,eAAe,GAAQ,UAAU;EAgBjD,CAAC"}
|
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
* Implements standard security headers and CORS protection
|
|
4
4
|
* Zero-dependency implementation replacing helmet/cors
|
|
5
5
|
*/
|
|
6
|
+
import { securityConfig } from '../config/security.js';
|
|
7
|
+
const normalizeCorsList = (values, fallback) => {
|
|
8
|
+
const normalized = (values ?? [])
|
|
9
|
+
.map((value) => (typeof value === 'string' ? value.trim() : ''))
|
|
10
|
+
.filter((value) => value !== '');
|
|
11
|
+
return normalized.length > 0 ? normalized : fallback;
|
|
12
|
+
};
|
|
13
|
+
const getSecurityCorsConfig = () => {
|
|
14
|
+
const config = securityConfig;
|
|
15
|
+
return config?.cors ?? {};
|
|
16
|
+
};
|
|
17
|
+
const resolveCorsOrigin = () => {
|
|
18
|
+
const origins = normalizeCorsList(getSecurityCorsConfig().origins, ['*']);
|
|
19
|
+
return origins.includes('*') ? '*' : origins;
|
|
20
|
+
};
|
|
6
21
|
const DEFAULT_OPTIONS = {
|
|
7
22
|
hsts: {
|
|
8
23
|
maxAge: 15552000, // 180 days
|
|
@@ -13,13 +28,33 @@ const DEFAULT_OPTIONS = {
|
|
|
13
28
|
action: 'SAMEORIGIN',
|
|
14
29
|
},
|
|
15
30
|
cors: {
|
|
16
|
-
origin:
|
|
17
|
-
methods:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
origin: resolveCorsOrigin(),
|
|
32
|
+
methods: normalizeCorsList(getSecurityCorsConfig().methods, [
|
|
33
|
+
'GET',
|
|
34
|
+
'HEAD',
|
|
35
|
+
'PUT',
|
|
36
|
+
'PATCH',
|
|
37
|
+
'POST',
|
|
38
|
+
'DELETE',
|
|
39
|
+
]),
|
|
40
|
+
allowedHeaders: normalizeCorsList(getSecurityCorsConfig().allowedHeaders, [
|
|
41
|
+
'Content-Type',
|
|
42
|
+
'Authorization',
|
|
43
|
+
'X-Requested-With',
|
|
44
|
+
'X-CSRF-Token',
|
|
45
|
+
]),
|
|
46
|
+
credentials: getSecurityCorsConfig().credentials,
|
|
47
|
+
maxAge: getSecurityCorsConfig().maxAge,
|
|
21
48
|
},
|
|
22
49
|
};
|
|
50
|
+
const mergeSecurityOptions = (options) => {
|
|
51
|
+
return {
|
|
52
|
+
hsts: { ...DEFAULT_OPTIONS.hsts, ...options.hsts },
|
|
53
|
+
frameguard: { ...DEFAULT_OPTIONS.frameguard, ...options.frameguard },
|
|
54
|
+
cors: { ...DEFAULT_OPTIONS.cors, ...options.cors },
|
|
55
|
+
csp: options.csp ?? DEFAULT_OPTIONS.csp,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
23
58
|
function applyHsts(res, hsts) {
|
|
24
59
|
if (!hsts)
|
|
25
60
|
return;
|
|
@@ -73,7 +108,7 @@ function applyCors(req, res, cors) {
|
|
|
73
108
|
res.setHeader('Access-Control-Allow-Headers', cors.allowedHeaders.join(', '));
|
|
74
109
|
}
|
|
75
110
|
if (cors.credentials !== undefined) {
|
|
76
|
-
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
111
|
+
res.setHeader('Access-Control-Allow-Credentials', cors.credentials ? 'true' : 'false');
|
|
77
112
|
}
|
|
78
113
|
if (cors.maxAge !== undefined) {
|
|
79
114
|
res.setHeader('Access-Control-Max-Age', cors.maxAge.toString());
|
|
@@ -90,7 +125,7 @@ export const SecurityMiddleware = Object.freeze({
|
|
|
90
125
|
* Create security middleware with options
|
|
91
126
|
*/
|
|
92
127
|
create(options = {}) {
|
|
93
|
-
const config =
|
|
128
|
+
const config = mergeSecurityOptions(options);
|
|
94
129
|
return async (req, res, next) => {
|
|
95
130
|
applyHsts(res, config.hsts);
|
|
96
131
|
applyFrameguard(res, config.frameguard);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export * from './CsrfMiddleware';
|
|
6
6
|
export * from './ErrorHandlerMiddleware';
|
|
7
7
|
export * from './LoggingMiddleware';
|
|
8
|
+
export * from './MiddlewareFailureBody';
|
|
8
9
|
export * from './MiddlewareFailureResponder';
|
|
9
10
|
export * from './MiddlewareStack';
|
|
10
11
|
export * from './RateLimiter';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,wCAAwC,CAAC;AACvD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
|
package/src/middleware/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export * from './CsrfMiddleware.js';
|
|
6
6
|
export * from './ErrorHandlerMiddleware.js';
|
|
7
7
|
export * from './LoggingMiddleware.js';
|
|
8
|
+
export * from './MiddlewareFailureBody.js';
|
|
8
9
|
export * from './MiddlewareFailureResponder.js';
|
|
9
10
|
export * from './MiddlewareStack.js';
|
|
10
11
|
export * from './RateLimiter.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuntimeAdapter.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeAdapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"RuntimeAdapter.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -157,26 +157,57 @@ const applyWriteHead = (responseData, statusCode, headers) => {
|
|
|
157
157
|
}
|
|
158
158
|
return null;
|
|
159
159
|
};
|
|
160
|
+
const closeWriterOnAbort = (request, response) => {
|
|
161
|
+
if (!request.signal || !response._writer)
|
|
162
|
+
return;
|
|
163
|
+
request.signal.addEventListener('abort', () => {
|
|
164
|
+
if (response._writer) {
|
|
165
|
+
try {
|
|
166
|
+
response._writer.close();
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Ignore close errors
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
response.emit('close');
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
const writeToResponseWriter = (response, chunk) => {
|
|
176
|
+
if (!response._writer)
|
|
177
|
+
return false;
|
|
178
|
+
try {
|
|
179
|
+
response._writer.write(new TextEncoder().encode(String(chunk)));
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const emitResponseListeners = (listeners, event, args) => {
|
|
187
|
+
if (listeners[event] === undefined)
|
|
188
|
+
return;
|
|
189
|
+
[...listeners[event]].forEach((fn) => {
|
|
190
|
+
fn(...args);
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
const isRequestAborted = (request) => request.signal?.aborted === true;
|
|
160
194
|
const resData = (responseData, request) => {
|
|
161
195
|
return {
|
|
162
|
-
statusCode
|
|
163
|
-
|
|
196
|
+
get statusCode() {
|
|
197
|
+
return responseData.statusCode;
|
|
198
|
+
},
|
|
199
|
+
set statusCode(value) {
|
|
200
|
+
responseData.statusCode = value;
|
|
201
|
+
},
|
|
202
|
+
get headers() {
|
|
203
|
+
return responseData.headers;
|
|
204
|
+
},
|
|
205
|
+
set headers(value) {
|
|
206
|
+
responseData.headers = value;
|
|
207
|
+
},
|
|
164
208
|
writeHead: function (statusCode, headers) {
|
|
165
209
|
this._writer = applyWriteHead(responseData, statusCode, headers);
|
|
166
|
-
|
|
167
|
-
if (request.signal && this._writer) {
|
|
168
|
-
request.signal.addEventListener('abort', () => {
|
|
169
|
-
if (this._writer) {
|
|
170
|
-
try {
|
|
171
|
-
this._writer.close();
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
// Ignore close errors
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
this.emit('close');
|
|
178
|
-
});
|
|
179
|
-
}
|
|
210
|
+
closeWriterOnAbort(request, this);
|
|
180
211
|
return this;
|
|
181
212
|
},
|
|
182
213
|
setHeader: function (name, value) {
|
|
@@ -199,16 +230,10 @@ const resData = (responseData, request) => {
|
|
|
199
230
|
},
|
|
200
231
|
write: function (chunk) {
|
|
201
232
|
if (this._writer) {
|
|
202
|
-
|
|
203
|
-
this._writer.write(new TextEncoder().encode(String(chunk)));
|
|
204
|
-
return true;
|
|
205
|
-
}
|
|
206
|
-
catch {
|
|
207
|
-
return false;
|
|
208
|
-
}
|
|
233
|
+
return writeToResponseWriter(this, chunk);
|
|
209
234
|
}
|
|
210
235
|
responseData.body = chunk;
|
|
211
|
-
return
|
|
236
|
+
return isRequestAborted(request) === false;
|
|
212
237
|
},
|
|
213
238
|
on: function (event, listener) {
|
|
214
239
|
this._listeners ??= {};
|
|
@@ -230,12 +255,7 @@ const resData = (responseData, request) => {
|
|
|
230
255
|
return this;
|
|
231
256
|
},
|
|
232
257
|
emit: function (event, ...args) {
|
|
233
|
-
|
|
234
|
-
// Create a copy to avoid issues if listeners remove themselves
|
|
235
|
-
[...this._listeners[event]].forEach((fn) => {
|
|
236
|
-
fn(...args);
|
|
237
|
-
});
|
|
238
|
-
}
|
|
258
|
+
emitResponseListeners(this._listeners, event, args);
|
|
239
259
|
},
|
|
240
260
|
_writer: null,
|
|
241
261
|
_listeners: {},
|