nuxt-feathers-zod 0.1.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 +283 -0
- package/dist/module.d.mts +17 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +124 -0
- package/dist/runtime/adapters/ofetch.d.ts +5 -0
- package/dist/runtime/adapters/ofetch.js +18 -0
- package/dist/runtime/composables/feathers.d.ts +5 -0
- package/dist/runtime/composables/feathers.js +9 -0
- package/dist/runtime/composables/pinia.d.ts +1 -0
- package/dist/runtime/composables/pinia.js +11 -0
- package/dist/runtime/errors.d.ts +3 -0
- package/dist/runtime/errors.js +5 -0
- package/dist/runtime/options/authentication/client.d.ts +13 -0
- package/dist/runtime/options/authentication/client.js +12 -0
- package/dist/runtime/options/authentication/index.d.ts +42 -0
- package/dist/runtime/options/authentication/index.js +71 -0
- package/dist/runtime/options/authentication/jwt-types.d.ts +29 -0
- package/dist/runtime/options/authentication/jwt-types.js +0 -0
- package/dist/runtime/options/authentication/jwt.d.ts +7 -0
- package/dist/runtime/options/authentication/jwt.js +19 -0
- package/dist/runtime/options/authentication/local.d.ts +8 -0
- package/dist/runtime/options/authentication/local.js +8 -0
- package/dist/runtime/options/client/index.d.ts +14 -0
- package/dist/runtime/options/client/index.js +33 -0
- package/dist/runtime/options/client/pinia.d.ts +14 -0
- package/dist/runtime/options/client/pinia.js +22 -0
- package/dist/runtime/options/database/index.d.ts +6 -0
- package/dist/runtime/options/database/index.js +8 -0
- package/dist/runtime/options/database/mongodb.d.ts +12 -0
- package/dist/runtime/options/database/mongodb.js +3 -0
- package/dist/runtime/options/index.d.ts +44 -0
- package/dist/runtime/options/index.js +63 -0
- package/dist/runtime/options/plugins.d.ts +20 -0
- package/dist/runtime/options/plugins.js +69 -0
- package/dist/runtime/options/server.d.ts +7 -0
- package/dist/runtime/options/server.js +11 -0
- package/dist/runtime/options/services.d.ts +6 -0
- package/dist/runtime/options/services.js +13 -0
- package/dist/runtime/options/transports/index.d.ts +23 -0
- package/dist/runtime/options/transports/index.js +14 -0
- package/dist/runtime/options/transports/rest.d.ts +9 -0
- package/dist/runtime/options/transports/rest.js +22 -0
- package/dist/runtime/options/transports/utils.d.ts +1 -0
- package/dist/runtime/options/transports/utils.js +7 -0
- package/dist/runtime/options/transports/websocket.d.ts +8 -0
- package/dist/runtime/options/transports/websocket.js +17 -0
- package/dist/runtime/options/utils.d.ts +11 -0
- package/dist/runtime/options/utils.js +22 -0
- package/dist/runtime/options/validator.d.ts +13 -0
- package/dist/runtime/options/validator.js +29 -0
- package/dist/runtime/plugins/feathers-auth.d.ts +11 -0
- package/dist/runtime/plugins/feathers-auth.js +13 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/services.d.ts +4 -0
- package/dist/runtime/services.js +14 -0
- package/dist/runtime/stores/auth.d.ts +28 -0
- package/dist/runtime/stores/auth.js +47 -0
- package/dist/runtime/templates/client/authentication.d.ts +2 -0
- package/dist/runtime/templates/client/authentication.js +28 -0
- package/dist/runtime/templates/client/client.d.ts +2 -0
- package/dist/runtime/templates/client/client.js +50 -0
- package/dist/runtime/templates/client/connection.d.ts +3 -0
- package/dist/runtime/templates/client/connection.js +39 -0
- package/dist/runtime/templates/client/index.d.ts +4 -0
- package/dist/runtime/templates/client/index.js +33 -0
- package/dist/runtime/templates/client/plugin.d.ts +2 -0
- package/dist/runtime/templates/client/plugin.js +81 -0
- package/dist/runtime/templates/server/authentication.d.ts +2 -0
- package/dist/runtime/templates/server/authentication.js +32 -0
- package/dist/runtime/templates/server/index.d.ts +3 -0
- package/dist/runtime/templates/server/index.js +33 -0
- package/dist/runtime/templates/server/mongodb.d.ts +2 -0
- package/dist/runtime/templates/server/mongodb.js +26 -0
- package/dist/runtime/templates/server/plugin.d.ts +2 -0
- package/dist/runtime/templates/server/plugin.js +110 -0
- package/dist/runtime/templates/server/server.d.ts +2 -0
- package/dist/runtime/templates/server/server.js +61 -0
- package/dist/runtime/templates/server/validators.d.ts +2 -0
- package/dist/runtime/templates/server/validators.js +30 -0
- package/dist/runtime/templates/types.d.ts +6 -0
- package/dist/runtime/templates/types.js +0 -0
- package/dist/runtime/templates/utils.d.ts +4 -0
- package/dist/runtime/templates/utils.js +6 -0
- package/dist/runtime/zod/format.d.ts +10 -0
- package/dist/runtime/zod/format.js +7 -0
- package/dist/runtime/zod/index.d.ts +4 -0
- package/dist/runtime/zod/index.js +4 -0
- package/dist/runtime/zod/objectId.d.ts +9 -0
- package/dist/runtime/zod/objectId.js +17 -0
- package/dist/runtime/zod/query.d.ts +43 -0
- package/dist/runtime/zod/query.js +75 -0
- package/dist/runtime/zod/validators.d.ts +17 -0
- package/dist/runtime/zod/validators.js +46 -0
- package/dist/types.d.mts +7 -0
- package/package.json +111 -0
package/README.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# nuxt-feathers-zod
|
|
2
|
+
|
|
3
|
+
Nuxt 4 module that embeds a **FeathersJS v5 (Dove)** server into **Nitro** and generates a **typed Feathers client** for your Nuxt app, with **Zod-first validation**.
|
|
4
|
+
It's using and inspired from project **[https://github.com/GaborTorma/feathers-nitro-adapter.git]()**
|
|
5
|
+
|
|
6
|
+
This repository ships a ready-to-run playground (`nuxi dev playground`) and a module you can install in your own Nuxt application.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- FeathersJS v5 server running inside Nitro (no separate server process required)
|
|
11
|
+
- REST transport (Koa or Express) and optional Socket.io (websocket)
|
|
12
|
+
- Zod schemas for data + query validation (server-side)
|
|
13
|
+
- Optional client integration with Pinia stores (via `feathers-pinia`)
|
|
14
|
+
- Generated types for services (`ServiceTypes`) and shared client service registrations (`*.shared.ts`)
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
- Node.js 18+ (or Bun)
|
|
19
|
+
- Nuxt 4
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
In your Nuxt application:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Bun
|
|
27
|
+
bun add nuxt-feathers-zod feathers-pinia
|
|
28
|
+
|
|
29
|
+
# npm
|
|
30
|
+
npm i nuxt-feathers-zod feathers-pinia
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then enable the module:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// nuxt.config.ts
|
|
37
|
+
export default defineNuxtConfig({
|
|
38
|
+
modules: ['nuxt-feathers-zod'],
|
|
39
|
+
})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Minimal configuration
|
|
43
|
+
|
|
44
|
+
Below is a minimal configuration that:
|
|
45
|
+
|
|
46
|
+
- exposes Feathers REST under `/feathers` (default)
|
|
47
|
+
- enables websocket (`/socket.io`)
|
|
48
|
+
- enables authentication (local + jwt)
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// nuxt.config.ts
|
|
52
|
+
export default defineNuxtConfig({
|
|
53
|
+
modules: ['nuxt-feathers-zod'],
|
|
54
|
+
feathers: {
|
|
55
|
+
servicesDirs: ['services'],
|
|
56
|
+
transports: {
|
|
57
|
+
rest: { path: '/feathers', framework: 'koa' },
|
|
58
|
+
websocket: { path: '/socket.io' },
|
|
59
|
+
},
|
|
60
|
+
database: {
|
|
61
|
+
mongo: {
|
|
62
|
+
url: process.env.MONGODB_URL || 'mongodb://127.0.0.1:27017/nuxt-feathers-zod',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
client: {
|
|
66
|
+
pinia: {
|
|
67
|
+
// where Pinia stores will be generated/loaded from (if you use them)
|
|
68
|
+
storesDirs: ['stores'],
|
|
69
|
+
// default id field for services
|
|
70
|
+
idField: 'id',
|
|
71
|
+
// per-service overrides
|
|
72
|
+
services: {
|
|
73
|
+
mongos: { idField: '_id' },
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
auth: {
|
|
78
|
+
entity: 'user',
|
|
79
|
+
service: 'users',
|
|
80
|
+
authStrategies: ['local', 'jwt'],
|
|
81
|
+
local: { usernameField: 'userId', passwordField: 'password' },
|
|
82
|
+
// IMPORTANT: always set in production via env
|
|
83
|
+
secret: process.env.AUTH_SECRET || 'dev-secret-change-me',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Transport examples
|
|
90
|
+
|
|
91
|
+
### REST with Koa (default)
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
export default defineNuxtConfig({
|
|
95
|
+
modules: ['nuxt-feathers-zod'],
|
|
96
|
+
feathers: {
|
|
97
|
+
transports: { rest: { framework: 'koa' } },
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### REST with Express
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
export default defineNuxtConfig({
|
|
106
|
+
modules: ['nuxt-feathers-zod'],
|
|
107
|
+
feathers: {
|
|
108
|
+
transports: { rest: { framework: 'express' } },
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If you use Express REST, ensure your project includes the Express transport dependencies (Feathers server side):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
bun add @feathersjs/express express
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### WebSocket with Socket.io
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
export default defineNuxtConfig({
|
|
123
|
+
modules: ['nuxt-feathers-zod'],
|
|
124
|
+
feathers: {
|
|
125
|
+
transports: {
|
|
126
|
+
websocket: { path: '/socket.io', connectTimeout: 45_000 },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
When both REST and websocket are enabled, the generated client typically uses REST on SSR and websocket in the browser.
|
|
133
|
+
|
|
134
|
+
## Service structure
|
|
135
|
+
|
|
136
|
+
Services live in `services/**` and follow this convention:
|
|
137
|
+
|
|
138
|
+
- `services/<name>/<name>.class.ts` – Feathers service class (MongoDB, memory, custom, ...)
|
|
139
|
+
- `services/<name>/<name>.schema.ts` – Zod schemas + Feathers resolvers
|
|
140
|
+
- `services/<name>/<name>.ts` – service registration + hooks
|
|
141
|
+
- `services/<name>/<name>.shared.ts` – client registration (used by generator)
|
|
142
|
+
|
|
143
|
+
## Using the generated client in your app
|
|
144
|
+
|
|
145
|
+
The module injects a typed Feathers client as `nuxtApp.$api`.
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
// example: in a component or composable
|
|
149
|
+
const { $api } = useNuxtApp()
|
|
150
|
+
|
|
151
|
+
// typed service access (if you generated types)
|
|
152
|
+
const users = $api.service('users')
|
|
153
|
+
const list = await users.find({ query: {} })
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Authentication: testing with curl
|
|
157
|
+
|
|
158
|
+
Create a user:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
curl -i -X POST "http://localhost:3000/feathers/users" \
|
|
162
|
+
-H "Content-Type: application/json" \
|
|
163
|
+
-d '{"userId":"demo","password":"demo123"}'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Authenticate:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
curl -i -X POST "http://localhost:3000/feathers/authentication" \
|
|
170
|
+
-H "Content-Type: application/json" \
|
|
171
|
+
-d '{"strategy":"local","userId":"demo","password":"demo123"}'
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Use the JWT to call a protected endpoint:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
curl -i "http://localhost:3000/feathers/users" \
|
|
178
|
+
-H "Authorization: Bearer <ACCESS_TOKEN>"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Playground
|
|
182
|
+
|
|
183
|
+
Run the playground:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
bun install
|
|
187
|
+
bun run dev
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Open:
|
|
191
|
+
|
|
192
|
+
- Nuxt app: `http://localhost:3000/`
|
|
193
|
+
- Feathers REST: `http://localhost:3000/feathers/*`
|
|
194
|
+
|
|
195
|
+
### End-to-end smoke test (REST + auth)
|
|
196
|
+
|
|
197
|
+
Once the dev server is up, run the following commands in a terminal.
|
|
198
|
+
|
|
199
|
+
Create a user:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
curl -i -X POST "http://localhost:3000/feathers/users" \
|
|
203
|
+
-H "Content-Type: application/json" \
|
|
204
|
+
-d '{"userId":"demo","password":"demo123"}'
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Authenticate (local strategy):
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
curl -i -X POST "http://localhost:3000/feathers/authentication" \
|
|
211
|
+
-H "Content-Type: application/json" \
|
|
212
|
+
-d '{"strategy":"local","userId":"demo","password":"demo123"}'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Copy the `accessToken` from the JSON response, then call a protected route:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
curl -i "http://localhost:3000/feathers/users" \
|
|
219
|
+
-H "Authorization: Bearer <ACCESS_TOKEN>"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Expected:
|
|
223
|
+
|
|
224
|
+
- `POST /feathers/users` returns `201`
|
|
225
|
+
- `POST /feathers/authentication` returns `201` and an `accessToken`
|
|
226
|
+
- `GET /feathers/users` returns `200` when `Authorization: Bearer ...` is provided
|
|
227
|
+
|
|
228
|
+
### WebSocket smoke test (Socket.io)
|
|
229
|
+
|
|
230
|
+
If you enabled `transports.websocket`, you can test websocket connectivity with a tiny script.
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# from the repo root
|
|
234
|
+
bun -e "
|
|
235
|
+
import { io } from 'socket.io-client'
|
|
236
|
+
const socket = io('http://localhost:3000', { path: '/socket.io', transports: ['websocket'] })
|
|
237
|
+
socket.on('connect', async () => {
|
|
238
|
+
console.log('connected', socket.id)
|
|
239
|
+
socket.disconnect()
|
|
240
|
+
process.exit(0)
|
|
241
|
+
})
|
|
242
|
+
socket.on('connect_error', (e) => {
|
|
243
|
+
console.error('connect_error', e?.message || e)
|
|
244
|
+
process.exit(1)
|
|
245
|
+
})
|
|
246
|
+
"
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
If you want to test authenticated websocket calls, use `@feathersjs/socketio-client` in a small script (see `playground/` for a browser-first example).
|
|
250
|
+
|
|
251
|
+
## Publishing to npm
|
|
252
|
+
|
|
253
|
+
This repository is a Nuxt module. The published package should only contain the compiled output (see `files: ["dist"]` in `package.json`).
|
|
254
|
+
|
|
255
|
+
Recommended flow:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# 1) install
|
|
259
|
+
bun install
|
|
260
|
+
|
|
261
|
+
# 2) run unit + type tests
|
|
262
|
+
bun run test:types
|
|
263
|
+
bun run test
|
|
264
|
+
|
|
265
|
+
# 3) build the module (produces ./dist)
|
|
266
|
+
bun run prepare
|
|
267
|
+
|
|
268
|
+
# 4) publish (from the repo root)
|
|
269
|
+
npm publish --access public
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Notes:
|
|
273
|
+
|
|
274
|
+
- Keep Feathers packages aligned (single version across the workspace). This repo uses `overrides` for that purpose.
|
|
275
|
+
- Do not publish `playground/` build artifacts (`playground/.nuxt`, `playground/node_modules`).
|
|
276
|
+
|
|
277
|
+
## Notes about SSR and Pinia auth bootstrap
|
|
278
|
+
|
|
279
|
+
The runtime auth bootstrap (`src/runtime/plugins/feathers-auth.ts`) re-authenticates **client-side only** to avoid SSR startup failures when the Feathers client is not yet injected.
|
|
280
|
+
|
|
281
|
+
## License
|
|
282
|
+
|
|
283
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { ModuleConfig, FeathersRuntimeConfig, FeathersPublicRuntimeConfig, ModuleOptions } from '../dist/runtime/options/index.js';
|
|
3
|
+
|
|
4
|
+
declare module '@nuxt/schema' {
|
|
5
|
+
interface NuxtConfig {
|
|
6
|
+
feathers?: ModuleConfig;
|
|
7
|
+
}
|
|
8
|
+
interface RuntimeConfig {
|
|
9
|
+
_feathers: FeathersRuntimeConfig;
|
|
10
|
+
}
|
|
11
|
+
interface PublicRuntimeConfig {
|
|
12
|
+
_feathers: FeathersPublicRuntimeConfig;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
16
|
+
|
|
17
|
+
export { _default as default };
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, addImportsDir, addTemplate, addServerPlugin, addImports, addPlugin, hasNuxtModule, installModule } from '@nuxt/kit';
|
|
2
|
+
import { consola } from 'consola';
|
|
3
|
+
import defu from 'defu';
|
|
4
|
+
import { resolveOptions, resolveRuntimeConfig, resolvePublicRuntimeConfig } from '../dist/runtime/options/index.js';
|
|
5
|
+
import { serverDefaults } from '../dist/runtime/options/server.js';
|
|
6
|
+
import { getServicesImports, addServicesImports } from '../dist/runtime/services.js';
|
|
7
|
+
import { getClientTemplates } from '../dist/runtime/templates/client/index.js';
|
|
8
|
+
import { getServerTemplates } from '../dist/runtime/templates/server/index.js';
|
|
9
|
+
|
|
10
|
+
function setAliases(options, nuxt) {
|
|
11
|
+
const resolver = createResolver(import.meta.url);
|
|
12
|
+
const aliases = {
|
|
13
|
+
"nuxt-feathers-zod/server": resolver.resolve(options.templateDir, "server/server"),
|
|
14
|
+
"nuxt-feathers-zod/validators": resolver.resolve("runtime/zod/validators"),
|
|
15
|
+
"nuxt-feathers-zod/query": resolver.resolve("runtime/zod/query"),
|
|
16
|
+
"nuxt-feathers-zod/zod": resolver.resolve("runtime/zod/index"),
|
|
17
|
+
"nuxt-feathers-zod/options": resolver.resolve("runtime/options")
|
|
18
|
+
};
|
|
19
|
+
nuxt.options.alias = defu(nuxt.options.alias, aliases);
|
|
20
|
+
if (options.client)
|
|
21
|
+
nuxt.options.alias["nuxt-feathers-zod/client"] = resolver.resolve(options.templateDir, "client/client");
|
|
22
|
+
nuxt.hook("nitro:config", async (nitroConfig) => {
|
|
23
|
+
nitroConfig.alias = defu(nitroConfig.alias, aliases);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function setTsIncludes(options, nuxt) {
|
|
27
|
+
const resolver = createResolver(import.meta.url);
|
|
28
|
+
const servicesDirs = options.servicesDirs.map((dir) => resolver.resolve(dir, "**/*.ts"));
|
|
29
|
+
nuxt.hook("prepare:types", async ({ tsConfig }) => {
|
|
30
|
+
tsConfig.include?.push(...servicesDirs);
|
|
31
|
+
});
|
|
32
|
+
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
33
|
+
nitroConfig.typescript?.tsConfig?.include?.push(...servicesDirs);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async function loadPinia(client) {
|
|
37
|
+
const storesDirs = client.pinia?.storesDirs;
|
|
38
|
+
if (storesDirs?.length) {
|
|
39
|
+
if (hasNuxtModule("@pinia/nuxt"))
|
|
40
|
+
return consola.warn("Pinia is already loaded, skipping your configuration");
|
|
41
|
+
await installModule("@pinia/nuxt", { storesDirs });
|
|
42
|
+
}
|
|
43
|
+
if (!hasNuxtModule("@pinia/nuxt"))
|
|
44
|
+
await installModule("@pinia/nuxt");
|
|
45
|
+
}
|
|
46
|
+
const module$1 = defineNuxtModule({
|
|
47
|
+
meta: {
|
|
48
|
+
name: "nuxt-feathers-zod",
|
|
49
|
+
configKey: "feathers",
|
|
50
|
+
compatibility: {
|
|
51
|
+
nuxt: "^4.0.0"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
// Default configuration options of the Nuxt module
|
|
55
|
+
defaults: {
|
|
56
|
+
transports: {
|
|
57
|
+
websocket: true
|
|
58
|
+
},
|
|
59
|
+
server: serverDefaults,
|
|
60
|
+
client: true,
|
|
61
|
+
servicesDirs: [],
|
|
62
|
+
validator: {
|
|
63
|
+
formats: [],
|
|
64
|
+
extendDefaults: true
|
|
65
|
+
},
|
|
66
|
+
loadFeathersConfig: false,
|
|
67
|
+
auth: true
|
|
68
|
+
},
|
|
69
|
+
async setup(options, nuxt) {
|
|
70
|
+
const resolver = createResolver(import.meta.url);
|
|
71
|
+
const resolvedOptions = await resolveOptions(options, nuxt);
|
|
72
|
+
nuxt.options.runtimeConfig._feathers = resolveRuntimeConfig(resolvedOptions);
|
|
73
|
+
nuxt.options.runtimeConfig.public._feathers = resolvePublicRuntimeConfig(resolvedOptions);
|
|
74
|
+
const servicesImports = await getServicesImports(resolvedOptions.servicesDirs);
|
|
75
|
+
await addServicesImports(servicesImports);
|
|
76
|
+
setAliases(resolvedOptions, nuxt);
|
|
77
|
+
setTsIncludes(resolvedOptions, nuxt);
|
|
78
|
+
if (resolvedOptions.transports.websocket) {
|
|
79
|
+
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
80
|
+
nitroConfig.experimental = defu(nitroConfig.experimental, { websocket: true });
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
84
|
+
let serverPluginDst;
|
|
85
|
+
for (const serverTemplate of getServerTemplates(resolvedOptions)) {
|
|
86
|
+
const tpl = addTemplate({ ...serverTemplate, options: resolvedOptions });
|
|
87
|
+
if (serverTemplate.filename?.endsWith("server/plugin.ts") || serverTemplate.filename?.endsWith("server/plugin"))
|
|
88
|
+
serverPluginDst = tpl.dst;
|
|
89
|
+
}
|
|
90
|
+
addServerPlugin(serverPluginDst ?? resolver.resolve(resolvedOptions.templateDir, "server/plugin.ts"));
|
|
91
|
+
if (resolvedOptions.client) {
|
|
92
|
+
const clientOptions = resolvedOptions.client;
|
|
93
|
+
if (clientOptions.pinia) {
|
|
94
|
+
await loadPinia(clientOptions);
|
|
95
|
+
nuxt.hook("vite:extendConfig", (config) => {
|
|
96
|
+
config.optimizeDeps?.include?.push("feathers-pinia");
|
|
97
|
+
});
|
|
98
|
+
if (resolvedOptions.auth) {
|
|
99
|
+
addImports({ from: resolver.resolve("./runtime/stores/auth"), name: "useAuthStore" });
|
|
100
|
+
addPlugin({ order: 1, src: resolver.resolve("./runtime/plugins/feathers-auth") });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
let clientPluginDst;
|
|
104
|
+
for (const clientTemplate of getClientTemplates(resolvedOptions, resolver)) {
|
|
105
|
+
const tpl = addTemplate({ ...clientTemplate, options: resolvedOptions });
|
|
106
|
+
if (clientTemplate.filename?.endsWith("client/plugin.ts") || clientTemplate.filename?.endsWith("client/plugin"))
|
|
107
|
+
clientPluginDst = tpl.dst;
|
|
108
|
+
}
|
|
109
|
+
addPlugin({ order: 0, src: clientPluginDst ?? resolver.resolve(resolvedOptions.templateDir, "client/plugin.ts"), mode: "client" });
|
|
110
|
+
}
|
|
111
|
+
nuxt.hook("mcp:setup", ({ mcp }) => {
|
|
112
|
+
mcp.tool("get-feathers-config", "Get the Feathers config", {}, async () => {
|
|
113
|
+
return {
|
|
114
|
+
content: [{
|
|
115
|
+
type: "text",
|
|
116
|
+
text: JSON.stringify(resolvedOptions, null, 2)
|
|
117
|
+
}]
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export { module$1 as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FetchClient } from "@feathersjs/rest-client";
|
|
2
|
+
export class OFetch extends FetchClient {
|
|
3
|
+
async request(options, params) {
|
|
4
|
+
const fetchOptions = Object.assign({}, options, params.connection);
|
|
5
|
+
fetchOptions.headers = Object.assign({ Accept: "application/json" }, this.options.headers, fetchOptions.headers);
|
|
6
|
+
if (options.body)
|
|
7
|
+
fetchOptions.body = options.body;
|
|
8
|
+
try {
|
|
9
|
+
const response = await this.connection.raw(options.url, fetchOptions);
|
|
10
|
+
const { _data, status } = response;
|
|
11
|
+
if (status === 204)
|
|
12
|
+
return null;
|
|
13
|
+
return _data;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
throw error.data;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ServiceTypes } from 'nuxt-feathers-zod/client';
|
|
2
|
+
export declare function useFeathers(): {
|
|
3
|
+
api: import("feathers-pinia").FeathersPiniaClient<import("nuxt-feathers-zod/client").ClientApplication>;
|
|
4
|
+
};
|
|
5
|
+
export declare function useService<L extends keyof ServiceTypes>(path: L): import("@feathersjs/feathers").FeathersService<import("feathers-pinia").FeathersPiniaClient<import("nuxt-feathers-zod/client").ClientApplication>, import("feathers-pinia").CreatePiniaServiceTypes<import("nuxt-feathers-zod/client").ClientApplication>[L]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createPiniaClient, defineGetters, defineSetters, defineValues, useAuth, useBackup, useDataStore, useInstanceDefaults, useServiceInstance, } from 'feathers-pinia';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthStrategies } from '.';
|
|
2
|
+
export interface AuthClientOptions {
|
|
3
|
+
header?: string;
|
|
4
|
+
scheme?: string;
|
|
5
|
+
storageKey?: string;
|
|
6
|
+
locationKey?: string;
|
|
7
|
+
locationErrorKey?: string;
|
|
8
|
+
jwtStrategy?: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
}
|
|
11
|
+
export type ResolvedAuthClientOptions = AuthClientOptions;
|
|
12
|
+
export declare function getAuthClientDefaults(authStrategies: AuthStrategies): ResolvedAuthClientOptions;
|
|
13
|
+
export declare function resolveAuthClientOptions(authClient: AuthClientOptions | undefined, authStrategies: AuthStrategies): ResolvedAuthClientOptions;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import defu from "defu";
|
|
2
|
+
import { getAuthClientJwtDefaults } from "./jwt.js";
|
|
3
|
+
export function getAuthClientDefaults(authStrategies) {
|
|
4
|
+
if (!authStrategies.includes("jwt"))
|
|
5
|
+
return {};
|
|
6
|
+
return getAuthClientJwtDefaults();
|
|
7
|
+
}
|
|
8
|
+
export function resolveAuthClientOptions(authClient, authStrategies) {
|
|
9
|
+
const defaultAuthClient = getAuthClientDefaults(authStrategies);
|
|
10
|
+
const resolvedAuthClient = defu(authClient || {}, defaultAuthClient);
|
|
11
|
+
return resolvedAuthClient;
|
|
12
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Import } from 'unimport';
|
|
2
|
+
import type { ModuleOptions } from '..';
|
|
3
|
+
import type { AuthClientOptions } from './client.js';
|
|
4
|
+
import type { AuthJwtOptions } from './jwt.js';
|
|
5
|
+
import type { AuthLocalOptions } from './local.js';
|
|
6
|
+
export type AuthStrategy = 'jwt' | 'local';
|
|
7
|
+
export type AuthStrategies = [AuthStrategy] | [AuthStrategy, AuthStrategy];
|
|
8
|
+
export interface StaticAuthOptions {
|
|
9
|
+
service: string;
|
|
10
|
+
entity: string;
|
|
11
|
+
entityClass: string;
|
|
12
|
+
}
|
|
13
|
+
export interface DefaultAuthOptions extends StaticAuthOptions {
|
|
14
|
+
authStrategies: AuthStrategies;
|
|
15
|
+
secret: string;
|
|
16
|
+
entityImport?: Import;
|
|
17
|
+
}
|
|
18
|
+
export interface AdditionalAuthOptions {
|
|
19
|
+
jwtOptions?: AuthJwtOptions;
|
|
20
|
+
local?: AuthLocalOptions;
|
|
21
|
+
client?: AuthClientOptions;
|
|
22
|
+
}
|
|
23
|
+
export type AuthOptions = Partial<DefaultAuthOptions> & AdditionalAuthOptions;
|
|
24
|
+
export interface ResolvedAuthOptions extends DefaultAuthOptions, AdditionalAuthOptions {
|
|
25
|
+
entityImport: Import;
|
|
26
|
+
}
|
|
27
|
+
export type ResolvedAuthOptionsOrDisabled = ResolvedAuthOptions | false;
|
|
28
|
+
export type ResolvedAuthOptionsWithOutEntityImport = Omit<ResolvedAuthOptions, 'entityImport'>;
|
|
29
|
+
export interface PublicAuthOptions {
|
|
30
|
+
authStrategies: AuthStrategies;
|
|
31
|
+
servicePath: string;
|
|
32
|
+
entityKey: string;
|
|
33
|
+
entityClass: string;
|
|
34
|
+
client: AuthClientOptions;
|
|
35
|
+
}
|
|
36
|
+
export declare const authStaticDefaults: StaticAuthOptions;
|
|
37
|
+
export declare function getAuthStaticDefaults(): StaticAuthOptions;
|
|
38
|
+
export declare const defaultAuthStrategies: AuthStrategies;
|
|
39
|
+
export declare function getDefaultAuthStrategies(): AuthStrategies;
|
|
40
|
+
export declare function getAuthDefaults(appDir: string, authStrategies?: AuthStrategies): ResolvedAuthOptionsWithOutEntityImport;
|
|
41
|
+
export declare const authClientDefaultOptions: AuthClientOptions;
|
|
42
|
+
export declare function resolveAuthOptions(auth: ModuleOptions['auth'], client: boolean, servicesImports: Import[], appDir: string): ResolvedAuthOptionsOrDisabled;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { capitalCase } from "change-case";
|
|
2
|
+
import defu from "defu";
|
|
3
|
+
import { klona } from "klona";
|
|
4
|
+
import { digest } from "ohash";
|
|
5
|
+
import { NuxtFeathersError } from "../../errors.js";
|
|
6
|
+
import { resolveAuthClientOptions } from "./client.js";
|
|
7
|
+
import { getAuthJwtDefaults } from "./jwt.js";
|
|
8
|
+
import { getAuthLocalDefaults } from "./local.js";
|
|
9
|
+
export const authStaticDefaults = {
|
|
10
|
+
entity: "user",
|
|
11
|
+
entityClass: "User",
|
|
12
|
+
service: "users"
|
|
13
|
+
};
|
|
14
|
+
export function getAuthStaticDefaults() {
|
|
15
|
+
return klona(authStaticDefaults);
|
|
16
|
+
}
|
|
17
|
+
export const defaultAuthStrategies = ["local", "jwt"];
|
|
18
|
+
export function getDefaultAuthStrategies() {
|
|
19
|
+
return klona(defaultAuthStrategies);
|
|
20
|
+
}
|
|
21
|
+
export function getAuthDefaults(appDir, authStrategies) {
|
|
22
|
+
authStrategies ||= getDefaultAuthStrategies();
|
|
23
|
+
const authOptions = {
|
|
24
|
+
...getAuthStaticDefaults(),
|
|
25
|
+
secret: digest(appDir),
|
|
26
|
+
authStrategies
|
|
27
|
+
};
|
|
28
|
+
if (authStrategies.includes("jwt"))
|
|
29
|
+
authOptions.jwtOptions = getAuthJwtDefaults();
|
|
30
|
+
if (authStrategies.includes("local"))
|
|
31
|
+
authOptions.local = getAuthLocalDefaults();
|
|
32
|
+
return authOptions;
|
|
33
|
+
}
|
|
34
|
+
function getEntityClass(authOptions) {
|
|
35
|
+
return authOptions.entityClass || capitalCase(authOptions.entity || "") || authStaticDefaults.entityClass;
|
|
36
|
+
}
|
|
37
|
+
export const authClientDefaultOptions = {
|
|
38
|
+
storageKey: "feathers-jwt"
|
|
39
|
+
};
|
|
40
|
+
export function resolveAuthOptions(auth, client, servicesImports, appDir) {
|
|
41
|
+
if (auth === false)
|
|
42
|
+
return false;
|
|
43
|
+
let authOptions;
|
|
44
|
+
const authDefaults = getAuthDefaults(appDir, auth?.authStrategies);
|
|
45
|
+
if (auth === true) {
|
|
46
|
+
authOptions = authDefaults;
|
|
47
|
+
} else {
|
|
48
|
+
authOptions = defu(auth, authDefaults);
|
|
49
|
+
authOptions.authStrategies = authDefaults.authStrategies;
|
|
50
|
+
if (!authOptions.authStrategies?.includes("jwt"))
|
|
51
|
+
delete authOptions.jwtOptions;
|
|
52
|
+
if (!authOptions.authStrategies?.includes("local"))
|
|
53
|
+
delete authOptions.local;
|
|
54
|
+
}
|
|
55
|
+
if (client)
|
|
56
|
+
authOptions.client = resolveAuthClientOptions(authOptions.client, authOptions.authStrategies);
|
|
57
|
+
else
|
|
58
|
+
delete authOptions.client;
|
|
59
|
+
const entityClass = getEntityClass(auth);
|
|
60
|
+
const entityImport = servicesImports.find((i) => i.as === entityClass);
|
|
61
|
+
if (!entityImport)
|
|
62
|
+
throw new NuxtFeathersError(`Entity class ${entityClass} not found in services imports`);
|
|
63
|
+
entityImport.from = entityImport.from.replace(/\.ts$/, "");
|
|
64
|
+
const resolvedAuth = {
|
|
65
|
+
...authOptions,
|
|
66
|
+
entityClass,
|
|
67
|
+
entityImport
|
|
68
|
+
};
|
|
69
|
+
console.log(resolvedAuth);
|
|
70
|
+
return resolvedAuth;
|
|
71
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type Algorithm = 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512' | 'PS256' | 'PS384' | 'PS512' | 'none';
|
|
2
|
+
export interface JwtHeader {
|
|
3
|
+
'alg': string | Algorithm;
|
|
4
|
+
'typ'?: string | undefined;
|
|
5
|
+
'cty'?: string | undefined;
|
|
6
|
+
'crit'?: Array<string | Exclude<keyof JwtHeader, 'crit'>> | undefined;
|
|
7
|
+
'kid'?: string | undefined;
|
|
8
|
+
'jku'?: string | undefined;
|
|
9
|
+
'x5u'?: string | string[] | undefined;
|
|
10
|
+
'x5t#S256'?: string | undefined;
|
|
11
|
+
'x5t'?: string | undefined;
|
|
12
|
+
'x5c'?: string | string[] | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface SignOptions {
|
|
15
|
+
algorithm?: Algorithm | undefined;
|
|
16
|
+
keyid?: string | undefined;
|
|
17
|
+
expiresIn?: string | number;
|
|
18
|
+
notBefore?: string | number | undefined;
|
|
19
|
+
audience?: string | string[] | undefined;
|
|
20
|
+
subject?: string | undefined;
|
|
21
|
+
issuer?: string | undefined;
|
|
22
|
+
jwtid?: string | undefined;
|
|
23
|
+
mutatePayload?: boolean | undefined;
|
|
24
|
+
noTimestamp?: boolean | undefined;
|
|
25
|
+
header?: JwtHeader | undefined;
|
|
26
|
+
encoding?: string | undefined;
|
|
27
|
+
allowInsecureKeySizes?: boolean | undefined;
|
|
28
|
+
allowInvalidAsymmetricKeyTypes?: boolean | undefined;
|
|
29
|
+
}
|
|
File without changes
|