nuxt-auto-crud 1.4.0 → 1.6.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.
Files changed (36) hide show
  1. package/README.md +113 -84
  2. package/dist/module.d.mts +26 -22
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +52 -9
  5. package/dist/runtime/composables/useRelationDisplay.d.ts +12 -0
  6. package/dist/runtime/composables/useRelationDisplay.js +48 -0
  7. package/dist/runtime/composables/useResourceSchemas.d.ts +19 -0
  8. package/dist/runtime/composables/useResourceSchemas.js +17 -0
  9. package/dist/runtime/server/api/[model]/[id].patch.js +3 -0
  10. package/dist/runtime/server/api/[model]/index.get.js +2 -1
  11. package/dist/runtime/server/api/_relations.get.d.ts +2 -0
  12. package/dist/runtime/server/api/_relations.get.js +24 -0
  13. package/dist/runtime/server/api/_schema/[table].get.d.ts +10 -0
  14. package/dist/runtime/server/api/_schema/[table].get.js +32 -0
  15. package/dist/runtime/server/api/_schema/index.get.d.ts +2 -0
  16. package/dist/runtime/server/api/_schema/index.get.js +24 -0
  17. package/dist/runtime/server/plugins/seed.d.ts +2 -0
  18. package/dist/runtime/server/plugins/seed.js +36 -0
  19. package/dist/runtime/server/utils/auth.js +1 -1
  20. package/dist/runtime/server/utils/config.d.ts +2 -2
  21. package/dist/runtime/server/utils/modelMapper.js +16 -8
  22. package/dist/runtime/server/utils/schema.d.ts +20 -0
  23. package/dist/runtime/server/utils/schema.js +70 -0
  24. package/package.json +8 -5
  25. package/src/runtime/composables/useRelationDisplay.ts +67 -0
  26. package/src/runtime/composables/useResourceSchemas.ts +42 -0
  27. package/src/runtime/server/api/[model]/[id].patch.ts +5 -0
  28. package/src/runtime/server/api/[model]/index.get.ts +5 -2
  29. package/src/runtime/server/api/_relations.get.ts +31 -0
  30. package/src/runtime/server/api/_schema/[table].get.ts +41 -0
  31. package/src/runtime/server/api/_schema/index.get.ts +31 -0
  32. package/src/runtime/server/plugins/seed.ts +55 -0
  33. package/src/runtime/server/utils/auth.ts +1 -1
  34. package/src/runtime/server/utils/config.ts +3 -3
  35. package/src/runtime/server/utils/modelMapper.ts +25 -11
  36. package/src/runtime/server/utils/schema.ts +96 -0
package/README.md CHANGED
@@ -1,16 +1,24 @@
1
1
  # Nuxt Auto CRUD
2
2
 
3
-
4
-
5
3
  > **Note:** This module is currently in its alpha stage. However, you can use it to accelerate MVP development. It has not been tested thoroughly enough for production use; only happy-path testing is performed for each release.
6
4
 
7
5
  Auto-generate RESTful CRUD APIs for your **Nuxt** application based solely on your database schema. Minimal configuration required.
8
6
 
7
+ **Core Philosophy:**
8
+ The main objective of this module is to **expose CRUD APIs without the need for writing code**. You define your database schema, and `nuxt-auto-crud` handles the rest.
9
+
10
+ You don't need to setup an extra server or database to create an MVP of an application. The Nuxt (Nitro) server and SQLite can save you time and money.
11
+ And you don't need a separate Strapi or Supabase setup to automate your CRUD process. `nuxt-auto-crud` will help you with that and accelerate your development exponentially.
12
+
13
+ While we provide a playground with a CMS-like interface, this is primarily to demonstrate the capabilities. You are expected to build your own frontend application to consume these APIs.
14
+
9
15
  - [✨ Release Notes](/CHANGELOG.md)
10
16
  - [🎮 Try the Playground](/playground)
11
17
 
12
18
  ## 🚀 CRUD APIs are ready to use without code
13
19
 
20
+ Once installed, your database tables automatically become API endpoints:
21
+
14
22
  - `GET /api/:model` - List all records
15
23
  - `POST /api/:model` - Create a new record
16
24
  - `GET /api/:model/:id` - Get record by ID
@@ -19,7 +27,7 @@ Auto-generate RESTful CRUD APIs for your **Nuxt** application based solely on yo
19
27
 
20
28
  ## 📦 How to install
21
29
 
22
- ### New Project (Recommended)
30
+ ### 1. Fullstack Template (Recommended)
23
31
 
24
32
  Start a new project with everything pre-configured using our template:
25
33
 
@@ -31,24 +39,20 @@ bun db:generate
31
39
  bun run dev
32
40
  ```
33
41
 
34
- Detailed instructions can be found in [https://auto-crud.clifland.in/](https://auto-crud.clifland.in/)
35
-
36
- ### Add User
37
- Open Nuxt DevTools (bottom-middle icon) > `...` menu > **Database** icon to add users.
38
- > **Note:** If the users table doesn't appear, restart the server (`Ctrl + C` and `bun run dev`).
42
+ **Template Usage Modes:**
39
43
 
40
- That's it! You can now access the APIs:
44
+ 1. **Fullstack App**: The template includes the `nuxt-auto-crud` module, providing both the backend APIs and the frontend UI.
45
+ 2. **Frontend Only**: You can use the template just for the frontend. In this case, you don't need to install the module in the frontend app. Instead, you would install `nuxt-auto-crud` in a separate backend setup (e.g., another Nuxt project acting as the API).
41
46
 
42
- ### Test API
43
- Visit [http://localhost:3000/api/users](http://localhost:3000/api/users).
47
+ Detailed instructions can be found in [https://auto-crud.clifland.in/](https://auto-crud.clifland.in/)
44
48
 
45
- ### Existing Project
49
+ ### 2. Manual Setup (Existing Project)
46
50
 
47
51
  If you want to add `nuxt-auto-crud` to an existing project, follow these steps:
48
52
 
49
53
  > **Note:** These instructions assume you are using NuxtHub. If you are using a custom SQLite setup (e.g. better-sqlite3, Turso), please see [Custom Setup](./custom-setup.md).
50
54
 
51
- ### 1. Install dependencies
55
+ #### Install dependencies
52
56
 
53
57
  ```bash
54
58
  # Install module and required dependencies
@@ -60,7 +64,7 @@ bun add nuxt-auto-crud @nuxthub/core@latest drizzle-orm
60
64
  bun add --dev wrangler drizzle-kit
61
65
  ```
62
66
 
63
- ### 2. Configure Nuxt
67
+ #### Configure Nuxt
64
68
 
65
69
  Add the modules to your `nuxt.config.ts`:
66
70
 
@@ -75,11 +79,12 @@ export default defineNuxtConfig({
75
79
 
76
80
  autoCrud: {
77
81
  schemaPath: 'server/database/schema', // default value
82
+ auth: false, // Disable auth by default for easy testing
78
83
  },
79
84
  })
80
85
  ```
81
86
 
82
- ### 3. Configure Drizzle
87
+ #### Configure Drizzle
83
88
 
84
89
  Add the generation script to your `package.json`:
85
90
 
@@ -88,6 +93,7 @@ Add the generation script to your `package.json`:
88
93
  "scripts": {
89
94
  "db:generate": "drizzle-kit generate"
90
95
  }
96
+ // ...
91
97
  }
92
98
  ```
93
99
 
@@ -99,12 +105,12 @@ import { defineConfig } from 'drizzle-kit'
99
105
 
100
106
  export default defineConfig({
101
107
  dialect: 'sqlite',
102
- schema: './server/database/schema.ts',
108
+ schema: './server/database/schema/index.ts', // Point to your schema index file
103
109
  out: './server/database/migrations'
104
110
  })
105
111
  ```
106
112
 
107
- ### 4. Setup Database Connection
113
+ #### Setup Database Connection
108
114
 
109
115
  Create `server/utils/drizzle.ts` to export the database instance:
110
116
 
@@ -124,12 +130,12 @@ export function useDrizzle() {
124
130
  export type User = typeof schema.users.$inferSelect
125
131
  ```
126
132
 
127
- ### 5. Define your database schema
133
+ #### Define your database schema
128
134
 
129
- Create `server/database/schema.ts`:
135
+ Create your schema files in `server/database/schema/`. For example, `server/database/schema/users.ts`:
130
136
 
131
137
  ```typescript
132
- // server/database/schema.ts
138
+ // server/database/schema/users.ts
133
139
  import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
134
140
 
135
141
  export const users = sqliteTable('users', {
@@ -142,7 +148,9 @@ export const users = sqliteTable('users', {
142
148
  })
143
149
  ```
144
150
 
145
- ### 6. Run the project
151
+ > **Note:** The `organization.ts` and `cms.ts` files you might see in the playground are just examples and are commented out by default. You should implement a robust schema tailored to your production needs.
152
+
153
+ #### Run the project
146
154
 
147
155
  ```bash
148
156
  cd <project-name>
@@ -150,15 +158,86 @@ bun db:generate
150
158
  bun run dev
151
159
  ```
152
160
 
153
- That's it! 🎉 Your CRUD APIs are now available:
161
+ That's it! 🎉 Your CRUD APIs are now available at `/api/users`.
162
+
163
+ ### 3. Backend-only App (API Mode)
164
+
165
+ If you are using Nuxt as a backend for a separate client application (e.g., mobile app, SPA), you can use this module to quickly generate REST APIs.
166
+
167
+ In this case, you might handle authentication differently (e.g., validating tokens in middleware) or disable the built-in auth checks if you have a global auth middleware.
168
+
169
+ ```ts
170
+ export default defineNuxtConfig({
171
+ modules: ['nuxt-auto-crud'],
172
+ autoCrud: {
173
+ auth: false // APIs are public (or handled by your own middleware)
174
+ }
175
+ })
176
+ ```
177
+
178
+ ## 🔐 Authentication Configuration
154
179
 
155
- - `GET /api/users` - List all users
156
- - `POST /api/users` - Create a new user
157
- - `GET /api/users/:id` - Get user by ID
158
- - `PATCH /api/users/:id` - Update user
159
- - `DELETE /api/users/:id` - Delete user
180
+ The module supports `auth: false` by default, which exposes all LCRUD APIs. You can enable authentication and authorization as needed.
181
+
182
+ ### Session Auth (Default)
183
+
184
+ Requires `nuxt-auth-utils` and `nuxt-authorization`.
185
+
186
+ ```typescript
187
+ export default defineNuxtConfig({
188
+ autoCrud: {
189
+ auth: {
190
+ type: 'session',
191
+ authentication: true, // Enables requireUserSession() check
192
+ authorization: true // Enables authorize(model, action) check
193
+ }
194
+ }
195
+ })
196
+ ```
197
+
198
+ ### JWT Auth
199
+
200
+ Useful for backend-only apps.
201
+
202
+ ```typescript
203
+ export default defineNuxtConfig({
204
+ autoCrud: {
205
+ auth: {
206
+ type: 'jwt',
207
+ authentication: true,
208
+ jwtSecret: process.env.JWT_SECRET,
209
+ authorization: true
210
+ }
211
+ }
212
+ })
213
+ ```
160
214
 
161
- _(Same endpoints for all your tables!)_
215
+ ## 🛡️ Resource Configuration (RBAC)
216
+
217
+ You can define fine-grained access control and resource policies using `autocrud.config.ts` in your project root. This file is optional and useful when you need specific rules per resource.
218
+
219
+ ```typescript
220
+ // autocrud.config.ts
221
+ export default {
222
+ resources: {
223
+ users: {
224
+ // Access Control
225
+ auth: {
226
+ // Admin has full access
227
+ admin: true,
228
+ // Public (unauthenticated) users can only list and read
229
+ public: ['list', 'read'],
230
+ },
231
+ // Field Visibility
232
+ publicColumns: ['id', 'name', 'avatar'], // Only these columns are returned to public users
233
+ },
234
+ }
235
+ }
236
+ ```
237
+
238
+ ## ⚠️ Known Issues
239
+
240
+ - **Foreign Key Naming:** Currently, if you have multiple foreign keys referring to the same table (e.g., `customer_id` and `author_id` both referring to the `users` table), the automatic relation handling might assume `user_id` for both. This is a known limitation in the current alpha version.
162
241
 
163
242
  ## 🎮 Try the Playground
164
243
 
@@ -172,15 +251,13 @@ cd nuxt-auto-crud
172
251
  # Install dependencies (parent folder)
173
252
  bun install
174
253
 
175
- # Run the playground (fullstack with auth)
176
- cd playground-fullstack
254
+ # Run the playground (Fullstack)
255
+ cd playground
177
256
  bun install
178
257
  bun db:generate
179
258
  bun run dev
180
259
  ```
181
260
 
182
- The playground includes a sample schema with users, posts, and comments tables, plus an interactive UI to explore all the features.
183
-
184
261
  ## 📖 Usage Examples
185
262
 
186
263
  ### Create a Record
@@ -224,57 +301,11 @@ const updated = await $fetch("/api/users/1", {
224
301
  ```typescript
225
302
  await $fetch("/api/users/1", {
226
303
  method: "DELETE",
227
- });
228
- ```
229
-
230
- ## Use Cases
231
-
232
- ### 1. Full-stack App (with Auth)
233
-
234
- If you are building a full-stack Nuxt application, you can easily integrate `nuxt-auth-utils` and `nuxt-authorization` to secure your auto-generated APIs.
235
-
236
- First, install the modules:
237
-
238
- ```bash
239
- npx nuxi@latest module add auth-utils
240
- npm install nuxt-authorization
241
- ```
242
-
243
- Then, configure `nuxt-auto-crud` in your `nuxt.config.ts`:
244
-
245
- ```ts
246
- export default defineNuxtConfig({
247
- modules: [
248
- 'nuxt-auto-crud',
249
- 'nuxt-auth-utils'
250
- ],
251
- autoCrud: {
252
- auth: {
253
- enabled: true, // Enables requireUserSession() check
254
- authorization: true // Enables authorize(model, action) check
255
- }
304
+ headers: {
305
+ // If auth is enabled
306
+ Authorization: 'Bearer ...'
256
307
  }
257
- })
258
- ```
259
-
260
- When `authorization` is enabled, the module will call `authorize(model, action)` where action is one of: `create`, `read`, `update`, `delete`.
261
-
262
- ### 2. Backend-only App (API Mode)
263
-
264
- If you are using Nuxt as a backend for a separate client application (e.g., mobile app, SPA), you can use this module to quickly generate REST APIs.
265
-
266
- In this case, you might handle authentication differently (e.g., validating tokens in middleware) or disable the built-in auth checks if you have a global auth middleware.
267
-
268
- ```ts
269
- export default defineNuxtConfig({
270
- modules: ['nuxt-auto-crud'],
271
- autoCrud: {
272
- auth: {
273
- enabled: false, // Default
274
- authorization: false // Default
275
- }
276
- }
277
- })
308
+ });
278
309
  ```
279
310
 
280
311
  ## Configuration
@@ -327,5 +358,3 @@ Contributions are welcome! Please check out the [contribution guide](/CONTRIBUTI
327
358
  ## 👨‍💻 Author
328
359
 
329
360
  Made with ❤️ by [Cliford Pereira](https://github.com/clifordpereira)
330
-
331
-
package/dist/module.d.mts CHANGED
@@ -14,27 +14,7 @@ interface ModuleOptions {
14
14
  /**
15
15
  * Authentication configuration
16
16
  */
17
- auth?: {
18
- /**
19
- * Authentication type
20
- * @default 'session'
21
- */
22
- type?: 'session' | 'jwt';
23
- /**
24
- * JWT Secret (required if type is 'jwt')
25
- */
26
- jwtSecret?: string;
27
- /**
28
- * Enable authentication checks (requires nuxt-auth-utils for session)
29
- * @default false
30
- */
31
- enabled: boolean;
32
- /**
33
- * Enable authorization checks (requires nuxt-authorization)
34
- * @default false
35
- */
36
- authorization?: boolean;
37
- };
17
+ auth?: boolean | AuthOptions;
38
18
  /**
39
19
  * Resource-specific configuration
40
20
  * Define public access and column visibility
@@ -55,10 +35,34 @@ interface ModuleOptions {
55
35
  };
56
36
  };
57
37
  }
38
+ interface AuthOptions {
39
+ /**
40
+ * Authentication type
41
+ * @default 'session'
42
+ */
43
+ type?: 'session' | 'jwt';
44
+ /**
45
+ * JWT Secret (required if type is 'jwt')
46
+ */
47
+ jwtSecret?: string;
48
+ /**
49
+ * Enable authentication checks (requires nuxt-auth-utils for session)
50
+ * @default false
51
+ */
52
+ authentication: boolean;
53
+ /**
54
+ * Enable authorization checks (requires nuxt-authorization)
55
+ * @default false
56
+ */
57
+ authorization?: boolean;
58
+ }
59
+ interface RuntimeModuleOptions extends Omit<ModuleOptions, 'auth'> {
60
+ auth: AuthOptions;
61
+ }
58
62
 
59
63
  declare module '@nuxt/schema' {
60
64
  interface RuntimeConfig {
61
- autoCrud: ModuleOptions;
65
+ autoCrud: RuntimeModuleOptions;
62
66
  }
63
67
  }
64
68
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-auto-crud",
3
3
  "configKey": "autoCrud",
4
- "version": "1.4.0",
4
+ "version": "1.6.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineNuxtModule, createResolver, addServerHandler, addServerImportsDir } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, addServerHandler, addServerImportsDir, addImportsDir, addServerPlugin } from '@nuxt/kit';
2
2
 
3
3
  const module$1 = defineNuxtModule({
4
4
  meta: {
@@ -7,7 +7,8 @@ const module$1 = defineNuxtModule({
7
7
  },
8
8
  defaults: {
9
9
  schemaPath: "server/database/schema",
10
- drizzlePath: "server/utils/drizzle"
10
+ drizzlePath: "server/utils/drizzle",
11
+ auth: false
11
12
  },
12
13
  async setup(options, nuxt) {
13
14
  const resolver = createResolver(import.meta.url);
@@ -27,17 +28,45 @@ const module$1 = defineNuxtModule({
27
28
  name: "autocrud",
28
29
  cwd: nuxt.options.rootDir
29
30
  });
30
- const mergedAuth = {
31
- ...externalConfig?.auth,
32
- ...options.auth
31
+ let mergedAuth = {
32
+ authentication: false,
33
+ authorization: false,
34
+ type: "session"
33
35
  };
36
+ if (options.auth === true) {
37
+ mergedAuth = {
38
+ authentication: true,
39
+ authorization: true,
40
+ type: "session",
41
+ ...typeof externalConfig?.auth === "object" ? externalConfig.auth : {}
42
+ };
43
+ } else if (options.auth === false) {
44
+ mergedAuth = {
45
+ authentication: false,
46
+ authorization: false,
47
+ type: "session"
48
+ };
49
+ } else {
50
+ mergedAuth = {
51
+ authentication: true,
52
+ // Default to true if object provided? Or undefined?
53
+ // If options.auth is undefined, we might want defaults.
54
+ // But if defaults say auth: false, then options.auth might be undefined.
55
+ // Let's stick to the plan: default is false.
56
+ ...typeof externalConfig?.auth === "object" ? externalConfig.auth : {},
57
+ ...typeof options.auth === "object" ? options.auth : {}
58
+ };
59
+ if (mergedAuth.authentication === void 0) {
60
+ mergedAuth.authentication = false;
61
+ }
62
+ }
34
63
  const mergedResources = {
35
64
  ...externalConfig?.resources,
36
65
  ...options.resources
37
66
  };
38
67
  nuxt.options.runtimeConfig.autoCrud = {
39
68
  auth: {
40
- enabled: mergedAuth.enabled ?? false,
69
+ authentication: mergedAuth.authentication ?? false,
41
70
  authorization: mergedAuth.authorization ?? false,
42
71
  type: mergedAuth.type ?? "session",
43
72
  jwtSecret: mergedAuth.jwtSecret
@@ -45,6 +74,21 @@ const module$1 = defineNuxtModule({
45
74
  resources: mergedResources || {}
46
75
  };
47
76
  const apiDir = resolver.resolve("./runtime/server/api");
77
+ addServerHandler({
78
+ route: "/api/_schema",
79
+ method: "get",
80
+ handler: resolver.resolve(apiDir, "_schema/index.get")
81
+ });
82
+ addServerHandler({
83
+ route: "/api/_schema/:table",
84
+ method: "get",
85
+ handler: resolver.resolve(apiDir, "_schema/[table].get")
86
+ });
87
+ addServerHandler({
88
+ route: "/api/_relations",
89
+ method: "get",
90
+ handler: resolver.resolve(apiDir, "_relations.get")
91
+ });
48
92
  addServerHandler({
49
93
  route: "/api/:model",
50
94
  method: "get",
@@ -71,9 +115,8 @@ const module$1 = defineNuxtModule({
71
115
  handler: resolver.resolve(apiDir, "[model]/[id].delete")
72
116
  });
73
117
  addServerImportsDir(resolver.resolve("./runtime/server/utils"));
74
- console.log("\u{1F680} Auto CRUD module loaded!");
75
- console.log(` - Schema: ${options.schemaPath}`);
76
- console.log(` - API: /api/[model]`);
118
+ addImportsDir(resolver.resolve("./runtime/composables"));
119
+ addServerPlugin(resolver.resolve("./runtime/server/plugins/seed"));
77
120
  }
78
121
  });
79
122
 
@@ -0,0 +1,12 @@
1
+ export declare const useRelationDisplay: (schema: {
2
+ resource: string;
3
+ fields: {
4
+ name: string;
5
+ type: string;
6
+ required?: boolean;
7
+ }[];
8
+ }) => {
9
+ fetchRelations: () => Promise<void>;
10
+ getDisplayValue: (key: string, value: unknown) => unknown;
11
+ relationsMap: import("vue").Ref<Record<string, Record<string, string>>, Record<string, Record<string, string>>>;
12
+ };
@@ -0,0 +1,48 @@
1
+ import { ref, useFetch, useRequestHeaders } from "#imports";
2
+ export const useRelationDisplay = (schema) => {
3
+ const resourceName = schema.resource;
4
+ const relationsMap = ref({});
5
+ const displayValues = ref({});
6
+ const headers = useRequestHeaders(["cookie"]);
7
+ const fetchRelations = async () => {
8
+ const { data: relations } = await useFetch("/api/_relations");
9
+ if (relations.value) {
10
+ relationsMap.value = relations.value;
11
+ }
12
+ const resourceRelations = relationsMap.value[resourceName] || {};
13
+ const relationFields = Object.keys(resourceRelations);
14
+ if (relationFields.length === 0) return;
15
+ await Promise.all(
16
+ relationFields.map(async (fieldName) => {
17
+ const targetTable = resourceRelations[fieldName];
18
+ try {
19
+ const relatedData = await $fetch(`/api/${targetTable}`, { headers });
20
+ if (relatedData) {
21
+ displayValues.value[fieldName] = relatedData.reduce(
22
+ (acc, item) => {
23
+ const id = item.id;
24
+ const label = item.name || item.title || item.email || item.username || `#${item.id}`;
25
+ acc[id] = label;
26
+ return acc;
27
+ },
28
+ {}
29
+ );
30
+ }
31
+ } catch (error) {
32
+ console.error(`Failed to fetch relation data for ${targetTable}:`, error);
33
+ }
34
+ })
35
+ );
36
+ };
37
+ const getDisplayValue = (key, value) => {
38
+ if (displayValues.value[key] && (typeof value === "number" || typeof value === "string")) {
39
+ return displayValues.value[key][value] || value;
40
+ }
41
+ return value;
42
+ };
43
+ return {
44
+ fetchRelations,
45
+ getDisplayValue,
46
+ relationsMap
47
+ };
48
+ };
@@ -0,0 +1,19 @@
1
+ import type { Ref } from 'vue';
2
+ export interface ResourceField {
3
+ name: string;
4
+ type: string;
5
+ required?: boolean;
6
+ selectOptions?: string[];
7
+ }
8
+ export interface ResourceSchema {
9
+ resource: string;
10
+ fields: ResourceField[];
11
+ }
12
+ export type ResourceSchemas = Record<string, ResourceSchema>;
13
+ export declare const useResourceSchemas: () => Promise<{
14
+ schemas: Ref<ResourceSchemas | null | undefined>;
15
+ getSchema: (resource: string) => ResourceSchema | undefined;
16
+ status: Ref<"idle" | "pending" | "success" | "error">;
17
+ error: Ref<any>;
18
+ refresh: () => Promise<void>;
19
+ }>;
@@ -0,0 +1,17 @@
1
+ import { useAsyncData, useRequestHeaders } from "#imports";
2
+ export const useResourceSchemas = async () => {
3
+ const { data: schemas, status, error, refresh } = await useAsyncData("resource-schemas", () => $fetch("/api/_schema", {
4
+ headers: useRequestHeaders(["cookie"])
5
+ }));
6
+ const getSchema = (resource) => {
7
+ if (!schemas.value) return void 0;
8
+ return schemas.value[resource];
9
+ };
10
+ return {
11
+ schemas,
12
+ getSchema,
13
+ status,
14
+ error,
15
+ refresh
16
+ };
17
+ };
@@ -21,6 +21,9 @@ export default eventHandler(async (event) => {
21
21
  const table = getTableForModel(model);
22
22
  const body = await readBody(event);
23
23
  const payload = filterUpdatableFields(model, body);
24
+ if ("updatedAt" in table) {
25
+ payload.updatedAt = /* @__PURE__ */ new Date();
26
+ }
24
27
  const updatedRecord = await useDrizzle().update(table).set(payload).where(eq(table.id, Number(id))).returning().get();
25
28
  if (!updatedRecord) {
26
29
  throw createError({
@@ -3,6 +3,7 @@ import { getTableForModel, filterHiddenFields, filterPublicColumns } from "../..
3
3
  import { useDrizzle } from "#site/drizzle";
4
4
  import { useAutoCrudConfig } from "../../utils/config.js";
5
5
  import { checkAdminAccess } from "../../utils/auth.js";
6
+ import { desc } from "drizzle-orm";
6
7
  export default eventHandler(async (event) => {
7
8
  console.log("[GET] Request received", event.path);
8
9
  const { resources } = useAutoCrudConfig();
@@ -19,7 +20,7 @@ export default eventHandler(async (event) => {
19
20
  }
20
21
  }
21
22
  const table = getTableForModel(model);
22
- const results = await useDrizzle().select().from(table).all();
23
+ const results = await useDrizzle().select().from(table).orderBy(desc(table.id)).all();
23
24
  return results.map((item) => {
24
25
  if (isAdmin) {
25
26
  return filterHiddenFields(model, item);
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Record<string, Record<string, string>>>>;
2
+ export default _default;
@@ -0,0 +1,24 @@
1
+ import { eventHandler, createError } from "h3";
2
+ import { getRelations } from "../utils/schema.js";
3
+ import { useAutoCrudConfig } from "../utils/config.js";
4
+ import { verifyJwtToken } from "../utils/jwt.js";
5
+ export default eventHandler(async (event) => {
6
+ const { auth } = useAutoCrudConfig();
7
+ if (auth?.authentication) {
8
+ let isAuthenticated = false;
9
+ if (auth.type === "jwt" && auth.jwtSecret) {
10
+ isAuthenticated = await verifyJwtToken(event, auth.jwtSecret);
11
+ } else {
12
+ try {
13
+ await requireUserSession(event);
14
+ isAuthenticated = true;
15
+ } catch {
16
+ isAuthenticated = false;
17
+ }
18
+ }
19
+ if (!isAuthenticated) {
20
+ throw createError({ statusCode: 401, message: "Unauthorized" });
21
+ }
22
+ }
23
+ return getRelations();
24
+ });
@@ -0,0 +1,10 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
2
+ resource: string;
3
+ fields: {
4
+ name: string;
5
+ type: string;
6
+ required: any;
7
+ selectOptions: undefined;
8
+ }[];
9
+ }>>;
10
+ export default _default;