@nano-app/plugins 0.10.0 → 0.11.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 CHANGED
@@ -19,9 +19,9 @@ createNanoApp({ plugins: [health()] });
19
19
 
20
20
  | Plugin | Import | Endpoints | Options |
21
21
  | -------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
22
- | `health` | `import health from '@nano-app/plugins/health'` | `GET /health` → `{ success: true, result: { status: "ok" } }` | `basePath` (default `"/health"`) |
23
- | `crud` | `import crud from '@nano-app/plugins/crud'` | On the tables listed in `models`, by their name in the app's schema (any other answers 404): `GET` and `QUERY` on `/api/<model>{/<id>}` → a list `{ result }` or one record, with `QueryParams` as the body of `QUERY`: Drizzle's relational query (`where`, `columns`, `orderBy`, `limit`, `offset`, `with`); `POST /api/<model>`, `PUT` and `DELETE` on `/api/<model>/<id>` → the record created, updated or deleted. Postgres casts `<id>` to the type of the `id` column. With Better Auth, each method asks for a permission on the table: `read` (`GET`, `QUERY`), `create`, `update`, `delete`, see [crud and related tables](#crud-and-related-tables) | `models` (the published ones), `dbSchema` (the app's Drizzle schema, as in `mainPlugin.database`), `validations` (zod schemas of the bodies, see [crud and the bodies](#crud-and-the-bodies)), `basePath` (default `"/api"`) |
24
- | `rate-limit` | `import rateLimit from '@nano-app/plugins/rate-limit'` | None: limits every request of the routes and plugins mounted after it, per client IP (see [Client IP](../backend/README.md#client-ip)); the addresses of an IPv6 `/56` network are one client. Each request spends a token of the client's bucket, which holds `capacity` and refills `refillPerSecond` tokens per second; without one it answers `429` with `message` and `Retry-After` (seconds until the next token). List it first in `plugins`. The buckets live in the memory of each process | `capacity` (default `100`), `refillPerSecond` (default `1`), `message` |
22
+ | `health` | `import health from '@nano-app/plugins/health'` | `GET /health` → `{ success: true, result: { status: "ok" } }`. Public: it answers without a session | `basePath` (default `"/health"`) |
23
+ | `crud` | `import crud from '@nano-app/plugins/crud'` | On the tables listed in `models`, by their name in the app's schema (any other answers 404): `GET` and `QUERY` on `/api/<model>{/<id>}` → a list `{ result }` or one record, with `QueryParams` as the body of `QUERY`: Drizzle's relational query (`where`, `columns`, `orderBy`, `limit`, `offset`, `with`); `POST /api/<model>`, `PUT` and `DELETE` on `/api/<model>/<id>` → the record created, updated or deleted. Postgres casts `<id>` to the type of the `id` column. With Better Auth, each method asks for a permission on the table: `read` (`GET`, `QUERY`), `create`, `update`, `delete`, see [crud and related tables](#crud-and-related-tables) | `models` (the published ones), `dbSchema` (the app's Drizzle schema, as in `database.schema`), `validations` (zod schemas of the bodies, see [crud and the bodies](#crud-and-the-bodies)), `basePath` (default `"/api"`) |
24
+ | `rate-limit` | `import rateLimit from '@nano-app/plugins/rate-limit'` | None: limits every request of the routes and plugins mounted after it, per client IP (see [Client IP](../backend/README.md#client-ip)); the addresses of an IPv6 `/56` network are one client. Each request spends a token of the client's bucket, which holds `capacity` and refills `refillPerSecond` tokens per second; without one it answers `429` with `message` and `Retry-After` (seconds until the next token). List it first in `plugins.before`. The buckets live in the memory of each process | `capacity` (default `100`), `refillPerSecond` (default `1`), `message` |
25
25
 
26
26
  What is not CRUD, such as creating a record with business logic, goes in a route of your own with its own URL: a route of yours on a `crud` URL takes every method of it.
27
27
 
@@ -49,7 +49,7 @@ crud({
49
49
 
50
50
  ### crud and related tables
51
51
 
52
- A `crud` query runs on the app's client, so it reaches the related tables Drizzle's relations give: `with` loads them and `where` filters by them, also the ones that are not in `models`. With Better Auth, the permission asked is only the one of the URL's table. What a query may load is up to the app: the `read` validation of the model decides it (a `z.strictObject` without `with` keeps a query in its table). Better Auth's tables (`user`, `account` with its password hashes, `session` with its tokens) hold secrets: never publish `account`, `session` or `verification`, and do not relate them to a published table without a `read` validation that leaves them out.
52
+ A `crud` query runs on the app's client, so it reaches the related tables Drizzle's relations give: `with` loads them and `where` filters by them, also the ones that are not in `models`. With Better Auth, the permission asked is only the one of the URL's table. What a query may load is up to the app: the `read` validation of the model decides it (a `z.strictObject` without `with` keeps a query in its table). Better Auth's tables live in `nano_auth`, outside the app's schema: `crud` does not reach them. A Postgres error of a write (a duplicate, a missing reference) answers 500.
53
53
 
54
54
  ### Layout
55
55
 
@@ -86,7 +86,6 @@ import { fileURLToPath } from 'node:url';
86
86
  export default createPlugin((options?: { basePath?: string }) => ({
87
87
  name: 'hello',
88
88
  basePath: options?.basePath ?? '/hello',
89
- stage: 'before',
90
89
  routesDir: resolve(dirname(fileURLToPath(import.meta.url)), 'routes'),
91
90
  }));
92
91
  ```
@@ -105,10 +104,10 @@ export default createRoute({
105
104
  import { createNanoApp } from '@nano-app/backend';
106
105
  import hello from './plugins/hello';
107
106
 
108
- createNanoApp({ plugins: [hello()] });
107
+ createNanoApp({ plugins: { before: [hello()] } });
109
108
  ```
110
109
 
111
- `stage` is `"before"` (default) or `"after"` the app's own routes. Mount order: base middlewares, `before` plugins, your routes, `after` plugins, 404, error handler.
110
+ The app lists it in `plugins.before` or `plugins.after` its own routes. Mount order: base middlewares, Better Auth, `before` plugins, your routes, `after` plugins, 404, error handler. With Better Auth on, its routes need a session unless they are `public`.
112
111
 
113
112
  Set `options` in the returned config to pass values to the plugin's routes: every handler and callback receives them in `params`, next to `db`. Callbacks: `callbacks.onMount(app, params)` on the plugin, once, before its endpoints (app-level middlewares go here); `onInit(params)` and `onBefore(req, method, params)` on each route. See the [backend README](../backend/README.md#callbacks).
114
113
 
@@ -129,15 +128,15 @@ Publish a separate package. Do not add it to this repository unless a maintainer
129
128
  }
130
129
  ```
131
130
 
132
- Export the `createPlugin` factory as the package entry. The consumer installs both packages and passes the factory to `plugins`.
131
+ Export the `createPlugin` factory as the package entry. The consumer installs both packages and lists it in `plugins.before` or `plugins.after`.
133
132
 
134
133
  Use MIT or Apache-2.0 if you want the plugin listed from this repo later. Open an issue with the package name and a short description. A maintainer adds the link. The plugin stays in your repository.
135
134
 
136
135
  ### Database
137
136
 
138
- Optional. Pass `database: { schema }` on the plugin config: the module of its Drizzle tables, with its `relations` when it has them. Its tables live in the Postgres schema `nano_<plugin name>`, which drizzle-kit creates when the module exports its `pgSchema`; a table elsewhere fails the startup.
137
+ Optional. Pass `database: { schema }` on the plugin config: the module of its Drizzle tables, with its `relations` when it has them. Keep its tables in the Postgres schema `nano_<plugin name>`, reserved for it, which drizzle-kit creates when the module exports its `pgSchema`; a table in the `nano_*` schema of another fails the startup.
139
138
 
140
- Its tables are applied with drizzle-kit by whoever installs it, like the app's schema. Handlers and callbacks receive its client as `params.db`.
139
+ `push: true` applies them at startup, and `migrations` the folder the plugin ships; without them whoever installs it applies them with drizzle-kit. Handlers and callbacks receive its client as `params.db`.
141
140
 
142
141
  ### What belongs in this repository
143
142
 
@@ -5,7 +5,6 @@ import { join } from "node:path";
5
5
  var crud_default = createPlugin((options) => ({
6
6
  name: "crud",
7
7
  basePath: options?.basePath ?? "/api",
8
- stage: "after",
9
8
  routesDir: join(import.meta.dirname, "routes"),
10
9
  options
11
10
  }));
@@ -5,7 +5,6 @@ import { join } from "node:path";
5
5
  var health_default = createPlugin((options) => ({
6
6
  name: "health",
7
7
  basePath: options?.basePath ?? "/health",
8
- stage: "before",
9
8
  routesDir: join(import.meta.dirname, "routes")
10
9
  }));
11
10
  export { health_default as default };
@@ -1,5 +1,8 @@
1
1
  import { createRoute } from "@nano-app/backend";
2
2
  // health/routes/index.route.ts
3
3
  /** Answers that the server is up */
4
- var index_route_default = createRoute({ GET: async () => ({ result: { status: "ok" } }) });
4
+ var index_route_default = createRoute({
5
+ public: true,
6
+ GET: async () => ({ result: { status: "ok" } })
7
+ });
5
8
  export { index_route_default as default };
@@ -9,7 +9,6 @@ var rate_limit_default = createPlugin((options) => {
9
9
  const { capacity = 100, refillPerSecond = 1, message = "Too many requests, please try again later." } = options ?? {};
10
10
  return {
11
11
  name: "rate-limit",
12
- stage: "before",
13
12
  routesDir: "",
14
13
  callbacks: { onMount: async (oApp) => {
15
14
  const fnRefill = (oBucket, iNow) => Math.min(capacity, oBucket.iTokens + (iNow - oBucket.iTime) / 1e3 * refillPerSecond);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nano-app/plugins",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Official plugins for @nano-app/backend",
5
5
  "type": "module",
6
6
  "exports": {