@zintrust/core 0.4.89 → 0.4.91
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 +2 -2
- package/src/index.js +3 -3
- package/src/middleware/SecurityMiddleware.d.ts +1 -0
- package/src/middleware/SecurityMiddleware.d.ts.map +1 -1
- package/src/middleware/SecurityMiddleware.js +93 -25
- package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.js +17 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.91",
|
|
4
4
|
"description": "Production-grade TypeScript backend framework for JavaScript",
|
|
5
5
|
"homepage": "https://zintrust.com",
|
|
6
6
|
"repository": {
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"overrides": {
|
|
71
71
|
"ajv": "^8.18.0",
|
|
72
|
-
"axios": "^1.
|
|
72
|
+
"axios": "^1.15.0",
|
|
73
73
|
"@tootallnate/once": "^3.0.1",
|
|
74
74
|
"node-forge": "^1.4.0",
|
|
75
75
|
"brace-expansion": "^5.0.5",
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v0.4.
|
|
2
|
+
* @zintrust/core v0.4.91
|
|
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-04-
|
|
8
|
+
* Built: 2026-04-10T08:00:44.737Z
|
|
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-04-
|
|
24
|
+
export const ZINTRUST_BUILD_DATE = '2026-04-10T08:00:44.703Z'; // 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":"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;
|
|
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,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;AAkPD,eAAO,MAAM,kBAAkB;IAC7B;;OAEG;qBACa,eAAe,GAAQ,UAAU;EAgBjD,CAAC"}
|
|
@@ -10,6 +10,29 @@ const normalizeCorsList = (values, fallback) => {
|
|
|
10
10
|
.filter((value) => value !== '');
|
|
11
11
|
return normalized.length > 0 ? normalized : fallback;
|
|
12
12
|
};
|
|
13
|
+
const parseHeaderList = (value) => {
|
|
14
|
+
return String(value ?? '')
|
|
15
|
+
.split(',')
|
|
16
|
+
.map((element) => element.trim())
|
|
17
|
+
.filter((element) => element !== '');
|
|
18
|
+
};
|
|
19
|
+
const hasWildcard = (values) => {
|
|
20
|
+
if (typeof values === 'string')
|
|
21
|
+
return values.trim() === '*';
|
|
22
|
+
return (values ?? []).some((value) => value.trim() === '*');
|
|
23
|
+
};
|
|
24
|
+
const mergeCorsHeaders = (configured, requested) => {
|
|
25
|
+
const merged = new Map();
|
|
26
|
+
for (const header of [...(configured ?? []), ...(requested ?? [])]) {
|
|
27
|
+
const normalized = header.toLowerCase();
|
|
28
|
+
if (normalized === '')
|
|
29
|
+
continue;
|
|
30
|
+
if (!merged.has(normalized)) {
|
|
31
|
+
merged.set(normalized, header);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return Array.from(merged.values());
|
|
35
|
+
};
|
|
13
36
|
const getSecurityCorsConfig = () => {
|
|
14
37
|
const config = securityConfig;
|
|
15
38
|
return config?.cors ?? {};
|
|
@@ -18,6 +41,61 @@ const resolveCorsOrigin = () => {
|
|
|
18
41
|
const origins = normalizeCorsList(getSecurityCorsConfig().origins, ['*']);
|
|
19
42
|
return origins.includes('*') ? '*' : origins;
|
|
20
43
|
};
|
|
44
|
+
const resolveAllowedOrigin = (configuredOrigin, requestOrigin, credentials) => {
|
|
45
|
+
if (configuredOrigin === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (typeof configuredOrigin === 'string') {
|
|
48
|
+
if (configuredOrigin.trim() === '*') {
|
|
49
|
+
return credentials === true && requestOrigin !== undefined ? requestOrigin : '*';
|
|
50
|
+
}
|
|
51
|
+
return configuredOrigin;
|
|
52
|
+
}
|
|
53
|
+
if (hasWildcard(configuredOrigin)) {
|
|
54
|
+
return credentials === true && requestOrigin !== undefined ? requestOrigin : '*';
|
|
55
|
+
}
|
|
56
|
+
if (requestOrigin === undefined || !configuredOrigin.includes(requestOrigin)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return requestOrigin;
|
|
60
|
+
};
|
|
61
|
+
const resolveAllowedMethods = (configuredMethods, requestMethod) => {
|
|
62
|
+
if (!hasWildcard(configuredMethods))
|
|
63
|
+
return configuredMethods ?? [];
|
|
64
|
+
if (requestMethod === undefined || requestMethod.trim() === '')
|
|
65
|
+
return ['*'];
|
|
66
|
+
return [requestMethod.trim()];
|
|
67
|
+
};
|
|
68
|
+
const resolveAllowedHeaders = (configuredHeaders, requestedHeaders) => {
|
|
69
|
+
if (hasWildcard(configuredHeaders)) {
|
|
70
|
+
return requestedHeaders.length > 0 ? requestedHeaders : ['*'];
|
|
71
|
+
}
|
|
72
|
+
return mergeCorsHeaders(configuredHeaders, requestedHeaders);
|
|
73
|
+
};
|
|
74
|
+
const resolveExposedHeaders = (configuredHeaders) => {
|
|
75
|
+
if (!hasWildcard(configuredHeaders))
|
|
76
|
+
return configuredHeaders ?? [];
|
|
77
|
+
return ['*'];
|
|
78
|
+
};
|
|
79
|
+
const applyCorsHeaders = (res, options) => {
|
|
80
|
+
if (options.origin !== undefined) {
|
|
81
|
+
res.setHeader('Access-Control-Allow-Origin', options.origin);
|
|
82
|
+
}
|
|
83
|
+
if (options.methods.length > 0) {
|
|
84
|
+
res.setHeader('Access-Control-Allow-Methods', options.methods.join(', '));
|
|
85
|
+
}
|
|
86
|
+
if (options.allowedHeaders.length > 0) {
|
|
87
|
+
res.setHeader('Access-Control-Allow-Headers', options.allowedHeaders.join(', '));
|
|
88
|
+
}
|
|
89
|
+
if (options.exposedHeaders.length > 0) {
|
|
90
|
+
res.setHeader('Access-Control-Expose-Headers', options.exposedHeaders.join(', '));
|
|
91
|
+
}
|
|
92
|
+
if (options.credentials !== undefined) {
|
|
93
|
+
res.setHeader('Access-Control-Allow-Credentials', options.credentials ? 'true' : 'false');
|
|
94
|
+
}
|
|
95
|
+
if (options.maxAge !== undefined) {
|
|
96
|
+
res.setHeader('Access-Control-Max-Age', options.maxAge.toString());
|
|
97
|
+
}
|
|
98
|
+
};
|
|
21
99
|
const DEFAULT_OPTIONS = {
|
|
22
100
|
hsts: {
|
|
23
101
|
maxAge: 15552000, // 180 days
|
|
@@ -43,6 +121,7 @@ const DEFAULT_OPTIONS = {
|
|
|
43
121
|
'X-Requested-With',
|
|
44
122
|
'X-CSRF-Token',
|
|
45
123
|
]),
|
|
124
|
+
exposedHeaders: normalizeCorsList(getSecurityCorsConfig().exposedHeaders, []),
|
|
46
125
|
credentials: getSecurityCorsConfig().credentials,
|
|
47
126
|
maxAge: getSecurityCorsConfig().maxAge,
|
|
48
127
|
},
|
|
@@ -87,34 +166,23 @@ function applyCsp(res, csp) {
|
|
|
87
166
|
function applyCors(req, res, cors) {
|
|
88
167
|
if (!cors)
|
|
89
168
|
return false;
|
|
169
|
+
const method = req.getMethod();
|
|
90
170
|
const originHeader = req.getHeader('origin');
|
|
91
171
|
const origin = typeof originHeader === 'string' ? originHeader : undefined;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
if (cors.methods) {
|
|
105
|
-
res.setHeader('Access-Control-Allow-Methods', cors.methods.join(', '));
|
|
106
|
-
}
|
|
107
|
-
if (cors.allowedHeaders) {
|
|
108
|
-
res.setHeader('Access-Control-Allow-Headers', cors.allowedHeaders.join(', '));
|
|
109
|
-
}
|
|
110
|
-
if (cors.credentials !== undefined) {
|
|
111
|
-
res.setHeader('Access-Control-Allow-Credentials', cors.credentials ? 'true' : 'false');
|
|
112
|
-
}
|
|
113
|
-
if (cors.maxAge !== undefined) {
|
|
114
|
-
res.setHeader('Access-Control-Max-Age', cors.maxAge.toString());
|
|
115
|
-
}
|
|
172
|
+
const requestedMethodHeader = method === 'OPTIONS' ? req.getHeader('access-control-request-method') : undefined;
|
|
173
|
+
const requestedMethod = typeof requestedMethodHeader === 'string' ? requestedMethodHeader : undefined;
|
|
174
|
+
const requestedHeadersHeader = method === 'OPTIONS' ? req.getHeader('access-control-request-headers') : undefined;
|
|
175
|
+
const requestedHeaders = typeof requestedHeadersHeader === 'string' ? parseHeaderList(requestedHeadersHeader) : [];
|
|
176
|
+
applyCorsHeaders(res, {
|
|
177
|
+
origin: resolveAllowedOrigin(cors.origin, origin, cors.credentials),
|
|
178
|
+
methods: resolveAllowedMethods(cors.methods, requestedMethod),
|
|
179
|
+
allowedHeaders: resolveAllowedHeaders(cors.allowedHeaders, requestedHeaders),
|
|
180
|
+
exposedHeaders: resolveExposedHeaders(cors.exposedHeaders),
|
|
181
|
+
credentials: cors.credentials,
|
|
182
|
+
maxAge: cors.maxAge,
|
|
183
|
+
});
|
|
116
184
|
// Handle Preflight
|
|
117
|
-
if (
|
|
185
|
+
if (method === 'OPTIONS') {
|
|
118
186
|
res.setStatus(204);
|
|
119
187
|
res.send('');
|
|
120
188
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLiteAdapter.d.ts","sourceRoot":"","sources":["../../../../src/orm/adapters/SQLiteAdapter.ts"],"names":[],"mappings":"AACA;;;GAGG;AAUH,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAe,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"SQLiteAdapter.d.ts","sourceRoot":"","sources":["../../../../src/orm/adapters/SQLiteAdapter.ts"],"names":[],"mappings":"AACA;;;GAGG;AAUH,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAe,MAAM,sBAAsB,CAAC;AA+N1F,iBAAS,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,gBAAgB,CA0FrE;AAED,eAAO,MAAM,aAAa;;EAExB,CAAC"}
|
|
@@ -66,6 +66,18 @@ function isSelectQuery(sql) {
|
|
|
66
66
|
const normalized = sql.trimStart().toLowerCase();
|
|
67
67
|
return normalized.startsWith('select') || normalized.startsWith('pragma');
|
|
68
68
|
}
|
|
69
|
+
const TRACE_STORAGE_TABLE_NAMES = [
|
|
70
|
+
'zin_trace_entries',
|
|
71
|
+
'zin_trace_entries_tags',
|
|
72
|
+
'zin_trace_monitoring',
|
|
73
|
+
];
|
|
74
|
+
function isTraceStorageQuery(sql) {
|
|
75
|
+
const normalized = sql.toLowerCase();
|
|
76
|
+
return TRACE_STORAGE_TABLE_NAMES.some((tableName) => normalized.includes(tableName));
|
|
77
|
+
}
|
|
78
|
+
function shouldLogQuery(sql) {
|
|
79
|
+
return databaseConfig.logging.enabled && !isTraceStorageQuery(sql);
|
|
80
|
+
}
|
|
69
81
|
function requireDb(db) {
|
|
70
82
|
if (db === null)
|
|
71
83
|
throw ErrorFactory.createConnectionError('Database not connected');
|
|
@@ -76,13 +88,13 @@ function executeQuery(db, sql, parameters) {
|
|
|
76
88
|
const stmt = db.prepare(sql);
|
|
77
89
|
if (isSelectQuery(sql)) {
|
|
78
90
|
const rows = stmt.all(parameters);
|
|
79
|
-
if (
|
|
91
|
+
if (shouldLogQuery(sql)) {
|
|
80
92
|
Logger.debug('SQLite query executed', { durationMs: performance.now() - start, sql });
|
|
81
93
|
}
|
|
82
94
|
return { rows, rowCount: rows.length };
|
|
83
95
|
}
|
|
84
96
|
const info = stmt.run(parameters);
|
|
85
|
-
if (
|
|
97
|
+
if (shouldLogQuery(sql)) {
|
|
86
98
|
Logger.debug('SQLite query executed', { durationMs: performance.now() - start, sql });
|
|
87
99
|
}
|
|
88
100
|
return { rows: [], rowCount: info.changes, lastInsertId: info.lastInsertRowid };
|
|
@@ -137,7 +149,9 @@ async function rawQuerySQLite(state, sql, parameters) {
|
|
|
137
149
|
throw ErrorFactory.createConfigError('Raw SQL queries are disabled');
|
|
138
150
|
}
|
|
139
151
|
const currentDb = requireDb(state.db);
|
|
140
|
-
|
|
152
|
+
if (!isTraceStorageQuery(sql)) {
|
|
153
|
+
Logger.warn(`Raw SQL Query executed: ${sql}`);
|
|
154
|
+
}
|
|
141
155
|
try {
|
|
142
156
|
return executeRawQuery(currentDb, sql, parameters);
|
|
143
157
|
}
|