@wovin/core 0.2.0 → 0.3.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 (115) hide show
  1. package/dist/applog/applog-utils.d.ts +15 -0
  2. package/dist/applog/applog-utils.d.ts.map +1 -1
  3. package/dist/applog/datom-types.d.ts +63 -7
  4. package/dist/applog/datom-types.d.ts.map +1 -1
  5. package/dist/applog.js +7 -1
  6. package/dist/blockstore.js +2 -0
  7. package/dist/blockstore.js.map +1 -1
  8. package/dist/{chunk-L5EEEGE6.js → chunk-2OXLPZQI.js} +747 -679
  9. package/dist/chunk-2OXLPZQI.js.map +1 -0
  10. package/dist/{chunk-QZXKQCAY.js → chunk-2PJFLZRC.js} +7 -2
  11. package/dist/{chunk-QZXKQCAY.js.map → chunk-2PJFLZRC.js.map} +1 -1
  12. package/dist/chunk-64EJIJAJ.js +17 -0
  13. package/dist/chunk-64EJIJAJ.js.map +1 -0
  14. package/dist/chunk-7QEGHKR4.js +17 -0
  15. package/dist/chunk-7QEGHKR4.js.map +1 -0
  16. package/dist/{chunk-PD3C7XUM.js → chunk-EHO2BFFY.js} +2 -2
  17. package/dist/chunk-ICBK7NC4.js +27 -0
  18. package/dist/chunk-ICBK7NC4.js.map +1 -0
  19. package/dist/{chunk-CPSDKFBG.js → chunk-OKXRRWNS.js} +5 -14
  20. package/dist/chunk-OKXRRWNS.js.map +1 -0
  21. package/dist/{chunk-3WZVG277.js → chunk-Q4EMPWA3.js} +17 -9
  22. package/dist/chunk-Q4EMPWA3.js.map +1 -0
  23. package/dist/{chunk-J2FDHGOZ.js → chunk-VGIACGWX.js} +3 -3
  24. package/dist/{chunk-3JZMOEOD.js → chunk-WVW4YXB5.js} +2 -2
  25. package/dist/chunk-XF4DWOAE.js +25 -0
  26. package/dist/chunk-XF4DWOAE.js.map +1 -0
  27. package/dist/index.js +17 -9
  28. package/dist/ipfs/car.d.ts.map +1 -1
  29. package/dist/ipfs.js +4 -4
  30. package/dist/ipns/gateway-resolver.d.ts +21 -0
  31. package/dist/ipns/gateway-resolver.d.ts.map +1 -0
  32. package/dist/ipns/ipns-record.d.ts +28 -7
  33. package/dist/ipns/ipns-record.d.ts.map +1 -1
  34. package/dist/ipns/ipns-w3name.d.ts +15 -0
  35. package/dist/ipns/ipns-w3name.d.ts.map +1 -0
  36. package/dist/ipns/ipns-watcher.d.ts +190 -0
  37. package/dist/ipns/ipns-watcher.d.ts.map +1 -0
  38. package/dist/ipns.d.ts +3 -0
  39. package/dist/ipns.d.ts.map +1 -1
  40. package/dist/ipns.js +488 -8
  41. package/dist/ipns.js.map +1 -1
  42. package/dist/pubsub/snap-push.d.ts +2 -2
  43. package/dist/pubsub/snap-push.d.ts.map +1 -1
  44. package/dist/pubsub.js +4 -4
  45. package/dist/query/basic.d.ts +3 -3
  46. package/dist/query/basic.d.ts.map +1 -1
  47. package/dist/query/entity-collection.d.ts.map +1 -1
  48. package/dist/query/matchers.d.ts +12 -1
  49. package/dist/query/matchers.d.ts.map +1 -1
  50. package/dist/query.js +7 -5
  51. package/dist/retrieve.js +4 -4
  52. package/dist/thread/indexes.d.ts +3 -2
  53. package/dist/thread/indexes.d.ts.map +1 -1
  54. package/dist/thread.js +1 -1
  55. package/dist/viewmodel/adapters/arktype.d.ts +33 -0
  56. package/dist/viewmodel/adapters/arktype.d.ts.map +1 -0
  57. package/dist/viewmodel/adapters/arktype.js +7 -0
  58. package/dist/viewmodel/adapters/arktype.js.map +1 -0
  59. package/dist/viewmodel/adapters/typebox.d.ts +35 -0
  60. package/dist/viewmodel/adapters/typebox.d.ts.map +1 -0
  61. package/dist/viewmodel/adapters/typebox.js +7 -0
  62. package/dist/viewmodel/adapters/typebox.js.map +1 -0
  63. package/dist/viewmodel/adapters/typia.d.ts +40 -0
  64. package/dist/viewmodel/adapters/typia.d.ts.map +1 -0
  65. package/dist/viewmodel/adapters/typia.js +7 -0
  66. package/dist/viewmodel/adapters/typia.js.map +1 -0
  67. package/dist/viewmodel/adapters/zod.d.ts +30 -0
  68. package/dist/viewmodel/adapters/zod.d.ts.map +1 -0
  69. package/dist/viewmodel/adapters/zod.js +7 -0
  70. package/dist/viewmodel/adapters/zod.js.map +1 -0
  71. package/dist/viewmodel/builder.d.ts +40 -0
  72. package/dist/viewmodel/builder.d.ts.map +1 -0
  73. package/dist/viewmodel/examples/all-adapters.d.ts +26 -0
  74. package/dist/viewmodel/examples/all-adapters.d.ts.map +1 -0
  75. package/dist/viewmodel/factory.d.ts +38 -0
  76. package/dist/viewmodel/factory.d.ts.map +1 -0
  77. package/dist/viewmodel/index.d.ts +10 -0
  78. package/dist/viewmodel/index.d.ts.map +1 -0
  79. package/dist/viewmodel/index.js +313 -0
  80. package/dist/viewmodel/index.js.map +1 -0
  81. package/dist/viewmodel/schema-adapter.d.ts +16 -0
  82. package/dist/viewmodel/schema-adapter.d.ts.map +1 -0
  83. package/dist/viewmodel/types.d.ts +97 -0
  84. package/dist/viewmodel/types.d.ts.map +1 -0
  85. package/package.json +29 -3
  86. package/src/applog/applog-utils.ts +48 -4
  87. package/src/applog/datom-types.ts +24 -5
  88. package/src/applog/object-values.test.ts +106 -0
  89. package/src/ipfs/car.ts +8 -2
  90. package/src/ipns/gateway-resolver.ts +63 -0
  91. package/src/ipns/ipns-record.ts +68 -17
  92. package/src/ipns/ipns-w3name.ts +103 -0
  93. package/src/ipns/ipns-watcher.ts +607 -0
  94. package/src/ipns.ts +3 -0
  95. package/src/pubsub/snap-push.ts +8 -6
  96. package/src/query/entity-collection.ts +2 -1
  97. package/src/query/matchers.ts +23 -1
  98. package/src/thread/basic.ts +2 -2
  99. package/src/thread/indexes.ts +15 -9
  100. package/src/viewmodel/adapters/arktype.ts +44 -0
  101. package/src/viewmodel/adapters/typebox.ts +59 -0
  102. package/src/viewmodel/adapters/typia.ts +50 -0
  103. package/src/viewmodel/adapters/zod.ts +55 -0
  104. package/src/viewmodel/builder.ts +71 -0
  105. package/src/viewmodel/examples/all-adapters.ts +206 -0
  106. package/src/viewmodel/factory.ts +330 -0
  107. package/src/viewmodel/index.ts +22 -0
  108. package/src/viewmodel/schema-adapter.ts +27 -0
  109. package/src/viewmodel/types.ts +152 -0
  110. package/dist/chunk-3WZVG277.js.map +0 -1
  111. package/dist/chunk-CPSDKFBG.js.map +0 -1
  112. package/dist/chunk-L5EEEGE6.js.map +0 -1
  113. /package/dist/{chunk-PD3C7XUM.js.map → chunk-EHO2BFFY.js.map} +0 -0
  114. /package/dist/{chunk-J2FDHGOZ.js.map → chunk-VGIACGWX.js.map} +0 -0
  115. /package/dist/{chunk-3JZMOEOD.js.map → chunk-WVW4YXB5.js.map} +0 -0
@@ -0,0 +1,330 @@
1
+ import type { ApplogForInsertOptionalAgent, ApplogValue, EntityID } from '../applog/datom-types.ts'
2
+ import { EntityID_LENGTH } from '../applog/datom-types.ts'
3
+ import { dateNowIso, getHashID } from '../applog/applog-utils.ts'
4
+ import { ensureTsPvAndFinalizeApplog } from '../applog/applog-helpers.ts'
5
+ import { lastWriteWins, liveEntityAt } from '../query/basic.ts'
6
+ import { SubscribableImpl } from '../query/subscribable.ts'
7
+ import type { Thread } from '../thread/basic.ts'
8
+ import { isInitEvent } from '../thread/basic.ts'
9
+ import { rollingFilter } from '../thread/filters.ts'
10
+ import { ObjectBuilder } from './builder.ts'
11
+ import {
12
+ type ISignalAdapter,
13
+ type IVMInstance,
14
+ type ViewModelFactoryOptions,
15
+ type VMInstanceMap,
16
+ getInstancesForThread,
17
+ } from './types.ts'
18
+
19
+ // ═══════════════════════════════════════════════════════════════
20
+ // Default (non-reactive) Signal Adapter
21
+ // ═══════════════════════════════════════════════════════════════
22
+
23
+ /**
24
+ * Default signal adapter — reads Subscribable values directly (snapshot).
25
+ * Subscribe-once to keep .value current. No framework reactivity.
26
+ */
27
+ export const DefaultSignalAdapter: ISignalAdapter = {
28
+ createGetter<T>(subscribable: { value: T; subscribe(cb: () => void): () => void }): () => T {
29
+ // Subscribe once to activate upstream (lazy activation)
30
+ subscribable.subscribe(() => {})
31
+ return () => subscribable.value
32
+ },
33
+ createWritable<T>(initial: T): [() => T, (v: T) => void] {
34
+ let current = initial
35
+ return [() => current, (v: T) => { current = v }]
36
+ },
37
+ }
38
+
39
+ // ═══════════════════════════════════════════════════════════════
40
+ // makeCurrentThread - convenience wrapper
41
+ // ═══════════════════════════════════════════════════════════════
42
+
43
+ function makeCurrent(thread: Thread, fn?: ViewModelFactoryOptions<any>['makeCurrentThread']): Thread {
44
+ if (fn) return fn(thread)
45
+ return lastWriteWins(thread, { tolerateAlreadyFiltered: true })
46
+ }
47
+
48
+ // ═══════════════════════════════════════════════════════════════
49
+ // Default persist function
50
+ // ═══════════════════════════════════════════════════════════════
51
+
52
+ /**
53
+ * Default applog persistence: finalize applogs and push into thread.
54
+ * Works with WriteableThread (which has insertRaw).
55
+ */
56
+ function defaultPersistApplogs(thread: Thread, applogs: ApplogForInsertOptionalAgent[]): void {
57
+ const finalized = applogs.map(log => ensureTsPvAndFinalizeApplog(log as any, thread))
58
+ const writable = thread as any
59
+ if (typeof writable.insertRaw === 'function') {
60
+ writable.insertRaw(finalized)
61
+ } else if (typeof writable.insert === 'function') {
62
+ writable.insert(applogs)
63
+ } else {
64
+ // Read-only thread — just finalize but don't persist
65
+ // This is fine for optimistic UI or read-only scenarios
66
+ }
67
+ }
68
+
69
+ // ═══════════════════════════════════════════════════════════════
70
+ // createViewModelFactory - THE MAIN FACTORY
71
+ // ═══════════════════════════════════════════════════════════════
72
+
73
+ /**
74
+ * Create a ViewModel factory for a given schema.
75
+ *
76
+ * Returns a base class that can be extended or used directly.
77
+ * The class provides:
78
+ * - Static `get(en, thread)` for singleton access
79
+ * - Static `buildNew(init, en)` for creating entities
80
+ * - Instance `buildUpdate(init)` for updating entities
81
+ * - Lazy reactive property accessors per attribute
82
+ * - `setDeleted()` for soft deletion
83
+ *
84
+ * Framework-specific reactivity (Solid, Vue, etc.) can be added by
85
+ * providing a custom `ISignalAdapter` in the options.
86
+ *
87
+ * @param options - Factory configuration
88
+ * @returns A VM class constructor with static methods
89
+ */
90
+ export function createViewModelFactory<T extends Record<string, ApplogValue>>(
91
+ options: ViewModelFactoryOptions<T>,
92
+ ) {
93
+ const {
94
+ adapter,
95
+ entityPrefix = adapter.getEntityPrefix(),
96
+ entityIdLength = EntityID_LENGTH,
97
+ generateEntityId,
98
+ vmName = entityPrefix,
99
+ signalAdapter = DefaultSignalAdapter,
100
+ } = options
101
+
102
+ const attrDefs = adapter.getAttributeDefs()
103
+ const defaults = adapter.getDefaults()
104
+
105
+ // Entity ID generation
106
+ const genId = generateEntityId ?? ((data: Partial<T> & { ts?: string }) =>
107
+ getHashID({ ...data, ts: data.ts ?? dateNowIso() }, entityIdLength) as EntityID)
108
+
109
+ // Persist function (can be overridden by extending class)
110
+ const persistFn = (thread: Thread, applogs: ApplogForInsertOptionalAgent[]) => {
111
+ defaultPersistApplogs(thread, applogs)
112
+ }
113
+
114
+ // ═══════════════════════════════════════════════════════════════
115
+ // The ViewModel Class
116
+ // ═══════════════════════════════════════════════════════════════
117
+ class ViewModel {
118
+ /** Per-instance signal storage */
119
+ _signals = new Map<string, () => ApplogValue>()
120
+ _signalAdapter: ISignalAdapter = signalAdapter
121
+
122
+ /** Reactive map for applog tracking: vl === this.en */
123
+ _targetMap: SubscribableImpl<Map<EntityID, Set<string>>>
124
+
125
+ /** Applogs in the current thread where vl === this.en */
126
+ _targetApplogs: Thread
127
+
128
+ constructor(
129
+ public en: EntityID,
130
+ public thread: Thread,
131
+ skipInit?: boolean,
132
+ ) {
133
+ if (skipInit) return
134
+
135
+ const currentThread = makeCurrent(thread, options.makeCurrentThread)
136
+
137
+ // Define lazy getters/setters for each attribute
138
+ for (const attr of attrDefs) {
139
+ if (attr.name === 'en') continue
140
+
141
+ const attrName = attr.name
142
+ const atPath = attr.atPath
143
+ const defaultValue = attr.defaultValue ?? defaults?.[attrName as keyof T]
144
+
145
+ Object.defineProperty(this, attrName, {
146
+ get(this: ViewModel) {
147
+ let signal = this._signals.get(attrName)
148
+ if (!signal) {
149
+ const subscribable = liveEntityAt(currentThread, this.en, atPath)
150
+ signal = this._signalAdapter.createGetter(subscribable)
151
+ this._signals.set(attrName, signal)
152
+ }
153
+ const value = signal()
154
+ return value ?? (defaultValue as ApplogValue | undefined) ?? value
155
+ },
156
+ set(this: ViewModel, v: ApplogValue) {
157
+ const applog: ApplogForInsertOptionalAgent = { en: this.en, at: atPath, vl: v }
158
+ persistFn(this.thread, [applog])
159
+ },
160
+ enumerable: true,
161
+ configurable: true,
162
+ })
163
+ }
164
+
165
+ // ── Applog tracking: applogs where vl === this.en ────────────
166
+ const targets = new Map<EntityID, Set<string>>()
167
+
168
+ this._targetApplogs = rollingFilter(currentThread, { vl: this.en })
169
+ this._targetMap = new SubscribableImpl(
170
+ targets,
171
+ () => this._targetApplogs.subscribe((event) => {
172
+ if (isInitEvent(event)) {
173
+ targets.clear()
174
+ for (const log of event.init) {
175
+ let ats = targets.get(log.en)
176
+ if (!ats) {
177
+ ats = new Set()
178
+ targets.set(log.en, ats)
179
+ }
180
+ ats.add(log.at)
181
+ }
182
+ } else {
183
+ for (const log of event.added) {
184
+ let ats = targets.get(log.en)
185
+ if (!ats) {
186
+ ats = new Set()
187
+ targets.set(log.en, ats)
188
+ }
189
+ ats.add(log.at)
190
+ }
191
+ if (event.removed) {
192
+ for (const log of event.removed) {
193
+ const ats = targets.get(log.en)
194
+ if (ats) {
195
+ ats.delete(log.at)
196
+ if (ats.size === 0) targets.delete(log.en)
197
+ }
198
+ }
199
+ }
200
+ }
201
+ this._targetMap._set(targets)
202
+ }, 'derived'),
203
+ )
204
+ }
205
+
206
+ /** Thread scoped to this entity */
207
+ get entityThread(): Thread {
208
+ return rollingFilter(this.thread, { en: this.en })
209
+ }
210
+
211
+ /** Applogs in the current thread where vl === this.en */
212
+ get targetApplogs(): Thread {
213
+ return this._targetApplogs
214
+ }
215
+
216
+ /** Set of entities that have an applog with this.en as the vl */
217
+ get targettedBy(): Set<EntityID> {
218
+ return new Set(this._targetMap.value.keys())
219
+ }
220
+
221
+ /** Set of at strings from applogs where vl === this.en */
222
+ get targettedVia(): Set<string> {
223
+ const via = new Set<string>()
224
+ for (const ats of this._targetMap.value.values()) {
225
+ for (const at of ats) via.add(at)
226
+ }
227
+ return via
228
+ }
229
+
230
+ /** Whether this entity is soft-deleted */
231
+ get isDeleted(): boolean {
232
+ let signal = this._signals.get('__isDeleted')
233
+ if (!signal) {
234
+ const currentThread = makeCurrent(this.thread, options.makeCurrentThread)
235
+ const subscribable = liveEntityAt(currentThread, this.en, 'isDeleted')
236
+ signal = this._signalAdapter.createGetter(subscribable)
237
+ this._signals.set('__isDeleted', signal)
238
+ }
239
+ return !!signal()
240
+ }
241
+
242
+ /** Soft-delete this entity */
243
+ setDeleted(thread = this.thread): void {
244
+ const applog: ApplogForInsertOptionalAgent = { en: this.en, at: 'isDeleted', vl: true }
245
+ persistFn(thread, [applog])
246
+ }
247
+
248
+ /** Get a builder for updating this entity */
249
+ buildUpdate(init: Partial<T> = {}): ObjectBuilder<T> {
250
+ return new ObjectBuilder<T>(init, this.en, entityPrefix)
251
+ }
252
+
253
+ /** Description for debugging */
254
+ get description(): string {
255
+ return `${vmName}VM(en=${this.en})`
256
+ }
257
+
258
+ /** Get the full entity state as a plain object */
259
+ toJSON(): Partial<T> {
260
+ const result: Record<string, ApplogValue> = {}
261
+ for (const attr of attrDefs) {
262
+ const value = (this as any)[attr.name]
263
+ if (value !== undefined && value !== null) {
264
+ result[attr.name] = value
265
+ }
266
+ }
267
+ return result as Partial<T>
268
+ }
269
+ }
270
+
271
+ // ── Static Methods ────────────────────────────────────────────
272
+
273
+ /**
274
+ * Get or create a VM instance for the given entity and thread.
275
+ * Implements the singleton pattern — returns cached instance if one exists.
276
+ */
277
+ function getVMClass(en: EntityID, thread: Thread): InstanceType<typeof ViewModel> {
278
+ if (!en || typeof en !== 'string') throw new Error(`[${vmName}VM.get] invalid en: ${en}`)
279
+ if (!thread) throw new Error(`[${vmName}VM.get] no thread provided`)
280
+
281
+ const threadMap = getInstancesForThread(thread)
282
+ let entityMap = threadMap.get(vmName) as VMInstanceMap<InstanceType<typeof ViewModel>> | undefined
283
+ if (!entityMap) {
284
+ entityMap = new Map()
285
+ threadMap.set(vmName, entityMap)
286
+ }
287
+
288
+ const existing = entityMap.get(en)
289
+ if (existing) return existing
290
+
291
+ const vm = new ViewModel(en, thread, false) as InstanceType<typeof ViewModel>
292
+ entityMap.set(en, vm)
293
+ return vm
294
+ }
295
+
296
+ /**
297
+ * Create a builder for constructing a new entity.
298
+ */
299
+ function buildNewEntity(init: Partial<T> = {}, en?: EntityID): ObjectBuilder<T> {
300
+ const entityId = en ?? genId(init as any)
301
+ return ObjectBuilder.create<T>(init, entityId, entityPrefix)
302
+ }
303
+
304
+ // Attach static methods to the class
305
+ const VMClass: any = ViewModel
306
+ VMClass.get = getVMClass
307
+ VMClass.buildNew = buildNewEntity
308
+ VMClass.vmName = vmName
309
+ VMClass.entityPrefix = entityPrefix
310
+
311
+ return VMClass as unknown as {
312
+ new(
313
+ en: EntityID,
314
+ thread: Thread,
315
+ skipInit?: boolean,
316
+ ): IVMInstance<T> & T
317
+
318
+ /** Get or create a VM instance for the given entity ID */
319
+ get(en: EntityID, thread: Thread): IVMInstance<T> & T
320
+
321
+ /** Create a builder for a new entity */
322
+ buildNew(init?: Partial<T>, en?: EntityID): ObjectBuilder<T>
323
+
324
+ /** The VM name (for debugging) */
325
+ readonly vmName: string
326
+
327
+ /** The entity prefix used for at-paths */
328
+ readonly entityPrefix: string
329
+ }
330
+ }
@@ -0,0 +1,22 @@
1
+ // Core ViewModel Abstraction
2
+ // Framework-agnostic ViewModel factory system for wovin threads
3
+
4
+ export { ObjectBuilder } from './builder.ts'
5
+ export { createViewModelFactory, DefaultSignalAdapter } from './factory.ts'
6
+ export { createAdapterFromAttributes, buildAtPath } from './schema-adapter.ts'
7
+ export type {
8
+ ISchemaAdapter,
9
+ ISignalAdapter,
10
+ IVMInstance,
11
+ IVMClass,
12
+ VMAttributeDef,
13
+ ViewModelFactoryOptions,
14
+ VMInstanceMap,
15
+ } from './types.ts'
16
+ export { GlobalVMInstances, getInstancesForThread } from './types.ts'
17
+
18
+ // Schema Adapters
19
+ export { createTypeBoxAdapter } from './adapters/typebox.ts'
20
+ export { createZodAdapter } from './adapters/zod.ts'
21
+ export { createArkTypeAdapter } from './adapters/arktype.ts'
22
+ export { createTypiaAdapter } from './adapters/typia.ts'
@@ -0,0 +1,27 @@
1
+ import type { ApplogValue } from '../applog/datom-types.ts'
2
+ import type { ISchemaAdapter, VMAttributeDef } from './types.ts'
3
+
4
+ /**
5
+ * Helper to create a simple schema adapter from a plain attribute list.
6
+ * Useful for quick VM definitions or when you don't have a formal schema library.
7
+ */
8
+ export function createAdapterFromAttributes<T extends Record<string, ApplogValue>>(
9
+ config: {
10
+ attributes: VMAttributeDef[]
11
+ entityPrefix: string
12
+ defaults?: Partial<T>
13
+ },
14
+ ): ISchemaAdapter<T> {
15
+ return {
16
+ getAttributeDefs: () => config.attributes,
17
+ getDefaults: () => (config.defaults ?? {}) as Partial<T>,
18
+ getEntityPrefix: () => config.entityPrefix,
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Helper to build at-paths from attribute names and an entity prefix.
24
+ */
25
+ export function buildAtPath(entityPrefix: string, attrName: string): string {
26
+ return `${entityPrefix}/${attrName}`
27
+ }
@@ -0,0 +1,152 @@
1
+ import type { ApplogValue, EntityID } from '../applog/datom-types.ts'
2
+ import type { Thread } from '../thread/basic.ts'
3
+ import type { ObjectBuilder } from './builder.ts'
4
+
5
+ // ═══════════════════════════════════════════════════════════════
6
+ // Attribute Definition
7
+ // ═══════════════════════════════════════════════════════════════
8
+
9
+ export interface VMAttributeDef {
10
+ /** Attribute name (short: e.g. 'name', 'content') */
11
+ name: string
12
+ /** The wovin at-path used in applogs (e.g. 'block/content', 'speaker/name') */
13
+ atPath: string
14
+ /** Whether the attribute is optional */
15
+ optional: boolean
16
+ /** Default value if not present in applogs */
17
+ defaultValue?: ApplogValue
18
+ }
19
+
20
+ // ═══════════════════════════════════════════════════════════════
21
+ // Schema Adapter Interface
22
+ // ═══════════════════════════════════════════════════════════════
23
+
24
+ /**
25
+ * A schema adapter converts a type-system schema (TypeBox, Zod, ArkType, Typia)
26
+ * into a uniform representation that the VM factory can consume.
27
+ */
28
+ export interface ISchemaAdapter<T extends Record<string, ApplogValue> = Record<string, ApplogValue>> {
29
+ /** Get the attribute definitions for this schema */
30
+ getAttributeDefs(): VMAttributeDef[]
31
+
32
+ /** Get default values for all attributes */
33
+ getDefaults(): Partial<T>
34
+
35
+ /** Optional: runtime validator */
36
+ createValidator?(): (value: unknown) => value is T
37
+
38
+ /** The entity prefix used for wovin at-paths (e.g. 'block', 'speaker') */
39
+ getEntityPrefix(): string
40
+ }
41
+
42
+ // ═══════════════════════════════════════════════════════════════
43
+ // ViewModel Factory Options
44
+ // ═══════════════════════════════════════════════════════════════
45
+
46
+ export interface ViewModelFactoryOptions<T extends Record<string, ApplogValue>> {
47
+ /** The schema adapter for this entity type */
48
+ adapter: ISchemaAdapter<T>
49
+
50
+ /** How to get the default thread context */
51
+ getDefaultThread?: () => Thread
52
+
53
+ /** EntityID generation length (default: 7) */
54
+ entityIdLength?: number
55
+
56
+ /** Function to generate entity IDs */
57
+ generateEntityId?: (data: Partial<T> & { ts?: string }) => EntityID
58
+
59
+ /** Override the entity prefix for at-paths */
60
+ entityPrefix?: string
61
+
62
+ /** Optional function to make thread current-state (lastWriteWins) */
63
+ makeCurrentThread?: (thread: Thread) => Thread
64
+
65
+ /** Name for the VM type (used in logging and debugging) */
66
+ vmName?: string
67
+
68
+ /**
69
+ * Signal adapter for framework-specific reactivity.
70
+ * Default: non-reactive (direct Subscribable reads).
71
+ * For SolidJS, pass createSolidSignalAdapter() from @wovin/ui-solid/viewmodel.
72
+ */
73
+ signalAdapter?: ISignalAdapter
74
+ }
75
+
76
+ // ═══════════════════════════════════════════════════════════════
77
+ // ViewModel Instance Interface
78
+ // ═══════════════════════════════════════════════════════════════
79
+
80
+ export interface IVMInstance<T extends Record<string, ApplogValue> = Record<string, ApplogValue>> {
81
+ readonly en: EntityID
82
+ readonly thread: Thread
83
+
84
+ /** Get a builder for updating this entity */
85
+ buildUpdate(init?: Partial<T>): ObjectBuilder<T>
86
+
87
+ /** Soft-delete this entity */
88
+ setDeleted(thread?: Thread): void
89
+
90
+ /** Whether this entity is deleted */
91
+ readonly isDeleted: boolean
92
+
93
+ /** The entity thread filtered to this entity */
94
+ readonly entityThread: Thread
95
+ }
96
+
97
+ // ═══════════════════════════════════════════════════════════════
98
+ // ViewModel Class Interface (what the factory returns)
99
+ // ═══════════════════════════════════════════════════════════════
100
+
101
+ export interface IVMClass<T extends Record<string, ApplogValue> = Record<string, ApplogValue>> {
102
+ new(en: EntityID, thread: Thread, ...args: any[]): IVMInstance<T>
103
+
104
+ /** Get or create a VM instance for the given entity ID and thread */
105
+ get(en: EntityID, thread: Thread): IVMInstance<T>
106
+
107
+ /** Create a new entity builder */
108
+ buildNew(init?: Partial<T>, en?: EntityID): ObjectBuilder<T>
109
+ }
110
+
111
+ // ═══════════════════════════════════════════════════════════════
112
+ // Signal Adapter Interface (framework-specific reactivity)
113
+ // ═══════════════════════════════════════════════════════════════
114
+
115
+ /**
116
+ * A signal adapter abstracts how the VM creates reactive signals for each attribute.
117
+ * The core factory uses a default (non-reactive) implementation.
118
+ * Framework-specific extensions (Solid, Vue, etc.) override this.
119
+ */
120
+ export interface ISignalAdapter {
121
+ /**
122
+ * Create a reactive getter for a subscribable value.
123
+ * Returns a function that returns the current value.
124
+ * In the default implementation, this is just () => subscribable.value.
125
+ */
126
+ createGetter<T>(subscribable: { value: T; subscribe(cb: () => void): () => void }): () => T
127
+
128
+ /**
129
+ * Create a writable signal for an attribute.
130
+ * Returns [get, set] pair.
131
+ * Default implementation stores and returns value directly.
132
+ */
133
+ createWritable<T>(initial: T): [() => T, (v: T) => void]
134
+ }
135
+
136
+ // ═══════════════════════════════════════════════════════════════
137
+ // Shared state maps
138
+ // ═══════════════════════════════════════════════════════════════
139
+
140
+ export type VMInstanceMap<T> = Map<EntityID, T>
141
+
142
+ /** WeakMap from Thread → Map<VMName, Map<EntityID, VMInstance>> */
143
+ export const GlobalVMInstances = new WeakMap<Thread, Map<string, Map<EntityID, unknown>>>()
144
+
145
+ export function getInstancesForThread(thread: Thread): Map<string, Map<EntityID, unknown>> {
146
+ let threadMap = GlobalVMInstances.get(thread)
147
+ if (!threadMap) {
148
+ threadMap = new Map()
149
+ GlobalVMInstances.set(thread, threadMap)
150
+ }
151
+ return threadMap
152
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pubsub/snap-push.ts","../src/ipfs/car.ts"],"sourcesContent":["import * as dagJson from '@ipld/dag-json'\nimport { Logger } from 'besonders-logger'\nimport { CID } from 'multiformats/cid'\nimport stringify from 'safe-stable-stringify'\nimport { ensureTsPvAndFinalizeApplog } from '../applog/applog-helpers.ts'\nimport type {\n\tApplog,\n\tApplogArrayMaybeEncrypted,\n\tApplogArrayMaybeEncryptedRO,\n\tApplogArrayNoCIDMaybeEncryptedRO,\n\tApplogEnc,\n\tApplogEncNoCid,\n\tCidString,\n} from '../applog/datom-types.ts'\nimport { BlockStoreish, DecodedCar, getDecodedBlock, makeCarBlob } from '../ipfs/car.ts'\nimport { encodeBlockOriginal, prepareForPub } from '../ipfs/ipfs-utils.ts'\nimport { lastWriteWins } from './../query/basic.ts'\nimport { ApplogsOrThread, getLogsFromThread, Thread } from '../thread.ts'\nimport { rollingFilter } from '../thread/filters.ts'\nimport { keepTruthy } from '../utils.ts'\nimport type { AppAgent, IShare, SnapBlockChunks, SnapBlockLogs, SnapBlockLogsOrChunks } from './pubsub-types.ts'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\n// export const neverEncryptAttrs = [\n// \t'agent/jwkd',\n// \t'agent/appAgent',\n// \t'pub/encryptedFor',\n// \t'pub/sharedKey',\n// ]\n\n// export interface WovinPublicationInfo {\n// \tid: string\n// }\n\nexport async function prepareSnapshotForPush(\n\tagent: AppAgent,\n\tappThread: Thread,\n\tthreadToPublish: ApplogsOrThread,\n\tshare: IShare,\n\tprevSnapCID: CID | null,\n\tprevCounter: number | null,\n) {\n\tif (prevCounter !== null && !prevSnapCID) {\n\t\tthrow ERROR('[prepareSnapshotForPush] prevCounter provided without prevSnapCID')\n\t}\n\t// TODO prevent publish if there is no new info\n\tlet logsToPublish = getLogsFromThread(threadToPublish)\n\n\t// const logsFromLastPush = await getLogsFromPub(publication)\n\t// logsToPublish = logsToPublish.filter(eachLog => !logsFromLastPush.includes(eachLog.cid)) // TODO deep compare includes\n\t// const prevPushCIDs = [\n\t// \tpublication.lastCID,\n\t// \t//TODO add this one and update the publication data after push\n\t// ]\n\t// const includedLogCIDs = [\n\t// \t'full array of CIDS from all previous pushes'\n\t// ]\n\n\tDEBUG(`[preparePubForPush] Collected ${logsToPublish.length} logs :`, {\n\t\tlogsToPublish,\n\t\tthreadOrLogsCount: (threadToPublish as any).nameAndSizeUntracked || (`[${(threadToPublish as any).length}]`),\n\t})\n\n\tconst { sharedAgents, sharedKeyMap, sharedKey, pubCounter } = share ?? {}\n\n\tconst getExistingOrNewLog = (thread: Thread, share: IShare, ag: string, at: string, vl) => {\n\t\tlet logInQuestion = rollingFilter(lastWriteWins(thread), { en: share.id, at }).latestLog\n\t\tif (!logInQuestion && vl !== undefined) {\n\t\t\tlogInQuestion = ensureTsPvAndFinalizeApplog({ ag, en: share.id, at, vl }, thread)\n\t\t}\n\t\treturn logInQuestion // can be undefined if the passed vl is undefined and the log is not found\n\t}\n\tconst shareNameLog = getExistingOrNewLog(appThread, share, agent.ag, 'share/name', share.name)\n\n\t// ? using did as it is derived from the same ecdh in note3 and part of the minimal AppAgent type required here in wovin core\n\tconst shareCounterLog = getExistingOrNewLog(appThread, share, agent.ag, 'share/counter', `${agent.did}<::>${pubCounter}`)\n\t// ? discuss if this works to bind the counter to a specific derivation key - did is not necessarily derived from the same key by all lib users\n\n\tconst encryptApplog = async (applog: Applog, keyToUse: CryptoKey): Promise<Uint8Array> => {\n\t\tconst { log: eachLog, cid } = prepareForPub(applog) // without cid\n\t\tconst enc = new TextEncoder()\n\t\tconst stringified = stringify(eachLog)\n\t\tconst stringifiedEncodedAppLogPayload = enc.encode(stringified) // TODO: consider encodeToDagJson instead\n\t\tVERBOSE('[odd]', { eachLog, stringified, stringifiedEncodedAppLogPayload })\n\n\t\ttry {\n\t\t\t// @ts-expect-error\n\t\t\tconst encPayload = await agent.crypto?.aes.encrypt(stringifiedEncodedAppLogPayload, keyToUse, 'AES-GCM')\n\t\t\t// TODO get rid of odd down here\n\t\t\tVERBOSE('[odd] encrypted length:', stringifiedEncodedAppLogPayload.length, { encPayload })\n\t\t\treturn encPayload\n\t\t} catch (err) {\n\t\t\tthrow ERROR('FAILED TO ENC payload length:', stringifiedEncodedAppLogPayload.length, { err })\n\t\t}\n\n\t\t// const decrypted = await decryptWithAesSharedKey(encPayload, keyToUse, 'string')\n\t}\n\n\tlet maybeEncryptedApplogs: ApplogEncNoCid[] | readonly Applog[]\n\tconst encryptedApplogs = [] as { enc: Uint8Array }[]\n\tconst agentSharedKeyLogs = []\n\tif (sharedAgents) { // encrypt all Applogs\n\t\tif (!sharedKey || !sharedKeyMap) {\n\t\t\tthrow ERROR('sharedAgents but no Keys/Map', { sharedAgents, sharedKeyMap, sharedKey })\n\t\t}\n\t\tVERBOSE('encrypting', { sharedAgents, sharedKeyMap })\n\n\t\tfor (const [eachAgent, eachEncKey] of Array.from(sharedKeyMap.entries())) {\n\t\t\tVERBOSE('adding key', { eachAgent, eachEncKey })\n\t\t\tagentSharedKeyLogs.push({\n\t\t\t\tag: agent.ag,\n\t\t\t\ten: eachAgent,\n\t\t\t\tat: 'share/sharedKey',\n\t\t\t\tvl: eachEncKey, // these are encrypted with the derived key from the local agent private and remote agent public keys\n\t\t\t})\n\t\t}\n\t\t// const encryptedForLogs = await insertApplogsInAppDB(agentSharedKeyLogs)\n\t\t// DEBUG(`[publish] adding agentSharedKeyLogs:`, encryptedForLogs)\n\t\tconst CIDlist: { cid: CidString; encCID?: CidString }[] = []\n\t\tconst pubCIDmap: Record<CidString, typeof CIDlist> = {}\n\t\t// TODO ensure that all needed keys are in\n\t\tfor (const eachLog of logsToPublish) {\n\t\t\tVERBOSE('[crypto] encrypting ', { eachLog, sharedKey })\n\t\t\t// try {\n\t\t\tconst encPayload = await encryptApplog(eachLog, sharedKey)\n\t\t\tDEBUG('[crypto] encrypted ', { eachLog, encPayload, sharedKey })\n\t\t\t// } catch (err) {\n\t\t\t// \t// its already traced in encryptAndTestDecrypt\n\t\t\t// \t// continue\n\t\t\t// }\n\t\t\tencryptedApplogs.push({ enc: encPayload })\n\t\t}\n\t\tmaybeEncryptedApplogs = encryptedApplogs\n\t} else {\n\t\tmaybeEncryptedApplogs = logsToPublish // publish nonEncrypted\n\t}\n\n\tDEBUG('adding all agent info and shareAtoms', {\n\t\tshare,\n\t\tagent,\n\t\tlogsToPublish,\n\t\t// threadToPublish, - very verbose\n\t\tagentSharedKeyLogs,\n\t})\n\tconst infoLogs = [\n\t\t...rollingFilter(lastWriteWins(appThread), { // TODO: use static filter for performance\n\t\t\ten: agent.ag,\n\t\t\tat: ['agent/ecdh', 'agent/jwkd', 'agent/appAgent'],\n\t\t}).applogs,\n\t\t...(shareNameLog ? [shareNameLog] : []),\n\t\t...(shareCounterLog ? [shareCounterLog] : []),\n\t\t...agentSharedKeyLogs,\n\t]\n\tDEBUG(`[prepareSnapshotForPush] info logs:`, infoLogs)\n\tif (!infoLogs.find(({ at }) => at === 'agent/appAgent')) throw ERROR(`[prepareSnapshotForPush] appThread missing agent/appAgent log`)\n\n\tconst applogsToEncode = keepTruthy(maybeEncryptedApplogs)\n\tconst infologsToEncode = keepTruthy(infoLogs)\n\tif (!applogsToEncode.length) {\n\t\tthrow ERROR('no valid applogs', { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID })\n\t}\n\tif (!infologsToEncode.length) {\n\t\tthrow ERROR('no valid infologs', { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID })\n\t}\n\tconst encodedSnapshot = await encodeSnapshotAsCar(agent, applogsToEncode, infologsToEncode, prevSnapCID, prevCounter)\n\tDEBUG('inPrepareSnapshotForPush', { encodedSnapshot })\n\treturn encodedSnapshot\n}\n\n/**\n * @param applogs Encrypted or plain applogs\n * @returns Car file\n */\nexport async function encodeSnapshotAsCar(\n\tagent: AppAgent,\n\tapplogs: ApplogArrayNoCIDMaybeEncryptedRO,\n\tinfoLogs: readonly Applog[],\n\tprevSnapCID: CID | null,\n\tprevCounter: number | null,\n) {\n\tDEBUG(`[encodeSnapshotAsCar] encoding`, { agent, applogs, infoLogs })\n\tconst { cids: infoLogCids, encodedApplogs: encodedInfoLogs } = await encodeApplogsAsIPLD(infoLogs)\n\tconst { cids: applogCids, encodedApplogs } = await encodeApplogsAsIPLD(applogs)\n\tlet blocks = encodedApplogs.concat(encodedInfoLogs)\n\t// We need to wrap the array to get a CID\n\tconst infoLogsWrap = await encodeBlockOriginal({ logs: infoLogCids })\n\tblocks.push(infoLogsWrap)\n\tconst { rootCID: chunkRootCID, blocks: chunkBlocks } = await chunkApplogs(applogCids)\n\tblocks = blocks.concat(chunkBlocks) // (i) concat bc. https://stackoverflow.com/a/51860949\n\tconst infoSignature = await agent.sign(infoLogsWrap.cid.bytes)\n\tconst applogsSignature = await agent.sign(chunkRootCID.bytes)\n\tconst root = {\n\t\tinfo: infoLogsWrap.cid,\n\t\tapplogs: chunkRootCID,\n\t\tinfoSignature,\n\t\tapplogsSignature,\n\t\tprev: prevSnapCID,\n\t\tprevCounter: !prevSnapCID ? 0 : prevCounter !== null ? prevCounter + 1 : null,\n\t}\n\tDEBUG('[encodeSnapshotAsCar] encoding root', { root, logCids: applogCids, infoLogCids })\n\tconst encodedRoot = await encodeBlockOriginal(root)\n\tblocks.push(encodedRoot)\n\tDEBUG('[encodeSnapshotAsCar] => root', { encodedRoot })\n\n\treturn {\n\t\tcid: encodedRoot.cid,\n\t\tblob: await makeCarBlob(encodedRoot.cid, blocks), // TODO: create CarBuilder (incl .encodeAndAdd({...}))\n\t\tblocks,\n\t\tinfoLogCids,\n\t\tapplogCids,\n\t}\n}\n\n/** (i) IPFS has a block size limit of 1MB - which is about 15K CIDs */\nexport async function chunkApplogs(applogCids: CID<unknown, 297, 18, 1>[], size = 10000) {\n\tif (!applogCids.length) throw ERROR(`[chunkApplogs] called with empty array`)\n\tconst chunks = []\n\t// TODO: chunk by stable btree based on size or something like that\n\tfor (let i = 0; i < applogCids.length; i += size) {\n\t\tconst chunk = await encodeBlockOriginal({ logs: applogCids.slice(i, Math.min(i + applogCids.length, i + size)) })\n\t\tchunks.push(chunk)\n\t}\n\tif (chunks.length === 1) return { rootCID: chunks[0].cid, blocks: chunks }\n\tconst root = await encodeBlockOriginal({ chunks: chunks.map(chunk => chunk.cid) })\n\tconst blocks = [root, ...chunks]\n\tDEBUG(`[chunkApplogs] ${applogCids.length} logs chunked into ${chunks.length}`, { applogCids, root, blocks, chunks, dagJson })\n\treturn { rootCID: root.cid, blocks, chunks }\n}\nexport async function unchunkApplogsBlock(block: SnapBlockLogsOrChunks, blockStore: BlockStoreish): Promise<CID[]> {\n\tif (isSnapBlockChunks(block)) {\n\t\treturn (await Promise.all(\n\t\t\tblock.chunks.map(async (chunkCid) => {\n\t\t\t\tconst block = (await getDecodedBlock(blockStore, chunkCid)) as SnapBlockLogs\n\t\t\t\tif (!block.logs) throw ERROR(`Weird chunk`, block)\n\t\t\t\treturn block.logs\n\t\t\t}),\n\t\t)).flat()\n\t} else {\n\t\treturn block.logs\n\t}\n}\nexport function isSnapBlockChunks(block: SnapBlockLogsOrChunks): block is SnapBlockChunks {\n\treturn (block as any).chunks\n}\n/**\n * @param applogs Encrypted or plain applogs\n * @returns Car file\n */\nexport async function encodeSnapshotApplogsAsCar(\n\tapplogs: ApplogArrayMaybeEncryptedRO,\n) {\n\tconst encoded = await encodeApplogsAsIPLD(applogs)\n\tif (!encoded) throw ERROR('invalid applogs cannot continue', { applogs, encoded })\n\tconst { cids, encodedApplogs } = encoded\n\tconst root = { applogs: cids }\n\tconst encodedRoot = await encodeBlockOriginal(root)\n\tDEBUG('[encodeSnapshotApplogsAsCar] encoded root', { cids, encodedRoot })\n\n\treturn await makeCarBlob(encodedRoot.cid, [encodedRoot, ...encodedApplogs])\n}\n\nasync function encodeApplogsAsIPLD(applogs: ApplogArrayNoCIDMaybeEncryptedRO) {\n\tDEBUG({ applogs })\n\tconst validApplogs = applogs.filter(eachLog => !!eachLog)\n\tDEBUG({ validApplogs })\n\tif (!validApplogs.length) throw ERROR('no valid applogs')\n\tconst preppedLogs = validApplogs.map(log => prepareForPub(log as Applog).log)\n\tconst encodedApplogs = await Promise.all(preppedLogs.map(encodeBlockOriginal))\n\tDEBUG('[encodeApplogsAsIpld] encoded applogs', { preppedLogs, encodedApplogs })\n\n\tconst cids = encodedApplogs.map(b => {\n\t\tif (!b.cid) throw ERROR(`[publish] no cid for encoded log:`, b)\n\t\treturn b.cid\n\t})\n\treturn { cids, encodedApplogs }\n}\n","import { CarReader, CarWriter } from '@ipld/car'\nimport * as dagJson from '@ipld/dag-json'\nimport { Logger } from 'besonders-logger'\nimport { BlockView, CID } from 'multiformats'\nimport { sortApplogsByTs } from '../applog/applog-utils.ts'\nimport { Applog, ApplogArrayMaybeEncrypted, CidString } from '../applog/datom-types.ts'\nimport { unchunkApplogsBlock } from '../pubsub/snap-push.ts'\nimport { SnapBlockLogs, SnapBlockLogsOrChunks, SnapRootBlock } from '../pubsub/pubsub-types.ts'\nimport { areCidsEqual, containsCid } from './ipfs-utils.ts'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport type CIDForCar = CID // Exclude<Parameters<(typeof CarWriter)['create']>[0], void>\nexport type BlockForCar = Parameters<CarWriter['put']>[0]\n\nexport interface BlockStoreish {\n\tget(cid: CID): PromiseLike<Uint8Array> // (i) not using decoded version to be similar to blockstore-idb\n}\n\nexport interface DecodedCar {\n\trootCID: CID\n\t// blocks: Map<CidString, any>\n\tblockStore: BlockStoreish\n}\n\n/** Warning: unsorted & maybe encrypted */\nexport async function decodePubFromCar(car: CarReader) {\n\tconst decoded = await getBlocksOfCar(car)\n\treturn await decodePubFromBlocks(decoded)\n}\n\nexport async function decodePubFromBlocks(\n\t{ rootCID, blockStore }: DecodedCar,\n\t_recursionTrace: CID[] = [], // DEPRECATED: kept for API compat, unused in iterative version\n\tstopAtCID?: CID // NEW: stop iteration when we hit this CID\n) {\n\tif (!rootCID || !blockStore) {\n\t\tthrow ERROR('Empty roots/blocks', { rootCID, blockStore })\n\t}\n\n\tlet allApplogs: ApplogArrayMaybeEncrypted = []\n\tlet firstInfo: { logs: CID[] } | null = null\n\tlet currentCID: CID | undefined = rootCID\n\tconst visited = new Set<string>() // Loop detection (replaces recursionTrace)\n\tlet applogsCID: CID | null = null // From first snapshot only\n\n\twhile (currentCID) {\n\t\tconst cidStr = currentCID.toString()\n\n\t\t// Loop detection\n\t\tif (visited.has(cidStr)) {\n\t\t\tthrow ERROR('[decodePubFromBlocks] pub chain has a loop', {\n\t\t\t\tcurrentCID: cidStr,\n\t\t\t\tvisited: [...visited]\n\t\t\t})\n\t\t}\n\t\tvisited.add(cidStr)\n\n\t\t// Decode current snapshot\n\t\tconst root = (await getDecodedBlock(blockStore, currentCID)) as SnapRootBlock\n\t\tVERBOSE(`[decodePubFromBlocks] root:`, cidStr, root, { blockStore })\n\t\tif (!root) {\n\t\t\tthrow ERROR('[decodePubFromBlocks] root not found in blockStore', { blockStore, currentCID: cidStr })\n\t\t}\n\n\t\t// Decode applogs for this snapshot\n\t\tlet pubLogsArray: CID[]\n\t\tif (root?.info) {\n\t\t\t// New(er) format\n\t\t\tif (!applogsCID) applogsCID = root.applogs // Save from first snapshot\n\t\t\tconst applogsBlock = (await getDecodedBlock(blockStore, root.applogs)) as SnapBlockLogsOrChunks\n\t\t\tpubLogsArray = await unchunkApplogsBlock(applogsBlock, blockStore)\n\t\t\t// Info only from first (most recent) snapshot\n\t\t\tif (!firstInfo) {\n\t\t\t\tfirstInfo = (await getDecodedBlock(blockStore, root.info)) as SnapBlockLogs\n\t\t\t\tDEBUG(`new format - infoLogs`, firstInfo.logs.map(l => ({ [l.toString()]: l })))\n\t\t\t}\n\t\t\t// TODO: verify signatures\n\t\t} else {\n\t\t\t// Old format\n\t\t\tpubLogsArray = root.applogs as any as CID[]\n\t\t}\n\n\t\tconst resolveLogFromCidLink = async (cidOrLink: CID) => {\n\t\t\tconst cid = cidOrLink\n\t\t\tconst applog = (await getDecodedBlock(blockStore, cid)) as Applog\n\t\t\tif (!applog) {\n\t\t\t\tERROR(`Could not find applog CID in pub blocks:`, cid.toString(), { cid, root, blockStore })\n\t\t\t\tthrow new Error(`Could not find applog CID in pub blocks: ${cid.toString()}`)\n\t\t\t}\n\t\t\tif ((applog.pv as any) instanceof CID) applog.pv = (applog.pv as any as CID).toV1().toString()\n\t\t\treturn {\n\t\t\t\t...applog,\n\t\t\t\tcid: cid.toV1().toString(),\n\t\t\t}\n\t\t}\n\n\t\tconst snapshotApplogs = await Promise.all(pubLogsArray.map(resolveLogFromCidLink))\n\t\tallApplogs = allApplogs.concat(snapshotApplogs)\n\n\t\t// Check if we should stop\n\t\tif (!root.prev) {\n\t\t\tbreak // End of chain\n\t\t}\n\t\tif (stopAtCID && areCidsEqual(root.prev, stopAtCID)) {\n\t\t\tDEBUG('[decodePubFromBlocks] stopping at stopAtCID:', stopAtCID.toString())\n\t\t\tbreak // Reached already-pulled snapshot\n\t\t}\n\n\t\t// Verify prev exists before continuing\n\t\tconst prevBytes = await blockStore.get(root.prev)\n\t\tif (!prevBytes) {\n\t\t\tthrow ERROR('[decodePubFromBlocks] prev snapshot missing from blockStore', {\n\t\t\t\tcurrentCID: cidStr,\n\t\t\t\tprev: root.prev.toString(),\n\t\t\t\tstopAtCID: stopAtCID?.toString(),\n\t\t\t\tvisited: [...visited]\n\t\t\t})\n\t\t}\n\n\t\tcurrentCID = root.prev // Move to previous snapshot\n\t}\n\n\tconst result = {\n\t\tcid: rootCID,\n\t\tinfo: firstInfo ? {\n\t\t\t...firstInfo,\n\t\t\tlogs: await Promise.all(firstInfo.logs.map(async (cidOrLink: CID) => {\n\t\t\t\tconst cid = cidOrLink\n\t\t\t\tconst applog = (await getDecodedBlock(blockStore, cid)) as Applog\n\t\t\t\tif (!applog) {\n\t\t\t\t\tERROR(`Could not find info log CID in pub blocks:`, cid.toString(), { cid, blockStore })\n\t\t\t\t\tthrow new Error(`Could not find info log CID in pub blocks: ${cid.toString()}`)\n\t\t\t\t}\n\t\t\t\tif ((applog.pv as any) instanceof CID) applog.pv = (applog.pv as any as CID).toV1().toString()\n\t\t\t\treturn {\n\t\t\t\t\t...applog,\n\t\t\t\t\tcid: cid.toV1().toString(),\n\t\t\t\t}\n\t\t\t})),\n\t\t} : null,\n\t\tapplogsCID,\n\t\tapplogs: allApplogs,\n\t}\n\tDEBUG('[decodePubFromBlocks] result:', result, { rootCID: rootCID.toString(), blockStore, applogs: allApplogs })\n\treturn result\n}\n\nexport async function getBlocksOfCar(car: CarReader) {\n\tconst rootsFromCar = await car.getRoots()\n\tconst roots = rootsFromCar.map(c => ((typeof c.toV1 === 'function') ? c : CID.decode(c.bytes)).toV1().toString() as CidString) // HACK\n\tconst blocks = new Map<CidString, any>()\n\tfor await (const { cid: cidFromCarblocks, bytes } of car.blocks()) {\n\t\tconst cid = (typeof cidFromCarblocks.toV1 === 'function') ? cidFromCarblocks : CID.decode(cidFromCarblocks.bytes)\n\t\tVERBOSE({ cidFromCarblocks, cid })\n\t\t// blocks.set(cid.toV1().toString(), dagJson.decode(bytes)) // HACK: tried using CID as map key, but because it's based on referential equality it's not working\n\t\tblocks.set(cid.toV1().toString(), bytes) // HACK: tried using CID as map key, but because it's based on referential equality it's not working\n\t}\n\tif (roots.length !== 1) {\n\t\tWARN('Unexpected roots count:', roots)\n\t}\n\treturn {\n\t\trootCID: CID.parse(roots[0]),\n\t\tblockStore: {\n\t\t\tget: (cid) => blocks.get(cid.toV1().toString()),\n\t\t},\n\t} satisfies DecodedCar\n}\nexport async function getDecodedBlock(blockStore: BlockStoreish, cid: CID) {\n\ttry {\n\t\tvar blob = await blockStore.get(cid)\n\t\tif (!blob) {\n\t\t\tWARN('returning null')\n\t\t\treturn null // I don't think this ever happens actually\n\t\t}\n\t} catch (err) {\n\t\tif ((err as any).message === 'Not Found') return null\n\t\tthrow err\n\t}\n\treturn dagJson.decode(blob)\n}\n\n// make out in the car... been a while but also sounds nice\nexport async function makeCarOut(roots: CIDForCar, blocks: BlockForCar[]) {\n\tconst { writer, out } = CarWriter.create(Array.isArray(roots) ? roots : [roots])\n\n\t// add the blocks to the CAR and close it\n\tVERBOSE(`Writing ${blocks.length} blocks to CAR`, { roots, blocks })\n\tblocks.forEach(b => writer.put(b))\n\twriter.close()\n\t// VERBOSE(`Wrote ${blocks.length} blocks to CAR`, writer)\n\treturn out\n} /** create a new CarWriter, with the encoded block as the root */\n\n// export async function makeCarReader(roots: CIDForCar, blocks: BlockForCar[]) {\n// \tconst out = await makeCarOut(roots, blocks)\n\n// \t// create a new CarReader we can hand to web3.storage.putCar\n// \tconst reader = await CarReader.fromIterable(out)\n// \tVERBOSE(`CAR reader`, reader)\n// \treturn reader\n// } /** create a new CarWriter, with the encoded block as the root */\n\nexport async function makeCarBlob(roots: CIDForCar, blocks: BlockForCar[]) {\n\tconst carOut = await makeCarOut(roots, blocks)\n\tconst chunks = []\n\tfor await (const chunk of carOut) {\n\t\tchunks.push(chunk)\n\t}\n\tconst blob = new Blob(chunks)\n\treturn blob\n}\nexport async function carFromBlob(blob: Blob | File): Promise<CarReader> {\n\treturn CarReader.fromBytes(new Uint8Array(await blob.arrayBuffer()))\n}\n\nfunction extractCids(value: unknown): CID[] {\n\tif (value instanceof CID) return [value]\n\tif (Array.isArray(value)) return value.flatMap(extractCids)\n\tif (value && typeof value === 'object') return Object.values(value).flatMap(extractCids)\n\treturn []\n}\n\nconst MAX_COLLECT_BLOCKS = 1_000_000\n\nexport async function collectDagBlocks(\n\tstartCID: CID,\n\tblockStore: BlockStoreish,\n): Promise<BlockForCar[]> {\n\tconst visited = new Set<string>()\n\tconst blocks: BlockForCar[] = []\n\tconst queue: CID[] = [startCID]\n\n\twhile (queue.length > 0) {\n\t\tif (blocks.length >= MAX_COLLECT_BLOCKS) {\n\t\t\tWARN(`[collectDagBlocks] hit ${MAX_COLLECT_BLOCKS} block limit, returning partial result`)\n\t\t\tbreak\n\t\t}\n\n\t\tconst cid = queue.shift()!\n\t\tconst cidStr = cid.toString()\n\t\tif (visited.has(cidStr)) continue\n\t\tvisited.add(cidStr)\n\n\t\tlet bytes: Uint8Array\n\t\ttry {\n\t\t\tbytes = await blockStore.get(cid)\n\t\t} catch {\n\t\t\tWARN(`[collectDagBlocks] block not found: ${cidStr}, stopping this branch`)\n\t\t\tcontinue\n\t\t}\n\t\tif (!bytes) {\n\t\t\tWARN(`[collectDagBlocks] block not found: ${cidStr}, stopping this branch`)\n\t\t\tcontinue\n\t\t}\n\n\t\tblocks.push({ cid, bytes })\n\n\t\tif (blocks.length % 1000 === 0) {\n\t\t\tLOG(`[collectDagBlocks] collected ${blocks.length} blocks...`)\n\t\t}\n\n\t\ttry {\n\t\t\tconst decoded = dagJson.decode(bytes)\n\t\t\tconst childCids = extractCids(decoded)\n\t\t\tfor (const child of childCids) {\n\t\t\t\tif (!visited.has(child.toString())) {\n\t\t\t\t\tqueue.push(child)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not dag-json — leaf block, no children to walk\n\t\t}\n\t}\n\n\tDEBUG(`[collectDagBlocks] collected ${blocks.length} blocks from ${startCID.toString()}`)\n\treturn blocks\n}\n\nexport function streamReaderToIterable(bodyReader: ReadableStreamDefaultReader<Uint8Array>): AsyncIterable<Uint8Array> {\n\treturn (async function*() {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await bodyReader.read()\n\t\t\tVERBOSE(`[car] chunk`, { done, value })\n\t\t\tif (done) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tyield value\n\t\t}\n\t})()\n}\n"],"mappings":"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","names":["dagJson","Logger","WARN","LOG","DEBUG","VERBOSE","ERROR","Logger","share","dagJson","block"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/query/divergences.ts","../src/query/matchers.ts","../src/query/entity-collection.ts"],"sourcesContent":["import { Logger } from 'besonders-logger'\nimport stringify from 'safe-stable-stringify'\nimport { Applog, CidString } from '../applog/datom-types.ts'\nimport { createDebugName } from '../utils/debug-name.ts'\nimport { Thread } from '../thread/basic.ts'\nimport { ThreadInMemory } from '../thread/writeable.ts'\nimport { memoizedFn } from './memoized.ts'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport interface DivergenceLeaf {\n\tlog: Applog\n\tthread: Thread\n}\n\nexport const queryDivergencesByPrev = memoizedFn('queryDivergencesByPrev', function queryConflictingByPrev(\n\tsourceThread: Thread,\n) {\n\tDEBUG(`queryDivergencesByPrev<${sourceThread.nameAndSizeUntracked}>`)\n\tif (sourceThread.filters.includes('lastWriteWins')) WARN(`queryDivergencesByPrev on thread lastWriteWins`, sourceThread)\n\n\tconst logsForNode = new Map<CidString, Applog[]>()\n\tconst leafs = new Set<CidString>()\n\tVERBOSE('all applogs:', sourceThread.applogs)\n\tfor (const log of sourceThread.applogs) {\n\t\tlet prevLogs\n\t\tif (log.pv) {\n\t\t\tprevLogs = log.pv && logsForNode.get(log.pv.toString())\n\t\t\tleafs.delete(log.pv.toString())\n\t\t}\n\t\tVERBOSE('traversing log', { log, prevLogs, leafs: Array.from(leafs) })\n\t\tlogsForNode.set(log.cid, prevLogs ? [...prevLogs, log] : [log])\n\t\tleafs.add(log.cid)\n\t}\n\tconst divergences = Array.from(leafs).map(leafID => {\n\t\tconst thread = new ThreadInMemory(\n\t\t\tcreateDebugName({\n\t\t\t\tcaller: 'DivergenceLeaf',\n\t\t\t\tthread: sourceThread,\n\t\t\t\tpattern: `leaf: ${leafID}`,\n\t\t\t}),\n\t\t\tlogsForNode.get(leafID),\n\t\t\tsourceThread.filters,\n\t\t\ttrue,\n\t\t)\n\t\treturn ({ log: thread.latestLog, thread })\n\t})\n\t// TODO: migrate to SubscribableArray for reactive updates\n\treturn divergences\n})\n","import { DatomPart } from '../applog/datom-types.ts'\n\nexport function includes(str: string) {\n\treturn (vl: DatomPart) => vl?.includes?.(str)\n}\nexport function includedIn(arr: string[]) {\n\treturn (vl: DatomPart) => arr?.includes?.(vl)\n}\n","import { Logger } from 'besonders-logger'\nimport { Applog, ApplogValue, DatalogQueryPattern, EntityID } from '../applog/datom-types.ts'\nimport { isInitEvent, Thread } from '../thread/basic.ts'\nimport { makeFilter, rollingFilter } from '../thread/filters.ts'\nimport { resolveKeyMapper } from './basic.ts'\nimport { memoizedFn } from './memoized.ts'\nimport { SubscribableImpl } from './subscribable.ts'\nimport type { Subscribable } from './subscribable.ts'\nimport type { StripExplicitPrefix, StripFirstPrefix } from './attr-helpers.ts'\n\nconst { DEBUG } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport function liveEntityCollection<A extends string>(\n\tthread: Thread, discoveryPattern: DatalogQueryPattern, liveAttributes: readonly A[],\n): Subscribable<ReadonlyMap<EntityID, Record<A, ApplogValue | null>>>\nexport function liveEntityCollection<A extends string>(\n\tthread: Thread, discoveryPattern: DatalogQueryPattern, liveAttributes: readonly A[],\n\topts: { stripAtPrefix: true },\n): Subscribable<ReadonlyMap<EntityID, Record<StripFirstPrefix<A>, ApplogValue | null>>>\nexport function liveEntityCollection<A extends string, P extends string>(\n\tthread: Thread, discoveryPattern: DatalogQueryPattern, liveAttributes: readonly A[],\n\topts: { stripAtPrefix: P },\n): Subscribable<ReadonlyMap<EntityID, Record<StripExplicitPrefix<A, P>, ApplogValue | null>>>\nexport function liveEntityCollection<A extends string>(\n\tthread: Thread, discoveryPattern: DatalogQueryPattern, liveAttributes: readonly A[],\n\topts: { mapKeys: (attr: A) => string },\n): Subscribable<ReadonlyMap<EntityID, Record<string, ApplogValue | null>>>\nexport function liveEntityCollection<A extends string>(\n\tthread: Thread, discoveryPattern: DatalogQueryPattern, liveAttributes: readonly A[],\n\topts: { stripAtPrefix?: true | string; mapKeys?: (attr: A) => string },\n): Subscribable<ReadonlyMap<EntityID, Record<string, ApplogValue | null>>>\nexport function liveEntityCollection<A extends string>(\n\tthread: Thread,\n\tdiscoveryPattern: DatalogQueryPattern,\n\tliveAttributes: readonly A[],\n\topts?: { stripAtPrefix?: true | string; mapKeys?: (attr: A) => string },\n): Subscribable<ReadonlyMap<EntityID, Record<string, ApplogValue | null>>> {\n\treturn _liveEntityCollection(thread, discoveryPattern, liveAttributes,\n\t\topts as { stripAtPrefix?: true | string; mapKeys?: (attr: string) => string })\n}\n\nconst _liveEntityCollection = memoizedFn('liveEntityCollection',\n\tfunction liveEntityCollection<A extends string>(\n\t\tthread: Thread,\n\t\tdiscoveryPattern: DatalogQueryPattern,\n\t\tliveAttributes: readonly A[],\n\t\topts?: { stripAtPrefix?: true | string; mapKeys?: (attr: string) => string },\n\t): Subscribable<ReadonlyMap<EntityID, Record<string, ApplogValue | null>>> {\n\t\tDEBUG('liveEntityCollection', discoveryPattern, liveAttributes)\n\t\tconst discoveryAttr = discoveryPattern.at as string\n\t\tconst allAttrs = new Set([discoveryAttr, ...liveAttributes])\n\t\tconst filtered = rollingFilter(thread, { at: [...allAttrs] })\n\t\tconst isDiscoveryMatch = makeFilter(discoveryPattern)\n\t\tconst attrSet = new Set<string>(liveAttributes)\n\t\tconst key = resolveKeyMapper(opts)\n\n\t\tconst map = new Map<EntityID, Record<string, ApplogValue | null>>()\n\n\t\tfunction makeRecord(entityId: EntityID): Record<string, ApplogValue | null> {\n\t\t\tconst record = {} as Record<string, ApplogValue | null>\n\t\t\tfor (const attr of liveAttributes) record[key(attr)] = null\n\t\t\t// Backfill from current filtered state\n\t\t\tfor (const log of filtered.applogs) {\n\t\t\t\tif (log.en === entityId && attrSet.has(log.at)) {\n\t\t\t\t\trecord[key(log.at)] = log.vl\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn record\n\t\t}\n\n\t\tfunction buildFull(applogs: readonly Applog[]) {\n\t\t\tmap.clear()\n\t\t\tfor (const log of isDiscoveryMatch(applogs)) {\n\t\t\t\tif (!map.has(log.en)) map.set(log.en, makeRecord(log.en))\n\t\t\t}\n\t\t}\n\n\t\tfunction addLog(log: Applog) {\n\t\t\t// Discovery match → ensure entity exists\n\t\t\tif (isDiscoveryMatch([log]).length > 0 && !map.has(log.en)) {\n\t\t\t\tmap.set(log.en, makeRecord(log.en))\n\t\t\t\treturn // makeRecord already backfilled attrs\n\t\t\t}\n\t\t\t// Attribute match → update value\n\t\t\tif (attrSet.has(log.at)) {\n\t\t\t\tconst record = map.get(log.en)\n\t\t\t\tif (record) record[key(log.at)] = log.vl\n\t\t\t}\n\t\t}\n\n\t\tfunction removeLog(log: Applog) {\n\t\t\tif (isDiscoveryMatch([log]).length > 0) {\n\t\t\t\t// Check if entity still has another discovery match\n\t\t\t\tconst stillDiscovered = filtered.applogs.some(\n\t\t\t\t\tl => l.en === log.en && isDiscoveryMatch([l]).length > 0,\n\t\t\t\t)\n\t\t\t\tif (!stillDiscovered) {\n\t\t\t\t\tmap.delete(log.en)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (attrSet.has(log.at)) {\n\t\t\t\tconst record = map.get(log.en)\n\t\t\t\tif (record) {\n\t\t\t\t\t// Find current value from remaining applogs\n\t\t\t\t\tconst current = filtered.applogs.find(l => l.en === log.en && l.at === log.at)\n\t\t\t\t\trecord[key(log.at)] = current?.vl ?? null\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Initial build\n\t\tbuildFull(filtered.applogs)\n\n\t\tconst result = new SubscribableImpl<ReadonlyMap<EntityID, Record<string, ApplogValue | null>>>(\n\t\t\tmap,\n\t\t\t() => filtered.subscribe((event) => {\n\t\t\t\tif (isInitEvent(event)) {\n\t\t\t\t\tbuildFull(event.init)\n\t\t\t\t} else {\n\t\t\t\t\t// Process removes before adds — LWW updates appear as remove+add in same delta\n\t\t\t\t\tif (event.removed) for (const log of event.removed) removeLog(log)\n\t\t\t\t\tfor (const log of event.added) addLog(log)\n\t\t\t\t}\n\t\t\t\tresult._set(map)\n\t\t\t}, 'derived'),\n\t\t\t{ equals: false },\n\t\t)\n\t\treturn result\n\t},\n)\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,cAAc;AAQvB,IAAM,EAAE,MAAM,KAAK,OAAO,SAAS,MAAM,IAAI,OAAO,MAAM,OAAO,IAAI;AAO9D,IAAM,yBAAyB,WAAW,0BAA0B,SAAS,uBACnF,cACC;AACD,QAAM,0BAA0B,aAAa,oBAAoB,GAAG;AACpE,MAAI,aAAa,QAAQ,SAAS,eAAe,EAAG,MAAK,kDAAkD,YAAY;AAEvH,QAAM,cAAc,oBAAI,IAAyB;AACjD,QAAM,QAAQ,oBAAI,IAAe;AACjC,UAAQ,gBAAgB,aAAa,OAAO;AAC5C,aAAW,OAAO,aAAa,SAAS;AACvC,QAAI;AACJ,QAAI,IAAI,IAAI;AACX,iBAAW,IAAI,MAAM,YAAY,IAAI,IAAI,GAAG,SAAS,CAAC;AACtD,YAAM,OAAO,IAAI,GAAG,SAAS,CAAC;AAAA,IAC/B;AACA,YAAQ,kBAAkB,EAAE,KAAK,UAAU,OAAO,MAAM,KAAK,KAAK,EAAE,CAAC;AACrE,gBAAY,IAAI,IAAI,KAAK,WAAW,CAAC,GAAG,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC;AAC9D,UAAM,IAAI,IAAI,GAAG;AAAA,EAClB;AACA,QAAM,cAAc,MAAM,KAAK,KAAK,EAAE,IAAI,YAAU;AACnD,UAAM,SAAS,IAAI;AAAA,MAClB,gBAAgB;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,SAAS,SAAS,MAAM;AAAA,MACzB,CAAC;AAAA,MACD,YAAY,IAAI,MAAM;AAAA,MACtB,aAAa;AAAA,MACb;AAAA,IACD;AACA,WAAQ,EAAE,KAAK,OAAO,WAAW,OAAO;AAAA,EACzC,CAAC;AAED,SAAO;AACR,CAAC;;;AC/CM,SAAS,SAAS,KAAa;AACrC,SAAO,CAAC,OAAkB,IAAI,WAAW,GAAG;AAC7C;AACO,SAAS,WAAW,KAAe;AACzC,SAAO,CAAC,OAAkB,KAAK,WAAW,EAAE;AAC7C;;;ACPA,SAAS,UAAAA,eAAc;AAUvB,IAAM,EAAE,OAAAC,OAAM,IAAIC,QAAO,MAAMA,QAAO,IAAI;AAqBnC,SAAS,qBACf,QACA,kBACA,gBACA,MAC0E;AAC1E,SAAO;AAAA,IAAsB;AAAA,IAAQ;AAAA,IAAkB;AAAA,IACtD;AAAA,EAA6E;AAC/E;AAEA,IAAM,wBAAwB;AAAA,EAAW;AAAA,EACxC,SAASC,sBACR,QACA,kBACA,gBACA,MAC0E;AAC1E,IAAAF,OAAM,wBAAwB,kBAAkB,cAAc;AAC9D,UAAM,gBAAgB,iBAAiB;AACvC,UAAM,WAAW,oBAAI,IAAI,CAAC,eAAe,GAAG,cAAc,CAAC;AAC3D,UAAM,WAAW,cAAc,QAAQ,EAAE,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC;AAC5D,UAAM,mBAAmB,WAAW,gBAAgB;AACpD,UAAM,UAAU,IAAI,IAAY,cAAc;AAC9C,UAAM,MAAM,iBAAiB,IAAI;AAEjC,UAAM,MAAM,oBAAI,IAAkD;AAElE,aAAS,WAAW,UAAwD;AAC3E,YAAM,SAAS,CAAC;AAChB,iBAAW,QAAQ,eAAgB,QAAO,IAAI,IAAI,CAAC,IAAI;AAEvD,iBAAW,OAAO,SAAS,SAAS;AACnC,YAAI,IAAI,OAAO,YAAY,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC/C,iBAAO,IAAI,IAAI,EAAE,CAAC,IAAI,IAAI;AAAA,QAC3B;AAAA,MACD;AACA,aAAO;AAAA,IACR;AAEA,aAAS,UAAU,SAA4B;AAC9C,UAAI,MAAM;AACV,iBAAW,OAAO,iBAAiB,OAAO,GAAG;AAC5C,YAAI,CAAC,IAAI,IAAI,IAAI,EAAE,EAAG,KAAI,IAAI,IAAI,IAAI,WAAW,IAAI,EAAE,CAAC;AAAA,MACzD;AAAA,IACD;AAEA,aAAS,OAAO,KAAa;AAE5B,UAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,SAAS,KAAK,CAAC,IAAI,IAAI,IAAI,EAAE,GAAG;AAC3D,YAAI,IAAI,IAAI,IAAI,WAAW,IAAI,EAAE,CAAC;AAClC;AAAA,MACD;AAEA,UAAI,QAAQ,IAAI,IAAI,EAAE,GAAG;AACxB,cAAM,SAAS,IAAI,IAAI,IAAI,EAAE;AAC7B,YAAI,OAAQ,QAAO,IAAI,IAAI,EAAE,CAAC,IAAI,IAAI;AAAA,MACvC;AAAA,IACD;AAEA,aAAS,UAAU,KAAa;AAC/B,UAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,SAAS,GAAG;AAEvC,cAAM,kBAAkB,SAAS,QAAQ;AAAA,UACxC,OAAK,EAAE,OAAO,IAAI,MAAM,iBAAiB,CAAC,CAAC,CAAC,EAAE,SAAS;AAAA,QACxD;AACA,YAAI,CAAC,iBAAiB;AACrB,cAAI,OAAO,IAAI,EAAE;AACjB;AAAA,QACD;AAAA,MACD;AACA,UAAI,QAAQ,IAAI,IAAI,EAAE,GAAG;AACxB,cAAM,SAAS,IAAI,IAAI,IAAI,EAAE;AAC7B,YAAI,QAAQ;AAEX,gBAAM,UAAU,SAAS,QAAQ,KAAK,OAAK,EAAE,OAAO,IAAI,MAAM,EAAE,OAAO,IAAI,EAAE;AAC7E,iBAAO,IAAI,IAAI,EAAE,CAAC,IAAI,SAAS,MAAM;AAAA,QACtC;AAAA,MACD;AAAA,IACD;AAGA,cAAU,SAAS,OAAO;AAE1B,UAAM,SAAS,IAAI;AAAA,MAClB;AAAA,MACA,MAAM,SAAS,UAAU,CAAC,UAAU;AACnC,YAAI,YAAY,KAAK,GAAG;AACvB,oBAAU,MAAM,IAAI;AAAA,QACrB,OAAO;AAEN,cAAI,MAAM,QAAS,YAAW,OAAO,MAAM,QAAS,WAAU,GAAG;AACjE,qBAAW,OAAO,MAAM,MAAO,QAAO,GAAG;AAAA,QAC1C;AACA,eAAO,KAAK,GAAG;AAAA,MAChB,GAAG,SAAS;AAAA,MACZ,EAAE,QAAQ,MAAM;AAAA,IACjB;AACA,WAAO;AAAA,EACR;AACD;","names":["Logger","DEBUG","Logger","liveEntityCollection"]}