vasp-cli 0.1.3 → 0.2.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 (66) hide show
  1. package/dist/vasp +23 -24
  2. package/package.json +1 -1
  3. package/templates/templates/shared/.env.example.hbs +14 -0
  4. package/templates/templates/shared/.gitignore.hbs +8 -0
  5. package/templates/templates/shared/auth/client/Login.vue.hbs +46 -0
  6. package/templates/templates/shared/auth/client/Register.vue.hbs +42 -0
  7. package/templates/templates/shared/auth/server/index.hbs +51 -0
  8. package/templates/templates/shared/auth/server/middleware.hbs +33 -0
  9. package/templates/templates/shared/auth/server/providers/github.hbs +48 -0
  10. package/templates/templates/shared/auth/server/providers/google.hbs +53 -0
  11. package/templates/templates/shared/auth/server/providers/usernameAndPassword.hbs +69 -0
  12. package/templates/templates/shared/bunfig.toml.hbs +2 -0
  13. package/templates/templates/shared/drizzle/schema.hbs +48 -0
  14. package/templates/templates/shared/jobs/_job.hbs +29 -0
  15. package/templates/templates/shared/jobs/boss.hbs +15 -0
  16. package/templates/templates/shared/package.json.hbs +32 -0
  17. package/templates/templates/shared/server/db/client.hbs +12 -0
  18. package/templates/templates/shared/server/index.hbs +52 -0
  19. package/templates/templates/shared/server/routes/actions/_action.hbs +20 -0
  20. package/templates/templates/shared/server/routes/crud/_crud.hbs +55 -0
  21. package/templates/templates/shared/server/routes/jobs/_schedule.hbs +12 -0
  22. package/templates/templates/shared/server/routes/queries/_query.hbs +20 -0
  23. package/templates/templates/shared/server/routes/realtime/_channel.hbs +78 -0
  24. package/templates/templates/shared/server/routes/realtime/index.hbs +9 -0
  25. package/templates/templates/shared/tsconfig.json.hbs +21 -0
  26. package/templates/templates/spa/js/index.html.hbs +12 -0
  27. package/templates/templates/spa/js/src/App.vue.hbs +3 -0
  28. package/templates/templates/spa/js/src/main.js.hbs +9 -0
  29. package/templates/templates/spa/js/src/router/index.js.hbs +41 -0
  30. package/templates/templates/spa/js/src/vasp/auth.js.hbs +45 -0
  31. package/templates/templates/spa/js/src/vasp/client/actions.js.hbs +15 -0
  32. package/templates/templates/spa/js/src/vasp/client/crud.js.hbs +30 -0
  33. package/templates/templates/spa/js/src/vasp/client/index.js.hbs +16 -0
  34. package/templates/templates/spa/js/src/vasp/client/queries.js.hbs +15 -0
  35. package/templates/templates/spa/js/src/vasp/client/realtime.js.hbs +51 -0
  36. package/templates/templates/spa/js/src/vasp/plugin.js.hbs +11 -0
  37. package/templates/templates/spa/js/vite.config.js.hbs +26 -0
  38. package/templates/templates/spa/ts/index.html.hbs +12 -0
  39. package/templates/templates/spa/ts/src/App.vue.hbs +3 -0
  40. package/templates/templates/spa/ts/src/main.ts.hbs +9 -0
  41. package/templates/templates/spa/ts/src/router/index.ts.hbs +41 -0
  42. package/templates/templates/spa/ts/src/vasp/auth.ts.hbs +53 -0
  43. package/templates/templates/spa/ts/src/vasp/client/actions.ts.hbs +19 -0
  44. package/templates/templates/spa/ts/src/vasp/client/crud.ts.hbs +37 -0
  45. package/templates/templates/spa/ts/src/vasp/client/index.ts.hbs +17 -0
  46. package/templates/templates/spa/ts/src/vasp/client/queries.ts.hbs +19 -0
  47. package/templates/templates/spa/ts/src/vasp/client/realtime.ts.hbs +56 -0
  48. package/templates/templates/spa/ts/src/vasp/client/types.ts.hbs +33 -0
  49. package/templates/templates/spa/ts/src/vasp/plugin.ts.hbs +12 -0
  50. package/templates/templates/spa/ts/vite.config.ts.hbs +26 -0
  51. package/templates/templates/ssr/js/_page.vue.hbs +10 -0
  52. package/templates/templates/ssr/js/app.vue.hbs +3 -0
  53. package/templates/templates/ssr/js/composables/useAuth.js.hbs +52 -0
  54. package/templates/templates/ssr/js/composables/useVasp.js.hbs +6 -0
  55. package/templates/templates/ssr/js/middleware/auth.js.hbs +8 -0
  56. package/templates/templates/ssr/js/nuxt.config.js.hbs +15 -0
  57. package/templates/templates/ssr/js/plugins/vasp.client.js.hbs +17 -0
  58. package/templates/templates/ssr/js/plugins/vasp.server.js.hbs +33 -0
  59. package/templates/templates/ssr/ts/_page.vue.hbs +10 -0
  60. package/templates/templates/ssr/ts/app.vue.hbs +3 -0
  61. package/templates/templates/ssr/ts/composables/useAuth.ts.hbs +56 -0
  62. package/templates/templates/ssr/ts/composables/useVasp.ts.hbs +10 -0
  63. package/templates/templates/ssr/ts/middleware/auth.ts.hbs +8 -0
  64. package/templates/templates/ssr/ts/nuxt.config.ts.hbs +19 -0
  65. package/templates/templates/ssr/ts/plugins/vasp.client.ts.hbs +17 -0
  66. package/templates/templates/ssr/ts/plugins/vasp.server.ts.hbs +33 -0
@@ -0,0 +1,20 @@
1
+ import { Elysia } from 'elysia'
2
+ import { db } from '../../db/client.{{ext}}'
3
+ {{#if requiresAuth}}
4
+ import { requireAuth } from '../../auth/middleware.{{ext}}'
5
+ {{/if}}
6
+ import { {{namedExport}} } from '{{importPath fnSource ext}}'
7
+
8
+ export const {{camelCase name}}Route = new Elysia()
9
+ {{#if requiresAuth}}
10
+ .use(requireAuth)
11
+ .get('/api/queries/{{camelCase name}}', async ({ query, user }) => {
12
+ const result = await {{namedExport}}({ db, user, args: query })
13
+ return result
14
+ })
15
+ {{else}}
16
+ .get('/api/queries/{{camelCase name}}', async ({ query }) => {
17
+ const result = await {{namedExport}}({ db, args: query })
18
+ return result
19
+ })
20
+ {{/if}}
@@ -0,0 +1,78 @@
1
+ import { Elysia } from 'elysia'
2
+ {{#if ../hasAuth}}
3
+ import jwt from '@elysiajs/jwt'
4
+ {{/if}}
5
+
6
+ // Room-based subscriber map for '{{name}}' channel
7
+ // Each room key maps to a set of connected WebSocket clients
8
+ const rooms = new Map()
9
+
10
+ function getRoom(roomId) {
11
+ if (!rooms.has(roomId)) rooms.set(roomId, new Set())
12
+ return rooms.get(roomId)
13
+ }
14
+
15
+ /**
16
+ * Publish a realtime event to all subscribers in a specific room of '{{name}}'.
17
+ * Called automatically by CRUD mutation handlers.
18
+ */
19
+ export function publish{{pascalCase name}}(event, data, roomId = 'default') {
20
+ const room = rooms.get(roomId)
21
+ if (!room) return
22
+ const message = JSON.stringify({ channel: '{{camelCase name}}', room: roomId, event, data })
23
+ for (const ws of room) {
24
+ try { ws.send(message) } catch { room.delete(ws) }
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Broadcast to all rooms of '{{name}}'.
30
+ */
31
+ export function broadcast{{pascalCase name}}(event, data) {
32
+ const message = JSON.stringify({ channel: '{{camelCase name}}', event, data })
33
+ for (const [, room] of rooms) {
34
+ for (const ws of room) {
35
+ try { ws.send(message) } catch { room.delete(ws) }
36
+ }
37
+ }
38
+ }
39
+
40
+ export const {{camelCase name}}Channel = new Elysia()
41
+ {{#if ../hasAuth}}
42
+ .use(jwt({ name: 'jwt', secret: process.env.JWT_SECRET || 'vasp-dev-secret' }))
43
+ {{/if}}
44
+ .ws('/ws/{{camelCase name}}', {
45
+ {{#if ../hasAuth}}
46
+ async beforeHandle({ jwt: jwtPlugin, request }) {
47
+ const url = new URL(request.url)
48
+ const token = url.searchParams.get('token')
49
+ if (!token) return new Response('Unauthorized', { status: 401 })
50
+ const payload = await jwtPlugin.verify(token)
51
+ if (!payload) return new Response('Unauthorized', { status: 401 })
52
+ },
53
+ {{/if}}
54
+ open(ws) {
55
+ const room = ws.data?.query?.room ?? 'default'
56
+ getRoom(room).add(ws)
57
+ ws.data._room = room
58
+ },
59
+ message(ws, msg) {
60
+ // Client can switch rooms via { action: 'join', room: 'roomId' }
61
+ try {
62
+ const parsed = typeof msg === 'string' ? JSON.parse(msg) : msg
63
+ if (parsed.action === 'join' && parsed.room) {
64
+ const oldRoom = ws.data._room
65
+ if (oldRoom) rooms.get(oldRoom)?.delete(ws)
66
+ ws.data._room = parsed.room
67
+ getRoom(parsed.room).add(ws)
68
+ ws.send(JSON.stringify({ ack: 'joined', room: parsed.room }))
69
+ return
70
+ }
71
+ } catch { /* ignore parse errors */ }
72
+ ws.send(JSON.stringify({ ack: msg }))
73
+ },
74
+ close(ws) {
75
+ const room = ws.data?._room
76
+ if (room) rooms.get(room)?.delete(ws)
77
+ },
78
+ })
@@ -0,0 +1,9 @@
1
+ import { Elysia } from 'elysia'
2
+ {{#each realtimes}}
3
+ import { {{camelCase name}}Channel } from './{{camelCase name}}.{{../ext}}'
4
+ {{/each}}
5
+
6
+ export const realtimeRoutes = new Elysia()
7
+ {{#each realtimes}}
8
+ .use({{camelCase name}}Channel)
9
+ {{/each}}
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "noUnusedLocals": true,
9
+ "noUnusedParameters": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "esModuleInterop": true,
12
+ "skipLibCheck": true,
13
+ "jsx": "preserve",
14
+ "paths": {
15
+ "@src/*": ["./src/*"],
16
+ "@vasp-framework/client": ["./src/vasp/client/index.ts"]
17
+ }
18
+ },
19
+ "include": ["src/**/*.ts", "src/**/*.vue", "server/**/*.ts", "drizzle/**/*.ts"],
20
+ "exclude": ["node_modules", "dist", ".vasp-gen"]
21
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{appTitle}}</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.js"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <RouterView />
3
+ </template>
@@ -0,0 +1,9 @@
1
+ import { createApp } from 'vue'
2
+ import App from './App.vue'
3
+ import router from './router/index.js'
4
+ import { vaspPlugin } from './vasp/plugin.js'
5
+
6
+ const app = createApp(App)
7
+ app.use(router)
8
+ app.use(vaspPlugin)
9
+ app.mount('#app')
@@ -0,0 +1,41 @@
1
+ import { createRouter, createWebHistory } from 'vue-router'
2
+ {{#if hasAuth}}
3
+ import { useAuth } from '../vasp/auth.js'
4
+ {{/if}}
5
+
6
+ const routes = [
7
+ {{#each routes}}
8
+ {
9
+ path: '{{path}}',
10
+ component: () => import('{{lookup ../pagesMap to}}'),
11
+ },
12
+ {{/each}}
13
+ {{#if hasAuth}}
14
+ {
15
+ path: '/login',
16
+ component: () => import('../pages/Login.vue'),
17
+ },
18
+ {
19
+ path: '/register',
20
+ component: () => import('../pages/Register.vue'),
21
+ },
22
+ {{/if}}
23
+ ]
24
+
25
+ const router = createRouter({
26
+ history: createWebHistory(),
27
+ routes,
28
+ })
29
+
30
+ {{#if hasAuth}}
31
+ router.beforeEach(async (to) => {
32
+ const { user, checkAuth } = useAuth()
33
+ await checkAuth()
34
+ const publicPaths = ['/login', '/register']
35
+ if (!user.value && !publicPaths.includes(to.path)) {
36
+ return '/login'
37
+ }
38
+ })
39
+ {{/if}}
40
+
41
+ export default router
@@ -0,0 +1,45 @@
1
+ import { ref } from 'vue'
2
+ import { $fetch } from 'ofetch'
3
+
4
+ const user = ref(null)
5
+ let checked = false
6
+
7
+ const API = import.meta.env.VITE_API_URL || '/api'
8
+
9
+ export function useAuth() {
10
+ async function checkAuth() {
11
+ if (checked) return
12
+ checked = true
13
+ try {
14
+ user.value = await $fetch(`${API}/auth/me`, { credentials: 'include' })
15
+ } catch {
16
+ user.value = null
17
+ }
18
+ }
19
+
20
+ async function login(username, password) {
21
+ user.value = await $fetch(`${API}/auth/login`, {
22
+ method: 'POST',
23
+ body: { username, password },
24
+ credentials: 'include',
25
+ })
26
+ return user.value
27
+ }
28
+
29
+ async function register(username, password, email) {
30
+ user.value = await $fetch(`${API}/auth/register`, {
31
+ method: 'POST',
32
+ body: { username, password, email },
33
+ credentials: 'include',
34
+ })
35
+ return user.value
36
+ }
37
+
38
+ async function logout() {
39
+ await $fetch(`${API}/auth/logout`, { method: 'POST', credentials: 'include' })
40
+ user.value = null
41
+ checked = false
42
+ }
43
+
44
+ return { user, checkAuth, login, register, logout }
45
+ }
@@ -0,0 +1,15 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { useVasp } from '@vasp-framework/runtime'
3
+
4
+ {{#each actions}}
5
+ /**
6
+ * Call the '{{name}}' action on the Vasp backend.
7
+ * @param {unknown} args - Arguments to pass to the action function
8
+ * @returns {Promise<unknown>}
9
+ */
10
+ export async function {{camelCase name}}(args) {
11
+ const { $vasp } = useVasp()
12
+ return $vasp.action('{{camelCase name}}', args)
13
+ }
14
+
15
+ {{/each}}
@@ -0,0 +1,30 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { $fetch } from 'ofetch'
3
+
4
+ const API = import.meta.env.VITE_API_URL || '/api'
5
+
6
+ {{#each cruds}}
7
+ /**
8
+ * CRUD helpers for the '{{entity}}' entity.
9
+ */
10
+ export function use{{pascalCase entity}}Crud() {
11
+ const base = `${API}/crud/{{camelCase entity}}`
12
+
13
+ return {
14
+ {{#if (includes operations "list")}}
15
+ list: () => $fetch(base, { credentials: 'include' }),
16
+ {{/if}}
17
+ {{#if (includes operations "create")}}
18
+ create: (data) => $fetch(base, { method: 'POST', body: data, credentials: 'include' }),
19
+ {{/if}}
20
+ get: (id) => $fetch(`${base}/${id}`, { credentials: 'include' }),
21
+ {{#if (includes operations "update")}}
22
+ update: (id, data) => $fetch(`${base}/${id}`, { method: 'PUT', body: data, credentials: 'include' }),
23
+ {{/if}}
24
+ {{#if (includes operations "delete")}}
25
+ remove: (id) => $fetch(`${base}/${id}`, { method: 'DELETE', credentials: 'include' }),
26
+ {{/if}}
27
+ }
28
+ }
29
+
30
+ {{/each}}
@@ -0,0 +1,16 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // Re-run `vasp build` or restart `vasp start` to regenerate
3
+
4
+ export { useVasp } from '@vasp-framework/runtime'
5
+ {{#each queries}}
6
+ export { {{camelCase name}} } from './queries.js'
7
+ {{/each}}
8
+ {{#each actions}}
9
+ export { {{camelCase name}} } from './actions.js'
10
+ {{/each}}
11
+ {{#each cruds}}
12
+ export { use{{pascalCase entity}}Crud } from './crud.js'
13
+ {{/each}}
14
+ {{#if hasRealtime}}
15
+ export { useRealtime } from './realtime.js'
16
+ {{/if}}
@@ -0,0 +1,15 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { useVasp } from '@vasp-framework/runtime'
3
+
4
+ {{#each queries}}
5
+ /**
6
+ * Call the '{{name}}' query on the Vasp backend.
7
+ * @param {unknown} [args] - Arguments to pass to the query function
8
+ * @returns {Promise<unknown>}
9
+ */
10
+ export async function {{camelCase name}}(args) {
11
+ const { $vasp } = useVasp()
12
+ return $vasp.query('{{camelCase name}}', args)
13
+ }
14
+
15
+ {{/each}}
@@ -0,0 +1,51 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { ref, onUnmounted } from 'vue'
3
+
4
+ const WS_BASE = import.meta.env.VITE_WS_URL || `ws://${location.host}`
5
+
6
+ /**
7
+ * useRealtime — subscribe to a Vasp realtime channel.
8
+ *
9
+ * @example
10
+ * const { on } = useRealtime('todoChannel')
11
+ * on('created', (todo) => todos.value.push(todo))
12
+ */
13
+ export function useRealtime(channelName) {
14
+ const connected = ref(false)
15
+ const handlers = new Map()
16
+ let ws = null
17
+ let reconnectTimer = null
18
+
19
+ function connect() {
20
+ ws = new WebSocket(`${WS_BASE}/ws/${channelName}`)
21
+
22
+ ws.onopen = () => { connected.value = true }
23
+ ws.onclose = () => {
24
+ connected.value = false
25
+ reconnectTimer = setTimeout(connect, 3000) // auto-reconnect
26
+ }
27
+ ws.onerror = () => ws.close()
28
+ ws.onmessage = ({ data }) => {
29
+ try {
30
+ const msg = JSON.parse(data)
31
+ if (msg.channel === channelName && handlers.has(msg.event)) {
32
+ handlers.get(msg.event)(msg.data)
33
+ }
34
+ } catch {}
35
+ }
36
+ }
37
+
38
+ function on(event, handler) {
39
+ handlers.set(event, handler)
40
+ }
41
+
42
+ function disconnect() {
43
+ clearTimeout(reconnectTimer)
44
+ ws?.close()
45
+ }
46
+
47
+ connect()
48
+ onUnmounted(disconnect)
49
+
50
+ return { connected, on, disconnect }
51
+ }
@@ -0,0 +1,11 @@
1
+ import { createVaspClient } from '@vasp-framework/runtime'
2
+
3
+ export const vaspPlugin = {
4
+ install(app) {
5
+ const client = createVaspClient({
6
+ baseURL: import.meta.env.VITE_API_URL || '/api',
7
+ })
8
+ app.provide('$vasp', client)
9
+ app.config.globalProperties.$vasp = client
10
+ },
11
+ }
@@ -0,0 +1,26 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+ import { fileURLToPath, URL } from 'node:url'
4
+
5
+ export default defineConfig({
6
+ plugins: [vue()],
7
+ resolve: {
8
+ alias: {
9
+ '@src': fileURLToPath(new URL('./src', import.meta.url)),
10
+ '@vasp-framework/client': fileURLToPath(new URL('./src/vasp/client', import.meta.url)),
11
+ },
12
+ },
13
+ server: {
14
+ port: {{frontendPort}},
15
+ proxy: {
16
+ '/api': {
17
+ target: 'http://localhost:{{backendPort}}',
18
+ changeOrigin: true,
19
+ },
20
+ '/ws': {
21
+ target: 'ws://localhost:{{backendPort}}',
22
+ ws: true,
23
+ },
24
+ },
25
+ },
26
+ })
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{appTitle}}</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <RouterView />
3
+ </template>
@@ -0,0 +1,9 @@
1
+ import { createApp } from 'vue'
2
+ import App from './App.vue'
3
+ import router from './router/index.js'
4
+ import { vaspPlugin } from './vasp/plugin.js'
5
+
6
+ const app = createApp(App)
7
+ app.use(router)
8
+ app.use(vaspPlugin)
9
+ app.mount('#app')
@@ -0,0 +1,41 @@
1
+ import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
2
+ {{#if hasAuth}}
3
+ import { useAuth } from '../vasp/auth.js'
4
+ {{/if}}
5
+
6
+ const routes: RouteRecordRaw[] = [
7
+ {{#each routes}}
8
+ {
9
+ path: '{{path}}',
10
+ component: () => import('{{lookup ../pagesMap to}}'),
11
+ },
12
+ {{/each}}
13
+ {{#if hasAuth}}
14
+ {
15
+ path: '/login',
16
+ component: () => import('../pages/Login.vue'),
17
+ },
18
+ {
19
+ path: '/register',
20
+ component: () => import('../pages/Register.vue'),
21
+ },
22
+ {{/if}}
23
+ ]
24
+
25
+ const router = createRouter({
26
+ history: createWebHistory(),
27
+ routes,
28
+ })
29
+
30
+ {{#if hasAuth}}
31
+ router.beforeEach(async (to) => {
32
+ const { user, checkAuth } = useAuth()
33
+ await checkAuth()
34
+ const publicPaths = ['/login', '/register']
35
+ if (!user.value && !publicPaths.includes(to.path)) {
36
+ return '/login'
37
+ }
38
+ })
39
+ {{/if}}
40
+
41
+ export default router
@@ -0,0 +1,53 @@
1
+ import { ref, type Ref } from 'vue'
2
+ import { $fetch } from 'ofetch'
3
+
4
+ export interface AuthUser {
5
+ id: number
6
+ username: string
7
+ email: string | null
8
+ createdAt: Date
9
+ updatedAt: Date
10
+ }
11
+
12
+ const user: Ref<AuthUser | null> = ref(null)
13
+ let checked = false
14
+
15
+ const API = import.meta.env.VITE_API_URL || '/api'
16
+
17
+ export function useAuth() {
18
+ async function checkAuth(): Promise<void> {
19
+ if (checked) return
20
+ checked = true
21
+ try {
22
+ user.value = await $fetch<AuthUser>(`${API}/auth/me`, { credentials: 'include' })
23
+ } catch {
24
+ user.value = null
25
+ }
26
+ }
27
+
28
+ async function login(username: string, password: string): Promise<AuthUser> {
29
+ user.value = await $fetch<AuthUser>(`${API}/auth/login`, {
30
+ method: 'POST',
31
+ body: { username, password },
32
+ credentials: 'include',
33
+ })
34
+ return user.value!
35
+ }
36
+
37
+ async function register(username: string, password: string, email?: string): Promise<AuthUser> {
38
+ user.value = await $fetch<AuthUser>(`${API}/auth/register`, {
39
+ method: 'POST',
40
+ body: { username, password, email },
41
+ credentials: 'include',
42
+ })
43
+ return user.value!
44
+ }
45
+
46
+ async function logout(): Promise<void> {
47
+ await $fetch(`${API}/auth/logout`, { method: 'POST', credentials: 'include' })
48
+ user.value = null
49
+ checked = false
50
+ }
51
+
52
+ return { user, checkAuth, login, register, logout }
53
+ }
@@ -0,0 +1,19 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { useVasp } from '@vasp-framework/runtime'
3
+ import type {
4
+ {{#each actions}}
5
+ {{pascalCase name}}Args,
6
+ {{pascalCase name}}Return,
7
+ {{/each}}
8
+ } from './types.js'
9
+
10
+ {{#each actions}}
11
+ /**
12
+ * Call the '{{name}}' action on the Vasp backend.
13
+ */
14
+ export async function {{camelCase name}}(args: {{pascalCase name}}Args): Promise<{{pascalCase name}}Return> {
15
+ const { $vasp } = useVasp()
16
+ return $vasp.action('{{camelCase name}}', args) as Promise<{{pascalCase name}}Return>
17
+ }
18
+
19
+ {{/each}}
@@ -0,0 +1,37 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { $fetch } from 'ofetch'
3
+ import type {
4
+ {{#each cruds}}
5
+ {{pascalCase entity}},
6
+ New{{pascalCase entity}},
7
+ {{/each}}
8
+ } from './types.js'
9
+
10
+ const API = import.meta.env.VITE_API_URL || '/api'
11
+
12
+ {{#each cruds}}
13
+ export function use{{pascalCase entity}}Crud() {
14
+ const base = `${API}/crud/{{camelCase entity}}`
15
+
16
+ return {
17
+ {{#if (includes operations "list")}}
18
+ list: (): Promise<{{pascalCase entity}}[]> => $fetch(base, { credentials: 'include' }),
19
+ {{/if}}
20
+ {{#if (includes operations "create")}}
21
+ create: (data: New{{pascalCase entity}}): Promise<{{pascalCase entity}}> =>
22
+ $fetch(base, { method: 'POST', body: data, credentials: 'include' }),
23
+ {{/if}}
24
+ get: (id: number): Promise<{{pascalCase entity}}> =>
25
+ $fetch(`${base}/${id}`, { credentials: 'include' }),
26
+ {{#if (includes operations "update")}}
27
+ update: (id: number, data: Partial<New{{pascalCase entity}}>): Promise<{{pascalCase entity}}> =>
28
+ $fetch(`${base}/${id}`, { method: 'PUT', body: data, credentials: 'include' }),
29
+ {{/if}}
30
+ {{#if (includes operations "delete")}}
31
+ remove: (id: number): Promise<{ ok: boolean }> =>
32
+ $fetch(`${base}/${id}`, { method: 'DELETE', credentials: 'include' }),
33
+ {{/if}}
34
+ }
35
+ }
36
+
37
+ {{/each}}
@@ -0,0 +1,17 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // Re-run `vasp build` or restart `vasp start` to regenerate
3
+
4
+ export { useVasp } from '@vasp-framework/runtime'
5
+ {{#each queries}}
6
+ export { {{camelCase name}} } from './queries.js'
7
+ {{/each}}
8
+ {{#each actions}}
9
+ export { {{camelCase name}} } from './actions.js'
10
+ {{/each}}
11
+ {{#each cruds}}
12
+ export { use{{pascalCase entity}}Crud } from './crud.js'
13
+ {{/each}}
14
+ {{#if hasRealtime}}
15
+ export { useRealtime } from './realtime.js'
16
+ {{/if}}
17
+ export type * from './types.js'
@@ -0,0 +1,19 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { useVasp } from '@vasp-framework/runtime'
3
+ import type {
4
+ {{#each queries}}
5
+ {{pascalCase name}}Args,
6
+ {{pascalCase name}}Return,
7
+ {{/each}}
8
+ } from './types.js'
9
+
10
+ {{#each queries}}
11
+ /**
12
+ * Call the '{{name}}' query on the Vasp backend.
13
+ */
14
+ export async function {{camelCase name}}(args?: {{pascalCase name}}Args): Promise<{{pascalCase name}}Return> {
15
+ const { $vasp } = useVasp()
16
+ return $vasp.query('{{camelCase name}}', args) as Promise<{{pascalCase name}}Return>
17
+ }
18
+
19
+ {{/each}}