@zintrust/core 0.1.8 → 0.1.9
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/README.md +17 -0
- package/package.json +1 -2
- package/src/cache/Cache.d.ts.map +1 -1
- package/src/cache/Cache.js +8 -2
- package/src/cache/CacheDriverRegistry.d.ts +15 -0
- package/src/cache/CacheDriverRegistry.d.ts.map +1 -0
- package/src/cache/CacheDriverRegistry.js +19 -0
- package/src/cli/commands/AddCommand.d.ts.map +1 -1
- package/src/cli/commands/AddCommand.js +20 -1
- package/src/cli/scaffolding/ControllerGenerator.js +2 -2
- package/src/cli/scaffolding/FeatureScaffolder.js +5 -5
- package/src/cli/scaffolding/RouteGenerator.js +1 -1
- package/src/cli/scaffolding/SeederGenerator.js +1 -1
- package/src/cli/scaffolding/ServiceIntegrationTestGenerator.js +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +4 -4
- package/src/common/uuid.d.ts +1 -1
- package/src/common/uuid.d.ts.map +1 -1
- package/src/common/uuid.js +3 -3
- package/src/config/cache.js +1 -1
- package/src/config/mail.d.ts +8 -0
- package/src/config/mail.d.ts.map +1 -1
- package/src/config/mail.js +17 -0
- package/src/config/type.d.ts +11 -2
- package/src/config/type.d.ts.map +1 -1
- package/src/index.d.ts +4 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +7 -0
- package/src/microservices/MicroserviceGenerator.js +7 -7
- package/src/microservices/PostgresAdapter.d.ts.map +1 -1
- package/src/microservices/PostgresAdapter.js +18 -0
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/Database.js +5 -0
- package/src/orm/DatabaseAdapterRegistry.d.ts +14 -0
- package/src/orm/DatabaseAdapterRegistry.d.ts.map +1 -0
- package/src/orm/DatabaseAdapterRegistry.js +19 -0
- package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.js +33 -2
- package/src/runtime/PluginManager.d.ts.map +1 -1
- package/src/runtime/PluginManager.js +68 -0
- package/src/runtime/PluginRegistry.d.ts +6 -1
- package/src/runtime/PluginRegistry.d.ts.map +1 -1
- package/src/runtime/PluginRegistry.js +56 -34
- package/src/scripts/TemplateImportsCheck.d.ts +2 -0
- package/src/scripts/TemplateImportsCheck.d.ts.map +1 -0
- package/src/scripts/TemplateImportsCheck.js +111 -0
- package/src/templates/adapters/MySQLAdapter.ts.tpl +9 -5
- package/src/templates/adapters/PostgreSQLAdapter.ts.tpl +9 -5
- package/src/templates/adapters/SQLServerAdapter.ts.tpl +9 -5
- package/src/templates/adapters/SQLiteAdapter.ts.tpl +67 -18
- package/src/templates/features/Queue.ts.tpl +2 -3
- package/src/templates/project/basic/README.md.tpl +4 -0
- package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +1 -1
- package/src/templates/project/basic/app/Models/Post.ts.tpl +1 -1
- package/src/templates/project/basic/app/Models/User.ts.tpl +1 -1
- package/src/templates/project/basic/config/FileLogWriter.ts.tpl +4 -3
- package/src/templates/project/basic/config/SecretsManager.ts.tpl +2 -2
- package/src/templates/project/basic/config/StartupConfigValidator.ts.tpl +2 -2
- package/src/templates/project/basic/config/app.ts.tpl +2 -2
- package/src/templates/project/basic/config/broadcast.ts.tpl +2 -2
- package/src/templates/project/basic/config/cache.ts.tpl +3 -3
- package/src/templates/project/basic/config/cloudflare.ts.tpl +1 -1
- package/src/templates/project/basic/config/database.ts.tpl +2 -2
- package/src/templates/project/basic/config/env.ts.tpl +1 -1
- package/src/templates/project/basic/config/features.ts.tpl +1 -1
- package/src/templates/project/basic/config/index.ts.tpl +16 -16
- package/src/templates/project/basic/config/logger.ts.tpl +9 -7
- package/src/templates/project/basic/config/logging/KvLogger.ts.tpl +2 -2
- package/src/templates/project/basic/config/mail.ts.tpl +17 -2
- package/src/templates/project/basic/config/middleware.ts.tpl +10 -7
- package/src/templates/project/basic/config/notification.ts.tpl +2 -2
- package/src/templates/project/basic/config/queue.ts.tpl +2 -2
- package/src/templates/project/basic/config/security.ts.tpl +4 -3
- package/src/templates/project/basic/config/startup.ts.tpl +1 -1
- package/src/templates/project/basic/config/storage.ts.tpl +2 -2
- package/src/templates/project/basic/config/type.ts.tpl +17 -5
- package/src/templates/project/basic/routes/api.ts.tpl +6 -6
- package/src/templates/project/basic/routes/health.ts.tpl +11 -7
- package/src/templates/project/basic/routes/storage.ts.tpl +8 -5
- package/src/templates/project/basic/src/index.ts.tpl +2 -0
- package/src/templates/project/basic/src/zintrust.plugins.ts.tpl +8 -0
- package/src/tools/broadcast/drivers/Redis.js +1 -1
- package/src/tools/mail/Mail.d.ts +1 -1
- package/src/tools/mail/Mail.d.ts.map +1 -1
- package/src/tools/mail/Mail.js +11 -0
- package/src/tools/mail/MailDriverRegistry.d.ts +16 -0
- package/src/tools/mail/MailDriverRegistry.d.ts.map +1 -0
- package/src/tools/mail/MailDriverRegistry.js +19 -0
- package/src/tools/queue/drivers/Redis.js +1 -1
|
@@ -4,13 +4,64 @@
|
|
|
4
4
|
* Production Implementation
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
import { performance } from 'node:perf_hooks';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
ErrorFactory,
|
|
11
|
+
FeatureFlags,
|
|
12
|
+
Logger,
|
|
13
|
+
QueryBuilder,
|
|
14
|
+
type DatabaseConfig,
|
|
15
|
+
type IDatabaseAdapter,
|
|
16
|
+
type QueryResult,
|
|
17
|
+
} from '@zintrust/core';
|
|
18
|
+
|
|
19
|
+
type SqliteRunInfo = { changes: number };
|
|
20
|
+
type SqliteStatement = {
|
|
21
|
+
all: (params?: readonly unknown[]) => unknown[];
|
|
22
|
+
run: (params?: readonly unknown[]) => SqliteRunInfo;
|
|
23
|
+
};
|
|
24
|
+
type SqliteDatabase = {
|
|
25
|
+
prepare: (sql: string) => SqliteStatement;
|
|
26
|
+
pragma: (value: string) => void;
|
|
27
|
+
close: () => void;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function isMissingEsmPackage(error: unknown, packageName: string): boolean {
|
|
31
|
+
if (typeof error !== 'object' || error === null) return false;
|
|
32
|
+
const maybe = error as { code?: unknown; message?: unknown };
|
|
33
|
+
const code = typeof maybe.code === 'string' ? maybe.code : '';
|
|
34
|
+
const message = typeof maybe.message === 'string' ? maybe.message : '';
|
|
35
|
+
// Some runners/wrappers preserve `code` but sanitize/omit the message.
|
|
36
|
+
if (code === 'ERR_MODULE_NOT_FOUND' && message.length === 0) return true;
|
|
37
|
+
if (code === 'ERR_MODULE_NOT_FOUND' && message.includes(`'${packageName}'`)) return true;
|
|
38
|
+
if (message.includes(`Cannot find package '${packageName}'`)) return true;
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function importSqliteDatabaseConstructor(): Promise<
|
|
43
|
+
new (filename: string) => SqliteDatabase
|
|
44
|
+
> {
|
|
45
|
+
try {
|
|
46
|
+
const mod = (await import('better-sqlite3')) as unknown as {
|
|
47
|
+
default?: new (filename: string) => SqliteDatabase;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const ctor = (mod as unknown as { default?: unknown }).default;
|
|
51
|
+
if (typeof ctor === 'function') return ctor as new (filename: string) => SqliteDatabase;
|
|
52
|
+
|
|
53
|
+
// Some CJS packages may not present a `default` export under certain loaders.
|
|
54
|
+
return mod as unknown as new (filename: string) => SqliteDatabase;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (isMissingEsmPackage(error, 'better-sqlite3')) {
|
|
57
|
+
throw ErrorFactory.createConfigError(
|
|
58
|
+
"SQLite adapter requires the 'better-sqlite3' package (run `zin add db:sqlite` or `zin plugin install db:sqlite`)."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throw ErrorFactory.createTryCatchError('Failed to load SQLite driver', { cause: error });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
14
65
|
|
|
15
66
|
function normalizeFilename(database: string | null | undefined): string {
|
|
16
67
|
const value = (database ?? '').trim();
|
|
@@ -21,13 +72,13 @@ function isSelectQuery(sql: string): boolean {
|
|
|
21
72
|
return sql.trimStart().toLowerCase().startsWith('select');
|
|
22
73
|
}
|
|
23
74
|
|
|
24
|
-
function requireDb(db:
|
|
75
|
+
function requireDb(db: SqliteDatabase | null): SqliteDatabase {
|
|
25
76
|
if (db === null) throw ErrorFactory.createConnectionError('Database not connected');
|
|
26
77
|
return db;
|
|
27
78
|
}
|
|
28
79
|
|
|
29
80
|
function executeQuery(
|
|
30
|
-
db:
|
|
81
|
+
db: SqliteDatabase,
|
|
31
82
|
sql: string,
|
|
32
83
|
parameters: readonly unknown[]
|
|
33
84
|
): QueryResult {
|
|
@@ -45,11 +96,7 @@ function executeQuery(
|
|
|
45
96
|
return { rows: [], rowCount: info.changes };
|
|
46
97
|
}
|
|
47
98
|
|
|
48
|
-
function executeRawQuery<T>(
|
|
49
|
-
db: Database.Database,
|
|
50
|
-
sql: string,
|
|
51
|
-
parameters: readonly unknown[]
|
|
52
|
-
): T[] {
|
|
99
|
+
function executeRawQuery<T>(db: SqliteDatabase, sql: string, parameters: readonly unknown[]): T[] {
|
|
53
100
|
const stmt = db.prepare(sql);
|
|
54
101
|
if (isSelectQuery(sql)) return stmt.all(parameters) as T[];
|
|
55
102
|
stmt.run(parameters);
|
|
@@ -57,7 +104,7 @@ function executeRawQuery<T>(
|
|
|
57
104
|
}
|
|
58
105
|
|
|
59
106
|
type SQLiteAdapterState = {
|
|
60
|
-
db:
|
|
107
|
+
db: SqliteDatabase | null;
|
|
61
108
|
config: DatabaseConfig;
|
|
62
109
|
};
|
|
63
110
|
|
|
@@ -65,7 +112,9 @@ async function connectSQLite(state: SQLiteAdapterState): Promise<void> {
|
|
|
65
112
|
if (state.db !== null) return;
|
|
66
113
|
|
|
67
114
|
const filename = normalizeFilename(state.config.database);
|
|
68
|
-
|
|
115
|
+
|
|
116
|
+
const SqliteDatabaseCtor = await importSqliteDatabaseConstructor();
|
|
117
|
+
state.db = new SqliteDatabaseCtor(filename);
|
|
69
118
|
|
|
70
119
|
// Enable WAL mode for better concurrency
|
|
71
120
|
state.db.pragma('journal_mode = WAL');
|
|
@@ -118,7 +167,7 @@ async function rawQuerySQLite<T>(
|
|
|
118
167
|
async function transactionSQLite<T>(
|
|
119
168
|
state: SQLiteAdapterState,
|
|
120
169
|
adapter: IDatabaseAdapter,
|
|
121
|
-
callback: (adapter: IDatabaseAdapter, db:
|
|
170
|
+
callback: (adapter: IDatabaseAdapter, db: SqliteDatabase) => Promise<T>
|
|
122
171
|
): Promise<T> {
|
|
123
172
|
const currentDb = requireDb(state.db);
|
|
124
173
|
|
|
@@ -162,7 +211,7 @@ function createSQLiteAdapter(config: DatabaseConfig): IDatabaseAdapter {
|
|
|
162
211
|
},
|
|
163
212
|
|
|
164
213
|
async transaction<T>(
|
|
165
|
-
callback: (adapter: IDatabaseAdapter, db:
|
|
214
|
+
callback: (adapter: IDatabaseAdapter, db: SqliteDatabase) => Promise<T>
|
|
166
215
|
): Promise<T> {
|
|
167
216
|
return transactionSQLite(state, adapter, callback);
|
|
168
217
|
},
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// TEMPLATE_START
|
|
2
2
|
|
|
3
|
-
import { generateSecureJobId } from '@
|
|
4
|
-
import { Logger } from '@config/logger';
|
|
3
|
+
import { generateSecureJobId, Logger } from '@zintrust/core';
|
|
5
4
|
|
|
6
5
|
export interface QueueJob {
|
|
7
6
|
id: string;
|
|
@@ -44,4 +43,4 @@ export const Queue = Object.freeze({
|
|
|
44
43
|
},
|
|
45
44
|
});
|
|
46
45
|
|
|
47
|
-
// TEMPLATE_END
|
|
46
|
+
// TEMPLATE_END
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Example controller demonstrating request handling
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { User } from '
|
|
6
|
+
import { User } from '../Models/User';
|
|
7
7
|
import { Logger } from '@zintrust/core';
|
|
8
8
|
import { IRequest } from '@zintrust/core';
|
|
9
9
|
import { IResponse } from '@zintrust/core';
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ensureDirSafe } from '@zintrust/core';
|
|
7
|
-
import
|
|
8
|
-
import * as
|
|
9
|
-
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
|
|
10
|
+
import { Env } from './env';
|
|
10
11
|
|
|
11
12
|
const getCwdSafe = (): string => {
|
|
12
13
|
try {
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* Supports: AWS Secrets Manager, Parameter Store, Cloudflare KV, Deno env
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Logger } from '@
|
|
7
|
+
import { Logger } from '@zintrust/core';
|
|
8
8
|
import type {
|
|
9
9
|
GetSecretOptions,
|
|
10
10
|
SecretConfig,
|
|
11
11
|
SecretsManagerInstance,
|
|
12
12
|
SetSecretOptions,
|
|
13
|
-
} from '
|
|
13
|
+
} from './type';
|
|
14
14
|
import { ErrorFactory } from '@zintrust/core';
|
|
15
15
|
|
|
16
16
|
let instance: SecretsManagerInstance | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { appConfig } from '
|
|
2
|
-
import type { StartupConfigValidationError, StartupConfigValidationResult } from '
|
|
1
|
+
import { appConfig } from './app';
|
|
2
|
+
import type { StartupConfigValidationError, StartupConfigValidationResult } from './type';
|
|
3
3
|
import { ErrorFactory } from '@zintrust/core';
|
|
4
4
|
|
|
5
5
|
const isSensitiveKey = (key: string): boolean => {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Sealed namespace for immutability
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Env } from '
|
|
8
|
-
import type { Environment, ProcessLike, StartMode } from '
|
|
7
|
+
import { Env } from './env';
|
|
8
|
+
import type { Environment, ProcessLike, StartMode } from './type';
|
|
9
9
|
|
|
10
10
|
const getProcessLike = (): ProcessLike | undefined => {
|
|
11
11
|
return typeof process === 'undefined' ? undefined : (process as unknown as ProcessLike);
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* Driver selection must be dynamic (tests may mutate process.env).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Env } from '
|
|
8
|
+
import { Env } from './env';
|
|
9
9
|
import {
|
|
10
10
|
KnownBroadcastDriverConfig,
|
|
11
11
|
PusherBroadcastDriverConfig,
|
|
12
12
|
RedisBroadcastDriverConfig,
|
|
13
13
|
RedisHttpsBroadcastDriverConfig,
|
|
14
|
-
} from '
|
|
14
|
+
} from './type';
|
|
15
15
|
|
|
16
16
|
const normalizeDriverName = (value: string): string => value.trim().toLowerCase();
|
|
17
17
|
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Sealed namespace for immutability
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Env } from '
|
|
8
|
-
import { CacheConfigInput, CacheDriverConfig, CacheDrivers } from '
|
|
7
|
+
import { Env } from './env';
|
|
8
|
+
import { CacheConfigInput, CacheDriverConfig, CacheDrivers } from './type';
|
|
9
9
|
|
|
10
10
|
const getCacheDriver = (config: CacheConfigInput): CacheDriverConfig => {
|
|
11
11
|
const defaultDriver = config.default;
|
|
@@ -22,7 +22,7 @@ const cacheConfigObj = {
|
|
|
22
22
|
/**
|
|
23
23
|
* Default cache driver
|
|
24
24
|
*/
|
|
25
|
-
default: Env.
|
|
25
|
+
default: Env.CACHE_DRIVER,
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Cache drivers
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* This keeps runtime-specific globals out of adapters/drivers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { KVNamespace, WorkersEnv } from '
|
|
8
|
+
import { KVNamespace, WorkersEnv } from './type';
|
|
9
9
|
import type { DatabaseConfig, ID1Database } from '@zintrust/core';
|
|
10
10
|
|
|
11
11
|
const getWorkersEnv = (): WorkersEnv | null => {
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* Sealed namespace for immutability
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Env } from '
|
|
7
|
+
import { Env } from './env';
|
|
8
8
|
import {
|
|
9
9
|
DatabaseConfigShape,
|
|
10
10
|
DatabaseConnectionConfig,
|
|
11
11
|
DatabaseConnectionName,
|
|
12
|
-
} from '
|
|
12
|
+
} from './type';
|
|
13
13
|
|
|
14
14
|
const isDatabaseConnectionName = (value: string): value is DatabaseConnectionName => {
|
|
15
15
|
return value === 'sqlite' || value === 'postgresql' || value === 'mysql';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Safe for both Node.js and serverless runtimes (Cloudflare Workers, Deno, Lambda)
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { ProcessLike } from '
|
|
9
|
+
import { ProcessLike } from './type';
|
|
10
10
|
|
|
11
11
|
const getProcessLike = (): ProcessLike | undefined => {
|
|
12
12
|
return typeof process === 'undefined' ? undefined : (process as unknown as ProcessLike);
|
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
* Central export point for all configuration
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { appConfig } from '
|
|
7
|
-
import { cacheConfig } from '
|
|
8
|
-
import { databaseConfig } from '
|
|
9
|
-
import { microservicesConfig } from '
|
|
10
|
-
import { middlewareConfig } from '
|
|
11
|
-
import { queueConfig } from '
|
|
12
|
-
import { securityConfig } from '
|
|
13
|
-
import { storageConfig } from '
|
|
6
|
+
import { appConfig } from './app';
|
|
7
|
+
import { cacheConfig } from './cache';
|
|
8
|
+
import { databaseConfig } from './database';
|
|
9
|
+
import { microservicesConfig } from './microservices';
|
|
10
|
+
import { middlewareConfig } from './middleware';
|
|
11
|
+
import { queueConfig } from './queue';
|
|
12
|
+
import { securityConfig } from './security';
|
|
13
|
+
import { storageConfig } from './storage';
|
|
14
14
|
|
|
15
|
-
export { appConfig, type AppConfig } from '
|
|
16
|
-
export { cacheConfig, type CacheConfig } from '
|
|
17
|
-
export { databaseConfig, type DatabaseConfig } from '
|
|
18
|
-
export { microservicesConfig, type MicroservicesConfig } from '
|
|
19
|
-
export { middlewareConfig } from '
|
|
20
|
-
export { queueConfig, type QueueConfig } from '
|
|
21
|
-
export { securityConfig } from '
|
|
22
|
-
export { storageConfig, type StorageConfig } from '
|
|
15
|
+
export { appConfig, type AppConfig } from './app';
|
|
16
|
+
export { cacheConfig, type CacheConfig } from './cache';
|
|
17
|
+
export { databaseConfig, type DatabaseConfig } from './database';
|
|
18
|
+
export { microservicesConfig, type MicroservicesConfig } from './microservices';
|
|
19
|
+
export { middlewareConfig } from './middleware';
|
|
20
|
+
export { queueConfig, type QueueConfig } from './queue';
|
|
21
|
+
export { securityConfig } from './security';
|
|
22
|
+
export { storageConfig, type StorageConfig } from './storage';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Combined configuration object
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
* Sealed namespace pattern - all exports through Logger namespace
|
|
4
4
|
* Replaces console.* calls throughout the codebase
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { Logger } from '@zintrust/core';
|
|
7
|
+
|
|
8
|
+
import { appConfig } from './app';
|
|
9
|
+
import { Env } from './env';
|
|
8
10
|
|
|
9
11
|
interface ILogger {
|
|
10
12
|
debug(message: string, data?: unknown, category?: string): void;
|
|
@@ -87,7 +89,7 @@ let fileWriter: FileWriterModule['FileLogWriter'] | undefined;
|
|
|
87
89
|
const getFileWriter = (): void => {
|
|
88
90
|
if (fileWriter !== undefined) return;
|
|
89
91
|
if (fileWriterPromise !== undefined) return;
|
|
90
|
-
fileWriterPromise = import('
|
|
92
|
+
fileWriterPromise = import('./FileLogWriter')
|
|
91
93
|
.then((mod) => {
|
|
92
94
|
fileWriter = mod.FileLogWriter;
|
|
93
95
|
return mod;
|
|
@@ -195,7 +197,7 @@ const emitCloudLogs = (event: CloudLogEvent): void => {
|
|
|
195
197
|
void (async (): Promise<void> => {
|
|
196
198
|
try {
|
|
197
199
|
if (event.level === 'error' || event.level === 'fatal') {
|
|
198
|
-
const mod = await import('
|
|
200
|
+
const mod = await import('./logging/KvLogger');
|
|
199
201
|
void mod.KvLogger.enqueue(event);
|
|
200
202
|
}
|
|
201
203
|
} catch {
|
|
@@ -204,7 +206,7 @@ const emitCloudLogs = (event: CloudLogEvent): void => {
|
|
|
204
206
|
|
|
205
207
|
try {
|
|
206
208
|
if (event.level === 'warn' || event.level === 'error' || event.level === 'fatal') {
|
|
207
|
-
const mod = await import('
|
|
209
|
+
const mod = await import('./logging/SlackLogger');
|
|
208
210
|
void mod.SlackLogger.enqueue(event);
|
|
209
211
|
}
|
|
210
212
|
} catch {
|
|
@@ -212,7 +214,7 @@ const emitCloudLogs = (event: CloudLogEvent): void => {
|
|
|
212
214
|
}
|
|
213
215
|
|
|
214
216
|
try {
|
|
215
|
-
const mod = await import('
|
|
217
|
+
const mod = await import('./logging/HttpLogger');
|
|
216
218
|
void mod.HttpLogger.enqueue(event);
|
|
217
219
|
} catch {
|
|
218
220
|
// best-effort
|
|
@@ -364,7 +366,7 @@ export const cleanLogsOnce = async (): Promise<string[]> => {
|
|
|
364
366
|
if (!shouldLogToFile()) return [];
|
|
365
367
|
|
|
366
368
|
try {
|
|
367
|
-
const mod = await import('
|
|
369
|
+
const mod = await import('./FileLogWriter');
|
|
368
370
|
const deleted = mod.cleanOnce();
|
|
369
371
|
logInfo('Log cleanup executed', { deletedCount: deleted.length });
|
|
370
372
|
return deleted;
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* - KV_LOG_RETENTION_DAYS (default: 30)
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { Cloudflare } from '
|
|
12
|
-
import { Env } from '
|
|
11
|
+
import { Cloudflare } from '../cloudflare';
|
|
12
|
+
import { Env } from '../env';
|
|
13
13
|
|
|
14
14
|
export type KvLogEvent = {
|
|
15
15
|
timestamp: string;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Sealed namespace for immutability
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Env } from '
|
|
8
|
-
import type { MailConfigInput, MailDriverConfig, MailDriverName, MailDrivers } from '
|
|
7
|
+
import { Env } from './env';
|
|
8
|
+
import type { MailConfigInput, MailDriverConfig, MailDriverName, MailDrivers } from './type';
|
|
9
9
|
|
|
10
10
|
const getMailDriver = (config: MailConfigInput): MailDriverConfig => {
|
|
11
11
|
const defaultDriver = config.default;
|
|
@@ -67,6 +67,21 @@ const mailConfigObj = {
|
|
|
67
67
|
})(),
|
|
68
68
|
},
|
|
69
69
|
|
|
70
|
+
nodemailer: {
|
|
71
|
+
driver: 'nodemailer' as const,
|
|
72
|
+
host: Env.get('MAIL_HOST', ''),
|
|
73
|
+
port: Env.getInt('MAIL_PORT', 587),
|
|
74
|
+
username: Env.get('MAIL_USERNAME', ''),
|
|
75
|
+
password: Env.get('MAIL_PASSWORD', ''),
|
|
76
|
+
secure: (() => {
|
|
77
|
+
const raw = Env.get('MAIL_SECURE', '').trim().toLowerCase();
|
|
78
|
+
if (raw === 'starttls') return 'starttls' as const;
|
|
79
|
+
if (raw === 'tls' || raw === 'ssl' || raw === 'smtps' || raw === 'implicit') return true;
|
|
80
|
+
if (raw === 'none' || raw === 'off' || raw === 'false' || raw === '0') return false;
|
|
81
|
+
return Env.getBool('MAIL_SECURE', false);
|
|
82
|
+
})(),
|
|
83
|
+
},
|
|
84
|
+
|
|
70
85
|
ses: {
|
|
71
86
|
driver: 'ses' as const,
|
|
72
87
|
region: Env.get('AWS_REGION', 'us-east-1'),
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import {
|
|
2
|
+
CsrfMiddleware,
|
|
3
|
+
ErrorHandlerMiddleware,
|
|
4
|
+
LoggingMiddleware,
|
|
5
|
+
RateLimiter,
|
|
6
|
+
SecurityMiddleware,
|
|
7
|
+
type Middleware,
|
|
8
|
+
} from '@zintrust/core';
|
|
9
|
+
|
|
10
|
+
import { MiddlewareConfigType } from './type';
|
|
8
11
|
|
|
9
12
|
const shared = Object.freeze({
|
|
10
13
|
log: LoggingMiddleware.create(),
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Keeps runtime driver selection in one place and uses Env for safe access.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Env } from '
|
|
9
|
-
import type { NotificationProviders } from '
|
|
8
|
+
import { Env } from './env';
|
|
9
|
+
import type { NotificationProviders } from './type';
|
|
10
10
|
|
|
11
11
|
const notificationConfigObj = {
|
|
12
12
|
/**
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Sealed namespace for immutability
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Env } from '
|
|
7
|
+
import { Env } from './env';
|
|
8
8
|
|
|
9
|
-
import type { QueueConfigWithDrivers, QueueDriverName, QueueDriversConfig } from '
|
|
9
|
+
import type { QueueConfigWithDrivers, QueueDriverName, QueueDriversConfig } from './type';
|
|
10
10
|
|
|
11
11
|
const getQueueDriver = (config: QueueConfigWithDrivers): QueueDriversConfig[QueueDriverName] => {
|
|
12
12
|
const driverName = config.default;
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
* security domains (e.g., different keys for different microservices).
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
import {
|
|
19
|
+
import { Logger } from '@zintrust/core';
|
|
20
|
+
|
|
21
|
+
import { appConfig } from './app';
|
|
22
|
+
import { Env } from './env';
|
|
22
23
|
import { ErrorFactory } from '@zintrust/core';
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* Sealed namespace for immutability
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Env } from '
|
|
7
|
+
import { Env } from './env';
|
|
8
8
|
import type {
|
|
9
9
|
StorageConfigRuntime,
|
|
10
10
|
StorageDriverConfig,
|
|
11
11
|
StorageDriverName,
|
|
12
12
|
StorageDrivers,
|
|
13
|
-
} from '
|
|
13
|
+
} from './type';
|
|
14
14
|
|
|
15
15
|
const isStorageDriverName = (
|
|
16
16
|
value: string,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { Middleware } from '@zintrust/core';
|
|
2
|
+
|
|
3
|
+
import { Env } from './env';
|
|
3
4
|
|
|
4
5
|
export type Environment =
|
|
5
6
|
| 'development'
|
|
@@ -202,11 +203,11 @@ export type NotificationProviders = {
|
|
|
202
203
|
};
|
|
203
204
|
|
|
204
205
|
export type MiddlewareConfigType = {
|
|
205
|
-
global:
|
|
206
|
-
route: Record<string,
|
|
206
|
+
global: Middleware[];
|
|
207
|
+
route: Record<string, Middleware>;
|
|
207
208
|
};
|
|
208
209
|
|
|
209
|
-
export type MailDriverName = 'disabled' | 'sendgrid' | 'smtp' | 'ses' | 'mailgun';
|
|
210
|
+
export type MailDriverName = 'disabled' | 'sendgrid' | 'smtp' | 'ses' | 'mailgun' | 'nodemailer';
|
|
210
211
|
|
|
211
212
|
export type DisabledMailDriverConfig = {
|
|
212
213
|
driver: 'disabled';
|
|
@@ -234,6 +235,15 @@ export type SmtpMailDriverConfig = {
|
|
|
234
235
|
secure: boolean | 'starttls';
|
|
235
236
|
};
|
|
236
237
|
|
|
238
|
+
export type NodemailerMailDriverConfig = {
|
|
239
|
+
driver: 'nodemailer';
|
|
240
|
+
host: string;
|
|
241
|
+
port: number;
|
|
242
|
+
username: string;
|
|
243
|
+
password: string;
|
|
244
|
+
secure: boolean | 'starttls';
|
|
245
|
+
};
|
|
246
|
+
|
|
237
247
|
export type SesMailDriverConfig = {
|
|
238
248
|
driver: 'ses';
|
|
239
249
|
region: string;
|
|
@@ -244,6 +254,7 @@ export type MailDriverConfig =
|
|
|
244
254
|
| SendGridMailDriverConfig
|
|
245
255
|
| MailgunMailDriverConfig
|
|
246
256
|
| SmtpMailDriverConfig
|
|
257
|
+
| NodemailerMailDriverConfig
|
|
247
258
|
| SesMailDriverConfig;
|
|
248
259
|
|
|
249
260
|
export type MailDrivers = {
|
|
@@ -251,6 +262,7 @@ export type MailDrivers = {
|
|
|
251
262
|
sendgrid: SendGridMailDriverConfig;
|
|
252
263
|
mailgun: MailgunMailDriverConfig;
|
|
253
264
|
smtp: SmtpMailDriverConfig;
|
|
265
|
+
nodemailer: NodemailerMailDriverConfig;
|
|
254
266
|
ses: SesMailDriverConfig;
|
|
255
267
|
};
|
|
256
268
|
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* Demonstrates routing patterns
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
6
|
+
import { Env, type IRouter, Router } from '@zintrust/core';
|
|
7
|
+
|
|
8
|
+
import { UserController } from '../app/Controllers/UserController';
|
|
9
|
+
import { registerBroadcastRoutes } from './broadcast';
|
|
10
|
+
import { registerHealthRoutes } from './health';
|
|
11
|
+
import { registerStorageRoutes } from './storage';
|
|
12
12
|
|
|
13
13
|
export function registerRoutes(router: IRouter): void {
|
|
14
14
|
const userController = UserController.create();
|