@devbro/pashmak 0.1.55 → 0.1.57

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 (64) hide show
  1. package/dist/cjs/app/console/DefaultCommand.js +52 -0
  2. package/dist/cjs/app/console/KeyGenerateCommand.js +52 -0
  3. package/dist/cjs/app/console/StartCommand.js +52 -0
  4. package/dist/cjs/app/console/generate/GenerateApiDocsCommand.js +52 -0
  5. package/dist/cjs/app/console/generate/GenerateControllerCommand.js +52 -0
  6. package/dist/cjs/app/console/generate/index.js +52 -0
  7. package/dist/cjs/app/console/index.js +320 -70
  8. package/dist/cjs/app/console/migrate/GenerateMigrateCommand.js +52 -0
  9. package/dist/cjs/app/console/migrate/MigrateCommand.js +52 -0
  10. package/dist/cjs/app/console/migrate/MigrateRollbackCommand.js +52 -0
  11. package/dist/cjs/app/console/migrate/index.js +52 -0
  12. package/dist/cjs/app/console/project/CreateProjectCommand.js +263 -65
  13. package/dist/cjs/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
  14. package/dist/cjs/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
  15. package/dist/cjs/app/console/project/base_project/src/config/default.mts.tpl +13 -20
  16. package/dist/cjs/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
  17. package/dist/cjs/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
  18. package/dist/cjs/app/console/project/base_project/src/initialize.ts.tpl +48 -16
  19. package/dist/cjs/app/console/project/base_project/src/routes.ts.tpl +2 -2
  20. package/dist/cjs/app/console/queue/GenerateQueueMigrateCommand.js +52 -0
  21. package/dist/cjs/bin/pashmak_cli.js +265 -66
  22. package/dist/cjs/cache/MultiCache.js +71 -0
  23. package/dist/cjs/{cache.js → cache/cache.js} +54 -2
  24. package/dist/cjs/facades.js +52 -0
  25. package/dist/cjs/factories.js +52 -0
  26. package/dist/cjs/http.js +52 -0
  27. package/dist/cjs/index.js +1900 -2056
  28. package/dist/cjs/middlewares.js +112 -2
  29. package/dist/cjs/queue.js +52 -0
  30. package/dist/esm/app/console/project/CreateProjectCommand.d.mts +15 -2
  31. package/dist/esm/app/console/project/CreateProjectCommand.mjs +265 -67
  32. package/dist/esm/app/console/project/CreateProjectCommand.mjs.map +1 -1
  33. package/dist/esm/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
  34. package/dist/esm/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
  35. package/dist/esm/app/console/project/base_project/src/config/default.mts.tpl +13 -20
  36. package/dist/esm/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
  37. package/dist/esm/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
  38. package/dist/esm/app/console/project/base_project/src/initialize.ts.tpl +48 -16
  39. package/dist/esm/app/console/project/base_project/src/routes.ts.tpl +2 -2
  40. package/dist/esm/bin/pashmak_cli.mjs +2 -1
  41. package/dist/esm/bin/pashmak_cli.mjs.map +1 -1
  42. package/dist/esm/cache/MultiCache.d.mts +14 -0
  43. package/dist/esm/cache/MultiCache.mjs +47 -0
  44. package/dist/esm/cache/MultiCache.mjs.map +1 -0
  45. package/dist/esm/{cache.mjs → cache/cache.mjs} +1 -1
  46. package/dist/esm/cache/cache.mjs.map +1 -0
  47. package/dist/esm/config.mjs.map +1 -1
  48. package/dist/esm/factories.mjs +9 -0
  49. package/dist/esm/factories.mjs.map +1 -1
  50. package/dist/esm/index.d.mts +1 -7
  51. package/dist/esm/index.mjs +1 -32
  52. package/dist/esm/index.mjs.map +1 -1
  53. package/dist/esm/middlewares.d.mts +12 -1
  54. package/dist/esm/middlewares.mjs +52 -0
  55. package/dist/esm/middlewares.mjs.map +1 -1
  56. package/package.json +4 -2
  57. package/dist/cjs/app/console/project/base_project/package.json.tpl +0 -74
  58. package/dist/cjs/app/console/project/base_project/src/config/test.ts.tpl +0 -1
  59. package/dist/esm/app/console/project/base_project/package.json.tpl +0 -74
  60. package/dist/esm/app/console/project/base_project/src/config/test.ts.tpl +0 -1
  61. package/dist/esm/cache.mjs.map +0 -1
  62. /package/dist/cjs/app/console/project/base_project/src/config/{mailer.ts.tpl → mailers.ts.tpl} +0 -0
  63. /package/dist/esm/app/console/project/base_project/src/config/{mailer.ts.tpl → mailers.ts.tpl} +0 -0
  64. /package/dist/esm/{cache.d.mts → cache/cache.d.mts} +0 -0
@@ -1749,6 +1749,51 @@ var DatabaseTransport = class {
1749
1749
  // src/factories.mts
1750
1750
  var import_neko_cache = require("@devbro/neko-cache");
1751
1751
  var import_neko_storage = require("@devbro/neko-storage");
1752
+
1753
+ // src/cache/MultiCache.mts
1754
+ var MultiCache = class {
1755
+ constructor(caches) {
1756
+ this.caches = caches;
1757
+ }
1758
+ static {
1759
+ __name(this, "MultiCache");
1760
+ }
1761
+ async get(key) {
1762
+ for (const cache2 of this.caches) {
1763
+ const value = await cache2.get(key);
1764
+ if (value !== void 0) {
1765
+ return value;
1766
+ }
1767
+ }
1768
+ return void 0;
1769
+ }
1770
+ async put(key, value, ttl) {
1771
+ await Promise.all(this.caches.map((cache2) => cache2.put(key, value, ttl)));
1772
+ }
1773
+ async delete(key) {
1774
+ await Promise.all(this.caches.map((cache2) => cache2.delete(key)));
1775
+ }
1776
+ async has(key) {
1777
+ for (const cache2 of this.caches) {
1778
+ if (await cache2.has(key)) {
1779
+ return true;
1780
+ }
1781
+ }
1782
+ return false;
1783
+ }
1784
+ async increment(key, amount) {
1785
+ let rc = void 0;
1786
+ for (const cache2 of this.caches) {
1787
+ let rc2 = await cache2.increment(key, amount);
1788
+ if (rc === void 0) {
1789
+ rc = rc2;
1790
+ }
1791
+ }
1792
+ return rc;
1793
+ }
1794
+ };
1795
+
1796
+ // src/factories.mts
1752
1797
  var FlexibleFactory = class {
1753
1798
  static {
1754
1799
  __name(this, "FlexibleFactory");
@@ -1819,6 +1864,13 @@ CacheProviderFactory.register("redis", (opt) => {
1819
1864
  CacheProviderFactory.register("file", (opt) => {
1820
1865
  return new import_neko_cache.FileCacheProvider(opt);
1821
1866
  });
1867
+ CacheProviderFactory.register("multi", (opt) => {
1868
+ const caches = [];
1869
+ for (const c of opt.caches) {
1870
+ caches.push(cache(c));
1871
+ }
1872
+ return new MultiCache(caches);
1873
+ });
1822
1874
  CacheProviderFactory.register("disabled", (opt) => {
1823
1875
  return new import_neko_cache.DisabledCacheProvider();
1824
1876
  });
@@ -52,24 +52,17 @@ var CreateProjectCommand = class extends import_clipanion.Command {
52
52
  category: `Project`,
53
53
  description: `Create a new project`,
54
54
  details: `
55
- This command creates a new project with the specified name at the given path.
56
- If no path is provided, the project will be created in the current directory.
55
+ This command creates a new project interactively.
56
+ You will be prompted for the project path and other configuration options.
57
57
  `,
58
- examples: [
59
- [
60
- `Create a new project in specified directory`,
61
- `create project --path /path/to/my-project --git`
62
- ],
63
- [
64
- `Create a new project at a specific path with git initialized`,
65
- `create project --path /path/to/my-project --git`
66
- ]
67
- ]
68
- });
69
- projectPath = import_clipanion.Option.String("--path", { required: true });
70
- git = import_clipanion.Option.Boolean(`--git`, false, {
71
- description: `Initialize a git repository in the new project`
58
+ examples: [[`Create a new project`, `create project`]]
72
59
  });
60
+ projectPath = "";
61
+ executor = "";
62
+ packageManager = "";
63
+ linter = "";
64
+ validation_library = "";
65
+ database_type = "";
73
66
  async folderExists(folderPath) {
74
67
  try {
75
68
  const stats = await fs.stat(folderPath);
@@ -82,14 +75,148 @@ var CreateProjectCommand = class extends import_clipanion.Command {
82
75
  }
83
76
  }
84
77
  async execute() {
85
- const projectPath = import_path.default.join(this.projectPath);
86
- try {
87
- await fs.access(projectPath);
88
- console.error(`Error: Directory ${projectPath} already exists.`);
89
- return 1;
90
- } catch {
78
+ await this.setupProjectPath();
79
+ await this.setupGit();
80
+ await this.setupExecutorAndPackageManager();
81
+ await this.setupLinter();
82
+ await this.setupGeneralPackages();
83
+ await this.setupBaseProject();
84
+ await this.installPackages();
85
+ }
86
+ async processTplFolder(src, dest, data = {}) {
87
+ const files = await fs.readdir(src, { withFileTypes: true });
88
+ for (const file of files) {
89
+ const srcPath = import_path.default.join(src, file.name);
90
+ const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path.default.join(dest, file.name);
91
+ if (file.isDirectory()) {
92
+ await fs.mkdir(destPath, { recursive: true });
93
+ await this.processTplFolder(srcPath, destPath, data);
94
+ } else if (file.name.endsWith(".tpl")) {
95
+ await this.processTplFile(srcPath, destPath, data);
96
+ } else {
97
+ throw new Error(
98
+ "unexpected non tpl file: " + srcPath + " " + file.name
99
+ );
100
+ }
101
+ }
102
+ }
103
+ async processTplFile(src, dest, data = {}) {
104
+ import_handlebars.default.registerHelper("eq", (a, b) => a === b);
105
+ const compiledTemplate = import_handlebars.default.compile(
106
+ (await fs.readFile(src)).toString()
107
+ );
108
+ const template = await compiledTemplate(data);
109
+ await fs.writeFile(dest, template);
110
+ }
111
+ async setupProjectPath() {
112
+ const pathInput = await (0, import_prompts.input)({
113
+ message: "Enter project path (leave empty to use current directory):",
114
+ default: ""
115
+ });
116
+ this.projectPath = pathInput.trim() ? import_path.default.resolve(pathInput.trim()) : process.cwd();
117
+ await fs.mkdir(this.projectPath, { recursive: true });
118
+ const files = await fs.readdir(this.projectPath);
119
+ if (files.length > 0) {
120
+ throw new Error(
121
+ `Directory ${this.projectPath} is not empty. Please use an empty directory.`
122
+ );
123
+ }
124
+ }
125
+ async setupExecutorAndPackageManager() {
126
+ this.executor = await (0, import_prompts.select)({
127
+ message: "Select a TypeScript executor",
128
+ choices: [
129
+ {
130
+ name: "Bun",
131
+ value: "bun",
132
+ description: "Fast all-in-one JavaScript runtime"
133
+ },
134
+ {
135
+ name: "TSX",
136
+ value: "tsx",
137
+ description: "TypeScript execute (tsx) - Node.js enhanced with esbuild"
138
+ }
139
+ ]
140
+ });
141
+ this.packageManager = this.executor === "bun" ? "bun" : await (0, import_prompts.select)({
142
+ message: "Select a package manager",
143
+ choices: [
144
+ {
145
+ name: "Yarn",
146
+ value: "yarn",
147
+ description: "Fast, reliable, and secure dependency management"
148
+ },
149
+ {
150
+ name: "npm",
151
+ value: "npm",
152
+ description: "Node package manager (default)"
153
+ },
154
+ {
155
+ name: "Bun",
156
+ value: "bun",
157
+ description: "Ultra-fast package manager built into Bun"
158
+ }
159
+ ],
160
+ default: "yarn"
161
+ });
162
+ (0, import_child_process.execSync)(`${this.packageManager} init -y`, {
163
+ stdio: "inherit",
164
+ cwd: this.projectPath
165
+ });
166
+ const packageJsonPath = import_path.default.join(this.projectPath, `package.json`);
167
+ let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
168
+ packageJson.type = "module";
169
+ packageJson.scripts = packageJson.scripts || {};
170
+ packageJson.scripts.prepare = "husky init";
171
+ packageJson.scripts.clean = "rm -rf dist";
172
+ if (this.executor === "bun") {
173
+ packageJson.scripts.dev = "bun run dev";
174
+ packageJson.scripts.start = "bun run pdev";
175
+ packageJson.scripts.build = "bun run build";
176
+ packageJson.scripts.test = "vitest";
177
+ packageJson.scripts["test:watch"] = "vitest --watch";
178
+ packageJson.scripts["test:coverage"] = "vitest run --coverage";
179
+ } else if (this.executor === "tsx") {
180
+ packageJson.scripts.dev = "tsx --watch -r tsconfig-paths/register src/index.ts start --all | npx pino-pretty";
181
+ packageJson.scripts.start = "tsx dist/index.js";
182
+ packageJson.scripts.build = "tsc";
183
+ packageJson.scripts.test = "vitest";
184
+ packageJson.scripts["test:watch"] = "vitest --watch";
185
+ packageJson.scripts["test:coverage"] = "vitest run --coverage";
186
+ }
187
+ await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
188
+ }
189
+ async setupLinter() {
190
+ this.linter = await (0, import_prompts.select)({
191
+ message: "Select a linter",
192
+ choices: [
193
+ {
194
+ name: "Biome",
195
+ value: "biome",
196
+ description: "Fast formatter and linter for JavaScript, TypeScript, and more"
197
+ },
198
+ {
199
+ name: "ESLint",
200
+ value: "eslint",
201
+ description: "Find and fix problems in your JavaScript code"
202
+ }
203
+ ]
204
+ });
205
+ const packageJsonPath = import_path.default.join(this.projectPath, `package.json`);
206
+ let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
207
+ if (this.linter === "biome") {
208
+ packageJson.scripts.lint = "biome check . --ext .ts,.tsx";
209
+ packageJson.scripts.format = "biome format . --ext .ts,.tsx --write";
210
+ this.addPackage("@biomejs/biome", true);
211
+ } else if (this.linter === "eslint") {
212
+ packageJson.scripts.lint = "eslint . --ext .ts,.tsx";
213
+ packageJson.scripts.format = "eslint . --ext .ts,.tsx --fix";
214
+ this.addPackage("eslint", true);
91
215
  }
92
- const validation_library = await (0, import_prompts.select)({
216
+ await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
217
+ }
218
+ async setupGeneralPackages() {
219
+ this.validation_library = await (0, import_prompts.select)({
93
220
  message: "Select a package you want for validation",
94
221
  choices: [
95
222
  {
@@ -110,8 +237,42 @@ var CreateProjectCommand = class extends import_clipanion.Command {
110
237
  }
111
238
  ]
112
239
  });
113
- await fs.mkdir(projectPath, { recursive: true });
114
- console.log(`Created project directory at: ${projectPath}`);
240
+ this.validation_library === "none" || await this.addPackage(this.validation_library);
241
+ this.database_type = await (0, import_prompts.select)({
242
+ message: "Select a database type (you can add more databases later)",
243
+ choices: [
244
+ {
245
+ name: "PostgreSQL",
246
+ value: "postgresql",
247
+ description: "A powerful, open source object-relational database system"
248
+ },
249
+ {
250
+ name: "MySQL",
251
+ value: "mysql",
252
+ description: "The world's most popular open source database"
253
+ },
254
+ {
255
+ name: "SQLite",
256
+ value: "sqlite",
257
+ description: "A C library that provides a lightweight disk-based database"
258
+ }
259
+ ]
260
+ });
261
+ if (this.database_type === "postgresql") {
262
+ await this.addPackage("pg pg-cursor");
263
+ } else if (this.database_type === "mysql") {
264
+ await this.addPackage("mysql2");
265
+ } else if (this.database_type === "sqlite") {
266
+ await this.addPackage("sqlite3");
267
+ }
268
+ await this.addPackage("@devbro/pashmak tsconfig-paths dotenv ");
269
+ await this.addPackage(
270
+ "husky vitest supertest @types/supertest pino-pretty typescript tsx",
271
+ true
272
+ );
273
+ }
274
+ async setupBaseProject() {
275
+ console.log(`Using project directory: ${this.projectPath}`);
115
276
  const dirname = typeof __dirname === "undefined" ? import_path.default.dirname((0, import_url.fileURLToPath)(import_meta.url)) : __dirname;
116
277
  let basePath = import_path.default.join(dirname, `./base_project`);
117
278
  if (await this.folderExists(basePath) === false) {
@@ -119,53 +280,90 @@ var CreateProjectCommand = class extends import_clipanion.Command {
119
280
  }
120
281
  console.log(`Using base project path: ${basePath}`);
121
282
  const baseProjectPath = basePath;
122
- await this.processTplFolder(baseProjectPath, projectPath, {
123
- validation_library
283
+ await this.processTplFolder(baseProjectPath, this.projectPath, {
284
+ validation_library: this.validation_library,
285
+ executor: this.executor,
286
+ package_manager: this.packageManager,
287
+ linter: this.linter,
288
+ database_type: this.database_type
124
289
  });
125
- console.log(`Copied base project files to: ${projectPath}`);
126
- const packageJsonPath = import_path.default.join(projectPath, `package.json`);
127
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
128
- packageJson.name = import_change_case_all.Case.snake(import_path.default.basename(projectPath));
290
+ console.log(`Copied base project files to: ${this.projectPath}`);
291
+ const packageJsonPath = import_path.default.join(this.projectPath, "package.json");
292
+ let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
293
+ packageJson.name = import_change_case_all.Case.snake(import_path.default.basename(this.projectPath));
129
294
  await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
130
295
  console.log(`Updated package.json with project name: ${packageJson.name}`);
131
- if (this.git) {
132
- try {
133
- (0, import_child_process.execSync)(
134
- 'git init; git add --all; git commit --allow-empty -m "chore: first commit for pashmak"',
135
- {
136
- cwd: projectPath
137
- }
138
- );
139
- } catch (error) {
140
- console.error(`Failed to create project.`, error);
141
- return 1;
142
- }
296
+ }
297
+ async addPackage(packageName, dev = false) {
298
+ let install_command = "";
299
+ switch (this.packageManager) {
300
+ case "bun":
301
+ install_command = `bun add ${packageName}${dev ? " -d" : ""}`;
302
+ break;
303
+ case "yarn":
304
+ install_command = `yarn add ${packageName}${dev ? " -D" : ""} --no-install`;
305
+ break;
306
+ case "npm":
307
+ install_command = `npm install ${packageName}${dev ? " --save-dev" : ""} --package-lock-only`;
308
+ break;
143
309
  }
310
+ (0, import_child_process.execSync)(install_command, {
311
+ stdio: "inherit",
312
+ cwd: this.projectPath
313
+ });
144
314
  }
145
- async processTplFolder(src, dest, data = {}) {
146
- const files = await fs.readdir(src, { withFileTypes: true });
147
- for (const file of files) {
148
- const srcPath = import_path.default.join(src, file.name);
149
- const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path.default.join(dest, file.name);
150
- if (file.isDirectory()) {
151
- await fs.mkdir(destPath, { recursive: true });
152
- await this.processTplFolder(srcPath, destPath, data);
153
- } else if (file.name.endsWith(".tpl")) {
154
- await this.processTplFile(srcPath, destPath, data);
155
- } else {
156
- throw new Error(
157
- "unexpected non tpl file: " + srcPath + " " + file.name
158
- );
159
- }
315
+ async installPackages() {
316
+ const install_command = this.packageManager === "bun" ? `bun install` : this.packageManager === "yarn" ? `yarn` : `npm install`;
317
+ (0, import_child_process.execSync)(install_command, {
318
+ stdio: "inherit",
319
+ cwd: this.projectPath
320
+ });
321
+ }
322
+ async setupGit() {
323
+ const initGit = await (0, import_prompts.select)({
324
+ message: "Initialize a git repository?",
325
+ choices: [
326
+ {
327
+ name: "Yes",
328
+ value: true,
329
+ description: "Initialize git and create first commit"
330
+ },
331
+ {
332
+ name: "No",
333
+ value: false,
334
+ description: "Skip git initialization"
335
+ }
336
+ ]
337
+ });
338
+ if (initGit) {
339
+ const gitignoreContent = [
340
+ "node_modules/",
341
+ "dist/",
342
+ ".env",
343
+ ".env.*",
344
+ "!.env.example",
345
+ "*.log",
346
+ "coverage/",
347
+ ".DS_Store"
348
+ ].join("\n") + "\n";
349
+ await fs.writeFile(
350
+ import_path.default.join(this.projectPath, ".gitignore"),
351
+ gitignoreContent
352
+ );
353
+ (0, import_child_process.execSync)(
354
+ `git init; git add --all; git commit --allow-empty -m "chore: first commit"`,
355
+ {
356
+ cwd: this.projectPath
357
+ }
358
+ );
160
359
  }
161
360
  }
162
- async processTplFile(src, dest, data = {}) {
163
- import_handlebars.default.registerHelper("eq", (a, b) => a === b);
164
- const compiledTemplate = import_handlebars.default.compile(
165
- (await fs.readFile(src)).toString()
166
- );
167
- const template = await compiledTemplate(data);
168
- await fs.writeFile(dest, template);
361
+ async catch(error) {
362
+ if (Error.isError(error)) {
363
+ console.error(error.message);
364
+ } else {
365
+ console.error(error);
366
+ }
169
367
  }
170
368
  };
171
369
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,5 +1,15 @@
1
1
  export default {
2
2
  default: {
3
- type: 'disabled',
3
+ provider: 'disabled',
4
+ config: {},
5
+ },
6
+ };
7
+
8
+ export const $prod = {
9
+ default: {
10
+ provider: 'redis',
11
+ config: {
12
+ url: 'redis://redis:6379',
13
+ },
4
14
  },
5
15
  };
@@ -1,10 +1,12 @@
1
1
  export default {
2
2
  default: {
3
- host: process.env.DB_HOST,
4
- database: process.env.DB_NAME || 'test_db',
5
- user: process.env.DB_USER,
6
- password: process.env.DB_PASSWORD,
7
- port: parseInt(process.env.DB_PORT || '5432'),
8
- name: 'db',
3
+ provider: 'postgresql',
4
+ config: {
5
+ host: process.env.DB_HOST,
6
+ database: process.env.DB_NAME || 'test_db',
7
+ user: process.env.DB_USER,
8
+ password: process.env.DB_PASSWORD,
9
+ port: parseInt(process.env.DB_PORT || '5432'),
10
+ },
9
11
  },
10
12
  };
@@ -3,18 +3,24 @@ import os from 'os';
3
3
  import { getEnv } from '@devbro/pashmak/helper';
4
4
  import { dirname } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
- import { loadConfig } from '@devbro/pashmak/config';
6
+ import { loadConfigData, DotPaths } from '@devbro/pashmak/config';
7
+ import * as databases_config from './databases';
8
+ import * as storages_config from './storages';
9
+ import * as mailers_config from './mailers';
10
+ import * as queues_config from './queues';
11
+ import * as caches_config from './caches';
12
+ import * as loggers_config from './loggers';
7
13
 
8
14
  const __filename = fileURLToPath(import.meta.url);
9
15
  const __dirname = dirname(__filename);
10
16
 
11
17
  const project_configs = {
12
- databases: await loadConfig('./databases'),
13
- storages: await loadConfig('./storages'),
14
- mailer: await loadConfig('./mailer'),
15
- loggers: await loadConfig('./loggers'),
16
- queues: await loadConfig('./queues'),
17
- caches: await loadConfig('./caches'),
18
+ databases: loadConfigData(databases_config),
19
+ storages: loadConfigData(storages_config),
20
+ mailer: loadConfigData(mailers_config),
21
+ loggers: loadConfigData(loggers_config),
22
+ queues: loadConfigData(queues_config),
23
+ caches: loadConfigData(caches_config),
18
24
  base_url: getEnv('BASE_URL', 'http://localhost:' + getEnv('PORT', '3000')),
19
25
  port: getEnv('PORT', 3000),
20
26
  file_upload_path: path.join(os.tmpdir(), ''),
@@ -43,19 +49,6 @@ export const $test = {
43
49
  // Test environment overrides
44
50
  };
45
51
 
46
- export const $prod = {
47
- port: getEnv('PORT', 80),
48
- debug_mode: false,
49
- };
50
-
51
-
52
- type DotPaths<T> = {
53
- [K in keyof T & string]:
54
- T[K] extends Record<string, any>
55
- ? K | `${K}.${DotPaths<T[K]>}`
56
- : K
57
- }[keyof T & string];
58
-
59
52
  declare module '@devbro/neko-config' {
60
53
  interface ConfigKeys extends Record<DotPaths<typeof project_configs>, string> {
61
54
  }
@@ -1,10 +1,20 @@
1
1
  import { ctxSafe } from '@devbro/pashmak/context';
2
- import { LogMessage } from '@devbro/pashmak/logger';
3
2
 
4
3
  export default {
5
4
  default: {
6
- level: process.env.NODE_ENV === 'test' ? 'silent' : 'info',
7
- extrasFunction: (message: LogMessage) => {
5
+ level: 'info',
6
+ extrasFunction: (message: any) => {
7
+ let requestId = ctxSafe()?.get('requestId');
8
+ requestId && (message.requestId = requestId);
9
+ return message;
10
+ },
11
+ },
12
+ };
13
+
14
+ export const $test = {
15
+ default: {
16
+ level: 'silent',
17
+ extrasFunction: (message: any) => {
8
18
  let requestId = ctxSafe()?.get('requestId');
9
19
  requestId && (message.requestId = requestId);
10
20
  return message;
@@ -1,4 +1,3 @@
1
- import { LocalStorageProviderConfig } from '@devbro/pashmak/storage';
2
1
  import path from 'path';
3
2
  import os from 'os';
4
3
 
@@ -7,6 +6,6 @@ export default {
7
6
  provider: 'local',
8
7
  config: {
9
8
  basePath: path.join(os.tmpdir(), '/app-storage/'),
10
- } as LocalStorageProviderConfig,
9
+ },
11
10
  },
12
11
  };
@@ -1,24 +1,56 @@
1
- import dotenv from 'dotenv';
1
+ import dotenv from "dotenv";
2
2
  dotenv.config();
3
3
 
4
- import { bootstrap } from '@devbro/pashmak';
5
- import { dirname } from 'path';
6
- import { fileURLToPath } from 'url';
7
- import { loadConfig } from '@devbro/pashmak/config';
8
- import { httpServer, logger, mailer } from '@devbro/pashmak/facades';
9
- import { startQueueListeners } from '@/app/queues';
10
- import { HttpError } from '@devbro/pashmak/http';
11
- {{#if (eq validation_library "yup")}}import * as yup from 'yup';{{/if}}{{#if (eq validation_library "zod")}}import { z, ZodError } from 'zod';{{/if}}
4
+ import { config, loadConfigData } from "@devbro/pashmak/config";
5
+ import * as config_data from "./config/default.mts";
6
+ await config.load(loadConfigData(config_data));
12
7
 
13
- import './app/console';
14
- import './routes';
15
- import './schedules';
8
+ import { httpServer, logger } from "@devbro/pashmak/facades";
9
+ import { startQueueListeners } from "@/app/queues";
10
+ import { HttpError } from "@devbro/pashmak/http";
16
11
 
17
- const config_data = await loadConfig(dirname(fileURLToPath(import.meta.url)) + '/config/default');
12
+ import * as yup from "yup";
13
+ import { Request, Response, Middleware } from "@devbro/neko-router";
14
+ import { DatabaseProviderMiddleware } from "@devbro/pashmak/middlewares";
18
15
 
19
- await bootstrap({
20
- root_dir: dirname(fileURLToPath(import.meta.url)),
21
- config_data,
16
+ import "@devbro/pashmak";
17
+
18
+ import "./app/console";
19
+ import "./routes";
20
+ import "./schedules";
21
+
22
+ import { context_provider } from "@devbro/neko-context";
23
+
24
+ import { Connection } from "@devbro/neko-sql";
25
+ import { Global } from "@devbro/pashmak/global";
26
+ import { ctx } from "@devbro/pashmak/context";
27
+ import { BaseModel } from "@devbro/pashmak/orm";
28
+
29
+ context_provider.setPreLoader(async (f: Function) => {
30
+ const middlewares: Middleware[] = [];
31
+ const m = DatabaseProviderMiddleware.getInstance();
32
+ middlewares.push(m);
33
+
34
+ await m.call({} as Request, {} as Response, f as () => Promise<void>);
35
+ });
36
+
37
+ Global.set(
38
+ "database.default",
39
+ DatabaseProviderMiddleware.getInstance().getConnection(
40
+ config.get("databases.default") as any,
41
+ ),
42
+ );
43
+
44
+ BaseModel.setConnection(() => {
45
+ const key = ["database", "default"];
46
+ let rc: Connection | undefined;
47
+
48
+ if (ctx.isActive()) {
49
+ rc = ctx().get<Connection>(key);
50
+ } else if (Global.has(key)) {
51
+ rc = Global.get<Connection>(key);
52
+ }
53
+ return rc!;
22
54
  });
23
55
 
24
56
  httpServer().setErrorHandler(async (err: Error, req: any, res: any) => {
@@ -9,9 +9,9 @@ const router = routerFunc();
9
9
  router.addGlobalMiddleware(loggerMiddleware);
10
10
  router.addRoute(
11
11
  ["GET", "HEAD"],
12
- "/api/v1/meow",
12
+ "/",
13
13
  async (req: any, res: any) => {
14
- return { message: "meow meow!" };
14
+ return { message: "Welcome to Pashmak!" };
15
15
  },
16
16
  ).addMiddleware([]);
17
17