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,351 +0,0 @@
1
- /**
2
- * Subscription Manager for Live Query Subscriptions
3
- * Manages in-memory subscription registry and matching
4
- */
5
-
6
- import crypto from 'crypto';
7
- import { wsLogger } from './logger.js';
8
-
9
- /**
10
- * In-memory subscription registry
11
- * Structure: subscription_id -> { subscribable, user_id, connection_id, params }
12
- */
13
- const subscriptions = new Map();
14
-
15
- /**
16
- * Track subscriptions by connection for cleanup
17
- * Structure: connection_id -> Set<subscription_id>
18
- */
19
- const connectionSubscriptions = new Map();
20
-
21
- /**
22
- * Cache for subscribable metadata (scope tables, path mappings)
23
- * Structure: subscribable_name -> { scopeTables, pathMapping, rootEntity, relations }
24
- */
25
- const subscribableMetadataCache = new Map();
26
-
27
- /**
28
- * Register a new subscription
29
- * @param {string} subscribableName - Name of the subscribable
30
- * @param {number} userId - User ID
31
- * @param {string} connectionId - WebSocket connection ID
32
- * @param {object} params - Subscription parameters
33
- * @returns {string} - Subscription ID
34
- */
35
- export function registerSubscription(subscribableName, userId, connectionId, params) {
36
- const subscriptionId = crypto.randomUUID();
37
-
38
- // Store subscription
39
- subscriptions.set(subscriptionId, {
40
- subscribable: subscribableName,
41
- user_id: userId,
42
- connection_id: connectionId,
43
- params,
44
- created_at: new Date()
45
- });
46
-
47
- // Track by connection
48
- if (!connectionSubscriptions.has(connectionId)) {
49
- connectionSubscriptions.set(connectionId, new Set());
50
- }
51
- connectionSubscriptions.get(connectionId).add(subscriptionId);
52
-
53
- wsLogger.debug(`Subscription registered: ${subscriptionId.slice(0, 8)}... (${subscribableName})`, {
54
- user_id: userId,
55
- params
56
- });
57
-
58
- return subscriptionId;
59
- }
60
-
61
- /**
62
- * Unregister a subscription
63
- * @param {string} subscriptionId - Subscription ID to remove
64
- * @returns {boolean} - True if subscription was found and removed
65
- */
66
- export function unregisterSubscription(subscriptionId) {
67
- const sub = subscriptions.get(subscriptionId);
68
-
69
- if (!sub) {
70
- wsLogger.debug(`Subscription not found: ${subscriptionId}`);
71
- return false;
72
- }
73
-
74
- // Remove from connection tracking
75
- const connSubs = connectionSubscriptions.get(sub.connection_id);
76
- if (connSubs) {
77
- connSubs.delete(subscriptionId);
78
- if (connSubs.size === 0) {
79
- connectionSubscriptions.delete(sub.connection_id);
80
- }
81
- }
82
-
83
- // Remove subscription
84
- subscriptions.delete(subscriptionId);
85
-
86
- wsLogger.debug(`Subscription removed: ${subscriptionId.slice(0, 8)}...`);
87
- return true;
88
- }
89
-
90
- /**
91
- * Unregister subscription by params
92
- * Useful for unsubscribe_* methods that specify params instead of subscription ID
93
- * @param {string} subscribableName - Name of the subscribable
94
- * @param {string} connectionId - WebSocket connection ID
95
- * @param {object} params - Subscription parameters to match
96
- * @returns {boolean} - True if subscription was found and removed
97
- */
98
- export function unregisterSubscriptionByParams(subscribableName, connectionId, params) {
99
- const paramsStr = JSON.stringify(params);
100
-
101
- // Find matching subscription
102
- for (const [subId, sub] of subscriptions.entries()) {
103
- if (
104
- sub.subscribable === subscribableName &&
105
- sub.connection_id === connectionId &&
106
- JSON.stringify(sub.params) === paramsStr
107
- ) {
108
- return unregisterSubscription(subId);
109
- }
110
- }
111
-
112
- wsLogger.debug(`No matching subscription found for ${subscribableName} with params`, params);
113
- return false;
114
- }
115
-
116
- /**
117
- * Remove all subscriptions for a connection
118
- * Called when WebSocket connection closes
119
- * @param {string} connectionId - Connection ID
120
- * @returns {number} - Number of subscriptions removed
121
- */
122
- export function removeConnectionSubscriptions(connectionId) {
123
- const subIds = connectionSubscriptions.get(connectionId);
124
-
125
- if (!subIds) {
126
- return 0;
127
- }
128
-
129
- let count = 0;
130
- for (const subId of subIds) {
131
- if (subscriptions.delete(subId)) {
132
- count++;
133
- }
134
- }
135
-
136
- connectionSubscriptions.delete(connectionId);
137
-
138
- if (count > 0) {
139
- wsLogger.info(`Removed ${count} subscription(s) for connection ${connectionId.slice(0, 8)}...`);
140
- }
141
-
142
- return count;
143
- }
144
-
145
- /**
146
- * Get all subscriptions for a specific subscribable
147
- * @param {string} subscribableName - Name of the subscribable
148
- * @returns {Array} - Array of {subscriptionId, subscription} objects
149
- */
150
- export function getSubscriptionsByName(subscribableName) {
151
- const result = [];
152
-
153
- for (const [subId, sub] of subscriptions.entries()) {
154
- if (sub.subscribable === subscribableName) {
155
- result.push({ subscriptionId: subId, ...sub });
156
- }
157
- }
158
-
159
- return result;
160
- }
161
-
162
- /**
163
- * Get all subscriptions grouped by subscribable name
164
- * @returns {Map<string, Array>} - Map of subscribable name to array of subscriptions
165
- */
166
- export function getSubscriptionsBySubscribable() {
167
- const grouped = new Map();
168
-
169
- for (const [subId, sub] of subscriptions.entries()) {
170
- if (!grouped.has(sub.subscribable)) {
171
- grouped.set(sub.subscribable, []);
172
- }
173
- grouped.get(sub.subscribable).push({ subscriptionId: subId, ...sub });
174
- }
175
-
176
- return grouped;
177
- }
178
-
179
- /**
180
- * Check if params match (deep equality)
181
- * @param {object} a - First params object
182
- * @param {object} b - Second params object
183
- * @returns {boolean} - True if params match
184
- */
185
- export function paramsMatch(a, b) {
186
- return JSON.stringify(a) === JSON.stringify(b);
187
- }
188
-
189
- /**
190
- * Get subscription statistics
191
- * @returns {object} - Stats object
192
- */
193
- export function getStats() {
194
- return {
195
- total_subscriptions: subscriptions.size,
196
- active_connections: connectionSubscriptions.size,
197
- subscriptions_by_subscribable: Array.from(getSubscriptionsBySubscribable().entries()).map(
198
- ([name, subs]) => ({
199
- name,
200
- count: subs.length
201
- })
202
- )
203
- };
204
- }
205
-
206
- /**
207
- * Get all active subscriptions (for debugging)
208
- * @returns {Array} - Array of all subscriptions
209
- */
210
- export function getAllSubscriptions() {
211
- return Array.from(subscriptions.entries()).map(([id, sub]) => ({
212
- id,
213
- ...sub
214
- }));
215
- }
216
-
217
- /**
218
- * Get subscribable metadata (scope tables, path mapping) with caching
219
- * @param {string} subscribableName - Name of the subscribable
220
- * @param {function} sql - Database query function
221
- * @returns {Promise<{scopeTables: string[], pathMapping: object, rootEntity: string, relations: object}>}
222
- */
223
- export async function getSubscribableMetadata(subscribableName, sql) {
224
- // Check cache first (compiled mode populates this from embedded schema)
225
- if (subscribableMetadataCache.has(subscribableName)) {
226
- return subscribableMetadataCache.get(subscribableName);
227
- }
228
-
229
- // Interpreted mode: fetch from database table
230
- try {
231
- const result = await sql`
232
- SELECT scope_tables, root_entity, relations
233
- FROM dzql.subscribables
234
- WHERE name = ${subscribableName}
235
- `;
236
-
237
- if (result && result.length > 0) {
238
- const { scope_tables, root_entity, relations } = result[0];
239
-
240
- // Build path mapping from relations
241
- const pathMapping = buildPathMappingFromRelations(root_entity, relations);
242
-
243
- const metadata = {
244
- scopeTables: scope_tables || [],
245
- pathMapping,
246
- rootEntity: root_entity,
247
- relations: relations || {}
248
- };
249
-
250
- // Cache for future use
251
- subscribableMetadataCache.set(subscribableName, metadata);
252
-
253
- wsLogger.debug(`Cached metadata for subscribable ${subscribableName}:`, {
254
- scopeTables: metadata.scopeTables,
255
- pathMapping: metadata.pathMapping
256
- });
257
-
258
- return metadata;
259
- }
260
- } catch (e) {
261
- // Table doesn't exist or query failed
262
- wsLogger.debug(`Failed to fetch metadata for ${subscribableName}: ${e.message}`);
263
- }
264
-
265
- // Return empty metadata if nothing found (compiled mode without prior subscribe)
266
- const emptyMetadata = {
267
- scopeTables: [],
268
- pathMapping: {},
269
- rootEntity: null,
270
- relations: {}
271
- };
272
- return emptyMetadata;
273
- }
274
-
275
- /**
276
- * Build path mapping from relations configuration
277
- * Maps table names to their document path for client-side patching
278
- * @param {string} rootEntity - Root table name
279
- * @param {object} relations - Relations configuration
280
- * @returns {object} - Map of table name -> document path
281
- */
282
- function buildPathMappingFromRelations(rootEntity, relations) {
283
- const paths = {};
284
-
285
- // Root entity maps to top level
286
- if (rootEntity) {
287
- paths[rootEntity] = '.';
288
- }
289
-
290
- const buildPaths = (rels, parentPath = '') => {
291
- for (const [relName, relConfig] of Object.entries(rels || {})) {
292
- const entity = typeof relConfig === 'string' ? relConfig : relConfig?.entity;
293
- const currentPath = parentPath ? `${parentPath}.${relName}` : relName;
294
-
295
- if (entity) {
296
- paths[entity] = currentPath;
297
- }
298
-
299
- // Handle nested relations
300
- if (typeof relConfig === 'object' && relConfig !== null) {
301
- if (relConfig.include) {
302
- buildPaths(relConfig.include, currentPath);
303
- }
304
- if (relConfig.relations) {
305
- buildPaths(relConfig.relations, currentPath);
306
- }
307
- }
308
- }
309
- };
310
-
311
- buildPaths(relations);
312
- return paths;
313
- }
314
-
315
- /**
316
- * Clear the subscribable metadata cache
317
- * Called when subscribables are reregistered or updated
318
- * @param {string} [subscribableName] - Optional: clear specific subscribable, or all if not provided
319
- */
320
- export function clearSubscribableMetadataCache(subscribableName = null) {
321
- if (subscribableName) {
322
- subscribableMetadataCache.delete(subscribableName);
323
- wsLogger.debug(`Cleared metadata cache for ${subscribableName}`);
324
- } else {
325
- subscribableMetadataCache.clear();
326
- wsLogger.debug('Cleared all subscribable metadata cache');
327
- }
328
- }
329
-
330
- /**
331
- * Cache subscribable metadata (used by compiled mode to store embedded schema)
332
- * @param {string} subscribableName - Name of the subscribable
333
- * @param {object} metadata - Metadata to cache
334
- */
335
- export function cacheSubscribableMetadata(subscribableName, metadata) {
336
- subscribableMetadataCache.set(subscribableName, metadata);
337
- wsLogger.debug(`Cached compiled metadata for ${subscribableName}:`, {
338
- scopeTables: metadata.scopeTables
339
- });
340
- }
341
-
342
- /**
343
- * Get scope tables for a subscribable (convenience function)
344
- * @param {string} subscribableName - Name of the subscribable
345
- * @param {function} sql - Database query function
346
- * @returns {Promise<string[]>} - Array of table names in scope
347
- */
348
- export async function getSubscribableScopeTables(subscribableName, sql) {
349
- const metadata = await getSubscribableMetadata(subscribableName, sql);
350
- return metadata.scopeTables;
351
- }