@nano-app/backend 0.7.1 → 0.8.0
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 +36 -10
- package/build/index.d.ts +74 -49
- package/build/index.js +31 -24
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -46,17 +46,17 @@ export default createRoute({
|
|
|
46
46
|
|
|
47
47
|
## Routes
|
|
48
48
|
|
|
49
|
-
Each `*.route.ts` under `mainPlugin.routesDir` default-exports an object with the HTTP methods it implements. **The file path is the URL** (`index.route.ts` → `/`, `api/users.route.ts` → `/api/users`). `expression`
|
|
49
|
+
Each `*.route.ts` under `mainPlugin.routesDir` default-exports an object with the HTTP methods it implements. **The file path is the URL** (`index.route.ts` → `/`, `api/users.route.ts` → `/api/users`). `expression` is appended to that path as is, in Express syntax (`/:id`, `{/:id}` for optional):
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
52
|
export default createRoute({
|
|
53
|
-
expression: "
|
|
53
|
+
expression: "/:id", // → /users/:id
|
|
54
54
|
GET: async req => ({ success: true, result: { id: req.params.id } }),
|
|
55
55
|
DELETE: async req => ({ success: true, message: "Deleted" }),
|
|
56
56
|
});
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Each handler receives `(req,
|
|
59
|
+
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)):
|
|
60
60
|
|
|
61
61
|
```ts
|
|
62
62
|
type ApiResponse<T> = {
|
|
@@ -80,7 +80,7 @@ Every option is optional.
|
|
|
80
80
|
| `listener` | `() => {}` | Callback once the server is listening. |
|
|
81
81
|
| `settings` | `{}` | Values for `app.set()` (e.g. `{ "trust proxy": 1 }`). |
|
|
82
82
|
| `packages` | see below | Framework base middlewares. |
|
|
83
|
-
| `mainPlugin` | `{ routesDir: "src/routes"
|
|
83
|
+
| `mainPlugin` | `{ routesDir: "src/routes" }` | Your routes (`routesDir`, relative to `cwd`), `basePath` (e.g. `/api`, no trailing slash) and database: see [Database](#database). |
|
|
84
84
|
| `plugins` | `[]` | Plugins mounted around your routes, in order: see [Plugins](#plugins). |
|
|
85
85
|
|
|
86
86
|
`packages` accepts `morgan`, `cors`, `helmet`, `compression`, `rateLimit`, `express` (`express.json` options) and `urlencoded`. The merge is **per section**: passing one key keeps the others; pass `false`/`undefined` to disable one.
|
|
@@ -137,8 +137,8 @@ createNanoApp({ mainPlugin: { database: { enabled: true } } });
|
|
|
137
137
|
import { createRoute } from "@nano-app/backend";
|
|
138
138
|
import type { PrismaClient } from "../../.nano-app/prisma-clients/app/generated/client";
|
|
139
139
|
|
|
140
|
-
export default createRoute({
|
|
141
|
-
GET: async (_req, db
|
|
140
|
+
export default createRoute<PrismaClient>({
|
|
141
|
+
GET: async (_req, { db }) => ({ success: true, result: await db!.user.findMany() }),
|
|
142
142
|
});
|
|
143
143
|
```
|
|
144
144
|
|
|
@@ -150,12 +150,12 @@ export default createRoute({
|
|
|
150
150
|
- Each key falls back to its default, so `{ enabled: true }` is enough with the default layout. The client is always read from `.nano-app/prisma-clients/app/`, where `nano-app generate` writes it.
|
|
151
151
|
- Startup fails if `DATABASE_URL` is missing or the client cannot be loaded or is not a valid PostgreSQL Prisma client. The connection opens on the first query.
|
|
152
152
|
- The `nano_` prefix is reserved for the framework's plugins: a datasource schema starting with it fails the startup.
|
|
153
|
-
-
|
|
153
|
+
- Pass your generated `PrismaClient` to `createRoute<PrismaClient>` to type `db`; otherwise it is `any`, and without an enabled database `undefined`.
|
|
154
154
|
- For several PostgreSQL schemas, declare `schemas = ["public", "billing"]` in the datasource and `@@schema("billing")` on each model; one client covers them all.
|
|
155
155
|
|
|
156
156
|
## Plugins
|
|
157
157
|
|
|
158
|
-
A plugin is a group of endpoints mounted under a base path. Your routes are mounted as one (named `app`).
|
|
158
|
+
A plugin is a group of endpoints mounted under a base path. Your routes are mounted as one (named `app`). The official plugins are in [`@nano-app/plugins`](https://github.com/Nano-Nathan/nano-app/blob/main/plugins/README.md). You write one with `createPlugin` and list it in `plugins`. Nothing is mounted unless you list it.
|
|
159
159
|
|
|
160
160
|
```ts
|
|
161
161
|
// src/plugins/hello/index.ts
|
|
@@ -187,7 +187,32 @@ import hello from "./plugins/hello";
|
|
|
187
187
|
createNanoApp({ plugins: [hello()] });
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
`createPlugin` types the options of that plugin. Each plugin chooses its base path and whether it mounts `before` (default) or `after` your routes.
|
|
190
|
+
`createPlugin` types the options of that plugin. Each plugin chooses its base path and whether it mounts `before` (default) or `after` your routes. What the plugin puts in `options` reaches every callback and handler of its routes in `params`.
|
|
191
|
+
|
|
192
|
+
### Callbacks
|
|
193
|
+
|
|
194
|
+
Two levels. Only the plugin's receives the Express app, so nothing app-wide depends on the order of the route files.
|
|
195
|
+
|
|
196
|
+
| Level | Callback | Runs | Receives | Use |
|
|
197
|
+
|---|---|---|---|---|
|
|
198
|
+
| Plugin (`callbacks` in its config) | `onMount` | Once, after its database and before its endpoints | `(app, params)` | App-level middlewares (a guard), shared setup |
|
|
199
|
+
| Endpoint (`callbacks` in `createRoute`) | `onInit` | Once, when the endpoint is mounted | `(params)` | Setup of that route |
|
|
200
|
+
| Endpoint | `onBefore` | Before every request the endpoint handles | `(req, method, params)` | Validate or load; its return value reaches the handler as `params.onBeforeResult` |
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
export default createPlugin((options?: { publicPaths?: string[] }) => ({
|
|
204
|
+
name: "guard",
|
|
205
|
+
routesDir: resolve(dirname(fileURLToPath(import.meta.url)), "routes"),
|
|
206
|
+
options: { publicPaths: options?.publicPaths ?? [] },
|
|
207
|
+
callbacks: {
|
|
208
|
+
onMount: async (app, { publicPaths }) => {
|
|
209
|
+
app.use((req, _res, next) => next(publicPaths.includes(req.path) ? undefined : { status: 401, message: "Unauthorized" }));
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
}));
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The endpoints of one plugin have no guaranteed order: one route's `onInit` must not depend on another's. `mainPlugin` takes `callbacks` too.
|
|
191
216
|
|
|
192
217
|
Everything is mounted on one Express application, in this order: base middlewares → `before` plugins → your routes → `after` plugins → 404 → error handler.
|
|
193
218
|
|
|
@@ -216,8 +241,9 @@ GET /unknown // → 404 { success: false,
|
|
|
216
241
|
| `createNanoApp(config?)` | Creates and starts the app. |
|
|
217
242
|
| `createRoute(route)` | Types a route file. |
|
|
218
243
|
| `createPlugin(creator)` | Types a plugin factory and its options. |
|
|
244
|
+
| `createPluginCallbacks(callbacks)` | Types the callbacks of a plugin (`createPluginCallbacks<PrismaClient>` types `db`), e.g. to keep them in their own file. |
|
|
219
245
|
|
|
220
|
-
Also exported: the configuration types (`NanoAppConfig`, `PackagesConfig`, `PluginConfig`, `PluginStage`, `MainPluginConfig`, `DatabaseConfig`), the Express `Request` type and the HTTP contract (`ApiResponse`, `ApiPromise`, `QueryParams`, `RouteEntry`, `Handler`, `Handlers`, `NanoObject`).
|
|
246
|
+
Also exported: the configuration types (`NanoAppConfig`, `PackagesConfig`, `PluginConfig`, `PluginStage`, `MainPluginConfig`, `DatabaseConfig`), the Express `Request` type and the HTTP contract (`ApiResponse`, `ApiPromise`, `QueryParams`, `RouteEntry`, `Handler`, `Handlers`, `NanoObject`) and the callback types (`Params`, `Callbacks`, `PluginCallbacks`).
|
|
221
247
|
|
|
222
248
|
## Development
|
|
223
249
|
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import express, {
|
|
1
|
+
import express, { Request, Express } from 'express';
|
|
2
2
|
export { Request } from 'express';
|
|
3
3
|
import { Options } from 'express-rate-limit';
|
|
4
4
|
import { CorsOptions } from 'cors';
|
|
@@ -11,28 +11,85 @@ type DatabaseConfig = {
|
|
|
11
11
|
schemaPath: string;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
/** API response */
|
|
15
|
+
type ApiResponse<T = any> = {
|
|
16
|
+
success?: boolean;
|
|
17
|
+
result?: T;
|
|
18
|
+
message?: string;
|
|
19
|
+
warning?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type ApiPromise<T = any> = Promise<{
|
|
22
|
+
success?: boolean;
|
|
23
|
+
result?: T;
|
|
24
|
+
message?: string;
|
|
25
|
+
warning?: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
/** Query parameters sent in the `query` header (JSON). */
|
|
28
|
+
type QueryParams = {
|
|
29
|
+
skip?: number;
|
|
30
|
+
top?: number;
|
|
31
|
+
filter?: NanoObject;
|
|
32
|
+
orderby?: Record<string, "asc" | "desc">;
|
|
33
|
+
select?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** Extra params of handlers and callbacks */
|
|
37
|
+
type Params<DB = any> = Partial<NanoObject & {
|
|
38
|
+
db?: DB;
|
|
39
|
+
onBeforeResult?: NanoObject;
|
|
40
|
+
}>;
|
|
41
|
+
/** Endpoint handlers */
|
|
42
|
+
type Handler<DB> = (req: Request, params: Params<DB>) => ApiPromise;
|
|
43
|
+
type Handlers<DB = any> = {
|
|
44
|
+
GET?: Handler<DB>;
|
|
45
|
+
POST?: Handler<DB>;
|
|
46
|
+
PUT?: Handler<DB>;
|
|
47
|
+
DELETE?: Handler<DB>;
|
|
48
|
+
};
|
|
49
|
+
/** Callbacks */
|
|
50
|
+
type Callback<DB> = (params: Params<DB>) => Promise<void>;
|
|
51
|
+
type CallbackMethod<DB> = (req: Request, method: string, params: Params<DB>) => Promise<NanoObject>;
|
|
52
|
+
type CallbackMount<DB> = (app: Express, params: Params<DB>) => Promise<void>;
|
|
53
|
+
/** Callbacks of an endpoint. They never receive the app: what affects the whole app goes in the plugin's onMount */
|
|
54
|
+
type Callbacks<DB = any> = {
|
|
55
|
+
onInit?: Callback<DB>;
|
|
56
|
+
onBefore?: CallbackMethod<DB>;
|
|
57
|
+
};
|
|
58
|
+
/** Callbacks of a plugin */
|
|
59
|
+
type PluginCallbacks<DB = any> = {
|
|
60
|
+
onMount?: CallbackMount<DB>;
|
|
61
|
+
};
|
|
62
|
+
/** Entry of a route file (`*.route.ts`) */
|
|
63
|
+
type RouteEntry<DB = any> = {
|
|
64
|
+
expression?: string;
|
|
65
|
+
callbacks?: Callbacks<DB>;
|
|
66
|
+
} & Handlers<DB>;
|
|
67
|
+
type NanoObject<T = any> = Record<string, T>;
|
|
68
|
+
|
|
14
69
|
/** When a plugin is mounted, relative to the consumer routes */
|
|
15
70
|
type PluginStage = "before" | "after";
|
|
16
71
|
/** Plugin configuration: a group of endpoints */
|
|
17
|
-
type PluginConfig = {
|
|
72
|
+
type PluginConfig<Options = NanoObject> = {
|
|
18
73
|
/** Name of the plugin, same as his database (If have one) */
|
|
19
74
|
name: string;
|
|
20
75
|
/** Directory used to discover the `*.route.ts` files */
|
|
21
76
|
routesDir: string;
|
|
22
|
-
/** Base path prepended to every endpoint
|
|
77
|
+
/** Base path prepended to every endpoint, e.g. "/auth" (no trailing slash). Defaults to none */
|
|
23
78
|
basePath?: string;
|
|
24
79
|
/** Mount point relative to the consumer routes. Defaults to "before" */
|
|
25
80
|
stage?: PluginStage;
|
|
26
81
|
/** Prisma client the plugin needs, mounted before its endpoints */
|
|
27
82
|
database?: DatabaseConfig;
|
|
28
|
-
/**
|
|
29
|
-
|
|
83
|
+
/** Plugin options */
|
|
84
|
+
options?: Options;
|
|
85
|
+
/** Plugin callbacks */
|
|
86
|
+
callbacks?: PluginCallbacks;
|
|
30
87
|
};
|
|
31
88
|
/** The project's plugin: nano-app names it "app" and mounts it between the "before" and "after" plugins */
|
|
32
|
-
type MainPluginConfig = {
|
|
89
|
+
type MainPluginConfig<Options = NanoObject> = {
|
|
33
90
|
/** Directory of the project's `*.route.ts` files. Defaults to "src/routes" */
|
|
34
91
|
routesDir?: string;
|
|
35
|
-
/** Base path prepended to every route. Defaults to
|
|
92
|
+
/** Base path prepended to every route, e.g. "/api" (no trailing slash). Defaults to none */
|
|
36
93
|
basePath?: string;
|
|
37
94
|
/** The project's database */
|
|
38
95
|
database?: {
|
|
@@ -41,8 +98,10 @@ type MainPluginConfig = {
|
|
|
41
98
|
/** Prisma schema file, relative to `cwd`. Defaults to "src/prisma/schema.prisma" */
|
|
42
99
|
schemaPath?: string;
|
|
43
100
|
};
|
|
44
|
-
/**
|
|
45
|
-
|
|
101
|
+
/** Plugin options */
|
|
102
|
+
options?: Options;
|
|
103
|
+
/** Plugin callbacks */
|
|
104
|
+
callbacks?: PluginCallbacks;
|
|
46
105
|
};
|
|
47
106
|
|
|
48
107
|
/** Configuration of the framework's built-in packages */
|
|
@@ -83,42 +142,6 @@ type NanoAppConfig = {
|
|
|
83
142
|
mainPlugin?: MainPluginConfig;
|
|
84
143
|
};
|
|
85
144
|
|
|
86
|
-
/** API response */
|
|
87
|
-
type ApiResponse<T = any> = {
|
|
88
|
-
success?: boolean;
|
|
89
|
-
result?: T;
|
|
90
|
-
message?: string;
|
|
91
|
-
warning?: boolean;
|
|
92
|
-
};
|
|
93
|
-
type ApiPromise<T = any> = Promise<{
|
|
94
|
-
success?: boolean;
|
|
95
|
-
result?: T;
|
|
96
|
-
message?: string;
|
|
97
|
-
warning?: boolean;
|
|
98
|
-
}>;
|
|
99
|
-
/** Query parameters sent in the `query` header (JSON). */
|
|
100
|
-
type QueryParams = {
|
|
101
|
-
skip?: number;
|
|
102
|
-
top?: number;
|
|
103
|
-
filter?: NanoObject;
|
|
104
|
-
orderby?: Record<string, "asc" | "desc">;
|
|
105
|
-
select?: string;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/** Endpoint method: receives the request and, when the plugin has one, its Prisma client */
|
|
109
|
-
type Handler = (req: Request, db?: any) => ApiPromise;
|
|
110
|
-
type Handlers = {
|
|
111
|
-
GET?: Handler;
|
|
112
|
-
POST?: Handler;
|
|
113
|
-
PUT?: Handler;
|
|
114
|
-
DELETE?: Handler;
|
|
115
|
-
};
|
|
116
|
-
/** Entry of a route file (`*.route.ts`) */
|
|
117
|
-
type RouteEntry = {
|
|
118
|
-
expression?: string;
|
|
119
|
-
} & Handlers;
|
|
120
|
-
type NanoObject<T = any> = Record<string, T>;
|
|
121
|
-
|
|
122
145
|
/**
|
|
123
146
|
* Merges the consumer configuration with the initial one.
|
|
124
147
|
*/
|
|
@@ -141,10 +164,12 @@ declare class NanoApp {
|
|
|
141
164
|
/** Creates a new NanoApp instance */
|
|
142
165
|
declare function createNanoApp(config?: NanoAppConfig): NanoApp;
|
|
143
166
|
/** Creates and types a route object. */
|
|
144
|
-
declare function createRoute(route: RouteEntry): RouteEntry
|
|
167
|
+
declare function createRoute<DB>(route: RouteEntry<DB>): RouteEntry<DB>;
|
|
145
168
|
/** Creates a plugin: a function of the plugin's own options that returns its configuration. */
|
|
146
|
-
type Creator<Options> = (options?: Options) => PluginConfig
|
|
169
|
+
type Creator<Options> = (options?: Options) => PluginConfig<Options>;
|
|
147
170
|
declare function createPlugin<Options>(creator: Creator<Options>): Creator<Options>;
|
|
171
|
+
/** Creates and types the callbacks of a plugin. */
|
|
172
|
+
declare function createPluginCallbacks<DB>(callbacks: PluginCallbacks<DB>): PluginCallbacks<DB>;
|
|
148
173
|
|
|
149
|
-
export { NanoApp, createNanoApp, createPlugin, createRoute };
|
|
150
|
-
export type { ApiPromise, ApiResponse, DatabaseConfig, Handler, Handlers, MainPluginConfig, NanoAppConfig, NanoObject, PackagesConfig, PluginConfig, PluginStage, QueryParams, RouteEntry };
|
|
174
|
+
export { NanoApp, createNanoApp, createPlugin, createPluginCallbacks, createRoute };
|
|
175
|
+
export type { ApiPromise, ApiResponse, Callbacks, DatabaseConfig, Handler, Handlers, MainPluginConfig, NanoAppConfig, NanoObject, PackagesConfig, Params, PluginCallbacks, PluginConfig, PluginStage, QueryParams, RouteEntry };
|
package/build/index.js
CHANGED
|
@@ -221,17 +221,27 @@ var Formatter = class {
|
|
|
221
221
|
// src/routes/Endpoint.ts
|
|
222
222
|
var Endpoint = class {
|
|
223
223
|
methods;
|
|
224
|
+
callbacks;
|
|
224
225
|
/** Allowed methods */
|
|
225
|
-
constructor(methods) {
|
|
226
|
+
constructor(methods, callbacks = {}) {
|
|
226
227
|
this.methods = methods;
|
|
228
|
+
this.callbacks = callbacks;
|
|
227
229
|
}
|
|
228
230
|
/** Handler for all methods */
|
|
229
|
-
|
|
231
|
+
async mount(params) {
|
|
232
|
+
await this.callbacks.onInit?.(params);
|
|
233
|
+
return this.createHandler(params);
|
|
234
|
+
}
|
|
235
|
+
createHandler = (params) => (req, res, next) => {
|
|
230
236
|
const method = req.method.toUpperCase();
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
const fnMethod = this.methods[method];
|
|
238
|
+
if (fnMethod) {
|
|
239
|
+
(this.callbacks.onBefore?.(req, method, params) ?? Promise.resolve({})).then((onBeforeResult) => (
|
|
240
|
+
// Runs the method
|
|
241
|
+
fnMethod(req, { ...params, onBeforeResult }).then((response) => {
|
|
242
|
+
res.status(response.success ? 200 : 400).json(response);
|
|
243
|
+
})
|
|
244
|
+
)).catch(next);
|
|
235
245
|
} else {
|
|
236
246
|
res.status(405).json({ success: false, message: `Method ${method} not implemented` });
|
|
237
247
|
}
|
|
@@ -245,7 +255,7 @@ var Router = class {
|
|
|
245
255
|
basePath;
|
|
246
256
|
constructor(routesDir, basePath) {
|
|
247
257
|
this.routesDir = routesDir;
|
|
248
|
-
this.basePath = basePath ?? "
|
|
258
|
+
this.basePath = basePath ?? "";
|
|
249
259
|
}
|
|
250
260
|
async mount() {
|
|
251
261
|
if (!!this.routesDir) {
|
|
@@ -254,23 +264,15 @@ var Router = class {
|
|
|
254
264
|
extension: "route"
|
|
255
265
|
});
|
|
256
266
|
}
|
|
257
|
-
return Object.entries(this.routes).map(([filePath, { expression, ...methods }]) => {
|
|
267
|
+
return Object.entries(this.routes).map(([filePath, { expression, callbacks, ...methods }]) => {
|
|
258
268
|
const path = this.createPath(filePath, expression);
|
|
259
269
|
console.log(`[nano-app] [INFO] ${path}`);
|
|
260
|
-
return { path, endpoint: new Endpoint(methods) };
|
|
270
|
+
return { path, endpoint: new Endpoint(methods, callbacks) };
|
|
261
271
|
});
|
|
262
272
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (!!expression) {
|
|
267
|
-
path = `${isIndex ? "" : endpoint.replace(/\/+$/, "")}/${expression.replace(/^\/+/, "")}`;
|
|
268
|
-
}
|
|
269
|
-
const basePath = this.basePath.replace(/\/+$/, "");
|
|
270
|
-
if (basePath) {
|
|
271
|
-
path = path === "/" ? basePath : `${basePath}${path}`;
|
|
272
|
-
}
|
|
273
|
-
return path;
|
|
273
|
+
/** `basePath` + file path (`/index` is the folder itself) + `expression`, as Express reads them */
|
|
274
|
+
createPath(endpoint, expression = "") {
|
|
275
|
+
return `${this.basePath}${endpoint.replace(/\/index$/, "")}${expression}` || "/";
|
|
274
276
|
}
|
|
275
277
|
};
|
|
276
278
|
|
|
@@ -346,11 +348,12 @@ var Plugin = class {
|
|
|
346
348
|
}
|
|
347
349
|
/** Mounts its endpoints on express app */
|
|
348
350
|
async mount(app) {
|
|
349
|
-
const { name, routesDir, basePath, database,
|
|
351
|
+
const { name, routesDir, basePath, database, options, callbacks } = this.config;
|
|
350
352
|
const router = new Router(routesDir, basePath);
|
|
351
353
|
const db = database?.enabled ? await Database.mount(name, database) : void 0;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
+
const params = { ...options, db };
|
|
355
|
+
await callbacks?.onMount?.(app, params);
|
|
356
|
+
for (const { path, endpoint } of await router.mount()) app.all(path, await endpoint.mount(params));
|
|
354
357
|
}
|
|
355
358
|
};
|
|
356
359
|
|
|
@@ -396,7 +399,7 @@ var INITIAL_CONFIG = {
|
|
|
396
399
|
/** Main plugin to mount */
|
|
397
400
|
mainPlugin: {
|
|
398
401
|
routesDir: "src/routes",
|
|
399
|
-
basePath: "
|
|
402
|
+
basePath: "",
|
|
400
403
|
database: {
|
|
401
404
|
enabled: false,
|
|
402
405
|
schemaPath: "src/prisma/schema.prisma"
|
|
@@ -536,9 +539,13 @@ function createRoute(route) {
|
|
|
536
539
|
function createPlugin(creator) {
|
|
537
540
|
return creator;
|
|
538
541
|
}
|
|
542
|
+
function createPluginCallbacks(callbacks) {
|
|
543
|
+
return callbacks;
|
|
544
|
+
}
|
|
539
545
|
export {
|
|
540
546
|
NanoApp,
|
|
541
547
|
createNanoApp,
|
|
542
548
|
createPlugin,
|
|
549
|
+
createPluginCallbacks,
|
|
543
550
|
createRoute
|
|
544
551
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nano-app/backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
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",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsup",
|
|
20
20
|
"dev": "tsup --watch",
|
|
21
|
-
"test": "tsx --test tests/*.test.ts",
|
|
21
|
+
"test": "tsx --env-file-if-exists=../.env --test tests/*.test.ts",
|
|
22
22
|
"prepublishOnly": "pnpm run build"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|