@nano-app/backend 0.12.1 → 0.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,7 +34,7 @@ createNanoApp({ port: 3000 });
34
34
  import { createRoute } from '@nano-app/backend';
35
35
 
36
36
  export default createRoute({
37
- GET: async () => ({ success: true, result: { status: 'ok' } }),
37
+ GET: async () => ({ result: { status: 'ok' } }),
38
38
  });
39
39
  ```
40
40
 
@@ -53,16 +53,17 @@ Each `*.route.ts` under `mainPlugin.routesDir` default-exports an object with th
53
53
  ```ts
54
54
  export default createRoute({
55
55
  expression: '/:id', // → /users/:id
56
- GET: async req => ({ success: true, result: { id: req.params.id } }),
57
- DELETE: async req => ({ success: true, message: 'Deleted' }),
56
+ GET: async req => ({ result: { id: req.params.id } }),
57
+ DELETE: async req => ({ message: 'Deleted' }),
58
58
  });
59
59
  ```
60
60
 
61
- Each handler receives `(req, params)` and returns an `ApiResponse`. `params` holds the plugin's `options`, `db` (the Prisma client when a database is enabled, see [Database](#database)) and `onBeforeResult` (see [Callbacks](#callbacks)):
61
+ Each handler receives `(req, params)` and returns an `ApiResponse` without `success`: its `status` is the HTTP status (`200` by default) and the framework sets `success` to `status < 400`. `params` holds the plugin's `options`, `db` (the Prisma client when a database is enabled, see [Database](#database)) and `onBeforeResult` (see [Callbacks](#callbacks)):
62
62
 
63
63
  ```ts
64
64
  type ApiResponse<T> = {
65
- success?: boolean; // true → HTTP 200, any other value → HTTP 400
65
+ status?: number; // HTTP status, 200 by default; not sent in the body
66
+ success?: boolean; // set by the framework: status < 400
66
67
  result?: T;
67
68
  message?: string;
68
69
  warning?: boolean;
@@ -137,7 +138,7 @@ import { createRoute } from '@nano-app/backend';
137
138
  import type { PrismaClient } from '../../.nano-app/prisma-clients/app/generated/client';
138
139
 
139
140
  export default createRoute<PrismaClient>({
140
- GET: async (_req, { db }) => ({ success: true, result: await db!.user.findMany() }),
141
+ GET: async (_req, { db }) => ({ result: await db!.user.findMany() }),
141
142
  });
142
143
  ```
143
144
 
@@ -222,7 +223,7 @@ export default createPlugin((options?: { basePath?: string }) => ({
222
223
  import { createRoute } from '@nano-app/backend';
223
224
 
224
225
  export default createRoute({
225
- GET: async () => ({ success: true, result: { ok: true } }),
226
+ GET: async () => ({ result: { ok: true } }),
226
227
  });
227
228
  ```
228
229
 
@@ -263,7 +264,7 @@ The endpoints of one plugin have no guaranteed order: one route's `onInit` must
263
264
 
264
265
  Everything is mounted on one Express application, in this order: base middlewares → `before` plugins → your routes → `after` plugins → 404 → error handler.
265
266
 
266
- A plugin with a database follows the same rules, with its client in `.nano-app/prisma-clients/<name>`: a plugin of yours points `database.schemaPath` at its schema and you apply it with Prisma. Two plugins with the same name and a database fail at startup. If that folder holds the client of another schema from an earlier start, the startup warns and replaces it. An official plugin of `@nano-app/plugins` needs nothing from you: at startup nano-app applies its migrations to its own `nano_*` schema. See [PLUGINS.md](https://github.com/Nano-Nathan/nano-app/blob/main/PLUGINS.md).
267
+ A plugin with a database follows the same rules, with its client in `.nano-app/prisma-clients/<name>`: a plugin of yours points `database.schemaPath` at its schema and you apply it with Prisma. Two plugins with the same name and a database fail at startup. If that folder holds the client of another schema from an earlier start, the startup warns and replaces it. An official plugin of `@nano-app/plugins` needs nothing from you: at startup nano-app applies its migrations to its own `nano_*` schema. See [`@nano-app/plugins`](https://github.com/Nano-Nathan/nano-app/blob/main/plugins/README.md#database).
267
268
 
268
269
  ## Errors
269
270
 
package/build/index.d.ts CHANGED
@@ -4,9 +4,9 @@ import { Options } from "express-rate-limit";
4
4
  import "dotenv/config";
5
5
  import "jiti";
6
6
  import { BetterAuthOptions } from "better-auth";
7
- //#region ../core/types/api.d.ts
8
7
  /** API response */
9
8
  type ApiResponse<T = any> = {
9
+ status?: number;
10
10
  success?: boolean;
11
11
  result?: T;
12
12
  message?: string;
@@ -22,8 +22,6 @@ type QueryParams = {
22
22
  orderby?: NanoObject<'asc' | 'desc'>;
23
23
  select?: string;
24
24
  };
25
- //#endregion
26
- //#region ../core/types/objects.d.ts
27
25
  /** Extra params of handlers and callbacks */
28
26
  type Params<DB = any> = Partial<NanoObject & {
29
27
  db?: DB;
@@ -67,8 +65,6 @@ type RouteEntry<DB = any> = {
67
65
  } & Handlers<DB>;
68
66
  /** Generic object */
69
67
  type NanoObject<T = any> = Record<string, T>;
70
- //#endregion
71
- //#region src/types/database.d.ts
72
68
  /** Database client configuration. */
73
69
  type DatabaseConfig = {
74
70
  /** Whether the database is enabled. Defaults to false */
@@ -76,8 +72,6 @@ type DatabaseConfig = {
76
72
  /** Prisma schema file (`.prisma`), relative to `cwd` */
77
73
  schemaPath: string;
78
74
  };
79
- //#endregion
80
- //#region src/types/plugin.d.ts
81
75
  /** When a plugin is mounted, relative to the consumer routes */
82
76
  type PluginStage = 'before' | 'after';
83
77
  /** Plugin configuration: a group of endpoints */
@@ -115,8 +109,6 @@ type MainPluginConfig<Options = NanoObject> = {
115
109
  /** Plugin callbacks */
116
110
  callbacks?: PluginCallbacks;
117
111
  };
118
- //#endregion
119
- //#region src/types/app.d.ts
120
112
  /** Configuration of the framework's built-in packages */
121
113
  type PackagesConfig = {
122
114
  /** Morgan configuration */
@@ -156,14 +148,10 @@ type NanoAppConfig = {
156
148
  /** Main plugin to mount. */
157
149
  mainPlugin?: MainPluginConfig;
158
150
  };
159
- //#endregion
160
- //#region src/app/config.d.ts
161
151
  /** Merges the consumer configuration over the initial one; the main plugin is always named "app" */
162
152
  declare function mergeConfig(oConfig?: NanoAppConfig): NanoAppConfig & Required<Pick<NanoAppConfig, 'settings' | 'plugins' | 'packages'>> & {
163
153
  mainPlugin: PluginConfig;
164
154
  };
165
- //#endregion
166
- //#region src/app/NanoApp.d.ts
167
155
  /** Main NanoApp class */
168
156
  declare class NanoApp {
169
157
  protected oApp: Express;
@@ -176,8 +164,6 @@ declare class NanoApp {
176
164
  /** Adds the packages according to the configuration */
177
165
  private setPackages;
178
166
  }
179
- //#endregion
180
- //#region src/app/creators.d.ts
181
167
  /** Creates a new NanoApp instance */
182
168
  export declare function createNanoApp(oConfig?: NanoAppConfig): NanoApp;
183
169
  /** Creates and types a route object. */
@@ -187,5 +173,4 @@ type Creator<Options> = (options?: Options) => PluginConfig<Options>;
187
173
  export declare function createPlugin<Options>(fnCreator: Creator<Options>): Creator<Options>;
188
174
  /** Creates and types the callbacks of a plugin. */
189
175
  export declare function createPluginCallbacks<DB>(oCallbacks: PluginCallbacks<DB>): PluginCallbacks<DB>;
190
- //#endregion
191
176
  export { type ApiPromise, type ApiResponse, type Callbacks, type DatabaseConfig, type Handler, type Handlers, type MainPluginConfig, NanoApp, type NanoAppConfig, type NanoObject, type PackagesConfig, type Params, type PluginCallbacks, type PluginConfig, type PluginStage, type QueryParams, type Request, type RouteEntry };
package/build/index.js CHANGED
@@ -12,7 +12,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
12
12
  import { createJiti } from "jiti";
13
13
  import { execFileSync } from "node:child_process";
14
14
  import { createHash } from "node:crypto";
15
- //#region ../core/const.ts
15
+ // ../core/const.ts
16
16
  /** HTTP methods a route can handle */
17
17
  const HTTP_METHODS = [
18
18
  "GET",
@@ -25,8 +25,7 @@ const HTTP_METHODS = [
25
25
  const OFFICIAL_PLUGINS = "@nano-app/plugins";
26
26
  /** Error when the database URL is missing at startup */
27
27
  const MISSING_DATABASE_URL = "[nano-app] [ERROR] The DATABASE_URL environment variable is not defined.";
28
- //#endregion
29
- //#region ../core/loader/Validator.ts
28
+ // ../core/loader/Validator.ts
30
29
  const STORE_TYPES = ["app", "api"];
31
30
  /** Checks the consumer's files: invalid ones are warned about and discarded */
32
31
  var Validator = class Validator {
@@ -83,8 +82,7 @@ var Validator = class Validator {
83
82
  return this.oValidators[sExtension]?.()(oEntry, sFilePath) ? oEntry : void 0;
84
83
  }
85
84
  };
86
- //#endregion
87
- //#region ../core/loader/FileReader.ts
85
+ // ../core/loader/FileReader.ts
88
86
  /** Reads and loads files from disk, resolved from `cwd` */
89
87
  var FileReader = class {
90
88
  /** Loader of the consumer's modules; the Prisma runtime is loaded natively */
@@ -110,8 +108,7 @@ var FileReader = class {
110
108
  return sAbsolutePath;
111
109
  }
112
110
  };
113
- //#endregion
114
- //#region ../core/utils/Formatter.ts
111
+ // ../core/utils/Formatter.ts
115
112
  /** Formats values for logs and messages */
116
113
  var Formatter = class {
117
114
  /** Message of anything thrown: its `message` when it has one, else the value itself */
@@ -124,8 +121,7 @@ var Formatter = class {
124
121
  return oDate.toISOString().slice(0, 19).replace("T", " ");
125
122
  }
126
123
  };
127
- //#endregion
128
- //#region ../core/loader/FileLoader.ts
124
+ // ../core/loader/FileLoader.ts
129
125
  /** Finds, loads and validates the consumer's files */
130
126
  var FileLoader = class {
131
127
  /**
@@ -157,8 +153,7 @@ var FileLoader = class {
157
153
  return Validator.validate(oEntries, extension);
158
154
  }
159
155
  };
160
- //#endregion
161
- //#region src/routes/Endpoint.ts
156
+ // src/routes/Endpoint.ts
162
157
  /** Base class for all endpoints */
163
158
  var Endpoint = class {
164
159
  oMethods;
@@ -191,13 +186,17 @@ var Endpoint = class {
191
186
  ...oRequestParams,
192
187
  onBeforeResult
193
188
  })).then((oResponse) => {
194
- oRes.status(oResponse.success ? 200 : 400).json(oResponse);
189
+ const { status, ...oBody } = oResponse;
190
+ const iStatus = status ?? 200;
191
+ oRes.status(iStatus).json({
192
+ ...oBody,
193
+ success: iStatus < 400
194
+ });
195
195
  }).catch(fnNext);
196
196
  };
197
197
  }
198
198
  };
199
- //#endregion
200
- //#region src/routes/Router.ts
199
+ // src/routes/Router.ts
201
200
  /** Turns a folder of `*.route.ts` files into Express paths and endpoints */
202
201
  var Router = class {
203
202
  oRoutes = {};
@@ -227,8 +226,7 @@ var Router = class {
227
226
  return `${this.sBasePath}${sEndpoint.replace(/\/index$/, "")}${sExpression}` || "/";
228
227
  }
229
228
  };
230
- //#endregion
231
- //#region src/auth/BetterAuth.ts
229
+ // src/auth/BetterAuth.ts
232
230
  /** Better Auth on the app's Prisma client: the instance, its handler and a session guard */
233
231
  var BetterAuth = class {
234
232
  /** Creates the instance on the app's client, its handler and the guard */
@@ -260,8 +258,7 @@ var BetterAuth = class {
260
258
  };
261
259
  }
262
260
  };
263
- //#endregion
264
- //#region src/database/Prisma.ts
261
+ // src/database/Prisma.ts
265
262
  /** Runs the consumer's Prisma CLI: generates clients and applies official plugins' migrations */
266
263
  var Prisma = class {
267
264
  /** Folder of a client and its files, in the project */
@@ -336,8 +333,7 @@ var Prisma = class {
336
333
  }
337
334
  }
338
335
  };
339
- //#endregion
340
- //#region src/database/Database.ts
336
+ // src/database/Database.ts
341
337
  /** Prisma clients of the app and its plugins, one per name */
342
338
  var Database = class {
343
339
  static oAdapter;
@@ -396,8 +392,7 @@ var Database = class {
396
392
  return JSON.parse(readFileSync(join(sDir, "package.json"), "utf-8")).name === OFFICIAL_PLUGINS;
397
393
  }
398
394
  };
399
- //#endregion
400
- //#region src/routes/Plugin.ts
395
+ // src/routes/Plugin.ts
401
396
  /** A group of routes, with its options, callbacks and database */
402
397
  var Plugin = class {
403
398
  oConfig;
@@ -426,8 +421,7 @@ var Plugin = class {
426
421
  for (const { path, endpoint } of await oRouter.mount()) oApp.all(path, await endpoint.mount(oParams));
427
422
  }
428
423
  };
429
- //#endregion
430
- //#region src/app/config.ts
424
+ // src/app/config.ts
431
425
  /** Initial application configuration */
432
426
  const INITIAL_CONFIG = {
433
427
  /** Application port */
@@ -505,8 +499,7 @@ function mergeConfig(oConfig = {}) {
505
499
  }
506
500
  };
507
501
  }
508
- //#endregion
509
- //#region src/app/errors.ts
502
+ // src/app/errors.ts
510
503
  /** Whether anything thrown is an object, read as a HandlerError */
511
504
  function isHandlerError(oError) {
512
505
  return typeof oError === "object" && oError !== null;
@@ -543,8 +536,7 @@ const errorHandler = (oError, _oReq, oRes, _fnNext) => {
543
536
  if (status >= 500) console.error("[nano-app] [ERROR]", oError);
544
537
  oRes.status(status).json(body);
545
538
  };
546
- //#endregion
547
- //#region src/app/NanoApp.ts
539
+ // src/app/NanoApp.ts
548
540
  /** Main NanoApp class */
549
541
  var NanoApp = class {
550
542
  oApp;
@@ -598,8 +590,7 @@ var NanoApp = class {
598
590
  if (oConfig.urlencoded) this.oApp.use(express.urlencoded(oConfig.urlencoded));
599
591
  }
600
592
  };
601
- //#endregion
602
- //#region src/app/creators.ts
593
+ // src/app/creators.ts
603
594
  /** Creates a new NanoApp instance */
604
595
  function createNanoApp(oConfig) {
605
596
  return new NanoApp(oConfig);
@@ -615,5 +606,4 @@ function createPlugin(fnCreator) {
615
606
  function createPluginCallbacks(oCallbacks) {
616
607
  return oCallbacks;
617
608
  }
618
- //#endregion
619
609
  export { NanoApp, createNanoApp, createPlugin, createPluginCallbacks, createRoute };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nano-app/backend",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "Express server with file-convention routes, plugins and an optional PostgreSQL layer",
5
5
  "type": "module",
6
6
  "main": "build/index.js",
@@ -45,9 +45,9 @@
45
45
  "dependencies": {
46
46
  "compression": "^1.8.2",
47
47
  "cors": "^2.8.6",
48
- "dotenv": "^18.0.8",
48
+ "dotenv": "^18.0.9",
49
49
  "express": "^5.3.0",
50
- "express-rate-limit": "^8.7.1",
50
+ "express-rate-limit": "^8.7.2",
51
51
  "glob": "^13.0.6",
52
52
  "helmet": "^8.3.0",
53
53
  "jiti": "^2.7.0",
@@ -56,7 +56,7 @@
56
56
  "peerDependencies": {
57
57
  "@prisma/adapter-pg": "^7.10.1",
58
58
  "@prisma/client": "^7.10.1",
59
- "better-auth": "^1.7.12",
59
+ "better-auth": "^1.7.15",
60
60
  "pg": "^8.23.1"
61
61
  },
62
62
  "peerDependenciesMeta": {
@@ -80,12 +80,12 @@
80
80
  "@types/cors": "^2.8.19",
81
81
  "@types/express": "^5.0.6",
82
82
  "@types/morgan": "^1.9.10",
83
- "@types/node": "^26.6.5",
83
+ "@types/node": "^26.6.6",
84
84
  "@types/pg": "^8.20.0",
85
- "better-auth": "^1.7.12",
85
+ "better-auth": "^1.7.15",
86
86
  "pg": "^8.23.1",
87
87
  "prisma": "^7.10.1",
88
- "tsdown": "^0.23.1",
88
+ "tsdown": "^0.23.4",
89
89
  "tsx": "^4.23.15",
90
90
  "typescript": "^7.0.2"
91
91
  }