@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 CHANGED
@@ -15,13 +15,13 @@ import health from '@nano-app/plugins/health';
15
15
  createNanoApp({ plugins: [health()] });
16
16
  ```
17
17
 
18
- ## Plugins
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
- ## Layout
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
- The plugin contract: [PLUGINS.md](https://github.com/Nano-Nathan/nano-app/blob/main/PLUGINS.md).
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.
@@ -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 };
@@ -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
- //#region health/index.ts
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
- //#region health/routes/index.route.ts
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.0",
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.5",
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.1",
51
+ "tsdown": "^0.23.4",
52
52
  "tsx": "^4.23.15",
53
53
  "typescript": "^7.0.2"
54
54
  }