dzql 0.5.33 → 0.6.1

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 (142) 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 +309 -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 +653 -0
  20. package/docs/project-setup.md +456 -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 +166 -0
  39. package/src/client/index.ts +1 -0
  40. package/src/client/ws.ts +286 -0
  41. package/src/runtime/auth.ts +39 -0
  42. package/src/runtime/db.ts +33 -0
  43. package/src/runtime/errors.ts +51 -0
  44. package/src/runtime/index.ts +98 -0
  45. package/src/runtime/js_functions.ts +63 -0
  46. package/src/runtime/manifest_loader.ts +29 -0
  47. package/src/runtime/namespace.ts +483 -0
  48. package/src/runtime/server.ts +87 -0
  49. package/src/runtime/ws.ts +197 -0
  50. package/src/shared/ir.ts +197 -0
  51. package/tests/client.test.ts +38 -0
  52. package/tests/codegen.test.ts +71 -0
  53. package/tests/compiler.test.ts +45 -0
  54. package/tests/graph_rules.test.ts +173 -0
  55. package/tests/integration/db.test.ts +174 -0
  56. package/tests/integration/e2e.test.ts +65 -0
  57. package/tests/integration/features.test.ts +922 -0
  58. package/tests/integration/full_stack.test.ts +262 -0
  59. package/tests/integration/setup.ts +45 -0
  60. package/tests/ir.test.ts +32 -0
  61. package/tests/namespace.test.ts +395 -0
  62. package/tests/permissions.test.ts +55 -0
  63. package/tests/pinia.test.ts +48 -0
  64. package/tests/realtime.test.ts +22 -0
  65. package/tests/runtime.test.ts +80 -0
  66. package/tests/subscribable_gen.test.ts +72 -0
  67. package/tests/subscribable_reactivity.test.ts +258 -0
  68. package/tests/venues_gen.test.ts +25 -0
  69. package/tsconfig.json +20 -0
  70. package/tsconfig.tsbuildinfo +1 -0
  71. package/README.md +0 -90
  72. package/bin/cli.js +0 -727
  73. package/docs/compiler/ADVANCED_FILTERS.md +0 -183
  74. package/docs/compiler/CODING_STANDARDS.md +0 -415
  75. package/docs/compiler/COMPARISON.md +0 -673
  76. package/docs/compiler/QUICKSTART.md +0 -326
  77. package/docs/compiler/README.md +0 -134
  78. package/docs/examples/README.md +0 -38
  79. package/docs/examples/blog.sql +0 -160
  80. package/docs/examples/venue-detail-simple.sql +0 -8
  81. package/docs/examples/venue-detail-subscribable.sql +0 -45
  82. package/docs/for-ai/claude-guide.md +0 -1210
  83. package/docs/getting-started/quickstart.md +0 -125
  84. package/docs/getting-started/subscriptions-quick-start.md +0 -203
  85. package/docs/getting-started/tutorial.md +0 -1104
  86. package/docs/guides/atomic-updates.md +0 -299
  87. package/docs/guides/client-stores.md +0 -730
  88. package/docs/guides/composite-primary-keys.md +0 -158
  89. package/docs/guides/custom-functions.md +0 -362
  90. package/docs/guides/drop-semantics.md +0 -554
  91. package/docs/guides/field-defaults.md +0 -240
  92. package/docs/guides/interpreter-vs-compiler.md +0 -237
  93. package/docs/guides/many-to-many.md +0 -929
  94. package/docs/guides/subscriptions.md +0 -537
  95. package/docs/reference/api.md +0 -1373
  96. package/docs/reference/client.md +0 -224
  97. package/src/client/stores/index.js +0 -8
  98. package/src/client/stores/useAppStore.js +0 -285
  99. package/src/client/stores/useWsStore.js +0 -289
  100. package/src/client/ws.js +0 -762
  101. package/src/compiler/cli/compile-example.js +0 -33
  102. package/src/compiler/cli/compile-subscribable.js +0 -43
  103. package/src/compiler/cli/debug-compile.js +0 -44
  104. package/src/compiler/cli/debug-parse.js +0 -26
  105. package/src/compiler/cli/debug-path-parser.js +0 -18
  106. package/src/compiler/cli/debug-subscribable-parser.js +0 -21
  107. package/src/compiler/cli/index.js +0 -174
  108. package/src/compiler/codegen/auth-codegen.js +0 -153
  109. package/src/compiler/codegen/drop-semantics-codegen.js +0 -553
  110. package/src/compiler/codegen/graph-rules-codegen.js +0 -450
  111. package/src/compiler/codegen/notification-codegen.js +0 -232
  112. package/src/compiler/codegen/operation-codegen.js +0 -1382
  113. package/src/compiler/codegen/permission-codegen.js +0 -318
  114. package/src/compiler/codegen/subscribable-codegen.js +0 -827
  115. package/src/compiler/compiler.js +0 -371
  116. package/src/compiler/index.js +0 -11
  117. package/src/compiler/parser/entity-parser.js +0 -440
  118. package/src/compiler/parser/path-parser.js +0 -290
  119. package/src/compiler/parser/subscribable-parser.js +0 -244
  120. package/src/database/dzql-core.sql +0 -161
  121. package/src/database/migrations/001_schema.sql +0 -60
  122. package/src/database/migrations/002_functions.sql +0 -890
  123. package/src/database/migrations/003_operations.sql +0 -1135
  124. package/src/database/migrations/004_search.sql +0 -581
  125. package/src/database/migrations/005_entities.sql +0 -730
  126. package/src/database/migrations/006_auth.sql +0 -94
  127. package/src/database/migrations/007_events.sql +0 -133
  128. package/src/database/migrations/008_hello.sql +0 -18
  129. package/src/database/migrations/008a_meta.sql +0 -172
  130. package/src/database/migrations/009_subscriptions.sql +0 -240
  131. package/src/database/migrations/010_atomic_updates.sql +0 -157
  132. package/src/database/migrations/010_fix_m2m_events.sql +0 -94
  133. package/src/index.js +0 -40
  134. package/src/server/api.js +0 -9
  135. package/src/server/db.js +0 -442
  136. package/src/server/index.js +0 -317
  137. package/src/server/logger.js +0 -259
  138. package/src/server/mcp.js +0 -594
  139. package/src/server/meta-route.js +0 -251
  140. package/src/server/namespace.js +0 -292
  141. package/src/server/subscriptions.js +0 -351
  142. 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
- })