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,56 @@
1
+ // Auto-generated by Vasp — do not edit
2
+ import { ref, onUnmounted, type Ref } from 'vue'
3
+
4
+ const WS_BASE = import.meta.env.VITE_WS_URL || `ws://${location.host}`
5
+
6
+ export interface RealtimeMessage {
7
+ channel: string
8
+ event: string
9
+ data: unknown
10
+ }
11
+
12
+ export interface UseRealtimeResult {
13
+ connected: Ref<boolean>
14
+ on: (event: string, handler: (data: unknown) => void) => void
15
+ disconnect: () => void
16
+ }
17
+
18
+ export function useRealtime(channelName: string): UseRealtimeResult {
19
+ const connected = ref(false)
20
+ const handlers = new Map<string, (data: unknown) => void>()
21
+ let ws: WebSocket | null = null
22
+ let reconnectTimer: ReturnType<typeof setTimeout> | null = null
23
+
24
+ function connect() {
25
+ ws = new WebSocket(`${WS_BASE}/ws/${channelName}`)
26
+
27
+ ws.onopen = () => { connected.value = true }
28
+ ws.onclose = () => {
29
+ connected.value = false
30
+ reconnectTimer = setTimeout(connect, 3000)
31
+ }
32
+ ws.onerror = () => ws?.close()
33
+ ws.onmessage = ({ data }: MessageEvent<string>) => {
34
+ try {
35
+ const msg = JSON.parse(data) as RealtimeMessage
36
+ if (msg.channel === channelName) {
37
+ handlers.get(msg.event)?.(msg.data)
38
+ }
39
+ } catch {}
40
+ }
41
+ }
42
+
43
+ function on(event: string, handler: (data: unknown) => void) {
44
+ handlers.set(event, handler)
45
+ }
46
+
47
+ function disconnect() {
48
+ if (reconnectTimer) clearTimeout(reconnectTimer)
49
+ ws?.close()
50
+ }
51
+
52
+ connect()
53
+ onUnmounted(disconnect)
54
+
55
+ return { connected, on, disconnect }
56
+ }
@@ -0,0 +1,33 @@
1
+ // Auto-generated by Vasp — entity types inferred from Drizzle schema
2
+ import type {
3
+ {{#each cruds}}
4
+ {{pascalCase entity}},
5
+ New{{pascalCase entity}},
6
+ {{/each}}
7
+ {{#if hasAuth}}
8
+ User,
9
+ {{/if}}
10
+ } from '../../../../../../drizzle/schema.js'
11
+
12
+ {{#each queries}}
13
+ // Arguments and return type for '{{name}}' — customize as needed
14
+ export type {{pascalCase name}}Args = Record<string, unknown>
15
+ export type {{pascalCase name}}Return = unknown
16
+
17
+ {{/each}}
18
+ {{#each actions}}
19
+ // Arguments and return type for '{{name}}' — customize as needed
20
+ export type {{pascalCase name}}Args = Record<string, unknown>
21
+ export type {{pascalCase name}}Return = unknown
22
+
23
+ {{/each}}
24
+ // Re-export entity types for convenience
25
+ export type {
26
+ {{#each cruds}}
27
+ {{pascalCase entity}},
28
+ New{{pascalCase entity}},
29
+ {{/each}}
30
+ {{#if hasAuth}}
31
+ User,
32
+ {{/if}}
33
+ }
@@ -0,0 +1,12 @@
1
+ import type { App } from 'vue'
2
+ import { createVaspClient } from '@vasp-framework/runtime'
3
+
4
+ export const vaspPlugin = {
5
+ install(app: App) {
6
+ const client = createVaspClient({
7
+ baseURL: import.meta.env.VITE_API_URL || '/api',
8
+ })
9
+ app.provide('$vasp', client)
10
+ app.config.globalProperties.$vasp = client
11
+ },
12
+ }
@@ -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,10 @@
1
+ <template>
2
+ <{{componentName}} />
3
+ </template>
4
+
5
+ <script setup>
6
+ import {{componentName}} from '{{componentSource}}'
7
+ {{#if hasAuth}}
8
+ definePageMeta({ middleware: 'auth' })
9
+ {{/if}}
10
+ </script>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <NuxtPage />
3
+ </template>
@@ -0,0 +1,52 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // SSR-aware auth composable — uses cookies (httpOnly) and Nuxt's useRequestHeaders for server-side access
3
+ import { $fetch } from 'ofetch'
4
+
5
+ const _user = ref(null)
6
+ let _checked = false
7
+
8
+ export function useAuth() {
9
+ const config = useRuntimeConfig()
10
+ const baseURL = config.public.apiBase
11
+
12
+ // On server, forward cookies from the incoming request
13
+ const headers = import.meta.server ? useRequestHeaders(['cookie']) : {}
14
+
15
+ async function checkAuth() {
16
+ if (_checked) return
17
+ _checked = true
18
+ try {
19
+ _user.value = await $fetch(`${baseURL}/auth/me`, { headers, credentials: 'include' })
20
+ } catch {
21
+ _user.value = null
22
+ }
23
+ }
24
+
25
+ async function login(username, password) {
26
+ _user.value = await $fetch(`${baseURL}/auth/login`, {
27
+ method: 'POST',
28
+ body: { username, password },
29
+ credentials: 'include',
30
+ })
31
+ _checked = true
32
+ return _user.value
33
+ }
34
+
35
+ async function register(username, password, email) {
36
+ _user.value = await $fetch(`${baseURL}/auth/register`, {
37
+ method: 'POST',
38
+ body: { username, password, email },
39
+ credentials: 'include',
40
+ })
41
+ _checked = true
42
+ return _user.value
43
+ }
44
+
45
+ async function logout() {
46
+ await $fetch(`${baseURL}/auth/logout`, { method: 'POST', credentials: 'include' })
47
+ _user.value = null
48
+ _checked = false
49
+ }
50
+
51
+ return { user: _user, checkAuth, login, register, logout }
52
+ }
@@ -0,0 +1,6 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // Thin wrapper — the actual $vasp client is provided by vasp.server.js or vasp.client.js plugin
3
+ export const useVasp = () => {
4
+ const { $vasp } = useNuxtApp()
5
+ return { $vasp }
6
+ }
@@ -0,0 +1,8 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ export default defineNuxtRouteMiddleware((to) => {
3
+ const { user } = useAuth()
4
+ const publicPaths = ['/login', '/register']
5
+ if (!user.value && !publicPaths.includes(to.path)) {
6
+ return navigateTo('/login')
7
+ }
8
+ })
@@ -0,0 +1,15 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // https://nuxt.com/docs/api/configuration/nuxt-config
3
+ export default defineNuxtConfig({
4
+ compatibilityDate: '2024-11-01',
5
+ devtools: { enabled: true },
6
+ alias: {
7
+ '@src': '~/src',
8
+ },
9
+ runtimeConfig: {
10
+ backendUrl: process.env.BACKEND_URL || 'http://localhost:{{backendPort}}',
11
+ public: {
12
+ apiBase: process.env.API_BASE || 'http://localhost:{{backendPort}}/api',
13
+ },
14
+ },
15
+ })
@@ -0,0 +1,17 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // Runs only on the client after hydration — routes calls to the Elysia backend via ofetch
3
+ import { $fetch } from 'ofetch'
4
+
5
+ export default defineNuxtPlugin((nuxtApp) => {
6
+ const config = useRuntimeConfig()
7
+ const baseURL = config.public.apiBase
8
+
9
+ nuxtApp.provide('vasp', {
10
+ async query(name, args) {
11
+ return $fetch(`/queries/${name}`, { baseURL, method: 'GET', query: args })
12
+ },
13
+ async action(name, args) {
14
+ return $fetch(`/actions/${name}`, { baseURL, method: 'POST', body: args })
15
+ },
16
+ })
17
+ })
@@ -0,0 +1,33 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // Runs only on the server during SSR render — calls query/action functions directly (zero HTTP overhead)
3
+ {{#each queries}}
4
+ import { {{importName fn}} } from '{{fn.source}}'
5
+ {{/each}}
6
+ {{#each actions}}
7
+ import { {{importName fn}} } from '{{fn.source}}'
8
+ {{/each}}
9
+
10
+ export default defineNuxtPlugin((nuxtApp) => {
11
+ const queryFns = {
12
+ {{#each queries}}
13
+ {{camelCase name}}: {{importName fn}},
14
+ {{/each}}
15
+ }
16
+
17
+ const actionFns = {
18
+ {{#each actions}}
19
+ {{camelCase name}}: {{importName fn}},
20
+ {{/each}}
21
+ }
22
+
23
+ nuxtApp.provide('vasp', {
24
+ async query(name, args) {
25
+ if (!queryFns[name]) throw new Error(`[Vasp] Unknown query: ${name}`)
26
+ return queryFns[name](args)
27
+ },
28
+ async action(name, args) {
29
+ if (!actionFns[name]) throw new Error(`[Vasp] Unknown action: ${name}`)
30
+ return actionFns[name](args)
31
+ },
32
+ })
33
+ })
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <{{componentName}} />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import {{componentName}} from '{{componentSource}}'
7
+ {{#if hasAuth}}
8
+ definePageMeta({ middleware: 'auth' })
9
+ {{/if}}
10
+ </script>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <NuxtPage />
3
+ </template>
@@ -0,0 +1,56 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // SSR-aware auth composable — uses cookies (httpOnly) and Nuxt's useRequestHeaders for server-side access
3
+ import { $fetch } from 'ofetch'
4
+
5
+ interface AuthUser {
6
+ id: number
7
+ username: string
8
+ email?: string
9
+ }
10
+
11
+ const _user = ref<AuthUser | null>(null)
12
+ let _checked = false
13
+
14
+ export function useAuth() {
15
+ const config = useRuntimeConfig()
16
+ const baseURL = config.public.apiBase as string
17
+ const headers = import.meta.server ? useRequestHeaders(['cookie']) : {}
18
+
19
+ async function checkAuth(): Promise<void> {
20
+ if (_checked) return
21
+ _checked = true
22
+ try {
23
+ _user.value = await $fetch<AuthUser>(`${baseURL}/auth/me`, { headers, credentials: 'include' })
24
+ } catch {
25
+ _user.value = null
26
+ }
27
+ }
28
+
29
+ async function login(username: string, password: string): Promise<AuthUser> {
30
+ _user.value = await $fetch<AuthUser>(`${baseURL}/auth/login`, {
31
+ method: 'POST',
32
+ body: { username, password },
33
+ credentials: 'include',
34
+ })
35
+ _checked = true
36
+ return _user.value!
37
+ }
38
+
39
+ async function register(username: string, password: string, email?: string): Promise<AuthUser> {
40
+ _user.value = await $fetch<AuthUser>(`${baseURL}/auth/register`, {
41
+ method: 'POST',
42
+ body: { username, password, email },
43
+ credentials: 'include',
44
+ })
45
+ _checked = true
46
+ return _user.value!
47
+ }
48
+
49
+ async function logout(): Promise<void> {
50
+ await $fetch(`${baseURL}/auth/logout`, { method: 'POST', credentials: 'include' })
51
+ _user.value = null
52
+ _checked = false
53
+ }
54
+
55
+ return { user: _user, checkAuth, login, register, logout }
56
+ }
@@ -0,0 +1,10 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ interface VaspClient {
3
+ query<T = unknown>(name: string, args?: unknown): Promise<T>
4
+ action<T = unknown>(name: string, args?: unknown): Promise<T>
5
+ }
6
+
7
+ export const useVasp = (): { $vasp: VaspClient } => {
8
+ const { $vasp } = useNuxtApp()
9
+ return { $vasp: $vasp as VaspClient }
10
+ }
@@ -0,0 +1,8 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ export default defineNuxtRouteMiddleware((to) => {
3
+ const { user } = useAuth()
4
+ const publicPaths = ['/login', '/register']
5
+ if (!user.value && !publicPaths.includes(to.path)) {
6
+ return navigateTo('/login')
7
+ }
8
+ })
@@ -0,0 +1,19 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // https://nuxt.com/docs/api/configuration/nuxt-config
3
+ export default defineNuxtConfig({
4
+ compatibilityDate: '2024-11-01',
5
+ devtools: { enabled: true },
6
+ typescript: {
7
+ strict: true,
8
+ typeCheck: true,
9
+ },
10
+ alias: {
11
+ '@src': '~/src',
12
+ },
13
+ runtimeConfig: {
14
+ backendUrl: process.env.BACKEND_URL || 'http://localhost:{{backendPort}}',
15
+ public: {
16
+ apiBase: process.env.API_BASE || 'http://localhost:{{backendPort}}/api',
17
+ },
18
+ },
19
+ })
@@ -0,0 +1,17 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // Runs only on the client after hydration — routes calls to the Elysia backend via ofetch
3
+ import { $fetch } from 'ofetch'
4
+
5
+ export default defineNuxtPlugin((nuxtApp) => {
6
+ const config = useRuntimeConfig()
7
+ const baseURL = config.public.apiBase as string
8
+
9
+ nuxtApp.provide('vasp', {
10
+ async query<T = unknown>(name: string, args?: unknown): Promise<T> {
11
+ return $fetch<T>(`/queries/${name}`, { baseURL, method: 'GET', query: args as Record<string, unknown> })
12
+ },
13
+ async action<T = unknown>(name: string, args?: unknown): Promise<T> {
14
+ return $fetch<T>(`/actions/${name}`, { baseURL, method: 'POST', body: args })
15
+ },
16
+ })
17
+ })
@@ -0,0 +1,33 @@
1
+ // Auto-generated by Vasp — do not edit directly
2
+ // Runs only on the server during SSR render — calls query/action functions directly (zero HTTP overhead)
3
+ {{#each queries}}
4
+ import { {{importName fn}} } from '{{fn.source}}'
5
+ {{/each}}
6
+ {{#each actions}}
7
+ import { {{importName fn}} } from '{{fn.source}}'
8
+ {{/each}}
9
+
10
+ export default defineNuxtPlugin((nuxtApp) => {
11
+ const queryFns: Record<string, (args?: unknown) => Promise<unknown>> = {
12
+ {{#each queries}}
13
+ {{camelCase name}}: {{importName fn}} as (args?: unknown) => Promise<unknown>,
14
+ {{/each}}
15
+ }
16
+
17
+ const actionFns: Record<string, (args?: unknown) => Promise<unknown>> = {
18
+ {{#each actions}}
19
+ {{camelCase name}}: {{importName fn}} as (args?: unknown) => Promise<unknown>,
20
+ {{/each}}
21
+ }
22
+
23
+ nuxtApp.provide('vasp', {
24
+ async query<T = unknown>(name: string, args?: unknown): Promise<T> {
25
+ if (!queryFns[name]) throw new Error(`[Vasp] Unknown query: ${name}`)
26
+ return queryFns[name](args) as Promise<T>
27
+ },
28
+ async action<T = unknown>(name: string, args?: unknown): Promise<T> {
29
+ if (!actionFns[name]) throw new Error(`[Vasp] Unknown action: ${name}`)
30
+ return actionFns[name](args) as Promise<T>
31
+ },
32
+ })
33
+ })