dzql 0.5.33 → 0.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 (150) hide show
  1. package/.env.sample +28 -0
  2. package/compose.yml +28 -0
  3. package/dist/client/index.ts +1 -0
  4. package/dist/client/stores/useMyProfileStore.ts +114 -0
  5. package/dist/client/stores/useOrgDashboardStore.ts +131 -0
  6. package/dist/client/stores/useVenueDetailStore.ts +117 -0
  7. package/dist/client/ws.ts +716 -0
  8. package/dist/db/migrations/000_core.sql +92 -0
  9. package/dist/db/migrations/20251229T212912022Z_schema.sql +3020 -0
  10. package/dist/db/migrations/20251229T212912022Z_subscribables.sql +371 -0
  11. package/dist/runtime/manifest.json +1562 -0
  12. package/docs/README.md +293 -36
  13. package/docs/feature-requests/applyPatch-bug-report.md +85 -0
  14. package/docs/feature-requests/connection-ready-profile.md +57 -0
  15. package/docs/feature-requests/hidden-bug-report.md +111 -0
  16. package/docs/feature-requests/hidden-fields-subscribables.md +34 -0
  17. package/docs/feature-requests/subscribable-param-key-bug.md +38 -0
  18. package/docs/feature-requests/todo.md +146 -0
  19. package/docs/for_ai.md +641 -0
  20. package/docs/project-setup.md +432 -0
  21. package/examples/blog.ts +50 -0
  22. package/examples/invalid.ts +18 -0
  23. package/examples/venues.js +485 -0
  24. package/package.json +23 -60
  25. package/src/cli/codegen/client.ts +99 -0
  26. package/src/cli/codegen/manifest.ts +95 -0
  27. package/src/cli/codegen/pinia.ts +174 -0
  28. package/src/cli/codegen/realtime.ts +58 -0
  29. package/src/cli/codegen/sql.ts +698 -0
  30. package/src/cli/codegen/subscribable_sql.ts +547 -0
  31. package/src/cli/codegen/subscribable_store.ts +184 -0
  32. package/src/cli/codegen/types.ts +142 -0
  33. package/src/cli/compiler/analyzer.ts +52 -0
  34. package/src/cli/compiler/graph_rules.ts +251 -0
  35. package/src/cli/compiler/ir.ts +233 -0
  36. package/src/cli/compiler/loader.ts +132 -0
  37. package/src/cli/compiler/permissions.ts +227 -0
  38. package/src/cli/index.ts +164 -0
  39. package/src/client/index.ts +1 -0
  40. package/src/client/ws.ts +286 -0
  41. package/src/create/.env.example +8 -0
  42. package/src/create/README.md +101 -0
  43. package/src/create/compose.yml +14 -0
  44. package/src/create/domain.ts +153 -0
  45. package/src/create/package.json +24 -0
  46. package/src/create/server.ts +18 -0
  47. package/src/create/setup.sh +11 -0
  48. package/src/create/tsconfig.json +15 -0
  49. package/src/runtime/auth.ts +39 -0
  50. package/src/runtime/db.ts +33 -0
  51. package/src/runtime/errors.ts +51 -0
  52. package/src/runtime/index.ts +98 -0
  53. package/src/runtime/js_functions.ts +63 -0
  54. package/src/runtime/manifest_loader.ts +29 -0
  55. package/src/runtime/namespace.ts +483 -0
  56. package/src/runtime/server.ts +87 -0
  57. package/src/runtime/ws.ts +197 -0
  58. package/src/shared/ir.ts +197 -0
  59. package/tests/client.test.ts +38 -0
  60. package/tests/codegen.test.ts +71 -0
  61. package/tests/compiler.test.ts +45 -0
  62. package/tests/graph_rules.test.ts +173 -0
  63. package/tests/integration/db.test.ts +174 -0
  64. package/tests/integration/e2e.test.ts +65 -0
  65. package/tests/integration/features.test.ts +922 -0
  66. package/tests/integration/full_stack.test.ts +262 -0
  67. package/tests/integration/setup.ts +45 -0
  68. package/tests/ir.test.ts +32 -0
  69. package/tests/namespace.test.ts +395 -0
  70. package/tests/permissions.test.ts +55 -0
  71. package/tests/pinia.test.ts +48 -0
  72. package/tests/realtime.test.ts +22 -0
  73. package/tests/runtime.test.ts +80 -0
  74. package/tests/subscribable_gen.test.ts +72 -0
  75. package/tests/subscribable_reactivity.test.ts +258 -0
  76. package/tests/venues_gen.test.ts +25 -0
  77. package/tsconfig.json +20 -0
  78. package/tsconfig.tsbuildinfo +1 -0
  79. package/README.md +0 -90
  80. package/bin/cli.js +0 -727
  81. package/docs/compiler/ADVANCED_FILTERS.md +0 -183
  82. package/docs/compiler/CODING_STANDARDS.md +0 -415
  83. package/docs/compiler/COMPARISON.md +0 -673
  84. package/docs/compiler/QUICKSTART.md +0 -326
  85. package/docs/compiler/README.md +0 -134
  86. package/docs/examples/README.md +0 -38
  87. package/docs/examples/blog.sql +0 -160
  88. package/docs/examples/venue-detail-simple.sql +0 -8
  89. package/docs/examples/venue-detail-subscribable.sql +0 -45
  90. package/docs/for-ai/claude-guide.md +0 -1210
  91. package/docs/getting-started/quickstart.md +0 -125
  92. package/docs/getting-started/subscriptions-quick-start.md +0 -203
  93. package/docs/getting-started/tutorial.md +0 -1104
  94. package/docs/guides/atomic-updates.md +0 -299
  95. package/docs/guides/client-stores.md +0 -730
  96. package/docs/guides/composite-primary-keys.md +0 -158
  97. package/docs/guides/custom-functions.md +0 -362
  98. package/docs/guides/drop-semantics.md +0 -554
  99. package/docs/guides/field-defaults.md +0 -240
  100. package/docs/guides/interpreter-vs-compiler.md +0 -237
  101. package/docs/guides/many-to-many.md +0 -929
  102. package/docs/guides/subscriptions.md +0 -537
  103. package/docs/reference/api.md +0 -1373
  104. package/docs/reference/client.md +0 -224
  105. package/src/client/stores/index.js +0 -8
  106. package/src/client/stores/useAppStore.js +0 -285
  107. package/src/client/stores/useWsStore.js +0 -289
  108. package/src/client/ws.js +0 -762
  109. package/src/compiler/cli/compile-example.js +0 -33
  110. package/src/compiler/cli/compile-subscribable.js +0 -43
  111. package/src/compiler/cli/debug-compile.js +0 -44
  112. package/src/compiler/cli/debug-parse.js +0 -26
  113. package/src/compiler/cli/debug-path-parser.js +0 -18
  114. package/src/compiler/cli/debug-subscribable-parser.js +0 -21
  115. package/src/compiler/cli/index.js +0 -174
  116. package/src/compiler/codegen/auth-codegen.js +0 -153
  117. package/src/compiler/codegen/drop-semantics-codegen.js +0 -553
  118. package/src/compiler/codegen/graph-rules-codegen.js +0 -450
  119. package/src/compiler/codegen/notification-codegen.js +0 -232
  120. package/src/compiler/codegen/operation-codegen.js +0 -1382
  121. package/src/compiler/codegen/permission-codegen.js +0 -318
  122. package/src/compiler/codegen/subscribable-codegen.js +0 -827
  123. package/src/compiler/compiler.js +0 -371
  124. package/src/compiler/index.js +0 -11
  125. package/src/compiler/parser/entity-parser.js +0 -440
  126. package/src/compiler/parser/path-parser.js +0 -290
  127. package/src/compiler/parser/subscribable-parser.js +0 -244
  128. package/src/database/dzql-core.sql +0 -161
  129. package/src/database/migrations/001_schema.sql +0 -60
  130. package/src/database/migrations/002_functions.sql +0 -890
  131. package/src/database/migrations/003_operations.sql +0 -1135
  132. package/src/database/migrations/004_search.sql +0 -581
  133. package/src/database/migrations/005_entities.sql +0 -730
  134. package/src/database/migrations/006_auth.sql +0 -94
  135. package/src/database/migrations/007_events.sql +0 -133
  136. package/src/database/migrations/008_hello.sql +0 -18
  137. package/src/database/migrations/008a_meta.sql +0 -172
  138. package/src/database/migrations/009_subscriptions.sql +0 -240
  139. package/src/database/migrations/010_atomic_updates.sql +0 -157
  140. package/src/database/migrations/010_fix_m2m_events.sql +0 -94
  141. package/src/index.js +0 -40
  142. package/src/server/api.js +0 -9
  143. package/src/server/db.js +0 -442
  144. package/src/server/index.js +0 -317
  145. package/src/server/logger.js +0 -259
  146. package/src/server/mcp.js +0 -594
  147. package/src/server/meta-route.js +0 -251
  148. package/src/server/namespace.js +0 -292
  149. package/src/server/subscriptions.js +0 -351
  150. package/src/server/ws.js +0 -573
@@ -1,224 +0,0 @@
1
- # DZQL Client Quick Start
2
-
3
- **TL;DR:** Copy-paste guide to get a DZQL Vue.js app running in minutes.
4
-
5
- ## 1. Install
6
-
7
- ```bash
8
- npm install dzql pinia vue-router
9
- ```
10
-
11
- ## 2. Copy Template
12
-
13
- Copy the canonical App.vue template:
14
- ```bash
15
- cp node_modules/dzql/src/client/templates/App.vue src/App.vue
16
- ```
17
-
18
- Or create it manually:
19
-
20
- **src/App.vue:**
21
- ```vue
22
- <script setup>
23
- import { computed, onMounted } from 'vue'
24
- import { useWsStore, useAppStore } from 'dzql/client/stores'
25
- import LoginView from './components/LoginView.vue'
26
-
27
- const wsStore = useWsStore()
28
- const appStore = useAppStore()
29
- const state = computed(() => wsStore.appState)
30
- const profile = computed(() => wsStore.profile)
31
-
32
- onMounted(() => {
33
- appStore.initialize({ title: 'My App' })
34
- })
35
- </script>
36
-
37
- <template>
38
- <!-- CONNECTING -->
39
- <div v-if="state === 'connecting'">Connecting...</div>
40
-
41
- <!-- LOGIN -->
42
- <LoginView v-else-if="state === 'login'" />
43
-
44
- <!-- READY -->
45
- <div v-else>
46
- <nav>
47
- <h1>{{ appStore.title }}</h1>
48
- <button @click="wsStore.logout()">Logout</button>
49
- </nav>
50
- <router-view />
51
- </div>
52
- </template>
53
- ```
54
-
55
- ## 3. Create LoginView
56
-
57
- **src/components/LoginView.vue:**
58
- ```vue
59
- <script setup>
60
- import { ref } from 'vue'
61
- import { useWsStore } from 'dzql/client/stores'
62
-
63
- const wsStore = useWsStore()
64
- const email = ref('')
65
- const password = ref('')
66
-
67
- async function login() {
68
- try {
69
- await wsStore.login({ email: email.value, password: password.value })
70
- } catch (err) {
71
- alert(err.message)
72
- }
73
- }
74
- </script>
75
-
76
- <template>
77
- <form @submit.prevent="login">
78
- <input v-model="email" type="email" placeholder="Email" required />
79
- <input v-model="password" type="password" placeholder="Password" required />
80
- <button type="submit">Login</button>
81
- </form>
82
- </template>
83
- ```
84
-
85
- **Registration with options (e.g., organisation name):**
86
- ```vue
87
- <script setup>
88
- import { ref } from 'vue'
89
- import { useWsStore } from 'dzql/client/stores'
90
-
91
- const wsStore = useWsStore()
92
- const email = ref('')
93
- const password = ref('')
94
- const orgName = ref('')
95
-
96
- async function register() {
97
- try {
98
- await wsStore.register({
99
- email: email.value,
100
- password: password.value,
101
- options: { org_name: orgName.value }
102
- })
103
- } catch (err) {
104
- alert(err.message)
105
- }
106
- }
107
- </script>
108
-
109
- <template>
110
- <form @submit.prevent="register">
111
- <input v-model="email" type="email" placeholder="Email" required />
112
- <input v-model="password" type="password" placeholder="Password" required />
113
- <input v-model="orgName" type="text" placeholder="Organisation Name" />
114
- <button type="submit">Register</button>
115
- </form>
116
- </template>
117
- ```
118
-
119
- The `options` parameter allows passing additional JSONB data to the `register_user` and `login_user` PostgreSQL functions. This is useful for:
120
- - Organisation name during registration
121
- - Device ID for login tracking
122
- - Any custom fields your auth functions support
123
-
124
- See [API Reference - Authentication](./api.md#authentication) for details on configuring your PostgreSQL functions.
125
-
126
- ## 4. Setup main.js
127
-
128
- **src/main.js:**
129
- ```javascript
130
- import { createApp } from 'vue'
131
- import { createRouter, createWebHashHistory } from 'vue-router'
132
- import { createPinia } from 'pinia'
133
- import { useAppStore } from 'dzql/client/stores'
134
- import App from './App.vue'
135
-
136
- const pinia = createPinia()
137
-
138
- const router = createRouter({
139
- history: createWebHashHistory(),
140
- routes: [
141
- { path: '/', name: 'home', component: () => import('./views/Home.vue') },
142
- { path: '/:entity', name: 'entity-list', component: () => import('./views/EntityList.vue') },
143
- { path: '/:entity/:id', name: 'entity-detail', component: () => import('./views/EntityDetail.vue') }
144
- ]
145
- })
146
-
147
- const app = createApp(App)
148
- app.use(pinia)
149
- app.use(router)
150
-
151
- const appStore = useAppStore()
152
- appStore.setRouter(router)
153
-
154
- app.mount('#app')
155
- ```
156
-
157
- ## 5. Use DZQL API
158
-
159
- **Any component:**
160
- ```vue
161
- <script setup>
162
- import { ref, onMounted } from 'vue'
163
- import { useWsStore } from 'dzql/client/stores'
164
-
165
- const wsStore = useWsStore()
166
- const ws = wsStore.getWs()
167
- const venues = ref([])
168
-
169
- onMounted(async () => {
170
- const result = await ws.api.search.venues({ limit: 50 })
171
- venues.value = result.data
172
- })
173
-
174
- async function createVenue() {
175
- await ws.api.save.venues({ name: 'New Venue' })
176
- }
177
- </script>
178
-
179
- <template>
180
- <div v-for="venue in venues" :key="venue.id">
181
- {{ venue.name }}
182
- </div>
183
- <button @click="createVenue">Create</button>
184
- </template>
185
- ```
186
-
187
- ## That's It! 🎉
188
-
189
- You now have:
190
- - ✅ WebSocket connection with auto-reconnect
191
- - ✅ Three-phase lifecycle (connecting → login → ready)
192
- - ✅ Authentication (login/logout)
193
- - ✅ Router integration
194
- - ✅ DZQL API access
195
-
196
- ## Next Steps
197
-
198
- - Read [Client Stores Guide](../guides/client-stores.md) for complete API reference
199
- - Customize the App.vue template
200
- - Add your own components
201
- - Style with Tailwind/DaisyUI
202
-
203
- ## Common Issues
204
-
205
- **"Cannot find module 'dzql/client/stores'"**
206
- - Make sure you're using dzql v0.1.6 or later
207
- - Run `npm install dzql@latest`
208
-
209
- **Connection fails**
210
- - Check server is running
211
- - For dev, use explicit URL: `appStore.initialize({ wsUrl: 'ws://localhost:3000/ws' })`
212
-
213
- **Router not working**
214
- - Make sure you call `appStore.setRouter(router)` in main.js
215
-
216
- ## Example Projects
217
-
218
- Check `packages/client` for a complete working example.
219
-
220
- ## Help
221
-
222
- For more help, see:
223
- - [Client Stores Guide](../guides/client-stores.md) - Complete documentation
224
- - [GitHub Issues](https://github.com/blueshed/dzql/issues)
@@ -1,8 +0,0 @@
1
- /**
2
- * DZQL Client Stores
3
- *
4
- * Canonical Pinia stores for DZQL applications
5
- */
6
-
7
- export { useWsStore } from './useWsStore.js'
8
- export { useAppStore } from './useAppStore.js'
@@ -1,285 +0,0 @@
1
- /**
2
- * Canonical DZQL App Pinia Store
3
- *
4
- * Manages application-level state including:
5
- * - App initialization
6
- * - Router integration
7
- * - Global UI state
8
- * - Entity metadata caching
9
- *
10
- * Works with useWsStore to provide complete app lifecycle management.
11
- *
12
- * @example
13
- * // In main.js
14
- * import { createApp } from 'vue'
15
- * import { createPinia } from 'pinia'
16
- * import { useAppStore } from 'dzql/client/stores'
17
- * import App from './App.vue'
18
- *
19
- * const pinia = createPinia()
20
- * const app = createApp(App)
21
- * app.use(pinia)
22
- *
23
- * const appStore = useAppStore()
24
- * await appStore.initialize()
25
- *
26
- * app.mount('#app')
27
- */
28
- import { defineStore } from 'pinia'
29
- import { ref, computed } from 'vue'
30
- import { useWsStore } from './useWsStore.js'
31
-
32
- export const useAppStore = defineStore('dzql-app', () => {
33
- // ===== State =====
34
-
35
- /**
36
- * App title
37
- */
38
- const title = ref('DZQL App')
39
-
40
- /**
41
- * Current route/entity context
42
- */
43
- const currentEntity = ref(null)
44
- const currentId = ref(null)
45
-
46
- /**
47
- * Entity metadata cache
48
- * Maps entity name -> metadata object
49
- */
50
- const entityMetadata = ref({})
51
-
52
- /**
53
- * Loading states
54
- */
55
- const isLoadingMetadata = ref(false)
56
-
57
- /**
58
- * UI state
59
- */
60
- const sidebarOpen = ref(true)
61
- const propertiesPanelOpen = ref(true)
62
-
63
- /**
64
- * Router instance (set via setRouter)
65
- */
66
- let routerInstance = null
67
-
68
- // ===== Computed =====
69
-
70
- const hasMetadata = computed(() => Object.keys(entityMetadata.value).length > 0)
71
-
72
- const entityList = computed(() => {
73
- return Object.keys(entityMetadata.value).sort()
74
- })
75
-
76
- const currentEntityMeta = computed(() => {
77
- if (!currentEntity.value) return null
78
- return entityMetadata.value[currentEntity.value] || null
79
- })
80
-
81
- // ===== Actions =====
82
-
83
- /**
84
- * Initialize the app
85
- *
86
- * Connects to WebSocket and sets up app lifecycle.
87
- *
88
- * @param {Object} options
89
- * @param {string} [options.wsUrl] - WebSocket URL (auto-detected if not provided)
90
- * @param {string} [options.title] - App title
91
- * @returns {Promise<void>}
92
- *
93
- * @example
94
- * await appStore.initialize()
95
- *
96
- * @example
97
- * await appStore.initialize({
98
- * wsUrl: 'ws://localhost:3000/ws',
99
- * title: 'My DZQL App'
100
- * })
101
- */
102
- async function initialize(options = {}) {
103
- const wsStore = useWsStore()
104
-
105
- // Set app title if provided
106
- if (options.title) {
107
- title.value = options.title
108
- }
109
-
110
- // Connect to WebSocket
111
- await wsStore.connect(options.wsUrl)
112
-
113
- // If authenticated, fetch metadata
114
- if (wsStore.isAuthenticated) {
115
- await fetchMetadata()
116
- }
117
-
118
- console.log('[AppStore] Initialized')
119
- }
120
-
121
- /**
122
- * Fetch entity metadata from server
123
- *
124
- * Called automatically after authentication.
125
- *
126
- * @returns {Promise<void>}
127
- */
128
- async function fetchMetadata() {
129
- const wsStore = useWsStore()
130
- const ws = wsStore.getWs()
131
-
132
- if (!wsStore.isConnected) {
133
- console.warn('[AppStore] Cannot fetch metadata: not connected')
134
- return
135
- }
136
-
137
- try {
138
- isLoadingMetadata.value = true
139
-
140
- // Call the meta endpoint
141
- const result = await ws.call('meta')
142
-
143
- if (result && result.entities) {
144
- entityMetadata.value = result.entities
145
- console.log('[AppStore] Metadata loaded:', Object.keys(result.entities))
146
- }
147
-
148
- } catch (err) {
149
- console.error('[AppStore] Failed to fetch metadata:', err)
150
- } finally {
151
- isLoadingMetadata.value = false
152
- }
153
- }
154
-
155
- /**
156
- * Set the router instance
157
- *
158
- * Call this in main.js after creating the router to enable
159
- * programmatic navigation from the store.
160
- *
161
- * @param {Router} router - Vue Router instance
162
- *
163
- * @example
164
- * import { createRouter } from 'vue-router'
165
- * import { useAppStore } from 'dzql/client/stores'
166
- *
167
- * const router = createRouter({ ... })
168
- * const appStore = useAppStore()
169
- * appStore.setRouter(router)
170
- */
171
- function setRouter(router) {
172
- routerInstance = router
173
-
174
- // Watch route changes to update current context
175
- if (router) {
176
- router.afterEach((to) => {
177
- currentEntity.value = to.params.entity || null
178
- currentId.value = to.params.id || null
179
- })
180
- }
181
- }
182
-
183
- /**
184
- * Navigate to entity list
185
- *
186
- * @param {string} entity - Entity name
187
- *
188
- * @example
189
- * appStore.navigateToEntity('venues')
190
- */
191
- function navigateToEntity(entity) {
192
- if (routerInstance) {
193
- routerInstance.push({ name: 'entity-list', params: { entity } })
194
- }
195
- currentEntity.value = entity
196
- currentId.value = null
197
- }
198
-
199
- /**
200
- * Navigate to entity detail/edit
201
- *
202
- * @param {string} entity - Entity name
203
- * @param {number|string} id - Record ID or 'new'
204
- *
205
- * @example
206
- * appStore.navigateToEntityDetail('venues', 123)
207
- * appStore.navigateToEntityDetail('venues', 'new')
208
- */
209
- function navigateToEntityDetail(entity, id) {
210
- if (routerInstance) {
211
- const routeName = id === 'new' ? 'entity-create' : 'entity-edit'
212
- routerInstance.push({ name: routeName, params: { entity, id } })
213
- }
214
- currentEntity.value = entity
215
- currentId.value = id
216
- }
217
-
218
- /**
219
- * Navigate to home
220
- *
221
- * @example
222
- * appStore.navigateToHome()
223
- */
224
- function navigateToHome() {
225
- if (routerInstance) {
226
- routerInstance.push({ name: 'home' })
227
- }
228
- currentEntity.value = null
229
- currentId.value = null
230
- }
231
-
232
- /**
233
- * Toggle sidebar
234
- */
235
- function toggleSidebar() {
236
- sidebarOpen.value = !sidebarOpen.value
237
- }
238
-
239
- /**
240
- * Toggle properties panel
241
- */
242
- function togglePropertiesPanel() {
243
- propertiesPanelOpen.value = !propertiesPanelOpen.value
244
- }
245
-
246
- /**
247
- * Set current context (useful for manual navigation)
248
- *
249
- * @param {string|null} entity - Entity name
250
- * @param {number|string|null} id - Record ID
251
- */
252
- function setContext(entity, id = null) {
253
- currentEntity.value = entity
254
- currentId.value = id
255
- }
256
-
257
- // ===== Return Public API =====
258
-
259
- return {
260
- // State
261
- title,
262
- currentEntity,
263
- currentId,
264
- entityMetadata,
265
- isLoadingMetadata,
266
- sidebarOpen,
267
- propertiesPanelOpen,
268
-
269
- // Computed
270
- hasMetadata,
271
- entityList,
272
- currentEntityMeta,
273
-
274
- // Actions
275
- initialize,
276
- fetchMetadata,
277
- setRouter,
278
- navigateToEntity,
279
- navigateToEntityDetail,
280
- navigateToHome,
281
- toggleSidebar,
282
- togglePropertiesPanel,
283
- setContext
284
- }
285
- })