@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.
Files changed (88) hide show
  1. package/README.md +17 -0
  2. package/package.json +1 -2
  3. package/src/cache/Cache.d.ts.map +1 -1
  4. package/src/cache/Cache.js +8 -2
  5. package/src/cache/CacheDriverRegistry.d.ts +15 -0
  6. package/src/cache/CacheDriverRegistry.d.ts.map +1 -0
  7. package/src/cache/CacheDriverRegistry.js +19 -0
  8. package/src/cli/commands/AddCommand.d.ts.map +1 -1
  9. package/src/cli/commands/AddCommand.js +20 -1
  10. package/src/cli/scaffolding/ControllerGenerator.js +2 -2
  11. package/src/cli/scaffolding/FeatureScaffolder.js +5 -5
  12. package/src/cli/scaffolding/RouteGenerator.js +1 -1
  13. package/src/cli/scaffolding/SeederGenerator.js +1 -1
  14. package/src/cli/scaffolding/ServiceIntegrationTestGenerator.js +1 -1
  15. package/src/cli/scaffolding/ServiceScaffolder.js +4 -4
  16. package/src/common/uuid.d.ts +1 -1
  17. package/src/common/uuid.d.ts.map +1 -1
  18. package/src/common/uuid.js +3 -3
  19. package/src/config/cache.js +1 -1
  20. package/src/config/mail.d.ts +8 -0
  21. package/src/config/mail.d.ts.map +1 -1
  22. package/src/config/mail.js +17 -0
  23. package/src/config/type.d.ts +11 -2
  24. package/src/config/type.d.ts.map +1 -1
  25. package/src/index.d.ts +4 -0
  26. package/src/index.d.ts.map +1 -1
  27. package/src/index.js +7 -0
  28. package/src/microservices/MicroserviceGenerator.js +7 -7
  29. package/src/microservices/PostgresAdapter.d.ts.map +1 -1
  30. package/src/microservices/PostgresAdapter.js +18 -0
  31. package/src/orm/Database.d.ts.map +1 -1
  32. package/src/orm/Database.js +5 -0
  33. package/src/orm/DatabaseAdapterRegistry.d.ts +14 -0
  34. package/src/orm/DatabaseAdapterRegistry.d.ts.map +1 -0
  35. package/src/orm/DatabaseAdapterRegistry.js +19 -0
  36. package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
  37. package/src/orm/adapters/SQLiteAdapter.js +33 -2
  38. package/src/runtime/PluginManager.d.ts.map +1 -1
  39. package/src/runtime/PluginManager.js +68 -0
  40. package/src/runtime/PluginRegistry.d.ts +6 -1
  41. package/src/runtime/PluginRegistry.d.ts.map +1 -1
  42. package/src/runtime/PluginRegistry.js +56 -34
  43. package/src/scripts/TemplateImportsCheck.d.ts +2 -0
  44. package/src/scripts/TemplateImportsCheck.d.ts.map +1 -0
  45. package/src/scripts/TemplateImportsCheck.js +111 -0
  46. package/src/templates/adapters/MySQLAdapter.ts.tpl +9 -5
  47. package/src/templates/adapters/PostgreSQLAdapter.ts.tpl +9 -5
  48. package/src/templates/adapters/SQLServerAdapter.ts.tpl +9 -5
  49. package/src/templates/adapters/SQLiteAdapter.ts.tpl +67 -18
  50. package/src/templates/features/Queue.ts.tpl +2 -3
  51. package/src/templates/project/basic/README.md.tpl +4 -0
  52. package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +1 -1
  53. package/src/templates/project/basic/app/Models/Post.ts.tpl +1 -1
  54. package/src/templates/project/basic/app/Models/User.ts.tpl +1 -1
  55. package/src/templates/project/basic/config/FileLogWriter.ts.tpl +4 -3
  56. package/src/templates/project/basic/config/SecretsManager.ts.tpl +2 -2
  57. package/src/templates/project/basic/config/StartupConfigValidator.ts.tpl +2 -2
  58. package/src/templates/project/basic/config/app.ts.tpl +2 -2
  59. package/src/templates/project/basic/config/broadcast.ts.tpl +2 -2
  60. package/src/templates/project/basic/config/cache.ts.tpl +3 -3
  61. package/src/templates/project/basic/config/cloudflare.ts.tpl +1 -1
  62. package/src/templates/project/basic/config/database.ts.tpl +2 -2
  63. package/src/templates/project/basic/config/env.ts.tpl +1 -1
  64. package/src/templates/project/basic/config/features.ts.tpl +1 -1
  65. package/src/templates/project/basic/config/index.ts.tpl +16 -16
  66. package/src/templates/project/basic/config/logger.ts.tpl +9 -7
  67. package/src/templates/project/basic/config/logging/KvLogger.ts.tpl +2 -2
  68. package/src/templates/project/basic/config/mail.ts.tpl +17 -2
  69. package/src/templates/project/basic/config/middleware.ts.tpl +10 -7
  70. package/src/templates/project/basic/config/notification.ts.tpl +2 -2
  71. package/src/templates/project/basic/config/queue.ts.tpl +2 -2
  72. package/src/templates/project/basic/config/security.ts.tpl +4 -3
  73. package/src/templates/project/basic/config/startup.ts.tpl +1 -1
  74. package/src/templates/project/basic/config/storage.ts.tpl +2 -2
  75. package/src/templates/project/basic/config/type.ts.tpl +17 -5
  76. package/src/templates/project/basic/routes/api.ts.tpl +6 -6
  77. package/src/templates/project/basic/routes/health.ts.tpl +11 -7
  78. package/src/templates/project/basic/routes/storage.ts.tpl +8 -5
  79. package/src/templates/project/basic/src/index.ts.tpl +2 -0
  80. package/src/templates/project/basic/src/zintrust.plugins.ts.tpl +8 -0
  81. package/src/tools/broadcast/drivers/Redis.js +1 -1
  82. package/src/tools/mail/Mail.d.ts +1 -1
  83. package/src/tools/mail/Mail.d.ts.map +1 -1
  84. package/src/tools/mail/Mail.js +11 -0
  85. package/src/tools/mail/MailDriverRegistry.d.ts +16 -0
  86. package/src/tools/mail/MailDriverRegistry.d.ts.map +1 -0
  87. package/src/tools/mail/MailDriverRegistry.js +19 -0
  88. package/src/tools/queue/drivers/Redis.js +1 -1
@@ -4,13 +4,64 @@
4
4
  * Production Implementation
5
5
  */
6
6
 
7
- import { FeatureFlags } from '@config/features';
8
- import { Logger } from '@config/logger';
9
- import { ErrorFactory } from '@exceptions/ZintrustError';
10
- import { performance } from '@node-singletons/perf-hooks';
11
- import { DatabaseConfig, IDatabaseAdapter, QueryResult } from '@orm/DatabaseAdapter';
12
- import { QueryBuilder } from '@orm/QueryBuilder';
13
- import Database from 'better-sqlite3';
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: Database.Database | null): Database.Database {
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: Database.Database,
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: Database.Database | null;
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
- state.db = new Database(filename);
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: Database.Database) => Promise<T>
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: Database.Database) => Promise<T>
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 '@common/uuid';
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
@@ -6,6 +6,10 @@ Starter Task API built with Zintrust.
6
6
 
7
7
  ```bash
8
8
  npm install
9
+
10
+ # Install optional runtime drivers on-demand (example: SQLite)
11
+ zin add db:sqlite
12
+
9
13
  zin s
10
14
  ```
11
15
 
@@ -3,7 +3,7 @@
3
3
  * Example controller demonstrating request handling
4
4
  */
5
5
 
6
- import { User } from '@app/Models/User';
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';
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import { IRelationship } from '@zintrust/core';
6
- import { User } from '@app/Models/User';
6
+ import { User } from './User';
7
7
  import { IModel, Model, ModelConfig } from '@zintrust/core';
8
8
 
9
9
  export const PostConfig: ModelConfig = {
@@ -2,7 +2,7 @@
2
2
  * User Model
3
3
  */
4
4
 
5
- import { Post } from '@app/Models/Post';
5
+ import { Post } from './Post';
6
6
  import { IModel, Model } from '@zintrust/core';
7
7
 
8
8
  /**
@@ -4,9 +4,10 @@
4
4
  */
5
5
 
6
6
  import { ensureDirSafe } from '@zintrust/core';
7
- import { Env } from '@zintrust/core';
8
- import * as fs from '@node-singletons/fs';
9
- import * as path from '@node-singletons/path';
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 '@config/logger';
7
+ import { Logger } from '@zintrust/core';
8
8
  import type {
9
9
  GetSecretOptions,
10
10
  SecretConfig,
11
11
  SecretsManagerInstance,
12
12
  SetSecretOptions,
13
- } from '@config/type';
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 '@config/app';
2
- import type { StartupConfigValidationError, StartupConfigValidationResult } from '@config/type';
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 '@config/env';
8
- import type { Environment, ProcessLike, StartMode } from '@config/type';
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 '@config/env';
8
+ import { Env } from './env';
9
9
  import {
10
10
  KnownBroadcastDriverConfig,
11
11
  PusherBroadcastDriverConfig,
12
12
  RedisBroadcastDriverConfig,
13
13
  RedisHttpsBroadcastDriverConfig,
14
- } from '@config/type';
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 '@config/env';
8
- import { CacheConfigInput, CacheDriverConfig, CacheDrivers } from '@config/type';
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.get('CACHE_DRIVER', 'memory'),
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 '@config/type';
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 '@config/env';
7
+ import { Env } from './env';
8
8
  import {
9
9
  DatabaseConfigShape,
10
10
  DatabaseConnectionConfig,
11
11
  DatabaseConnectionName,
12
- } from '@config/type';
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 '@config/type';
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);
@@ -1,5 +1,5 @@
1
1
  import { Env } from '@zintrust/core';
2
- import { Logger } from '@config/logger';
2
+ import { Logger } from '@zintrust/core';
3
3
 
4
4
  /**
5
5
  * Feature Flags State
@@ -3,23 +3,23 @@
3
3
  * Central export point for all configuration
4
4
  */
5
5
 
6
- import { appConfig } from '@config/app';
7
- import { cacheConfig } from '@config/cache';
8
- import { databaseConfig } from '@config/database';
9
- import { microservicesConfig } from '@config/microservices';
10
- import { middlewareConfig } from '@config/middleware';
11
- import { queueConfig } from '@config/queue';
12
- import { securityConfig } from '@config/security';
13
- import { storageConfig } from '@config/storage';
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 '@config/app';
16
- export { cacheConfig, type CacheConfig } from '@config/cache';
17
- export { databaseConfig, type DatabaseConfig } from '@config/database';
18
- export { microservicesConfig, type MicroservicesConfig } from '@config/microservices';
19
- export { middlewareConfig } from '@config/middleware';
20
- export { queueConfig, type QueueConfig } from '@config/queue';
21
- export { securityConfig } from '@config/security';
22
- export { storageConfig, type StorageConfig } from '@config/storage';
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 { appConfig } from '@config/app';
7
- import { Env } from '@config/env';
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('@config/FileLogWriter')
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('@config/logging/KvLogger');
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('@config/logging/SlackLogger');
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('@config/logging/HttpLogger');
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('@config/FileLogWriter');
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 '@config/cloudflare';
12
- import { Env } from '@zintrust/core';
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 '@config/env';
8
- import type { MailConfigInput, MailDriverConfig, MailDriverName, MailDrivers } from '@config/type';
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 { MiddlewareConfigType } from '@config/type';
2
- import { CsrfMiddleware } from '@middleware/CsrfMiddleware';
3
- import { ErrorHandlerMiddleware } from '@middleware/ErrorHandlerMiddleware';
4
- import { LoggingMiddleware } from '@middleware/LoggingMiddleware';
5
- import type { Middleware } from '@middleware/MiddlewareStack';
6
- import { RateLimiter } from '@middleware/RateLimiter';
7
- import { SecurityMiddleware } from '@middleware/SecurityMiddleware';
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 '@config/env';
9
- import type { NotificationProviders } from '@config/type';
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 '@config/env';
7
+ import { Env } from './env';
8
8
 
9
- import type { QueueConfigWithDrivers, QueueDriverName, QueueDriversConfig } from '@config/type';
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 { appConfig } from '@config/app';
20
- import { Env } from '@config/env';
21
- import { Logger } from '@config/logger';
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,7 +4,7 @@
4
4
  * Startup-only controls (evaluated during Application.boot()).
5
5
  */
6
6
 
7
- import { Env } from '@config/env';
7
+ import { Env } from './env';
8
8
 
9
9
  export type StartupConfig = {
10
10
  healthChecksEnabled: boolean;
@@ -4,13 +4,13 @@
4
4
  * Sealed namespace for immutability
5
5
  */
6
6
 
7
- import { Env } from '@config/env';
7
+ import { Env } from './env';
8
8
  import type {
9
9
  StorageConfigRuntime,
10
10
  StorageDriverConfig,
11
11
  StorageDriverName,
12
12
  StorageDrivers,
13
- } from '@config/type';
13
+ } from './type';
14
14
 
15
15
  const isStorageDriverName = (
16
16
  value: string,
@@ -1,5 +1,6 @@
1
- import { Env } from '@config/env';
2
- import type { Middleware as MiddlewareFn } from '@middleware/MiddlewareStack';
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: MiddlewareFn[];
206
- route: Record<string, MiddlewareFn>;
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 { UserController } from '@app/Controllers/UserController';
7
- import { Env } from '@zintrust/core';
8
- import { registerBroadcastRoutes } from '@routes/broadcast';
9
- import { registerHealthRoutes } from '@routes/health';
10
- import { registerStorageRoutes } from '@routes/storage';
11
- import { type IRouter, Router } from '@zintrust/core';
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();