@zintrust/core 1.5.2 → 1.5.3
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/index.js +3 -3
- package/src/migrations/schema/Schema.d.ts.map +1 -1
- package/src/migrations/schema/Schema.js +121 -5
- package/src/templates/project/basic/config/middleware.ts.tpl +3 -3
- package/src/zintrust.plugins.d.ts +6 -3
- package/src/zintrust.plugins.d.ts.map +1 -1
- package/src/zintrust.plugins.js +6 -3
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @zintrust/core v1.5.
|
|
2
|
+
* @zintrust/core v1.5.3
|
|
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-27T18:25:25.253Z
|
|
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-27T18:25:25.219Z'; // 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":"Schema.d.ts","sourceRoot":"","sources":["../../../../src/migrations/schema/Schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../../../../src/migrations/schema/Schema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAM/C,OAAO,KAAK,EAKV,aAAa,EACd,MAAM,0BAA0B,CAAC;AAkYlC,iBAAS,mBAAmB,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,CAWzD;AAED,eAAO,MAAM,MAAM;;EAEjB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
2
|
+
import { isNonEmptyString, isObject } from '../../helper/index.js';
|
|
2
3
|
import { BaseAdapter } from '../../orm/DatabaseAdapter.js';
|
|
3
4
|
import { isSqliteFamily } from '../enum/index.js';
|
|
4
5
|
import { MigrationBlueprint } from '../schema/Blueprint.js';
|
|
@@ -9,18 +10,127 @@ function assertIdentifier(label, value) {
|
|
|
9
10
|
throw ErrorFactory.createValidationError(`Invalid ${label} identifier: ${value}`);
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
|
-
function isRecord(value) {
|
|
13
|
-
return typeof value === 'object' && value !== null;
|
|
14
|
-
}
|
|
15
13
|
function getStringProp(value, key) {
|
|
16
|
-
if (!
|
|
14
|
+
if (!isObject(value))
|
|
17
15
|
return null;
|
|
18
16
|
const v = value[key];
|
|
19
|
-
return
|
|
17
|
+
return isNonEmptyString(v) ? v : null;
|
|
20
18
|
}
|
|
21
19
|
function mapNames(rows) {
|
|
22
20
|
return rows.map((r) => getStringProp(r, 'name') ?? '').filter((name) => name.length > 0);
|
|
23
21
|
}
|
|
22
|
+
function normalizeSqliteAffinity(type) {
|
|
23
|
+
if (!isNonEmptyString(type))
|
|
24
|
+
return null;
|
|
25
|
+
const normalized = type.trim().toUpperCase();
|
|
26
|
+
if (normalized.includes('INT'))
|
|
27
|
+
return 'INTEGER';
|
|
28
|
+
if (normalized.includes('CHAR') ||
|
|
29
|
+
normalized.includes('CLOB') ||
|
|
30
|
+
normalized.includes('TEXT') ||
|
|
31
|
+
normalized.includes('UUID') ||
|
|
32
|
+
normalized.includes('DATE') ||
|
|
33
|
+
normalized.includes('TIME') ||
|
|
34
|
+
normalized.includes('JSON')) {
|
|
35
|
+
return 'TEXT';
|
|
36
|
+
}
|
|
37
|
+
if (normalized.includes('BLOB'))
|
|
38
|
+
return 'BLOB';
|
|
39
|
+
if (normalized.includes('REAL') || normalized.includes('FLOA') || normalized.includes('DOUB')) {
|
|
40
|
+
return 'REAL';
|
|
41
|
+
}
|
|
42
|
+
return 'NUMERIC';
|
|
43
|
+
}
|
|
44
|
+
function getPlannedSqliteAffinity(def) {
|
|
45
|
+
switch (def.type) {
|
|
46
|
+
case 'STRING':
|
|
47
|
+
case 'DATE':
|
|
48
|
+
case 'UUID':
|
|
49
|
+
case 'TEXT':
|
|
50
|
+
case 'JSON':
|
|
51
|
+
case 'TIMESTAMP':
|
|
52
|
+
return 'TEXT';
|
|
53
|
+
case 'INTEGER':
|
|
54
|
+
case 'BIGINT':
|
|
55
|
+
return 'INTEGER';
|
|
56
|
+
case 'REAL':
|
|
57
|
+
return 'REAL';
|
|
58
|
+
case 'BLOB':
|
|
59
|
+
return 'BLOB';
|
|
60
|
+
case 'BOOLEAN':
|
|
61
|
+
return 'NUMERIC';
|
|
62
|
+
default:
|
|
63
|
+
return 'NUMERIC';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function getSqliteTableColumns(db, tableName) {
|
|
67
|
+
assertIdentifier('table', tableName);
|
|
68
|
+
const rows = await db.query(`PRAGMA table_info("${tableName}")`, [], true);
|
|
69
|
+
return rows
|
|
70
|
+
.map((row) => {
|
|
71
|
+
const name = getStringProp(row, 'name');
|
|
72
|
+
if (!isNonEmptyString(name))
|
|
73
|
+
return null;
|
|
74
|
+
return {
|
|
75
|
+
name,
|
|
76
|
+
affinity: normalizeSqliteAffinity(getStringProp(row, 'type')),
|
|
77
|
+
};
|
|
78
|
+
})
|
|
79
|
+
.filter((row) => row !== null);
|
|
80
|
+
}
|
|
81
|
+
function getColumnAffinityLabel(affinity) {
|
|
82
|
+
return affinity ?? 'unknown';
|
|
83
|
+
}
|
|
84
|
+
function buildPlannedColumnMap(columns) {
|
|
85
|
+
return new Map(columns.map((column) => [column.name, getPlannedSqliteAffinity(column)]));
|
|
86
|
+
}
|
|
87
|
+
function getColumnAffinity(columnName, existingColumns, plannedColumns) {
|
|
88
|
+
return plannedColumns.get(columnName) ?? existingColumns.get(columnName) ?? null;
|
|
89
|
+
}
|
|
90
|
+
function describeSqliteForeignKey(tableName, fk, localColumns, plannedColumns, referencedColumns) {
|
|
91
|
+
const local = fk.columns.map((column) => {
|
|
92
|
+
const affinity = getColumnAffinity(column, localColumns, plannedColumns);
|
|
93
|
+
return `${tableName}.${column} [${getColumnAffinityLabel(affinity)}]`;
|
|
94
|
+
});
|
|
95
|
+
const referenced = fk.referencedColumns.map((column) => {
|
|
96
|
+
const affinity = referencedColumns.get(column) ?? null;
|
|
97
|
+
return `${fk.referencedTable}.${column} [${getColumnAffinityLabel(affinity)}]`;
|
|
98
|
+
});
|
|
99
|
+
const hasMismatch = fk.columns.some((column, index) => {
|
|
100
|
+
const localAffinity = getColumnAffinity(column, localColumns, plannedColumns);
|
|
101
|
+
const referencedAffinity = referencedColumns.get(fk.referencedColumns[index]) ?? null;
|
|
102
|
+
return (isNonEmptyString(localAffinity) &&
|
|
103
|
+
isNonEmptyString(referencedAffinity) &&
|
|
104
|
+
localAffinity !== referencedAffinity);
|
|
105
|
+
});
|
|
106
|
+
const mismatchSuffix = hasMismatch
|
|
107
|
+
? ' (detected SQLite affinity mismatch between local and referenced columns)'
|
|
108
|
+
: '';
|
|
109
|
+
return `Add foreign key "${fk.name}": ${local.join(', ')} -> ${referenced.join(', ')}${mismatchSuffix}`;
|
|
110
|
+
}
|
|
111
|
+
async function buildSqliteAlterTableDiagnostic(db, tableName, plan) {
|
|
112
|
+
const details = [];
|
|
113
|
+
if (plan.dropColumns.length > 0) {
|
|
114
|
+
details.push(`Drop columns: ${plan.dropColumns.join(', ')}`);
|
|
115
|
+
}
|
|
116
|
+
if (plan.addForeignKeys.length > 0) {
|
|
117
|
+
const localColumns = await getSqliteTableColumns(db, tableName);
|
|
118
|
+
const localColumnMap = new Map(localColumns.map((column) => [column.name, column.affinity]));
|
|
119
|
+
const plannedColumnMap = buildPlannedColumnMap(plan.addColumns);
|
|
120
|
+
for (const fk of plan.addForeignKeys) {
|
|
121
|
+
const referenced = await getSqliteTableColumns(db, fk.referencedTable);
|
|
122
|
+
const referencedColumnMap = new Map(referenced.map((column) => [column.name, column.affinity]));
|
|
123
|
+
details.push(describeSqliteForeignKey(tableName, fk, localColumnMap, plannedColumnMap, referencedColumnMap));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (plan.dropForeignKeys.length > 0) {
|
|
127
|
+
details.push(`Drop foreign keys: ${plan.dropForeignKeys.join(', ')}`);
|
|
128
|
+
}
|
|
129
|
+
return [
|
|
130
|
+
`SQLite/D1 schema.table('${tableName}') cannot drop columns or alter foreign keys without a table rebuild.`,
|
|
131
|
+
...details,
|
|
132
|
+
].join(' ');
|
|
133
|
+
}
|
|
24
134
|
function buildParameterized(db, sql, parameters) {
|
|
25
135
|
const adapter = db.getAdapterInstance(false);
|
|
26
136
|
return BaseAdapter.buildParameterizedQuery(sql, parameters, (i) => adapter.getPlaceholder(i));
|
|
@@ -58,6 +168,12 @@ async function schemaTable(db, tableName, callback) {
|
|
|
58
168
|
addForeignKeys: def.foreignKeys,
|
|
59
169
|
dropForeignKeys: blueprint.getDropForeignKeys(),
|
|
60
170
|
};
|
|
171
|
+
if (isSqliteFamily(db.getType()) &&
|
|
172
|
+
(plan.dropColumns.length > 0 ||
|
|
173
|
+
plan.addForeignKeys.length > 0 ||
|
|
174
|
+
plan.dropForeignKeys.length > 0)) {
|
|
175
|
+
throw ErrorFactory.createValidationError(await buildSqliteAlterTableDiagnostic(db, tableName, plan));
|
|
176
|
+
}
|
|
61
177
|
const statements = MigrationSchemaCompiler.compileAlterTable(db.getType(), tableName, plan);
|
|
62
178
|
await runStatements(db, statements);
|
|
63
179
|
}
|
|
@@ -32,17 +32,17 @@ export default {
|
|
|
32
32
|
.filter((m: string) => m.length > 0) as ReadonlyArray<string>,
|
|
33
33
|
fillRateLimit: {
|
|
34
34
|
windowMs: 60_000,
|
|
35
|
-
|
|
35
|
+
maxRequests: 5,
|
|
36
36
|
message: 'Too many fill requests, please try again later.',
|
|
37
37
|
},
|
|
38
38
|
authRateLimit: {
|
|
39
39
|
windowMs: 60_000,
|
|
40
|
-
|
|
40
|
+
maxRequests: 4,
|
|
41
41
|
message: 'Too many authentication attempts, please try again later.',
|
|
42
42
|
},
|
|
43
43
|
userMutationRateLimit: {
|
|
44
44
|
windowMs: 60_000,
|
|
45
|
-
|
|
45
|
+
maxRequests: 20,
|
|
46
46
|
message: 'Too many user mutation requests, please try again later.',
|
|
47
47
|
},
|
|
48
48
|
responders: {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* ZinTrust plugin auto-imports
|
|
3
|
+
*
|
|
4
|
+
* In real projects, this file is managed by `zin plugin install` and contains
|
|
5
|
+
* side-effect imports (e.g. `@zintrust/db-sqlite/register`) that register
|
|
6
|
+
* optional adapters/drivers into core registries.
|
|
7
|
+
*
|
|
5
8
|
*/
|
|
6
9
|
export type {};
|
|
7
10
|
export declare const __zintrustGeneratedPluginStub = "zintrust.plugins.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zintrust.plugins.d.ts","sourceRoot":"","sources":["../../src/zintrust.plugins.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"zintrust.plugins.d.ts","sourceRoot":"","sources":["../../src/zintrust.plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,YAAY,EAAE,CAAC;AAgBf,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;;AACnE,wBAAkB"}
|
package/src/zintrust.plugins.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* ZinTrust plugin auto-imports
|
|
3
|
+
*
|
|
4
|
+
* In real projects, this file is managed by `zin plugin install` and contains
|
|
5
|
+
* side-effect imports (e.g. `@zintrust/db-sqlite/register`) that register
|
|
6
|
+
* optional adapters/drivers into core registries.
|
|
7
|
+
*
|
|
5
8
|
*/
|
|
6
9
|
import * as TraceRuntime from './runtime/plugins/trace-runtime.js';
|
|
7
10
|
globalThis.__zintrust_system_trace_plugin_requested__ = true;
|