@nano-app/plugins 0.4.0 → 0.4.2
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 +94 -3
- package/build/health/index.d.ts +0 -2
- package/build/health/index.js +1 -2
- package/build/health/routes/index.route.js +2 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -15,13 +15,13 @@ import health from '@nano-app/plugins/health';
|
|
|
15
15
|
createNanoApp({ plugins: [health()] });
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Official plugins
|
|
19
19
|
|
|
20
20
|
| Plugin | Import | Endpoints | Options |
|
|
21
21
|
|---|---|---|---|
|
|
22
22
|
| `health` | `import health from '@nano-app/plugins/health'` | `GET /health` → `{ success: true, result: { status: "ok" } }` | `basePath` (default `"/health"`) |
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
### Layout
|
|
25
25
|
|
|
26
26
|
```
|
|
27
27
|
plugins/
|
|
@@ -32,4 +32,95 @@ plugins/
|
|
|
32
32
|
└── routes/ *.route.ts, mounted under the plugin's basePath
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
## Write a plugin
|
|
36
|
+
|
|
37
|
+
`@nano-app/backend` ships the plugin contract. A plugin is a `createPlugin` factory: options in, `PluginConfig` out. The app mounts only the plugins you list.
|
|
38
|
+
|
|
39
|
+
### A plugin in your app
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
src/
|
|
43
|
+
├── app.ts
|
|
44
|
+
└── plugins/
|
|
45
|
+
└── hello/
|
|
46
|
+
├── index.ts
|
|
47
|
+
└── routes/
|
|
48
|
+
└── index.route.ts → /hello
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// src/plugins/hello/index.ts
|
|
53
|
+
import { createPlugin } from '@nano-app/backend';
|
|
54
|
+
import { dirname, resolve } from 'node:path';
|
|
55
|
+
import { fileURLToPath } from 'node:url';
|
|
56
|
+
|
|
57
|
+
export default createPlugin((options?: { basePath?: string }) => ({
|
|
58
|
+
name: 'hello',
|
|
59
|
+
basePath: options?.basePath ?? '/hello',
|
|
60
|
+
stage: 'before',
|
|
61
|
+
routesDir: resolve(dirname(fileURLToPath(import.meta.url)), 'routes'),
|
|
62
|
+
}));
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// src/plugins/hello/routes/index.route.ts
|
|
67
|
+
import { createRoute } from '@nano-app/backend';
|
|
68
|
+
|
|
69
|
+
export default createRoute({
|
|
70
|
+
GET: async () => ({ result: { ok: true } }),
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
// src/app.ts
|
|
76
|
+
import { createNanoApp } from '@nano-app/backend';
|
|
77
|
+
import hello from './plugins/hello';
|
|
78
|
+
|
|
79
|
+
createNanoApp({ plugins: [hello()] });
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`stage` is `"before"` (default) or `"after"` the app's own routes. Mount order: base middlewares, `before` plugins, your routes, `after` plugins, 404, error handler.
|
|
83
|
+
|
|
84
|
+
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).
|
|
85
|
+
|
|
86
|
+
`routesDir` must be a real directory of `*.route.ts` files when you run the app from source (`tsx`). `jiti` loads them. There is no compile step for your routes.
|
|
87
|
+
|
|
88
|
+
### A plugin other people can install
|
|
89
|
+
|
|
90
|
+
Publish a separate package. Do not add it to this repository unless a maintainer has agreed to own it.
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"name": "@you/nano-app-plugin-hello",
|
|
95
|
+
"type": "module",
|
|
96
|
+
"peerDependencies": {
|
|
97
|
+
"@nano-app/backend": ">=0.11.0"
|
|
98
|
+
},
|
|
99
|
+
"license": "MIT"
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Export the `createPlugin` factory as the package entry. The consumer installs both packages and passes the factory to `plugins`.
|
|
104
|
+
|
|
105
|
+
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.
|
|
106
|
+
|
|
107
|
+
### Database
|
|
108
|
+
|
|
109
|
+
Optional. Set `database: { enabled: true, schemaPath }` on the plugin config. The schema must be PostgreSQL. Schemas starting with `nano_` are reserved for the official plugins: a schema inside the `@nano-app/plugins` package declares only `nano_*` schemas, and every other schema declares none.
|
|
110
|
+
|
|
111
|
+
At startup nano-app generates the plugin's client in `.nano-app/prisma-clients/<name>` (again only when the schema changed) and checks that every model can be read.
|
|
112
|
+
|
|
113
|
+
- **A plugin of yours, or from another package:** its tables are applied with Prisma by whoever installs it, like the app's schema.
|
|
114
|
+
- **An official plugin:** nano-app also migrates it, so the consumer runs nothing. Its schema ships in `build/<name>/schema.prisma` with a `migrations/` folder next to it. At startup `prisma migrate deploy` applies the pending ones to the plugin's first `nano_*` schema, where its history (`_prisma_migrations`) lives apart from the app's. Each migration runs once, in a transaction, one instance at a time.
|
|
115
|
+
|
|
116
|
+
#### Migrations of an official plugin
|
|
117
|
+
|
|
118
|
+
- Every schema change ships its own `migrations/<timestamp>_<name>/migration.sql`, reviewed like code. A published migration is never edited.
|
|
119
|
+
- Migrations only add: tables, nullable columns or columns with a default, indexes. Dropping or renaming takes two releases: stop using it first, remove it later.
|
|
120
|
+
- The database user of the consumer needs to create tables in the plugin's `nano_*` schema.
|
|
121
|
+
|
|
122
|
+
Handlers and callbacks receive that client as `params.db`. Type it with `createRoute<PrismaClient>`, passing your generated `PrismaClient`.
|
|
123
|
+
|
|
124
|
+
### What belongs in this repository
|
|
125
|
+
|
|
126
|
+
Pull requests to `backend/`, `core/`, `plugins/`, `frontend/` and `components/` are welcome. A pull request that adds `plugins/<name>` is not, until the maintainers ask for that plugin. Official plugins live in `plugins/<name>/`, are exported as `import <name> from '@nano-app/plugins/<name>'`, and `@nano-app/plugins` has its own version.
|
package/build/health/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
//#region health/index.d.ts
|
|
2
1
|
/** Health check: `GET /health` answers `{ status: "ok" }` while the server is up. */
|
|
3
2
|
declare const _default: (options?: {
|
|
4
3
|
basePath?: string;
|
|
5
4
|
} | undefined) => import("@nano-app/backend").PluginConfig<{
|
|
6
5
|
basePath?: string;
|
|
7
6
|
}>;
|
|
8
|
-
//#endregion
|
|
9
7
|
export { _default as default };
|
package/build/health/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dirname, resolve } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { createPlugin } from "@nano-app/backend";
|
|
4
|
-
|
|
4
|
+
// health/index.ts
|
|
5
5
|
/** Health check: `GET /health` answers `{ status: "ok" }` while the server is up. */
|
|
6
6
|
var health_default = createPlugin((options) => ({
|
|
7
7
|
name: "health",
|
|
@@ -9,5 +9,4 @@ var health_default = createPlugin((options) => ({
|
|
|
9
9
|
stage: "before",
|
|
10
10
|
routesDir: resolve(dirname(fileURLToPath(import.meta.url)), "routes")
|
|
11
11
|
}));
|
|
12
|
-
//#endregion
|
|
13
12
|
export { health_default as default };
|
|
@@ -1,9 +1,5 @@
|
|
|
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 () => ({
|
|
5
|
-
success: true,
|
|
6
|
-
result: { status: "ok" }
|
|
7
|
-
}) });
|
|
8
|
-
//#endregion
|
|
4
|
+
var index_route_default = createRoute({ GET: async () => ({ result: { status: "ok" } }) });
|
|
9
5
|
export { index_route_default as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nano-app/plugins",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Official plugins for @nano-app/backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"@nano-app/backend": "workspace:*",
|
|
44
44
|
"@prisma/adapter-pg": "^7.10.1",
|
|
45
45
|
"@prisma/client": "^7.10.1",
|
|
46
|
-
"@types/node": "^26.6.
|
|
46
|
+
"@types/node": "^26.6.6",
|
|
47
47
|
"@types/pg": "^8.23.1",
|
|
48
48
|
"glob": "^13.0.6",
|
|
49
49
|
"pg": "^8.23.1",
|
|
50
50
|
"prisma": "^7.10.1",
|
|
51
|
-
"tsdown": "^0.23.
|
|
51
|
+
"tsdown": "^0.23.4",
|
|
52
52
|
"tsx": "^4.23.15",
|
|
53
53
|
"typescript": "^7.0.2"
|
|
54
54
|
}
|