@zintrust/core 0.1.3 → 0.1.4

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 (31) hide show
  1. package/README.md +2 -2
  2. package/bin/zintrust.d.ts.map +1 -1
  3. package/bin/zintrust.js +59 -37
  4. package/package.json +1 -1
  5. package/src/cli/BaseCommand.js +1 -1
  6. package/src/cli/CLI.d.ts.map +1 -1
  7. package/src/cli/CLI.js +4 -3
  8. package/src/cli/commands/NewCommand.d.ts +4 -3
  9. package/src/cli/commands/NewCommand.d.ts.map +1 -1
  10. package/src/cli/commands/NewCommand.js +117 -31
  11. package/src/cli/scaffolding/ProjectScaffolder.d.ts.map +1 -1
  12. package/src/cli/scaffolding/ProjectScaffolder.js +15 -1
  13. package/src/index.d.ts +7 -2
  14. package/src/index.d.ts.map +1 -1
  15. package/src/index.js +4 -0
  16. package/src/scripts/TemplateSync.js +31 -1
  17. package/src/templates/project/basic/config/FileLogWriter.ts.tpl +1 -1
  18. package/src/templates/project/basic/config/SecretsManager.ts.tpl +1 -1
  19. package/src/templates/project/basic/config/StartupConfigValidator.ts.tpl +1 -1
  20. package/src/templates/project/basic/config/cloudflare.ts.tpl +1 -1
  21. package/src/templates/project/basic/config/logging/HttpLogger.ts.tpl +3 -3
  22. package/src/templates/project/basic/config/logging/SlackLogger.ts.tpl +2 -2
  23. package/src/templates/project/basic/config/security.ts.tpl +1 -1
  24. package/src/templates/project/basic/package.json.tpl +1 -1
  25. package/src/templates/project/basic/routes/api.ts.tpl +1 -1
  26. package/src/templates/project/basic/routes/broadcast.ts.tpl +1 -1
  27. package/src/templates/project/basic/routes/health.ts.tpl +3 -3
  28. package/src/templates/project/basic/routes/storage.ts.tpl +1 -1
  29. package/src/templates/project/basic/tsconfig.json.tpl +15 -1
  30. package/src/tools/storage/testing.d.ts.map +1 -1
  31. package/src/tools/storage/testing.js +1 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Getting Started with Zintrust
2
2
 
3
- Welcome to Zintrust, a production-grade TypeScript backend framework with proven architectural patterns and zero external dependencies.
3
+ Welcome to Zintrust, a production-grade TypeScript backend framework with proven architectural patterns and a minimal core (no Express/Fastify). The published npm package also includes a few runtime dependencies for the CLI and developer experience.
4
4
 
5
5
  ## Quick Start (2 minutes)
6
6
 
@@ -20,7 +20,7 @@ Your API is now running at `http://localhost:7777`
20
20
 
21
21
  ## What is Zintrust?
22
22
 
23
- Zintrust is a **zero-dependency** backend framework built on:
23
+ Zintrust is a **minimal-core** backend framework built on:
24
24
 
25
25
  - ✅ **Pure Node.js** - No Express, Fastify, or external HTTP libraries
26
26
  - ✅ **Type-Safe** - Strict TypeScript with 100% type coverage
@@ -1 +1 @@
1
- {"version":3,"file":"zintrust.d.ts","sourceRoot":"","sources":["../../bin/zintrust.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAmEH,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"zintrust.d.ts","sourceRoot":"","sources":["../../bin/zintrust.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AA8FH,OAAO,EAAE,CAAC"}
package/bin/zintrust.js CHANGED
@@ -5,8 +5,63 @@
5
5
  * Usage: zintrust [command] [options]
6
6
  * Shortcuts: zin, z
7
7
  */
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ const loadPackageVersionFast = () => {
12
+ try {
13
+ const here = path.dirname(fileURLToPath(import.meta.url));
14
+ const packagePath = path.join(here, '../package.json');
15
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
16
+ return typeof packageJson.version === 'string' ? packageJson.version : '0.0.0';
17
+ }
18
+ catch {
19
+ return '0.0.0';
20
+ }
21
+ };
22
+ const stripLeadingScriptArg = (rawArgs) => {
23
+ if (rawArgs.length === 0)
24
+ return rawArgs;
25
+ const first = rawArgs[0];
26
+ const looksLikeScript = typeof first === 'string' && (first.endsWith('.ts') || first.endsWith('.js'));
27
+ return looksLikeScript ? rawArgs.slice(1) : rawArgs;
28
+ };
29
+ const getArgsFromProcess = () => {
30
+ const rawArgs = process.argv.slice(2);
31
+ return { rawArgs, args: stripLeadingScriptArg(rawArgs) };
32
+ };
33
+ const isVersionRequest = (args) => {
34
+ return args.includes('-v') || args.includes('--version');
35
+ };
36
+ const shouldDebugArgs = (rawArgs) => {
37
+ return process.env['ZINTRUST_CLI_DEBUG_ARGS'] === '1' && rawArgs.includes('--verbose');
38
+ };
39
+ const handleCliFatal = async (error, context) => {
40
+ try {
41
+ const { Logger } = await import('../src/config/logger');
42
+ Logger.error(context, error);
43
+ }
44
+ catch {
45
+ // best-effort logging
46
+ }
47
+ try {
48
+ const { ErrorHandler } = await import('../src/cli/ErrorHandler');
49
+ ErrorHandler.handle(error);
50
+ }
51
+ catch {
52
+ // best-effort error handling
53
+ }
54
+ process.exit(1);
55
+ };
8
56
  async function main() {
9
57
  try {
58
+ // Fast path: print version and exit without bootstrapping the CLI.
59
+ // This keeps `zin -v` / `zin --version` snappy and avoids any debug output.
60
+ const { rawArgs: _rawArgs0, args: args0 } = getArgsFromProcess();
61
+ if (isVersionRequest(args0)) {
62
+ process.stdout.write(`${loadPackageVersionFast()}\n`);
63
+ return;
64
+ }
10
65
  const { EnvFileLoader } = await import('../src/cli/utils/EnvFileLoader');
11
66
  EnvFileLoader.ensureLoaded();
12
67
  const { CLI } = await import('../src/cli/CLI');
@@ -14,8 +69,8 @@ async function main() {
14
69
  // When executing via tsx (e.g. `npx tsx bin/zin.ts ...`), the script path can
15
70
  // appear as the first element of `process.argv.slice(2)`. Commander expects
16
71
  // args to start at the command name, so we strip a leading script path if present.
17
- const rawArgs = process.argv.slice(2);
18
- if (process.env['ZINTRUST_CLI_DEBUG_ARGS'] === '1') {
72
+ const { rawArgs, args } = getArgsFromProcess();
73
+ if (shouldDebugArgs(rawArgs)) {
19
74
  try {
20
75
  process.stderr.write(`[zintrust-cli] process.argv=${JSON.stringify(process.argv)}\n`);
21
76
  process.stderr.write(`[zintrust-cli] rawArgs=${JSON.stringify(rawArgs)}\n`);
@@ -24,45 +79,12 @@ async function main() {
24
79
  // ignore
25
80
  }
26
81
  }
27
- const args = rawArgs.length > 0 &&
28
- (rawArgs[0]?.endsWith('.ts') === true || rawArgs[0]?.endsWith('.js') === true)
29
- ? rawArgs.slice(1)
30
- : rawArgs;
31
82
  await cli.run(args);
32
83
  }
33
84
  catch (error) {
34
- try {
35
- const { Logger } = await import('../src/config/logger');
36
- Logger.error('CLI execution failed', error);
37
- }
38
- catch {
39
- // best-effort logging
40
- }
41
- try {
42
- const { ErrorHandler } = await import('../src/cli/ErrorHandler');
43
- ErrorHandler.handle(error);
44
- }
45
- catch {
46
- // best-effort error handling
47
- }
48
- process.exit(1);
85
+ await handleCliFatal(error, 'CLI execution failed');
49
86
  }
50
87
  }
51
88
  await main().catch(async (error) => {
52
- try {
53
- const { Logger } = await import('../src/config/logger');
54
- Logger.error('CLI fatal error', error);
55
- }
56
- catch {
57
- // best-effort logging
58
- }
59
- try {
60
- const { ErrorHandler } = await import('../src/cli/ErrorHandler');
61
- ErrorHandler.handle(error);
62
- }
63
- catch {
64
- // best-effort error handling
65
- }
66
- process.exit(1);
89
+ await handleCliFatal(error, 'CLI fatal error');
67
90
  });
68
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/core",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Production-grade TypeScript backend framework for JavaScript",
5
5
  "homepage": "https://zintrust.com",
6
6
  "repository": {
@@ -17,7 +17,7 @@ export const BaseCommand = Object.freeze({
17
17
  const getCommand = () => {
18
18
  const command = new Command(config.name);
19
19
  command.description(config.description);
20
- command.option('-v, --verbose', 'Enable verbose output');
20
+ command.option('--verbose', 'Enable verbose output');
21
21
  // Add custom options
22
22
  if (config.addOptions) {
23
23
  config.addOptions(command);
@@ -1 +1 @@
1
- {"version":3,"file":"CLI.d.ts","sourceRoot":"","sources":["../../../src/cli/CLI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,WAAW,IAAI;IACnB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,UAAU,IAAI,OAAO,CAAC;CACvB;AAqLD;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG;cACJ,IAAI;EAed,CAAC"}
1
+ {"version":3,"file":"CLI.d.ts","sourceRoot":"","sources":["../../../src/cli/CLI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,WAAW,IAAI;IACnB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,UAAU,IAAI,OAAO,CAAC;CACvB;AAsLD;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG;cACJ,IAAI;EAed,CAAC"}
package/src/cli/CLI.js CHANGED
@@ -159,12 +159,13 @@ const handleExecutionError = (error, version, log = true) => {
159
159
  */
160
160
  const runCLI = async (program, version, args) => {
161
161
  try {
162
- // Always show banner
163
- ErrorHandler.banner(version);
164
- // If version is requested, we've already shown the banner which includes the version.
162
+ // If version is requested, let Commander print it (no banner, fast/clean output).
165
163
  if (args.includes('-v') || args.includes('--version')) {
164
+ await program.parseAsync(['node', 'zintrust', ...args]);
166
165
  return;
167
166
  }
167
+ // Always show banner for normal commands
168
+ ErrorHandler.banner(version);
168
169
  // Show help if no arguments provided
169
170
  if (args.length === 0) {
170
171
  program.help();
@@ -3,7 +3,7 @@
3
3
  * Handles creation of new Zintrust projects
4
4
  */
5
5
  import { CommandOptions, IBaseCommand } from '../BaseCommand';
6
- type TemplateType = 'basic' | 'api' | 'microservice';
6
+ type TemplateType = 'basic' | 'api' | 'microservice' | 'fullstack';
7
7
  type DatabaseType = 'sqlite' | 'mysql' | 'postgresql' | 'mongodb';
8
8
  interface NewProjectConfigResult {
9
9
  template: TemplateType;
@@ -19,8 +19,9 @@ interface INewCommand extends IBaseCommand {
19
19
  getQuestions(name: string, defaults: NewProjectConfigResult): InquirerQuestion[];
20
20
  getSafeEnv(): NodeJS.ProcessEnv;
21
21
  getGitBinary(): string;
22
- runScaffolding(name: string, config: NewProjectConfigResult, overwrite?: boolean): Promise<unknown>;
23
- initializeGit(name: string): void;
22
+ runScaffolding(basePath: string, name: string, config: NewProjectConfigResult, overwrite?: boolean): Promise<unknown>;
23
+ initializeGit(projectPath: string): void;
24
+ promptForPackageManager(defaultPm: string): Promise<string | null>;
24
25
  }
25
26
  /**
26
27
  * New Command Factory
@@ -1 +1 @@
1
- {"version":3,"file":"NewCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/NewCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAe,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAY7E,KAAK,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,cAAc,CAAC;AACrD,KAAK,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC;AAYlE,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAiMhD,UAAU,WAAY,SAAQ,YAAY;IACxC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACxF,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACzF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,gBAAgB,EAAE,CAAC;IACjF,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC;IAChC,YAAY,IAAI,MAAM,CAAC;IACvB,cAAc,CACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,sBAAsB,EAC9B,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAwID;;;GAGG;AACH,eAAO,MAAM,UAAU;IACrB;;OAEG;cACO,WAAW;EAGrB,CAAC"}
1
+ {"version":3,"file":"NewCommand.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/NewCommand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAe,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAY7E,KAAK,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,cAAc,GAAG,WAAW,CAAC;AACnE,KAAK,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC;AAYlE,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAsOhD,UAAU,WAAY,SAAQ,YAAY;IACxC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACxF,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACzF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,gBAAgB,EAAE,CAAC;IACjF,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC;IAChC,YAAY,IAAI,MAAM,CAAC;IACvB,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,sBAAsB,EAC9B,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACpE;AAmOD;;;GAGG;AACH,eAAO,MAAM,UAAU;IACrB;;OAEG;cACO,WAAW;EAGrB,CAAC"}
@@ -70,14 +70,14 @@ const toConfigResult = (config) => ({
70
70
  const getQuestions = (name, defaults) => {
71
71
  return [
72
72
  {
73
- type: 'list',
73
+ type: 'rawlist',
74
74
  name: 'template',
75
75
  message: 'Project template:',
76
- choices: ['basic', 'api', 'microservice'],
76
+ choices: ['basic', 'api', 'microservice', 'fullstack'],
77
77
  default: defaults.template,
78
78
  },
79
79
  {
80
- type: 'list',
80
+ type: 'rawlist',
81
81
  name: 'database',
82
82
  message: 'Database driver:',
83
83
  choices: ['sqlite', 'mysql', 'postgresql', 'mongodb'],
@@ -150,6 +150,27 @@ const isFailureResult = (result) => {
150
150
  const maybe = result;
151
151
  return maybe.success === false;
152
152
  };
153
+ const promptForPackageManager = async (defaultPm) => {
154
+ const choices = [
155
+ { name: 'npm', value: 'npm' },
156
+ { name: 'yarn', value: 'yarn' },
157
+ { name: 'pnpm', value: 'pnpm' },
158
+ { name: 'bun', value: 'bun' },
159
+ { name: 'Skip installation', value: null },
160
+ ];
161
+ const answer = await PromptHelper.prompt([
162
+ {
163
+ type: 'rawlist',
164
+ name: 'packageManager',
165
+ message: 'Select package manager for dependency installation:',
166
+ choices,
167
+ default: defaultPm,
168
+ },
169
+ ]);
170
+ if (typeof answer !== 'object' || answer === null)
171
+ return null;
172
+ return answer['packageManager'] ?? null;
173
+ };
153
174
  const installDependencies = async (projectPath, log, packageManager, force = false) => {
154
175
  // Respect CI by default — avoid network installs in CI unless explicitly allowed
155
176
  const isCi = Boolean(process.env['CI']);
@@ -158,6 +179,10 @@ const installDependencies = async (projectPath, log, packageManager, force = fal
158
179
  log.info('Skipping automatic dependency installation in CI environment.');
159
180
  return;
160
181
  }
182
+ if (packageManager === null) {
183
+ log.info('⏭️ Skipping dependency installation (not selected).');
184
+ return;
185
+ }
161
186
  log.info('📦 Installing dependencies (this may take a minute)...');
162
187
  const pm = packageManager ?? resolvePackageManager();
163
188
  const args = ['install'];
@@ -175,7 +200,7 @@ const installDependencies = async (projectPath, log, packageManager, force = fal
175
200
  };
176
201
  const addOptions = (command) => {
177
202
  command.argument('<name>', 'Project name');
178
- command.option('--template <type>', 'Project template (basic, api, microservice)', 'basic');
203
+ command.option('--template <type>', 'Project template (basic, api, microservice, fullstack)', 'basic');
179
204
  command.option('--database <type>', 'Database driver (sqlite, mysql, postgresql)', 'sqlite');
180
205
  command.option('--port <number>', 'Default port number', '3003');
181
206
  command.option('--author <name>', 'Project author');
@@ -189,31 +214,90 @@ const addOptions = (command) => {
189
214
  command.option('--force', 'Overwrite existing directory');
190
215
  command.option('--overwrite', 'Overwrite existing directory');
191
216
  };
192
- const executeNewCommand = async (options, command) => {
193
- try {
194
- const argName = options.args?.[0];
195
- const projectName = argName ?? (await PromptHelper.projectName('my-zintrust-app', true));
196
- if (!projectName)
197
- throw ErrorFactory.createCliError('Project name is required');
198
- const config = await command.getProjectConfig(projectName, options);
199
- command.info(chalk.bold(`\n🚀 Creating new Zintrust project in ${projectName}...\n`));
200
- const overwrite = options['overwrite'] === true || options['force'] === true ? true : undefined;
201
- const result = await command.runScaffolding(projectName, config, overwrite);
202
- if (isFailureResult(result)) {
203
- throw ErrorFactory.createCliError(result.message ?? 'Project scaffolding failed', result);
204
- }
205
- if (options['git'] !== false) {
206
- command.initializeGit(projectName);
217
+ const resolveProjectName = async (options) => {
218
+ const argName = options.args?.[0];
219
+ const projectName = argName ?? (await PromptHelper.projectName('my-zintrust-app', true));
220
+ if (!projectName)
221
+ throw ErrorFactory.createCliError('Project name is required');
222
+ return projectName;
223
+ };
224
+ const resolveProjectTarget = async (options) => {
225
+ const input = await resolveProjectName(options);
226
+ const isPathLike = input.includes('/') || input.includes('\\');
227
+ if (!isPathLike) {
228
+ return {
229
+ basePath: process.cwd(),
230
+ name: input,
231
+ projectPath: path.resolve(process.cwd(), input),
232
+ display: input,
233
+ cdPath: input,
234
+ };
235
+ }
236
+ const projectPath = path.resolve(process.cwd(), input);
237
+ const name = path.basename(projectPath);
238
+ const basePath = path.dirname(projectPath);
239
+ const cdPath = input.startsWith('/') ? projectPath : input;
240
+ return {
241
+ basePath,
242
+ name,
243
+ projectPath,
244
+ display: input,
245
+ cdPath,
246
+ };
247
+ };
248
+ const createProject = async (target, options, command) => {
249
+ const config = await command.getProjectConfig(target.name, options);
250
+ command.info(chalk.bold(`\n🚀 Creating new Zintrust project in ${target.display}...\n`));
251
+ const overwrite = options['overwrite'] === true || options['force'] === true ? true : undefined;
252
+ const result = await command.runScaffolding(target.basePath, target.name, config, overwrite);
253
+ if (isFailureResult(result)) {
254
+ throw ErrorFactory.createCliError(result.message ?? 'Project scaffolding failed', result);
255
+ }
256
+ };
257
+ const maybeInitializeGit = (options, command, target) => {
258
+ if (options['git'] !== false) {
259
+ command.initializeGit(target.projectPath);
260
+ }
261
+ };
262
+ const maybeInstallDependencies = async (options, command, target) => {
263
+ if (options['install'] === false)
264
+ return;
265
+ const projectPath = target.projectPath;
266
+ let pm = options['packageManager'] ??
267
+ options['package-manager'];
268
+ // If no package manager specified and not in non-interactive mode, prompt user
269
+ if (pm === undefined && options['interactive'] !== false && options['no-interactive'] !== true) {
270
+ const defaultPm = resolvePackageManager();
271
+ const selectedPm = await command.promptForPackageManager(defaultPm);
272
+ if (selectedPm === null) {
273
+ command.info('⏭️ Skipping dependency installation.');
274
+ pm = '__skip__'; // Signal to skip installation
207
275
  }
208
- if (options['install'] !== false) {
209
- const projectPath = path.resolve(process.cwd(), projectName);
210
- const pm = options['packageManager'] ??
211
- options['package-manager'];
212
- const force = options['install'] === true;
213
- await installDependencies(projectPath, command, pm, force);
276
+ else {
277
+ pm = selectedPm;
214
278
  }
215
- command.success(`\n✨ Project ${projectName} created successfully!`);
216
- command.info(`\nNext steps:\n cd ${projectName}\n npm run dev\n`);
279
+ }
280
+ const force = options['install'] === true;
281
+ if (pm === '__skip__')
282
+ return;
283
+ const effectivePm = pm ?? resolvePackageManager();
284
+ await installDependencies(projectPath, command, pm, force);
285
+ return effectivePm;
286
+ };
287
+ const executeNewCommand = async (options, command) => {
288
+ try {
289
+ const target = await resolveProjectTarget(options);
290
+ await createProject(target, options, command);
291
+ maybeInitializeGit(options, command, target);
292
+ const installedWithPm = await maybeInstallDependencies(options, command, target);
293
+ command.success(`\n✨ Project ${target.name} created successfully!`);
294
+ const optPm = options['packageManager'] ??
295
+ options['package-manager'];
296
+ const effectivePm = installedWithPm ?? optPm ?? resolvePackageManager();
297
+ const runDevCmd = effectivePm === 'yarn' || effectivePm === 'pnpm'
298
+ ? `${effectivePm} dev`
299
+ : `${effectivePm} run dev`;
300
+ command.info(`\nNext steps:\n cd ${target.cdPath}\n ${runDevCmd}\n`);
217
301
  }
218
302
  catch (error) {
219
303
  throw ErrorFactory.createCliError(`Project creation failed: ${extractErrorMessage(error)}`, error);
@@ -257,8 +341,8 @@ const createNewCommandInstance = () => {
257
341
  getProjectConfig: async (name, options) => {
258
342
  return commandInstance.promptForConfig(name, options);
259
343
  },
260
- runScaffolding: async (name, config, overwrite) => {
261
- return ProjectScaffolder.scaffold(process.cwd(), {
344
+ runScaffolding: async (basePath, name, config, overwrite) => {
345
+ return ProjectScaffolder.scaffold(basePath, {
262
346
  name,
263
347
  force: overwrite === true,
264
348
  template: config.template,
@@ -268,12 +352,14 @@ const createNewCommandInstance = () => {
268
352
  description: config.description,
269
353
  });
270
354
  },
271
- initializeGit: (name) => {
272
- const projectPath = path.resolve(process.cwd(), name);
355
+ initializeGit: (projectPath) => {
273
356
  if (checkGitInstalled()) {
274
357
  initializeGitRepo(projectPath, commandInstance);
275
358
  }
276
359
  },
360
+ promptForPackageManager: async (defaultPm) => {
361
+ return promptForPackageManager(defaultPm);
362
+ },
277
363
  execute: async (options) => {
278
364
  await executeNewCommand(options, commandInstance);
279
365
  },
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ProjectScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACtD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IACpE,cAAc,IAAI,MAAM,CAAC;IACzB,sBAAsB,IAAI,OAAO,CAAC;IAClC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAAC;IACtD,gBAAgB,IAAI,OAAO,CAAC;IAC5B,aAAa,IAAI,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC3E;AAqWD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAMrE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAChE,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAsBA;AAwID;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAsB,GAAG,kBAAkB,CAsB/F;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAEhC;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;EAM5B,CAAC"}
1
+ {"version":3,"file":"ProjectScaffolder.d.ts","sourceRoot":"","sources":["../../../../src/cli/scaffolding/ProjectScaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACtD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IACpE,cAAc,IAAI,MAAM,CAAC;IACzB,sBAAsB,IAAI,OAAO,CAAC;IAClC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CAAC;IACtD,gBAAgB,IAAI,OAAO,CAAC;IAC5B,aAAa,IAAI,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC3E;AAqWD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAsBrE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAChE,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAsBA;AAwID;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAsB,GAAG,kBAAkB,CAsB/F;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAEhC;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;EAM5B,CAAC"}
@@ -317,7 +317,21 @@ export function getTemplate(name) {
317
317
  if (!fallback)
318
318
  return undefined;
319
319
  const disk = loadTemplateFromDisk(name, fallback);
320
- return disk ?? fallback;
320
+ if (disk)
321
+ return disk;
322
+ // If we don't have a dedicated disk template yet (e.g. fullstack/api/microservice),
323
+ // fall back to the starter project's file set so generated projects are runnable.
324
+ if (name !== 'basic') {
325
+ const basicFallback = TEMPLATE_MAP.get('basic');
326
+ const basicDisk = basicFallback ? loadTemplateFromDisk('basic', basicFallback) : undefined;
327
+ if (basicDisk) {
328
+ return {
329
+ ...fallback,
330
+ files: basicDisk.files,
331
+ };
332
+ }
333
+ }
334
+ return fallback;
321
335
  }
322
336
  export function validateOptions(options) {
323
337
  const errors = [];
package/src/index.d.ts CHANGED
@@ -24,6 +24,10 @@ export { QueryBuilder } from './orm/QueryBuilder';
24
24
  export type { IRelationship } from './orm/Relationships';
25
25
  export { Router } from './routing/Router';
26
26
  export type { IRouter } from './routing/Router';
27
+ export { delay, ensureDirSafe } from './common/index';
28
+ export { HttpClient } from './tools/http/Http';
29
+ export type { IHttpRequest, IHttpResponse } from './tools/http/Http';
30
+ export type { DatabaseConfig, ID1Database } from './orm/DatabaseAdapter';
27
31
  export { MemoryProfiler } from './profiling/MemoryProfiler';
28
32
  export { N1Detector } from './profiling/N1Detector';
29
33
  export { QueryLogger } from './profiling/QueryLogger';
@@ -32,12 +36,13 @@ export type { MemoryDelta, MemorySnapshot, N1Pattern, ProfileReport, QueryLogEnt
32
36
  export { ValidationError } from './validation/ValidationError';
33
37
  export type { FieldError } from './validation/ValidationError';
34
38
  export { Schema, Validator } from './validation/Validator';
39
+ export type { ISchema, SchemaType } from './validation/Validator';
35
40
  export { CsrfTokenManager } from './security/CsrfTokenManager';
36
- export type { CsrfTokenData } from './security/CsrfTokenManager';
41
+ export type { CsrfTokenData, CsrfTokenManagerType, ICsrfTokenManager, } from './security/CsrfTokenManager';
37
42
  export { Encryptor } from './security/Encryptor';
38
43
  export { Hash } from './security/Hash';
39
44
  export { JwtManager } from './security/JwtManager';
40
- export type { JwtOptions, JwtPayload } from './security/JwtManager';
45
+ export type { IJwtManager, JwtAlgorithm, JwtManagerType, JwtOptions, JwtPayload, } from './security/JwtManager';
41
46
  export { Xss } from './security/Xss';
42
47
  export { XssProtection } from './security/XssProtection';
43
48
  export { ErrorFactory } from './exceptions/ZintrustError';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/src/index.js CHANGED
@@ -18,6 +18,10 @@ export { Database, resetDatabase, useDatabase } from './orm/Database';
18
18
  export { Model } from './orm/Model';
19
19
  export { QueryBuilder } from './orm/QueryBuilder';
20
20
  export { Router } from './routing/Router';
21
+ // Common
22
+ export { delay, ensureDirSafe } from './common/index';
23
+ // HTTP Client
24
+ export { HttpClient } from './tools/http/Http';
21
25
  // Profiling
22
26
  export { MemoryProfiler } from './profiling/MemoryProfiler';
23
27
  export { N1Detector } from './profiling/N1Detector';
@@ -85,7 +85,10 @@ const syncProjectTemplateDir = (params) => {
85
85
  let updated = 0;
86
86
  let skipped = 0;
87
87
  for (const file of files) {
88
- const baseKey = `${params.baseDirRel}/${file.relPath}`;
88
+ const checksumSaltPart = typeof params.checksumSalt === 'string' && params.checksumSalt.length > 0
89
+ ? `|${params.checksumSalt}`
90
+ : '';
91
+ const baseKey = `${params.baseDirRel}/${file.relPath}${checksumSaltPart}`;
89
92
  const currentHash = hashFile(file.absPath);
90
93
  const storedHash = params.checksums[baseKey];
91
94
  const outRel = `${file.relPath}.tpl`;
@@ -108,6 +111,29 @@ const syncProjectTemplateDir = (params) => {
108
111
  }
109
112
  return { updated, skipped, total: files.length };
110
113
  };
114
+ const rewriteStarterTemplateImports = (relPath, content) => {
115
+ if (!relPath.endsWith('.ts') && !relPath.endsWith('.tsx') && !relPath.endsWith('.mts')) {
116
+ return content;
117
+ }
118
+ // Starter templates should import framework APIs from the public package surface,
119
+ // not from internal path-alias modules that only exist in the framework repo.
120
+ return (content
121
+ .replaceAll("'@routing/Router'", "'@zintrust/core'")
122
+ .replaceAll("'@orm/Database'", "'@zintrust/core'")
123
+ .replaceAll("'@orm/QueryBuilder'", "'@zintrust/core'")
124
+ .replaceAll("'@orm/DatabaseAdapter'", "'@zintrust/core'")
125
+ .replaceAll("'@exceptions/ZintrustError'", "'@zintrust/core'")
126
+ .replaceAll("'@common/index'", "'@zintrust/core'")
127
+ .replaceAll("'@httpClient/Http'", "'@zintrust/core'")
128
+ // Handle double-quoted module specifiers too
129
+ .replaceAll('"@routing/Router"', '"@zintrust/core"')
130
+ .replaceAll('"@orm/Database"', '"@zintrust/core"')
131
+ .replaceAll('"@orm/QueryBuilder"', '"@zintrust/core"')
132
+ .replaceAll('"@orm/DatabaseAdapter"', '"@zintrust/core"')
133
+ .replaceAll('"@exceptions/ZintrustError"', '"@zintrust/core"')
134
+ .replaceAll('"@common/index"', '"@zintrust/core"')
135
+ .replaceAll('"@httpClient/Http"', '"@zintrust/core"'));
136
+ };
111
137
  const syncRegistryMappings = (params) => {
112
138
  let updated = 0;
113
139
  let skipped = 0;
@@ -190,6 +216,8 @@ const syncStarterProjectTemplates = (params) => {
190
216
  baseDirRel: 'src/config',
191
217
  templateDirRel: `${params.projectRoot}/config`,
192
218
  description: 'Starter project config/* (from src/config/*)',
219
+ transformContent: rewriteStarterTemplateImports,
220
+ checksumSalt: 'starter-imports-v1',
193
221
  });
194
222
  const s3 = syncProjectTemplateDir({
195
223
  checksums: params.checksums,
@@ -202,6 +230,8 @@ const syncStarterProjectTemplates = (params) => {
202
230
  baseDirRel: 'routes',
203
231
  templateDirRel: `${params.projectRoot}/routes`,
204
232
  description: 'Starter project routes/*',
233
+ transformContent: rewriteStarterTemplateImports,
234
+ checksumSalt: 'starter-imports-v1',
205
235
  });
206
236
  const s5 = syncStarterEnvTemplate({
207
237
  checksums: params.checksums,
@@ -5,7 +5,7 @@
5
5
  * This module imports Node built-ins and should be loaded only in Node environments.
6
6
  */
7
7
 
8
- import { ensureDirSafe } from '@common/index';
8
+ import { ensureDirSafe } from '@zintrust/core';
9
9
  import { Env } from '@config/env';
10
10
  import * as fs from '@node-singletons/fs';
11
11
  import * as path from '@node-singletons/path';
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { Logger } from '@config/logger';
8
- import { ErrorFactory } from '@exceptions/ZintrustError';
8
+ import { ErrorFactory } from '@zintrust/core';
9
9
 
10
10
  export interface CloudflareKV {
11
11
  get(key: string): Promise<string | null>;
@@ -1,5 +1,5 @@
1
1
  import { appConfig } from '@config/app';
2
- import { ErrorFactory } from '@exceptions/ZintrustError';
2
+ import { ErrorFactory } from '@zintrust/core';
3
3
 
4
4
  export type StartupConfigValidationError = {
5
5
  key: string;
@@ -5,7 +5,7 @@
5
5
  * This keeps runtime-specific globals out of adapters/drivers.
6
6
  */
7
7
 
8
- import type { DatabaseConfig, ID1Database } from '@orm/DatabaseAdapter';
8
+ import type { DatabaseConfig, ID1Database } from '@zintrust/core';
9
9
 
10
10
  export type WorkersEnv = Record<string, unknown>;
11
11
 
@@ -9,10 +9,10 @@
9
9
  * - HTTP_LOG_AUTH_TOKEN (optional)
10
10
  */
11
11
 
12
- import { delay } from '@common/index';
12
+ import { delay } from '@zintrust/core';
13
13
  import { Env } from '@config/env';
14
- import { ErrorFactory } from '@exceptions/ZintrustError';
15
- import { HttpClient } from '@httpClient/Http';
14
+ import { ErrorFactory } from '@zintrust/core';
15
+ import { HttpClient } from '@zintrust/core';
16
16
 
17
17
  export type HttpLogEvent = {
18
18
  timestamp: string;
@@ -10,8 +10,8 @@
10
10
  */
11
11
 
12
12
  import { Env } from '@config/env';
13
- import { ErrorFactory } from '@exceptions/ZintrustError';
14
- import { HttpClient } from '@httpClient/Http';
13
+ import { ErrorFactory } from '@zintrust/core';
14
+ import { HttpClient } from '@zintrust/core';
15
15
 
16
16
  export type SlackLogEvent = {
17
17
  timestamp: string;
@@ -7,7 +7,7 @@
7
7
  import { appConfig } from '@config/app';
8
8
  import { Env } from '@config/env';
9
9
  import { Logger } from '@config/logger';
10
- import { ErrorFactory } from '@exceptions/ZintrustError';
10
+ import { ErrorFactory } from '@zintrust/core';
11
11
 
12
12
  /**
13
13
  * Helper to warn about missing secrets
@@ -11,7 +11,7 @@
11
11
  "type-check": "tsc --noEmit"
12
12
  },
13
13
  "dependencies": {
14
- "@zintrust/core": "^0.1.1"
14
+ "@zintrust/core": "^0.1.4"
15
15
  },
16
16
  "devDependencies": {
17
17
  "tsx": "^4.21.0",
@@ -8,7 +8,7 @@ import { Env } from '@config/env';
8
8
  import { registerBroadcastRoutes } from '@routes/broadcast';
9
9
  import { registerHealthRoutes } from '@routes/health';
10
10
  import { registerStorageRoutes } from '@routes/storage';
11
- import { type IRouter, Router } from '@routing/Router';
11
+ import { type IRouter, Router } from '@zintrust/core';
12
12
 
13
13
  export function registerRoutes(router: IRouter): void {
14
14
  const userController = UserController.create();
@@ -5,7 +5,7 @@
5
5
  * Provider setup and secret provisioning remain CLI-only.
6
6
  */
7
7
 
8
- import { type IRouter, Router } from '@routing/Router';
8
+ import { type IRouter, Router } from '@zintrust/core';
9
9
 
10
10
  export function registerBroadcastRoutes(router: IRouter): void {
11
11
  Router.get(router, '/broadcast/health', async (_req, res) => {
@@ -7,9 +7,9 @@ import { appConfig } from '@/config';
7
7
  import { RuntimeHealthProbes } from '@/health/RuntimeHealthProbes';
8
8
  import { Env } from '@config/env';
9
9
  import { Logger } from '@config/logger';
10
- import { useDatabase } from '@orm/Database';
11
- import { QueryBuilder } from '@orm/QueryBuilder';
12
- import { type IRouter, Router } from '@routing/Router';
10
+ import { useDatabase } from '@zintrust/core';
11
+ import { QueryBuilder } from '@zintrust/core';
12
+ import { type IRouter, Router } from '@zintrust/core';
13
13
 
14
14
  export function registerHealthRoutes(router: IRouter): void {
15
15
  registerHealthRoute(router);
@@ -1,6 +1,6 @@
1
1
  import { HTTP_HEADERS } from '@config/constants';
2
2
  import { Env } from '@config/env';
3
- import { type IRouter, Router } from '@routing/Router';
3
+ import { type IRouter, Router } from '@zintrust/core';
4
4
  import { LocalSignedUrl } from '@storage/LocalSignedUrl';
5
5
  import { Storage } from '@storage/index';
6
6
 
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
+ "baseUrl": ".",
3
4
  "outDir": "./dist",
4
5
  "rootDir": "./",
5
6
  "module": "ESNext",
@@ -10,9 +11,22 @@
10
11
  "paths": {
11
12
  "@/*": ["./src/*"],
12
13
  "@app/*": ["./app/*"],
14
+ "@toolkit/*": ["./app/Toolkit/*"],
13
15
  "@config/*": ["./config/*"],
14
16
  "@routes/*": ["./routes/*"],
15
- "@database/*": ["./database/*"]
17
+ "@database/*": ["./database/*"],
18
+
19
+ "@tools/*": ["./src/tools/*"],
20
+ "@httpClient/*": ["./src/tools/http/*"],
21
+ "@templates": ["./src/tools/templates/index.ts"],
22
+ "@templates/*": ["./src/tools/templates/*"],
23
+ "@mail/*": ["./src/tools/mail/*"],
24
+ "@storage": ["./src/tools/storage/index.ts"],
25
+ "@storage/*": ["./src/tools/storage/*"],
26
+ "@drivers/*": ["./src/tools/storage/drivers/*"],
27
+ "@notification/*": ["./src/tools/notification/*"],
28
+ "@broadcast/*": ["./src/tools/broadcast/*"],
29
+ "@queue/*": ["./src/tools/queue/*"]
16
30
  }
17
31
  },
18
32
  "include": ["src/**/*", "app/**/*", "routes/**/*", "database/**/*", "config/**/*"],
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../src/tools/storage/testing.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,eAAO,MAAM,WAAW;WACT,KAAK,CAAC,OAAO,CAAC;cAEX,MAAM,QAAQ,MAAM,YAAY,MAAM;cAM5C,MAAM,QAAQ,MAAM;iBAMjB,MAAM,QAAQ,MAAM;iBAId,MAAM,QAAQ,MAAM;cAW7B,MAAM,QAAQ,MAAM;kBAMtB,MAAM,QACN,MAAM,YACF;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;KAAE;uBAQvC,MAAM,QAAQ,MAAM;wBAMnB,MAAM,QAAQ,MAAM;;;EAgBxC,CAAC;AAEH,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../src/tools/storage/testing.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,eAAO,MAAM,WAAW;WACT,KAAK,CAAC,OAAO,CAAC;cAEX,MAAM,QAAQ,MAAM,YAAY,MAAM;cAM5C,MAAM,QAAQ,MAAM;iBAMjB,MAAM,QAAQ,MAAM;iBAId,MAAM,QAAQ,MAAM;cAW7B,MAAM,QAAQ,MAAM;kBAMtB,MAAM,QACN,MAAM,YACF;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;KAAE;uBASvC,MAAM,QAAQ,MAAM;wBAMnB,MAAM,QAAQ,MAAM;;;EAgBxC,CAAC;AAEH,eAAe,WAAW,CAAC"}
@@ -28,6 +28,7 @@ export const FakeStorage = Object.freeze({
28
28
  async tempUrl(disk, path, options) {
29
29
  const expiresIn = options?.expiresIn ?? 900;
30
30
  const method = options?.method ?? 'GET';
31
+ await Promise.resolve();
31
32
  return `fake://${disk}/${path}?expiresIn=${expiresIn}&method=${method}`;
32
33
  },
33
34
  // Test assertions