@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/core",
3
- "version": "0.4.19",
3
+ "version": "0.4.21",
4
4
  "description": "Production-grade TypeScript backend framework for JavaScript",
5
5
  "homepage": "https://zintrust.com",
6
6
  "repository": {
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/functions/cloudflare.ts"],"names":[],"mappings":";mBA0JuB,OAAO,QAAQ,OAAO,QAAQ,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;;AADhF,wBAoCE"}
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 importOptionalDefault = async (moduleId) => {
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.rootModuleId);
100
+ const rootOverride = await importOptionalDefault(rootStartupImporters[entry.file]);
61
101
  const serviceOverride = ProjectRuntime.getActiveService() === undefined
62
102
  ? undefined
63
- : await importOptionalDefault(entry.serviceModuleId);
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);
@@ -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,EAAE,MAAM,qBAAqB,CAAC;AAEnD,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;AA4TD,eAAO,MAAM,MAAM;qBA1DK,OAAO,aAAa,iBAAiB,KAAG,OAAO;EA4DrE,CAAC;AAEH,eAAe,MAAM,CAAC"}
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"}
@@ -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 = Router.match(router, req.getMethod(), req.getPath());
89
- if (!route) {
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.19
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-26T07:03:17.846Z
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-26T07:03:17.811Z'; // Replaced during build
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":"AAEA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,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
+ {"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: { error: message },
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":"AAKA,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;AAuCD,eAAO,MAAM,iBAAiB;qBACZ,cAAc,GAAQ,UAAU;EA6FhD,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
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 async (req, res, next) => {
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"}
@@ -0,0 +1,8 @@
1
+ export function createDefaultMiddlewareFailureBody(context) {
2
+ return {
3
+ error: {
4
+ code: context.reason,
5
+ message: context.message,
6
+ },
7
+ };
8
+ }
@@ -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;
@@ -14,7 +14,7 @@ export interface SecurityOptions {
14
14
  action?: 'DENY' | 'SAMEORIGIN';
15
15
  };
16
16
  cors?: {
17
- origin?: string;
17
+ origin?: string | string[];
18
18
  methods?: string[];
19
19
  allowedHeaders?: string[];
20
20
  credentials?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/SecurityMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,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,CAAC;QAChB,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;AA+FD,eAAO,MAAM,kBAAkB;IAC7B;;OAEG;qBACa,eAAe,GAAQ,UAAU;EAgBjD,CAAC"}
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: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
18
- allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
19
- credentials: true,
20
- maxAge: 86400,
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 = { ...DEFAULT_OPTIONS, ...options };
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"}
@@ -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: 200,
163
- headers: responseData.headers,
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
- // Handle abortion if signal is present
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
- try {
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 true;
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
- if (this._listeners?.[event] !== undefined) {
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: {},