@vertz/ui 0.2.12 → 0.2.13

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 (35) hide show
  1. package/README.md +70 -6
  2. package/dist/shared/{chunk-bjcpcq5j.js → chunk-2sth83bd.js} +1 -1
  3. package/dist/shared/{chunk-9e92w0wt.js → chunk-83g4h38e.js} +13 -0
  4. package/dist/shared/{chunk-2rs8a26p.js → chunk-8hsz5y4a.js} +92 -33
  5. package/dist/shared/{chunk-55tgkc7s.js → chunk-c30eg6wn.js} +1 -1
  6. package/dist/shared/{chunk-kg898f92.js → chunk-c9xxsrat.js} +7 -2
  7. package/dist/shared/{chunk-wn4gv1qd.js → chunk-dksg08fq.js} +1 -1
  8. package/dist/shared/{chunk-g4rch80a.js → chunk-h89w580h.js} +7 -0
  9. package/dist/shared/chunk-hw67ckr3.js +1212 -0
  10. package/dist/shared/{chunk-662f9zrb.js → chunk-j6qyxfdc.js} +7 -7
  11. package/dist/shared/{chunk-g1gf16fz.js → chunk-mj7b4t40.js} +107 -41
  12. package/dist/shared/{chunk-18jzqefd.js → chunk-nn9v1zmk.js} +4 -4
  13. package/dist/src/auth/public.d.ts +303 -0
  14. package/dist/src/auth/public.js +773 -0
  15. package/dist/src/css/public.js +22 -0
  16. package/dist/{form → src/form}/public.js +2 -2
  17. package/dist/{index.d.ts → src/index.d.ts} +218 -14
  18. package/dist/{index.js → src/index.js} +79 -229
  19. package/dist/{internals.d.ts → src/internals.d.ts} +265 -3
  20. package/dist/{internals.js → src/internals.js} +18 -10
  21. package/dist/{jsx-runtime → src/jsx-runtime}/index.js +1 -1
  22. package/dist/{query → src/query}/public.d.ts +3 -1
  23. package/dist/src/query/public.js +15 -0
  24. package/dist/{router → src/router}/public.d.ts +25 -4
  25. package/dist/{router → src/router}/public.js +9 -9
  26. package/dist/{test → src/test}/index.d.ts +12 -2
  27. package/dist/{test → src/test}/index.js +4 -4
  28. package/package.json +31 -25
  29. package/reactivity.json +67 -0
  30. package/dist/css/public.js +0 -22
  31. package/dist/query/public.js +0 -15
  32. package/dist/shared/chunk-9k2z3jfx.js +0 -528
  33. /package/dist/{css → src/css}/public.d.ts +0 -0
  34. /package/dist/{form → src/form}/public.d.ts +0 -0
  35. /package/dist/{jsx-runtime → src/jsx-runtime}/index.d.ts +0 -0
@@ -0,0 +1,1212 @@
1
+ import {
2
+ isNavPrefetchActive
3
+ } from "./chunk-jrtrk5z4.js";
4
+ import {
5
+ getAdapter,
6
+ isRenderNode
7
+ } from "./chunk-h89w580h.js";
8
+ import {
9
+ _tryOnCleanup,
10
+ batch,
11
+ computed,
12
+ domEffect,
13
+ getSSRContext,
14
+ lifecycleEffect,
15
+ popScope,
16
+ pushScope,
17
+ runCleanups,
18
+ setReadValueCallback,
19
+ signal,
20
+ untrack
21
+ } from "./chunk-8hsz5y4a.js";
22
+
23
+ // src/query/cache.ts
24
+ class MemoryCache {
25
+ _store = new Map;
26
+ get(key) {
27
+ return this._store.get(key);
28
+ }
29
+ set(key, value) {
30
+ this._store.set(key, value);
31
+ }
32
+ delete(key) {
33
+ this._store.delete(key);
34
+ }
35
+ clear() {
36
+ this._store.clear();
37
+ }
38
+ }
39
+
40
+ // src/query/invalidate.ts
41
+ var registry = new Set;
42
+ function registerActiveQuery(entityMeta, refetch) {
43
+ const registration = { entityMeta, refetch };
44
+ registry.add(registration);
45
+ return () => registry.delete(registration);
46
+ }
47
+ function invalidate(descriptor) {
48
+ const meta = descriptor._entity;
49
+ if (!meta)
50
+ return;
51
+ if (meta.kind === "get" && !meta.id)
52
+ return;
53
+ for (const reg of [...registry]) {
54
+ if (reg.entityMeta.entityType !== meta.entityType)
55
+ continue;
56
+ if (reg.entityMeta.kind !== meta.kind)
57
+ continue;
58
+ if (meta.kind === "get" && reg.entityMeta.id !== meta.id)
59
+ continue;
60
+ reg.refetch();
61
+ }
62
+ }
63
+
64
+ // src/query/key-derivation.ts
65
+ function deriveKey(thunk) {
66
+ return `__q:${hashString(thunk.toString())}`;
67
+ }
68
+ function hashString(str) {
69
+ let hash = 5381;
70
+ for (let i = 0;i < str.length; i++) {
71
+ hash = hash * 33 ^ str.charCodeAt(i);
72
+ }
73
+ return (hash >>> 0).toString(36);
74
+ }
75
+
76
+ // src/store/relation-registry.ts
77
+ var registry2 = new Map;
78
+ function registerRelationSchema(entityType, schema) {
79
+ registry2.set(entityType, Object.freeze(schema));
80
+ }
81
+ function getRelationSchema(entityType) {
82
+ return registry2.get(entityType);
83
+ }
84
+ function resetRelationSchemas_TEST_ONLY() {
85
+ registry2.clear();
86
+ }
87
+
88
+ // src/store/merge.ts
89
+ function shallowMerge(existing, incoming) {
90
+ const result = { ...existing };
91
+ for (const key of Object.keys(incoming)) {
92
+ const value = incoming[key];
93
+ if (value !== undefined) {
94
+ result[key] = value;
95
+ }
96
+ }
97
+ return result;
98
+ }
99
+ function shallowEqual(a, b) {
100
+ const keysA = Object.keys(a);
101
+ const keysB = Object.keys(b);
102
+ if (keysA.length !== keysB.length) {
103
+ return false;
104
+ }
105
+ for (const key of keysA) {
106
+ const valA = a[key];
107
+ const valB = b[key];
108
+ if (valA !== valB) {
109
+ if (Array.isArray(valA) && Array.isArray(valB)) {
110
+ if (valA.length !== valB.length)
111
+ return false;
112
+ for (let i = 0;i < valA.length; i++) {
113
+ if (valA[i] !== valB[i])
114
+ return false;
115
+ }
116
+ continue;
117
+ }
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+
124
+ // src/store/normalize.ts
125
+ function normalizeEntity(entityType, data, visiting) {
126
+ const schema = getRelationSchema(entityType);
127
+ if (!schema) {
128
+ return { normalized: data, extracted: new Map };
129
+ }
130
+ const extracted = new Map;
131
+ const normalized = { ...data };
132
+ const visitKey = `${entityType}/${data.id}`;
133
+ const visit = visiting ?? new Set;
134
+ if (visit.has(visitKey)) {
135
+ return { normalized: data, extracted };
136
+ }
137
+ visit.add(visitKey);
138
+ for (const [field, rel] of Object.entries(schema)) {
139
+ const value = data[field];
140
+ if (value == null)
141
+ continue;
142
+ if (rel.type === "one") {
143
+ if (typeof value === "string")
144
+ continue;
145
+ if (typeof value !== "object" || Array.isArray(value)) {
146
+ console.warn(`[vertz] ${entityType}.${field}: expected object or string for 'one' relation, got ${typeof value}`);
147
+ continue;
148
+ }
149
+ if (typeof value === "object" && !Array.isArray(value)) {
150
+ const nested = value;
151
+ if (typeof nested.id !== "string")
152
+ continue;
153
+ const nestedVisitKey = `${rel.entity}/${nested.id}`;
154
+ if (visit.has(nestedVisitKey)) {
155
+ normalized[field] = nested.id;
156
+ continue;
157
+ }
158
+ const nestedResult = normalizeEntity(rel.entity, nested, visit);
159
+ const list = extracted.get(rel.entity) ?? [];
160
+ list.push(nestedResult.normalized);
161
+ extracted.set(rel.entity, list);
162
+ for (const [type, items] of nestedResult.extracted) {
163
+ const existing = extracted.get(type) ?? [];
164
+ existing.push(...items);
165
+ extracted.set(type, existing);
166
+ }
167
+ normalized[field] = nested.id;
168
+ }
169
+ } else if (rel.type === "many") {
170
+ if (!Array.isArray(value)) {
171
+ console.warn(`[vertz] ${entityType}.${field}: expected array for 'many' relation, got ${typeof value}`);
172
+ continue;
173
+ }
174
+ const ids = [];
175
+ for (const element of value) {
176
+ if (typeof element === "string") {
177
+ ids.push(element);
178
+ } else if (typeof element === "object" && element != null && typeof element.id === "string") {
179
+ const nested = element;
180
+ const nestedVisitKey = `${rel.entity}/${nested.id}`;
181
+ if (visit.has(nestedVisitKey)) {
182
+ ids.push(nested.id);
183
+ continue;
184
+ }
185
+ const nestedResult = normalizeEntity(rel.entity, nested, visit);
186
+ const list = extracted.get(rel.entity) ?? [];
187
+ list.push(nestedResult.normalized);
188
+ extracted.set(rel.entity, list);
189
+ for (const [type, items] of nestedResult.extracted) {
190
+ const existing = extracted.get(type) ?? [];
191
+ existing.push(...items);
192
+ extracted.set(type, existing);
193
+ }
194
+ ids.push(nested.id);
195
+ } else {
196
+ ids.push(element);
197
+ }
198
+ }
199
+ normalized[field] = ids;
200
+ }
201
+ }
202
+ return { normalized, extracted };
203
+ }
204
+
205
+ // src/store/query-result-index.ts
206
+ class QueryResultIndex {
207
+ _indices = new Map;
208
+ set(queryKey, ids) {
209
+ this._indices.set(queryKey, ids);
210
+ }
211
+ get(queryKey) {
212
+ return this._indices.get(queryKey);
213
+ }
214
+ removeEntity(entityId) {
215
+ for (const [queryKey, ids] of this._indices.entries()) {
216
+ const filtered = ids.filter((id) => id !== entityId);
217
+ if (filtered.length !== ids.length) {
218
+ this._indices.set(queryKey, filtered);
219
+ }
220
+ }
221
+ }
222
+ clear(queryKey) {
223
+ this._indices.delete(queryKey);
224
+ }
225
+ snapshotEntity(entityId) {
226
+ const result = new Map;
227
+ for (const [queryKey, ids] of this._indices.entries()) {
228
+ if (ids.includes(entityId)) {
229
+ result.set(queryKey, [...ids]);
230
+ }
231
+ }
232
+ return result;
233
+ }
234
+ keys() {
235
+ return Array.from(this._indices.keys());
236
+ }
237
+ }
238
+
239
+ // src/store/entity-store.ts
240
+ class EntityStore {
241
+ _entities = new Map;
242
+ _typeListeners = new Map;
243
+ _queryIndices = new QueryResultIndex;
244
+ get queryIndices() {
245
+ return this._queryIndices;
246
+ }
247
+ constructor(options) {
248
+ if (options?.initialData) {
249
+ this.hydrate(options.initialData);
250
+ }
251
+ }
252
+ get(type, id) {
253
+ const typeMap = this._entities.get(type);
254
+ const entry = typeMap?.get(id);
255
+ if (entry) {
256
+ return entry.signal;
257
+ }
258
+ const sig = signal(undefined);
259
+ const newEntry = {
260
+ signal: sig,
261
+ base: {},
262
+ layers: new Map,
263
+ refCount: 0,
264
+ orphanedAt: null
265
+ };
266
+ this._getOrCreateTypeMap(type).set(id, newEntry);
267
+ return sig;
268
+ }
269
+ getMany(type, ids) {
270
+ return computed(() => ids.map((id) => this.get(type, id).value));
271
+ }
272
+ merge(type, data) {
273
+ const items = Array.isArray(data) ? data : [data];
274
+ if (items.length === 0) {
275
+ return;
276
+ }
277
+ batch(() => {
278
+ for (const item of items) {
279
+ const { normalized, extracted } = normalizeEntity(type, item);
280
+ for (const [nestedType, nestedItems] of extracted) {
281
+ for (const nestedItem of nestedItems) {
282
+ this._mergeOne(nestedType, nestedItem);
283
+ }
284
+ }
285
+ this._mergeOne(type, normalized);
286
+ }
287
+ });
288
+ }
289
+ remove(type, id) {
290
+ const typeMap = this._entities.get(type);
291
+ if (!typeMap?.has(id)) {
292
+ return;
293
+ }
294
+ const entry = typeMap.get(id);
295
+ if (entry) {
296
+ entry.signal.value = undefined;
297
+ }
298
+ typeMap.delete(id);
299
+ this._queryIndices.removeEntity(id);
300
+ this._notifyTypeChange(type);
301
+ }
302
+ onTypeChange(type, callback) {
303
+ const listeners = this._getOrCreateListeners(type);
304
+ listeners.add(callback);
305
+ return () => {
306
+ listeners.delete(callback);
307
+ };
308
+ }
309
+ has(type, id) {
310
+ const typeMap = this._entities.get(type);
311
+ if (!typeMap?.has(id)) {
312
+ return false;
313
+ }
314
+ const entry = typeMap.get(id);
315
+ return entry?.signal.peek() !== undefined;
316
+ }
317
+ size(type) {
318
+ const typeMap = this._entities.get(type);
319
+ if (!typeMap) {
320
+ return 0;
321
+ }
322
+ let count = 0;
323
+ for (const entry of typeMap.values()) {
324
+ if (entry.signal.peek() !== undefined) {
325
+ count++;
326
+ }
327
+ }
328
+ return count;
329
+ }
330
+ dehydrate() {
331
+ const entities = {};
332
+ for (const [type, typeMap] of this._entities.entries()) {
333
+ const typeEntities = {};
334
+ for (const [id, entry] of typeMap.entries()) {
335
+ if (entry.base !== undefined) {
336
+ typeEntities[id] = entry.base;
337
+ }
338
+ }
339
+ if (Object.keys(typeEntities).length > 0) {
340
+ entities[type] = typeEntities;
341
+ }
342
+ }
343
+ const queries = {};
344
+ for (const queryKey of this._queryIndices.keys()) {
345
+ const ids = this._queryIndices.get(queryKey);
346
+ if (ids) {
347
+ queries[queryKey] = { ids };
348
+ }
349
+ }
350
+ return {
351
+ entities,
352
+ ...Object.keys(queries).length > 0 ? { queries } : {}
353
+ };
354
+ }
355
+ hydrate(data) {
356
+ for (const [type, typeEntities] of Object.entries(data.entities)) {
357
+ const entities = Object.values(typeEntities).map((entity) => entity);
358
+ this.merge(type, entities);
359
+ }
360
+ if (data.queries) {
361
+ for (const [queryKey, queryData] of Object.entries(data.queries)) {
362
+ this._queryIndices.set(queryKey, queryData.ids);
363
+ }
364
+ }
365
+ }
366
+ applyLayer(type, id, mutationId, patch) {
367
+ const entry = this._entities.get(type)?.get(id);
368
+ if (!entry)
369
+ return;
370
+ entry.layers.set(mutationId, patch);
371
+ this._recomputeVisible(entry);
372
+ }
373
+ addRef(type, id) {
374
+ const entry = this._entities.get(type)?.get(id);
375
+ if (!entry)
376
+ return;
377
+ entry.refCount++;
378
+ entry.orphanedAt = null;
379
+ }
380
+ removeRef(type, id) {
381
+ const entry = this._entities.get(type)?.get(id);
382
+ if (!entry)
383
+ return;
384
+ if (entry.refCount > 0) {
385
+ entry.refCount--;
386
+ }
387
+ if (entry.refCount === 0) {
388
+ entry.orphanedAt = Date.now();
389
+ }
390
+ }
391
+ evictOrphans(maxAge = 300000) {
392
+ const now = Date.now();
393
+ let count = 0;
394
+ for (const [_type, typeMap] of this._entities) {
395
+ for (const [id, entry] of typeMap) {
396
+ if (entry.refCount === 0 && entry.orphanedAt !== null && now - entry.orphanedAt >= maxAge && entry.layers.size === 0) {
397
+ entry.signal.value = undefined;
398
+ typeMap.delete(id);
399
+ this._queryIndices.removeEntity(id);
400
+ count++;
401
+ }
402
+ }
403
+ }
404
+ return count;
405
+ }
406
+ inspect(type, id) {
407
+ const entry = this._entities.get(type)?.get(id);
408
+ if (!entry)
409
+ return;
410
+ return {
411
+ base: entry.base,
412
+ layers: entry.layers,
413
+ visible: entry.signal.peek(),
414
+ refCount: entry.refCount,
415
+ orphanedAt: entry.orphanedAt
416
+ };
417
+ }
418
+ rollbackLayer(type, id, mutationId) {
419
+ const entry = this._entities.get(type)?.get(id);
420
+ if (!entry)
421
+ return;
422
+ entry.layers.delete(mutationId);
423
+ this._recomputeVisible(entry);
424
+ }
425
+ removeOptimistic(type, id, _mutationId) {
426
+ this.remove(type, id);
427
+ }
428
+ restoreOptimistic(type, _id, _mutationId, entitySnapshot, indexSnapshot) {
429
+ if (entitySnapshot) {
430
+ this.merge(type, entitySnapshot);
431
+ }
432
+ for (const [queryKey, ids] of indexSnapshot) {
433
+ this._queryIndices.set(queryKey, ids);
434
+ }
435
+ }
436
+ commitLayer(type, id, mutationId, serverData) {
437
+ const entry = this._entities.get(type)?.get(id);
438
+ if (!entry)
439
+ return;
440
+ const { normalized, extracted } = normalizeEntity(type, serverData);
441
+ for (const [nestedType, nestedItems] of extracted) {
442
+ for (const nestedItem of nestedItems) {
443
+ this._mergeOne(nestedType, nestedItem);
444
+ }
445
+ }
446
+ entry.base = normalized;
447
+ entry.layers.delete(mutationId);
448
+ this._recomputeVisible(entry);
449
+ }
450
+ _mergeOne(type, item) {
451
+ const id = item.id;
452
+ const typeMap = this._entities.get(type);
453
+ const entry = typeMap?.get(id);
454
+ if (entry) {
455
+ const mergedBase = shallowMerge(entry.base, item);
456
+ if (!shallowEqual(entry.base, mergedBase)) {
457
+ entry.base = mergedBase;
458
+ this._recomputeVisible(entry);
459
+ }
460
+ } else {
461
+ const newSignal = signal(item);
462
+ const newEntry = {
463
+ signal: newSignal,
464
+ base: item,
465
+ layers: new Map,
466
+ refCount: 0,
467
+ orphanedAt: null
468
+ };
469
+ this._getOrCreateTypeMap(type).set(id, newEntry);
470
+ this._notifyTypeChange(type);
471
+ }
472
+ }
473
+ _recomputeVisible(entry) {
474
+ let visible = { ...entry.base };
475
+ for (const patch of entry.layers.values()) {
476
+ visible = shallowMerge(visible, patch);
477
+ }
478
+ const current = entry.signal.peek();
479
+ if (current == null || !shallowEqual(current, visible)) {
480
+ untrack(() => {
481
+ entry.signal.value = visible;
482
+ });
483
+ }
484
+ }
485
+ _getOrCreateTypeMap(type) {
486
+ let typeMap = this._entities.get(type);
487
+ if (!typeMap) {
488
+ typeMap = new Map;
489
+ this._entities.set(type, typeMap);
490
+ }
491
+ return typeMap;
492
+ }
493
+ _getOrCreateListeners(type) {
494
+ let listeners = this._typeListeners.get(type);
495
+ if (!listeners) {
496
+ listeners = new Set;
497
+ this._typeListeners.set(type, listeners);
498
+ }
499
+ return listeners;
500
+ }
501
+ _notifyTypeChange(type) {
502
+ const listeners = this._typeListeners.get(type);
503
+ if (listeners) {
504
+ for (const callback of listeners) {
505
+ callback();
506
+ }
507
+ }
508
+ }
509
+ }
510
+
511
+ // src/store/query-envelope-store.ts
512
+ class QueryEnvelopeStore {
513
+ _envelopes = new Map;
514
+ get(queryKey) {
515
+ return this._envelopes.get(queryKey);
516
+ }
517
+ set(queryKey, envelope) {
518
+ this._envelopes.set(queryKey, envelope);
519
+ }
520
+ clear() {
521
+ this._envelopes.clear();
522
+ }
523
+ }
524
+
525
+ // src/store/entity-store-singleton.ts
526
+ var _store = new EntityStore;
527
+ var _envelopeStore = new QueryEnvelopeStore;
528
+ function getEntityStore() {
529
+ const ctx = getSSRContext();
530
+ if (ctx)
531
+ return ctx.entityStore;
532
+ return _store;
533
+ }
534
+ function getQueryEnvelopeStore() {
535
+ const ctx = getSSRContext();
536
+ if (ctx)
537
+ return ctx.envelopeStore;
538
+ return _envelopeStore;
539
+ }
540
+
541
+ // src/query/query.ts
542
+ import {
543
+ isQueryDescriptor
544
+ } from "@vertz/fetch";
545
+
546
+ // src/store/mutation-event-bus.ts
547
+ function createMutationEventBus() {
548
+ const listeners = new Map;
549
+ return {
550
+ subscribe(entityType, callback) {
551
+ let set = listeners.get(entityType);
552
+ if (!set) {
553
+ set = new Set;
554
+ listeners.set(entityType, set);
555
+ }
556
+ set.add(callback);
557
+ return () => set?.delete(callback);
558
+ },
559
+ emit(entityType) {
560
+ const set = listeners.get(entityType);
561
+ if (set) {
562
+ for (const cb of [...set])
563
+ cb();
564
+ }
565
+ },
566
+ clear() {
567
+ listeners.clear();
568
+ }
569
+ };
570
+ }
571
+
572
+ // src/store/mutation-event-bus-singleton.ts
573
+ var _bus = createMutationEventBus();
574
+ function getMutationEventBus() {
575
+ return _bus;
576
+ }
577
+
578
+ // src/store/resolve.ts
579
+ function resolveReferences(entity, entityType, store, visiting, refKeys) {
580
+ const schema = getRelationSchema(entityType);
581
+ if (!schema) {
582
+ if (refKeys && typeof entity.id === "string") {
583
+ refKeys.add(`${entityType}:${entity.id}`);
584
+ }
585
+ return entity;
586
+ }
587
+ const visitKey = `${entityType}/${entity.id}`;
588
+ const visit = visiting ?? new Set;
589
+ if (visit.has(visitKey)) {
590
+ return entity;
591
+ }
592
+ visit.add(visitKey);
593
+ if (refKeys && typeof entity.id === "string") {
594
+ refKeys.add(`${entityType}:${entity.id}`);
595
+ }
596
+ const resolved = { ...entity };
597
+ for (const [field, rel] of Object.entries(schema)) {
598
+ const value = entity[field];
599
+ if (value == null)
600
+ continue;
601
+ if (rel.type === "one") {
602
+ if (typeof value === "string") {
603
+ const referenced = store.get(rel.entity, value).value;
604
+ if (referenced) {
605
+ resolved[field] = resolveReferences(referenced, rel.entity, store, visit, refKeys);
606
+ } else {
607
+ resolved[field] = null;
608
+ }
609
+ } else if (typeof value === "object" && !Array.isArray(value)) {
610
+ resolved[field] = value;
611
+ }
612
+ } else if (rel.type === "many") {
613
+ if (Array.isArray(value)) {
614
+ const items = [];
615
+ for (const element of value) {
616
+ if (typeof element === "string") {
617
+ const referenced = store.get(rel.entity, element).value;
618
+ if (referenced) {
619
+ items.push(resolveReferences(referenced, rel.entity, store, visit, refKeys));
620
+ }
621
+ } else if (typeof element === "object" && element != null) {
622
+ items.push(element);
623
+ }
624
+ }
625
+ resolved[field] = items;
626
+ }
627
+ }
628
+ }
629
+ return resolved;
630
+ }
631
+
632
+ // src/query/ssr-hydration.ts
633
+ function hydrateQueryFromSSR(key, resolve, options) {
634
+ const ssrData = globalThis.__VERTZ_SSR_DATA__;
635
+ if (!ssrData)
636
+ return null;
637
+ const persistent = options?.persistent ?? false;
638
+ const existing = ssrData.find((entry) => entry.key === key);
639
+ if (existing) {
640
+ resolve(existing.data);
641
+ if (!persistent)
642
+ return () => {};
643
+ }
644
+ const handler = (event) => {
645
+ const detail = event.detail;
646
+ if (detail.key === key) {
647
+ resolve(detail.data);
648
+ if (!persistent) {
649
+ document.removeEventListener("vertz:ssr-data", handler);
650
+ }
651
+ }
652
+ };
653
+ document.addEventListener("vertz:ssr-data", handler);
654
+ return () => {
655
+ document.removeEventListener("vertz:ssr-data", handler);
656
+ };
657
+ }
658
+
659
+ // src/query/query.ts
660
+ function isSSR() {
661
+ return getSSRContext() !== undefined;
662
+ }
663
+ function getGlobalSSRTimeout() {
664
+ return getSSRContext()?.globalSSRTimeout;
665
+ }
666
+ var defaultCache = new MemoryCache;
667
+ var inflight = new Map;
668
+ function getDefaultCache() {
669
+ const ctx = getSSRContext();
670
+ if (ctx)
671
+ return ctx.queryCache;
672
+ return defaultCache;
673
+ }
674
+ function getInflight() {
675
+ const ctx = getSSRContext();
676
+ if (ctx)
677
+ return ctx.inflight;
678
+ return inflight;
679
+ }
680
+ function query(source, options = {}) {
681
+ if (isQueryDescriptor(source)) {
682
+ const entityMeta2 = source._entity;
683
+ return query(async () => {
684
+ const result = await source._fetch();
685
+ if (!result.ok)
686
+ throw result.error;
687
+ return result.data;
688
+ }, { ...options, key: source._key, _entityMeta: entityMeta2 });
689
+ }
690
+ const thunk = source;
691
+ const {
692
+ initialData,
693
+ debounce: debounceMs,
694
+ enabled = true,
695
+ key: customKey,
696
+ cache = getDefaultCache(),
697
+ _entityMeta: entityMeta
698
+ } = options;
699
+ const baseKey = deriveKey(thunk);
700
+ const depHashSignal = signal("");
701
+ const cacheKeyComputed = computed(() => {
702
+ const dh = depHashSignal.value;
703
+ return customKey ?? (dh ? `${baseKey}:${dh}` : `${baseKey}:init`);
704
+ });
705
+ function getCacheKey() {
706
+ return cacheKeyComputed.value;
707
+ }
708
+ function callThunkWithCapture() {
709
+ const captured = [];
710
+ const prevCb = setReadValueCallback((v) => captured.push(v));
711
+ let promise;
712
+ try {
713
+ promise = thunk();
714
+ } finally {
715
+ setReadValueCallback(prevCb);
716
+ }
717
+ const serialized = captured.map((v) => JSON.stringify(v)).join("|");
718
+ untrack(() => {
719
+ depHashSignal.value = hashString(serialized);
720
+ });
721
+ return promise;
722
+ }
723
+ const rawData = signal(initialData);
724
+ const loading = signal(initialData === undefined && enabled);
725
+ const revalidating = signal(false);
726
+ const error = signal(undefined);
727
+ const entityBacked = signal(false);
728
+ function normalizeToEntityStore(result) {
729
+ if (!entityMeta)
730
+ return;
731
+ const store = getEntityStore();
732
+ if (entityMeta.kind === "get" && result && typeof result === "object" && "id" in result) {
733
+ store.merge(entityMeta.entityType, result);
734
+ entityBacked.value = true;
735
+ }
736
+ if (entityMeta.kind === "list" && result && typeof result === "object") {
737
+ const listResult = result;
738
+ if (Array.isArray(listResult.items)) {
739
+ store.merge(entityMeta.entityType, listResult.items);
740
+ const ids = listResult.items.map((item) => item.id);
741
+ const queryKey = customKey ?? entityMeta.entityType;
742
+ store.queryIndices.set(queryKey, ids);
743
+ const { items: _, ...rest } = result;
744
+ if (Object.keys(rest).length > 0) {
745
+ getQueryEnvelopeStore().set(queryKey, rest);
746
+ }
747
+ entityBacked.value = true;
748
+ }
749
+ }
750
+ }
751
+ const referencedKeys = new Set;
752
+ const data = entityMeta ? computed(() => {
753
+ if (!entityBacked.value)
754
+ return rawData.value;
755
+ const raw = rawData.value;
756
+ const store = getEntityStore();
757
+ const newKeys = new Set;
758
+ if (entityMeta.kind === "get" && entityMeta.id) {
759
+ const entity = store.get(entityMeta.entityType, entityMeta.id).value;
760
+ if (!entity) {
761
+ updateRefCounts(store, referencedKeys, newKeys);
762
+ return;
763
+ }
764
+ const resolved = resolveReferences(entity, entityMeta.entityType, store, undefined, newKeys);
765
+ updateRefCounts(store, referencedKeys, newKeys);
766
+ return resolved;
767
+ }
768
+ const queryKey = customKey ?? entityMeta.entityType;
769
+ const ids = store.queryIndices.get(queryKey);
770
+ if (ids) {
771
+ const items = ids.map((id) => {
772
+ const entity = store.get(entityMeta.entityType, id).value;
773
+ if (!entity)
774
+ return null;
775
+ return resolveReferences(entity, entityMeta.entityType, store, undefined, newKeys);
776
+ }).filter((item) => item != null);
777
+ const envelope = getQueryEnvelopeStore().get(queryKey);
778
+ updateRefCounts(store, referencedKeys, newKeys);
779
+ return { ...envelope, items };
780
+ }
781
+ updateRefCounts(store, referencedKeys, newKeys);
782
+ return raw;
783
+ }) : rawData;
784
+ if (initialData !== undefined) {
785
+ cache.set(getCacheKey(), initialData);
786
+ }
787
+ const ssrTimeout = options.ssrTimeout ?? getGlobalSSRTimeout() ?? 300;
788
+ if (isSSR() && enabled && ssrTimeout !== 0 && initialData === undefined) {
789
+ const promise = callThunkWithCapture();
790
+ const key = untrack(() => getCacheKey());
791
+ const cached = cache.get(key);
792
+ if (cached !== undefined) {
793
+ promise.catch(() => {});
794
+ normalizeToEntityStore(cached);
795
+ rawData.value = cached;
796
+ loading.value = false;
797
+ } else {
798
+ promise.catch(() => {});
799
+ const ctx = getSSRContext();
800
+ if (ctx) {
801
+ ctx.queries.push({
802
+ promise,
803
+ timeout: ssrTimeout,
804
+ resolve: (result) => {
805
+ normalizeToEntityStore(result);
806
+ rawData.value = result;
807
+ loading.value = false;
808
+ cache.set(key, result);
809
+ },
810
+ key
811
+ });
812
+ }
813
+ }
814
+ }
815
+ let ssrHydrationCleanup = null;
816
+ let ssrHydrated = false;
817
+ let navPrefetchDeferred = false;
818
+ if (!isSSR() && enabled && initialData === undefined) {
819
+ const hydrationKey = customKey ?? baseKey;
820
+ const isNavigation = isNavPrefetchActive();
821
+ ssrHydrationCleanup = hydrateQueryFromSSR(hydrationKey, (result) => {
822
+ normalizeToEntityStore(result);
823
+ rawData.value = result;
824
+ loading.value = false;
825
+ cache.set(hydrationKey, result);
826
+ ssrHydrated = true;
827
+ }, { persistent: isNavigation });
828
+ if (!ssrHydrated && ssrHydrationCleanup !== null && isNavPrefetchActive()) {
829
+ if (customKey) {
830
+ const cached = cache.get(customKey);
831
+ if (cached !== undefined) {
832
+ normalizeToEntityStore(cached);
833
+ rawData.value = cached;
834
+ loading.value = false;
835
+ ssrHydrated = true;
836
+ }
837
+ }
838
+ }
839
+ if (!ssrHydrated && ssrHydrationCleanup !== null && isNavPrefetchActive()) {
840
+ navPrefetchDeferred = true;
841
+ const doneHandler = () => {
842
+ document.removeEventListener("vertz:nav-prefetch-done", doneHandler);
843
+ if (rawData.peek() === undefined && !ssrHydrated) {
844
+ refetchTrigger.value = refetchTrigger.peek() + 1;
845
+ }
846
+ };
847
+ document.addEventListener("vertz:nav-prefetch-done", doneHandler);
848
+ const prevCleanup = ssrHydrationCleanup;
849
+ ssrHydrationCleanup = () => {
850
+ prevCleanup?.();
851
+ document.removeEventListener("vertz:nav-prefetch-done", doneHandler);
852
+ };
853
+ }
854
+ }
855
+ let fetchId = 0;
856
+ let debounceTimer;
857
+ let intervalTimer;
858
+ const refetchIntervalOption = options.refetchInterval;
859
+ const hasInterval = typeof refetchIntervalOption === "function" || typeof refetchIntervalOption === "number" && refetchIntervalOption > 0;
860
+ let intervalIteration = 0;
861
+ const inflightKeys = new Set;
862
+ const refetchTrigger = signal(0);
863
+ let intervalPaused = false;
864
+ function scheduleInterval() {
865
+ if (!hasInterval || isSSR() || intervalPaused)
866
+ return;
867
+ let ms;
868
+ if (typeof refetchIntervalOption === "function") {
869
+ ms = refetchIntervalOption(rawData.peek(), intervalIteration);
870
+ } else {
871
+ ms = refetchIntervalOption;
872
+ }
873
+ if (ms === false || ms <= 0) {
874
+ intervalIteration = 0;
875
+ return;
876
+ }
877
+ intervalIteration++;
878
+ clearTimeout(intervalTimer);
879
+ intervalTimer = setTimeout(() => {
880
+ refetch();
881
+ }, ms);
882
+ }
883
+ let visibilityHandler;
884
+ if (hasInterval && enabled && !isSSR() && typeof document !== "undefined") {
885
+ visibilityHandler = () => {
886
+ if (document.visibilityState === "hidden") {
887
+ intervalPaused = true;
888
+ clearTimeout(intervalTimer);
889
+ } else {
890
+ intervalPaused = false;
891
+ refetch();
892
+ }
893
+ };
894
+ document.addEventListener("visibilitychange", visibilityHandler);
895
+ }
896
+ function handleFetchPromise(promise, id, key) {
897
+ promise.then((result) => {
898
+ getInflight().delete(key);
899
+ inflightKeys.delete(key);
900
+ if (id !== fetchId)
901
+ return;
902
+ cache.set(key, result);
903
+ normalizeToEntityStore(result);
904
+ rawData.value = result;
905
+ loading.value = false;
906
+ revalidating.value = false;
907
+ scheduleInterval();
908
+ }, (err) => {
909
+ getInflight().delete(key);
910
+ inflightKeys.delete(key);
911
+ if (id !== fetchId)
912
+ return;
913
+ error.value = err;
914
+ loading.value = false;
915
+ revalidating.value = false;
916
+ scheduleInterval();
917
+ });
918
+ }
919
+ function startFetch(fetchPromise, key) {
920
+ const id = ++fetchId;
921
+ untrack(() => {
922
+ if (rawData.value !== undefined) {
923
+ revalidating.value = true;
924
+ } else {
925
+ loading.value = true;
926
+ }
927
+ error.value = undefined;
928
+ });
929
+ const existing = getInflight().get(key);
930
+ if (existing) {
931
+ handleFetchPromise(existing, id, key);
932
+ return;
933
+ }
934
+ getInflight().set(key, fetchPromise);
935
+ inflightKeys.add(key);
936
+ handleFetchPromise(fetchPromise, id, key);
937
+ }
938
+ function refetch() {
939
+ const key = getCacheKey();
940
+ cache.delete(key);
941
+ getInflight().delete(key);
942
+ refetchTrigger.value = refetchTrigger.peek() + 1;
943
+ }
944
+ let disposeFn;
945
+ if (enabled) {
946
+ let isFirst = true;
947
+ disposeFn = lifecycleEffect(() => {
948
+ refetchTrigger.value;
949
+ if (isFirst && ssrHydrated) {
950
+ isFirst = false;
951
+ return;
952
+ }
953
+ if (isFirst && navPrefetchDeferred) {
954
+ if (customKey) {
955
+ const cached = untrack(() => cache.get(customKey));
956
+ if (cached !== undefined) {
957
+ untrack(() => {
958
+ rawData.value = cached;
959
+ loading.value = false;
960
+ });
961
+ isFirst = false;
962
+ return;
963
+ }
964
+ } else {
965
+ const trackPromise = callThunkWithCapture();
966
+ trackPromise.catch(() => {});
967
+ const derivedKey = untrack(() => getCacheKey());
968
+ const cached = untrack(() => cache.get(derivedKey));
969
+ if (cached !== undefined) {
970
+ untrack(() => {
971
+ rawData.value = cached;
972
+ loading.value = false;
973
+ });
974
+ isFirst = false;
975
+ return;
976
+ }
977
+ }
978
+ isFirst = false;
979
+ return;
980
+ }
981
+ if (customKey) {
982
+ const existing = untrack(() => getInflight().get(customKey));
983
+ if (existing) {
984
+ const id = ++fetchId;
985
+ untrack(() => {
986
+ if (rawData.value !== undefined) {
987
+ revalidating.value = true;
988
+ } else {
989
+ loading.value = true;
990
+ }
991
+ error.value = undefined;
992
+ });
993
+ handleFetchPromise(existing, id, customKey);
994
+ isFirst = false;
995
+ return;
996
+ }
997
+ }
998
+ const promise = callThunkWithCapture();
999
+ const key = untrack(() => getCacheKey());
1000
+ if (!customKey) {
1001
+ const existing = untrack(() => getInflight().get(key));
1002
+ if (existing) {
1003
+ promise.catch(() => {});
1004
+ const id = ++fetchId;
1005
+ untrack(() => {
1006
+ if (rawData.value !== undefined) {
1007
+ revalidating.value = true;
1008
+ } else {
1009
+ loading.value = true;
1010
+ }
1011
+ error.value = undefined;
1012
+ });
1013
+ handleFetchPromise(existing, id, key);
1014
+ isFirst = false;
1015
+ return;
1016
+ }
1017
+ }
1018
+ const isNavigation = ssrHydrationCleanup !== null;
1019
+ const shouldCheckCache = isNavigation || (isFirst ? !!customKey : !customKey);
1020
+ if (shouldCheckCache) {
1021
+ const cached = untrack(() => cache.get(key));
1022
+ if (cached !== undefined) {
1023
+ promise.catch(() => {});
1024
+ untrack(() => {
1025
+ rawData.value = cached;
1026
+ loading.value = false;
1027
+ error.value = undefined;
1028
+ });
1029
+ isFirst = false;
1030
+ scheduleInterval();
1031
+ return;
1032
+ }
1033
+ }
1034
+ if (isFirst && initialData !== undefined) {
1035
+ promise.catch(() => {});
1036
+ isFirst = false;
1037
+ scheduleInterval();
1038
+ return;
1039
+ }
1040
+ isFirst = false;
1041
+ if (debounceMs !== undefined && debounceMs > 0) {
1042
+ clearTimeout(debounceTimer);
1043
+ promise.catch(() => {});
1044
+ debounceTimer = setTimeout(() => {
1045
+ startFetch(promise, key);
1046
+ }, debounceMs);
1047
+ } else {
1048
+ startFetch(promise, key);
1049
+ }
1050
+ });
1051
+ }
1052
+ function dispose() {
1053
+ if (referencedKeys.size > 0) {
1054
+ const store = getEntityStore();
1055
+ for (const key of referencedKeys) {
1056
+ const [type, id] = splitRefKey(key);
1057
+ store.removeRef(type, id);
1058
+ }
1059
+ referencedKeys.clear();
1060
+ }
1061
+ disposeFn?.();
1062
+ unsubscribeBus?.();
1063
+ unregisterFromRegistry?.();
1064
+ ssrHydrationCleanup?.();
1065
+ clearTimeout(debounceTimer);
1066
+ clearTimeout(intervalTimer);
1067
+ if (visibilityHandler && typeof document !== "undefined") {
1068
+ document.removeEventListener("visibilitychange", visibilityHandler);
1069
+ }
1070
+ fetchId++;
1071
+ for (const key of inflightKeys) {
1072
+ getInflight().delete(key);
1073
+ }
1074
+ inflightKeys.clear();
1075
+ }
1076
+ let unsubscribeBus;
1077
+ let unregisterFromRegistry;
1078
+ if (entityMeta && enabled && !isSSR()) {
1079
+ unsubscribeBus = getMutationEventBus().subscribe(entityMeta.entityType, refetch);
1080
+ unregisterFromRegistry = registerActiveQuery(entityMeta, refetch);
1081
+ }
1082
+ _tryOnCleanup(dispose);
1083
+ return {
1084
+ data,
1085
+ loading,
1086
+ revalidating,
1087
+ error,
1088
+ refetch,
1089
+ revalidate: refetch,
1090
+ dispose
1091
+ };
1092
+ }
1093
+ function updateRefCounts(store, oldKeys, newKeys) {
1094
+ for (const key of oldKeys) {
1095
+ if (!newKeys.has(key)) {
1096
+ const [type, id] = splitRefKey(key);
1097
+ store.removeRef(type, id);
1098
+ }
1099
+ }
1100
+ for (const key of newKeys) {
1101
+ if (!oldKeys.has(key)) {
1102
+ const [type, id] = splitRefKey(key);
1103
+ store.addRef(type, id);
1104
+ }
1105
+ }
1106
+ oldKeys.clear();
1107
+ for (const key of newKeys)
1108
+ oldKeys.add(key);
1109
+ }
1110
+ function splitRefKey(key) {
1111
+ const idx = key.indexOf(":");
1112
+ return [key.slice(0, idx), key.slice(idx + 1)];
1113
+ }
1114
+
1115
+ // src/query/query-match.ts
1116
+ var cache = new WeakMap;
1117
+ function queryMatch(queryResult, handlers) {
1118
+ const key = queryResult;
1119
+ const existing = cache.get(key);
1120
+ if (existing && !existing.disposed) {
1121
+ existing.handlers = handlers;
1122
+ return existing.wrapper;
1123
+ }
1124
+ if (existing) {
1125
+ cache.delete(key);
1126
+ }
1127
+ const wrapper = getAdapter().createElement("span");
1128
+ wrapper.style.display = "contents";
1129
+ const entry = { wrapper, handlers, disposed: false };
1130
+ cache.set(key, entry);
1131
+ let currentBranch = null;
1132
+ let branchCleanups = [];
1133
+ const outerScope = pushScope();
1134
+ domEffect(() => {
1135
+ const isLoading = queryResult.loading.value;
1136
+ const err = queryResult.error.value;
1137
+ const dataValue = queryResult.data.value;
1138
+ let branch;
1139
+ if (isLoading || err === undefined && dataValue === undefined) {
1140
+ branch = "loading";
1141
+ } else if (err !== undefined) {
1142
+ branch = "error";
1143
+ } else {
1144
+ branch = "data";
1145
+ }
1146
+ if (branch === currentBranch) {
1147
+ return;
1148
+ }
1149
+ runCleanups(branchCleanups);
1150
+ while (wrapper.firstChild) {
1151
+ wrapper.removeChild(wrapper.firstChild);
1152
+ }
1153
+ currentBranch = branch;
1154
+ const scope = pushScope();
1155
+ let branchResult = null;
1156
+ if (branch === "loading") {
1157
+ branchResult = entry.handlers.loading();
1158
+ } else if (branch === "error") {
1159
+ branchResult = entry.handlers.error(err);
1160
+ } else {
1161
+ const dataSignal = queryResult.data;
1162
+ const dataProxy = new Proxy({}, {
1163
+ get(_target, prop, receiver) {
1164
+ const current = dataSignal.value;
1165
+ if (current == null)
1166
+ return;
1167
+ const value = Reflect.get(current, prop, receiver);
1168
+ if (typeof value === "function") {
1169
+ return value.bind(current);
1170
+ }
1171
+ return value;
1172
+ },
1173
+ has(_target, prop) {
1174
+ const current = dataSignal.value;
1175
+ if (current == null)
1176
+ return false;
1177
+ return Reflect.has(current, prop);
1178
+ },
1179
+ ownKeys() {
1180
+ const current = dataSignal.value;
1181
+ if (current == null)
1182
+ return [];
1183
+ return Reflect.ownKeys(current);
1184
+ },
1185
+ getOwnPropertyDescriptor(_target, prop) {
1186
+ const current = dataSignal.value;
1187
+ if (current == null)
1188
+ return;
1189
+ return Reflect.getOwnPropertyDescriptor(current, prop);
1190
+ }
1191
+ });
1192
+ branchResult = entry.handlers.data(dataProxy);
1193
+ }
1194
+ popScope();
1195
+ branchCleanups = scope;
1196
+ if (branchResult != null && isRenderNode(branchResult)) {
1197
+ wrapper.appendChild(branchResult);
1198
+ }
1199
+ });
1200
+ popScope();
1201
+ const dispose = () => {
1202
+ entry.disposed = true;
1203
+ runCleanups(branchCleanups);
1204
+ runCleanups(outerScope);
1205
+ cache.delete(key);
1206
+ };
1207
+ wrapper.dispose = dispose;
1208
+ _tryOnCleanup(dispose);
1209
+ return wrapper;
1210
+ }
1211
+
1212
+ export { MemoryCache, invalidate, deriveKey, registerRelationSchema, getRelationSchema, resetRelationSchemas_TEST_ONLY, EntityStore, QueryEnvelopeStore, getEntityStore, getQueryEnvelopeStore, getMutationEventBus, query, queryMatch };