@wovin/core 0.1.36 → 0.2.2

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 (213) hide show
  1. package/README.md +0 -12
  2. package/dist/applog/applog-helpers.d.ts +12 -12
  3. package/dist/applog/applog-helpers.d.ts.map +1 -1
  4. package/dist/applog/applog-utils.d.ts +40 -6
  5. package/dist/applog/applog-utils.d.ts.map +1 -1
  6. package/dist/applog/datom-types.d.ts +67 -12
  7. package/dist/applog/datom-types.d.ts.map +1 -1
  8. package/dist/applog.d.ts +3 -3
  9. package/dist/applog.d.ts.map +1 -1
  10. package/dist/{applog.min.js → applog.js} +12 -7
  11. package/dist/blockstore.d.ts +1 -1
  12. package/dist/blockstore.d.ts.map +1 -1
  13. package/dist/{blockstore.min.js → blockstore.js} +1 -3
  14. package/dist/{blockstore.min.js.map → blockstore.js.map} +1 -1
  15. package/dist/chunk-22WDFLXO.js +138 -0
  16. package/dist/chunk-22WDFLXO.js.map +1 -0
  17. package/dist/chunk-3SUFNJEZ.js +1026 -0
  18. package/dist/chunk-3SUFNJEZ.js.map +1 -0
  19. package/dist/chunk-6ALNRM3J.js +435 -0
  20. package/dist/chunk-6ALNRM3J.js.map +1 -0
  21. package/dist/chunk-7Z5YDQKK.js +1 -0
  22. package/dist/{chunk-KXMTKPF4.min.js → chunk-BLF5MAWU.js} +8 -8
  23. package/dist/chunk-BLF5MAWU.js.map +1 -0
  24. package/dist/chunk-E46VTKTZ.js +1 -0
  25. package/dist/{chunk-H3VQJP56.min.js → chunk-HUIQ54TT.js} +9 -9
  26. package/dist/chunk-HUIQ54TT.js.map +1 -0
  27. package/dist/{chunk-BRC7LSM6.min.js → chunk-OC6Z6CQW.js} +5 -5
  28. package/dist/chunk-OC6Z6CQW.js.map +1 -0
  29. package/dist/chunk-SHUHRHOT.js +1923 -0
  30. package/dist/chunk-SHUHRHOT.js.map +1 -0
  31. package/dist/{chunk-QPGEBDMJ.min.js → chunk-YDAKBU6Q.js} +1 -1
  32. package/dist/chunk-YDAKBU6Q.js.map +1 -0
  33. package/dist/chunk-ZAADLBSB.js +36 -0
  34. package/dist/chunk-ZAADLBSB.js.map +1 -0
  35. package/dist/index.d.ts +7 -7
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/{index.min.js → index.js} +81 -46
  38. package/dist/ipfs/car.d.ts +11 -11
  39. package/dist/ipfs/car.d.ts.map +1 -1
  40. package/dist/ipfs/ipfs-utils.d.ts +2 -2
  41. package/dist/ipfs/ipfs-utils.d.ts.map +1 -1
  42. package/dist/ipfs.d.ts +3 -3
  43. package/dist/ipfs.d.ts.map +1 -1
  44. package/dist/{ipfs.min.js → ipfs.js} +7 -10
  45. package/dist/ipns.d.ts +1 -1
  46. package/dist/ipns.d.ts.map +1 -1
  47. package/dist/ipns.js +64 -0
  48. package/dist/ipns.js.map +1 -0
  49. package/dist/pubsub/pub-pull.d.ts +3 -3
  50. package/dist/pubsub/pub-pull.d.ts.map +1 -1
  51. package/dist/pubsub/pubsub-types.d.ts +3 -3
  52. package/dist/pubsub/pubsub-types.d.ts.map +1 -1
  53. package/dist/pubsub/snap-push.d.ts +4 -4
  54. package/dist/pubsub/snap-push.d.ts.map +1 -1
  55. package/dist/pubsub/ucan.d.ts +1 -1
  56. package/dist/pubsub/ucan.d.ts.map +1 -1
  57. package/dist/pubsub.d.ts +4 -4
  58. package/dist/pubsub.d.ts.map +1 -1
  59. package/dist/{pubsub.min.js → pubsub.js} +7 -10
  60. package/dist/query/attr-helpers.d.ts +5 -0
  61. package/dist/query/attr-helpers.d.ts.map +1 -0
  62. package/dist/query/basic.d.ts +87 -23
  63. package/dist/query/basic.d.ts.map +1 -1
  64. package/dist/query/divergences.d.ts +5 -5
  65. package/dist/query/divergences.d.ts.map +1 -1
  66. package/dist/query/entity-collection.d.ts +19 -0
  67. package/dist/query/entity-collection.d.ts.map +1 -0
  68. package/dist/query/matchers.d.ts +12 -1
  69. package/dist/query/matchers.d.ts.map +1 -1
  70. package/dist/query/memoized.d.ts +66 -0
  71. package/dist/query/memoized.d.ts.map +1 -0
  72. package/dist/query/situations.d.ts +2 -1
  73. package/dist/query/situations.d.ts.map +1 -1
  74. package/dist/query/subscribable.d.ts +111 -0
  75. package/dist/query/subscribable.d.ts.map +1 -0
  76. package/dist/query/types.d.ts +54 -14
  77. package/dist/query/types.d.ts.map +1 -1
  78. package/dist/query.d.ts +9 -5
  79. package/dist/query.d.ts.map +1 -1
  80. package/dist/{query.min.js → query.js} +55 -34
  81. package/dist/retrieve/index.d.ts +1 -1
  82. package/dist/retrieve/index.d.ts.map +1 -1
  83. package/dist/retrieve/update-thread.d.ts +3 -3
  84. package/dist/retrieve/update-thread.d.ts.map +1 -1
  85. package/dist/retrieve.d.ts +1 -1
  86. package/dist/retrieve.d.ts.map +1 -1
  87. package/dist/retrieve.js +14 -0
  88. package/dist/thread/basic.d.ts +15 -19
  89. package/dist/thread/basic.d.ts.map +1 -1
  90. package/dist/thread/filters.d.ts +8 -10
  91. package/dist/thread/filters.d.ts.map +1 -1
  92. package/dist/thread/indexes.d.ts +57 -0
  93. package/dist/thread/indexes.d.ts.map +1 -0
  94. package/dist/thread/mapped.d.ts +40 -11
  95. package/dist/thread/mapped.d.ts.map +1 -1
  96. package/dist/thread/utils.d.ts +5 -5
  97. package/dist/thread/utils.d.ts.map +1 -1
  98. package/dist/thread/writeable.d.ts +2 -2
  99. package/dist/thread/writeable.d.ts.map +1 -1
  100. package/dist/thread.d.ts +6 -5
  101. package/dist/thread.d.ts.map +1 -1
  102. package/dist/{thread.min.js → thread.js} +9 -6
  103. package/dist/types/typescript-utils.d.ts +6 -5
  104. package/dist/types/typescript-utils.d.ts.map +1 -1
  105. package/dist/types.d.ts +1 -1
  106. package/dist/types.d.ts.map +1 -1
  107. package/dist/{types.min.js → types.js} +3 -4
  108. package/dist/utils/debug-name.d.ts +13 -0
  109. package/dist/utils/debug-name.d.ts.map +1 -0
  110. package/dist/utils.d.ts +1 -1
  111. package/dist/utils.d.ts.map +1 -1
  112. package/dist/utils.js +9 -0
  113. package/package.json +32 -23
  114. package/src/applog/applog-helpers.ts +155 -0
  115. package/src/applog/applog-utils.test.ts +108 -0
  116. package/src/applog/applog-utils.ts +551 -0
  117. package/src/applog/datom-types.ts +167 -0
  118. package/src/applog/object-values.test.ts +106 -0
  119. package/src/applog.ts +3 -0
  120. package/src/blockstore/index.ts +36 -0
  121. package/src/blockstore.ts +1 -0
  122. package/src/index.ts +8 -0
  123. package/src/ipfs/car.ts +291 -0
  124. package/src/ipfs/fetch-snapshot-chain.ts +135 -0
  125. package/src/ipfs/ipfs-utils.ts +132 -0
  126. package/src/ipfs.ts +3 -0
  127. package/src/ipns/ipns-record.ts +115 -0
  128. package/src/ipns.ts +1 -0
  129. package/src/pubsub/UCAN Specs Overview.md +217 -0
  130. package/src/pubsub/connector.ts +9 -0
  131. package/src/pubsub/pub-pull.ts +31 -0
  132. package/src/pubsub/pubsub-types.ts +90 -0
  133. package/src/pubsub/snap-push.ts +278 -0
  134. package/src/pubsub/ucan-example.ts +61 -0
  135. package/src/pubsub/ucan.ts +56 -0
  136. package/src/pubsub.ts +4 -0
  137. package/src/query/attr-helpers.ts +5 -0
  138. package/src/query/basic.ts +1245 -0
  139. package/src/query/divergences.ts +50 -0
  140. package/src/query/entity-collection.ts +132 -0
  141. package/src/query/liveFilterAndMap.test.ts +102 -0
  142. package/src/query/matchers.ts +30 -0
  143. package/src/query/memoized.test.ts +151 -0
  144. package/src/query/memoized.ts +180 -0
  145. package/src/query/query-steps.ts +4 -0
  146. package/src/query/query.test.ts +538 -0
  147. package/src/query/situations.ts +261 -0
  148. package/src/query/subscribable.test.ts +245 -0
  149. package/src/query/subscribable.ts +234 -0
  150. package/src/query/types.ts +155 -0
  151. package/src/query/withoutDeleted.test.ts +204 -0
  152. package/src/query.ts +9 -0
  153. package/src/retrieve/index.ts +1 -0
  154. package/src/retrieve/update-thread.ts +248 -0
  155. package/src/retrieve.ts +1 -0
  156. package/src/test/perf/query.1m.perf.test.ts +94 -0
  157. package/src/test/perf/query.perf.test.ts +389 -0
  158. package/src/test/perf/query.realdata.perf.test.ts +182 -0
  159. package/src/thread/basic.ts +209 -0
  160. package/src/thread/filters.ts +227 -0
  161. package/src/thread/indexes.ts +256 -0
  162. package/src/thread/joinThreads.test.ts +304 -0
  163. package/src/thread/mapped.ts +226 -0
  164. package/src/thread/utils.ts +144 -0
  165. package/src/thread/writeable.ts +163 -0
  166. package/src/thread.ts +6 -0
  167. package/src/types/typescript-utils.ts +64 -0
  168. package/src/types.ts +1 -0
  169. package/src/utils/debug-name.ts +54 -0
  170. package/src/utils.ts +4 -0
  171. package/dist/chunk-2Y2PYHGR.min.js +0 -65
  172. package/dist/chunk-2Y2PYHGR.min.js.map +0 -1
  173. package/dist/chunk-5MMGBK2U.min.js +0 -1
  174. package/dist/chunk-7IDQIMQO.min.js +0 -1
  175. package/dist/chunk-BRC7LSM6.min.js.map +0 -1
  176. package/dist/chunk-COXXILXC.min.js +0 -512
  177. package/dist/chunk-COXXILXC.min.js.map +0 -1
  178. package/dist/chunk-GDX2OO7L.min.js +0 -9080
  179. package/dist/chunk-GDX2OO7L.min.js.map +0 -1
  180. package/dist/chunk-H3VQJP56.min.js.map +0 -1
  181. package/dist/chunk-HYMC7W6S.min.js +0 -1549
  182. package/dist/chunk-HYMC7W6S.min.js.map +0 -1
  183. package/dist/chunk-KEHU7HGZ.min.js +0 -5216
  184. package/dist/chunk-KEHU7HGZ.min.js.map +0 -1
  185. package/dist/chunk-KXMTKPF4.min.js.map +0 -1
  186. package/dist/chunk-PHITDXZT.min.js +0 -36
  187. package/dist/chunk-QO2KMGDN.min.js +0 -3771
  188. package/dist/chunk-QO2KMGDN.min.js.map +0 -1
  189. package/dist/chunk-QPGEBDMJ.min.js.map +0 -1
  190. package/dist/chunk-WXLCBTHX.min.js +0 -1606
  191. package/dist/chunk-WXLCBTHX.min.js.map +0 -1
  192. package/dist/ipns.min.js +0 -6419
  193. package/dist/ipns.min.js.map +0 -1
  194. package/dist/mobx/mobx-utils.d.ts +0 -82
  195. package/dist/mobx/mobx-utils.d.ts.map +0 -1
  196. package/dist/mobx.d.ts +0 -2
  197. package/dist/mobx.d.ts.map +0 -1
  198. package/dist/mobx.min.js +0 -141
  199. package/dist/retrieve.min.js +0 -17
  200. package/dist/types.min.js.map +0 -1
  201. package/dist/utils.min.js +0 -10
  202. package/dist/utils.min.js.map +0 -1
  203. /package/dist/{applog.min.js.map → applog.js.map} +0 -0
  204. /package/dist/{chunk-5MMGBK2U.min.js.map → chunk-7Z5YDQKK.js.map} +0 -0
  205. /package/dist/{chunk-7IDQIMQO.min.js.map → chunk-E46VTKTZ.js.map} +0 -0
  206. /package/dist/{chunk-PHITDXZT.min.js.map → index.js.map} +0 -0
  207. /package/dist/{index.min.js.map → ipfs.js.map} +0 -0
  208. /package/dist/{ipfs.min.js.map → pubsub.js.map} +0 -0
  209. /package/dist/{mobx.min.js.map → query.js.map} +0 -0
  210. /package/dist/{pubsub.min.js.map → retrieve.js.map} +0 -0
  211. /package/dist/{query.min.js.map → thread.js.map} +0 -0
  212. /package/dist/{retrieve.min.js.map → types.js.map} +0 -0
  213. /package/dist/{thread.min.js.map → utils.js.map} +0 -0
@@ -0,0 +1,163 @@
1
+ import { Logger } from 'besonders-logger'
2
+ import { ensureTsPvAndFinalizeApplogs } from '../applog/applog-helpers.ts'
3
+ import { isTsBefore, removeDuplicateAppLogs, sortApplogsByTs } from '../applog/applog-utils.ts'
4
+ import { type Applog, ApplogForInsert, CidString, isValidApplog } from '../applog/datom-types.ts'
5
+ import { Thread } from './basic.ts'
6
+
7
+ const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars
8
+
9
+ export abstract class WriteableThread extends Thread {
10
+ constructor(
11
+ name: string,
12
+ // parents: Thread | readonly Thread[] | null, // ? would this ever be a thing
13
+ applogs: Applog[] = [],
14
+ filters: readonly string[],
15
+ ) {
16
+ super(name, null, filters, applogs)
17
+ }
18
+
19
+ public purge(cidsToPurge: CidString[]) {
20
+ const beforeCount = this.applogs.length
21
+ // HACK setting readonly
22
+ this._applogs = this.applogs.filter(log => !(cidsToPurge.includes(log.cid)))
23
+ return beforeCount - this.applogs.length
24
+ }
25
+ public insert(appLogsToInsert: ApplogForInsert[]) {
26
+ DEBUG(`[WriteableThread.insert] ENTER - ${appLogsToInsert.length} applogs for thread "${this.name}"`)
27
+ DEBUG(`[WriteableThread.insert] About to call ensureTsPvAndFinalizeApplogs`)
28
+ const mapped = ensureTsPvAndFinalizeApplogs(appLogsToInsert, this)
29
+ DEBUG(`[WriteableThread.insert] ensureTsPvAndFinalizeApplogs completed, mapped=${mapped.length} applogs`)
30
+ DEBUG(`[WriteableThread.insert] About to call insertRaw`)
31
+ const result = this.insertRaw(mapped)
32
+ DEBUG(`[WriteableThread.insert] insertRaw completed`)
33
+ return result
34
+ }
35
+
36
+ /**
37
+ * Insert only applogs not already in this thread.
38
+ * @param byRef If true, compares by reference; if false, compares by CID (default)
39
+ * @returns The applogs that were actually inserted
40
+ */
41
+ public insertMissing(appLogsToInsert: readonly Applog[], byRef = false): Applog[] {
42
+ const missing = appLogsToInsert.filter(log => !this.hasApplog(log, byRef))
43
+ if (missing.length === 0) {
44
+ VERBOSE(`[insertMissing] no missing applogs`)
45
+ return []
46
+ }
47
+ return this.insertRaw(missing) ?? []
48
+ }
49
+
50
+ /**
51
+ * Insert raw applogs directly into the thread.
52
+ *
53
+ * STRICT VALIDATION: This method throws errors for:
54
+ * - Duplicate applogs in input array (programming error)
55
+ * - Invalid applogs (missing required fields)
56
+ * - Applogs already in thread (programming error)
57
+ *
58
+ * For external imports where duplicates are expected, use removeDuplicateAppLogs(..., 'cleanup')
59
+ * before calling this method.
60
+ *
61
+ * @param appLogsToInsert Must be deduplicated and validated. Needs to be mutable because it will be sorted
62
+ * (and if you need to clone it, so do it when you need to) - this is weird as TS is slathering type safety onto ducks
63
+ * @throws Error if validation fails
64
+ */
65
+ public insertRaw(appLogsToInsert: Applog[]) {
66
+ DEBUG(`[WriteableThread.insertRaw] ENTER - ${appLogsToInsert.length} applogs for thread "${this.name}"`)
67
+ DEBUG(`[WriteableThread.insertRaw] About to deduplicate`)
68
+ const deduplicated = removeDuplicateAppLogs(appLogsToInsert, 'safety')
69
+ if (deduplicated.length !== appLogsToInsert.length) {
70
+ throw ERROR(`[insertRaw] duplicate applogs passed: ${appLogsToInsert.length - deduplicated.length}`, {
71
+ appLogsToInsert,
72
+ deduplicated,
73
+ })
74
+ }
75
+ DEBUG(`[WriteableThread.insertRaw] Deduplication done`)
76
+
77
+ DEBUG(`[WriteableThread.insertRaw] About to validate`)
78
+ const bogus = appLogsToInsert.filter(log => !isValidApplog(log))
79
+ if (bogus.length) {
80
+ throw ERROR(`[insertRaw] bogus applogs passed: ${bogus.length}`, { bogus })
81
+ }
82
+ DEBUG(`[WriteableThread.insertRaw] Validation done`)
83
+
84
+ DEBUG(`[WriteableThread.insertRaw] About to check for existing`)
85
+ const existing = appLogsToInsert.filter(log => this.hasApplog(log, false))
86
+ if (existing.length) {
87
+ throw ERROR(`[insertRaw] already existing applogs passed: ${existing.length}`, { existing })
88
+ }
89
+ DEBUG(`[WriteableThread.insertRaw] Existing check done`)
90
+
91
+ if (!appLogsToInsert.length) {
92
+ WARN('[insertRaw] skipping empty insert empty logs array')
93
+ return
94
+ }
95
+
96
+ ;(!this.hasParents && !(this instanceof ThreadInMemory) ? LOG : DEBUG)(
97
+ 'Inserting:',
98
+ appLogsToInsert.length === 1 ? appLogsToInsert[0] : appLogsToInsert,
99
+ { ds: this },
100
+ )
101
+ DEBUG(`[WriteableThread.insertRaw] About to sort applogs`)
102
+ sortApplogsByTs(appLogsToInsert)
103
+ const sortNeeded = this._applogs.length && isTsBefore(appLogsToInsert[0], this._applogs[this._applogs.length - 1])
104
+ DEBUG(`[WriteableThread.insertRaw] About to push to _applogs array`)
105
+ // Chunked push: spread is fast but causes stack overflow with 100k+ items
106
+ // Chunking keeps us under the limit while using optimized push()
107
+ const CHUNK_SIZE = 50_000
108
+ for (let i = 0; i < appLogsToInsert.length; i += CHUNK_SIZE) {
109
+ this._applogs.push(...appLogsToInsert.slice(i, i + CHUNK_SIZE))
110
+ }
111
+ if (sortNeeded) {
112
+ DEBUG(`[WriteableThread.insertRaw] About to sort _applogs (sortNeeded=true)`)
113
+ sortApplogsByTs(this._applogs)
114
+ }
115
+ DEBUG(`[WriteableThread.insertRaw] About to notify subscribers`)
116
+ this.notifySubscribers({ added: appLogsToInsert, removed: null })
117
+ DEBUG(`[WriteableThread.insertRaw] Subscribers notified`)
118
+
119
+ // ? persist sync
120
+ DEBUG(`[WriteableThread.insertRaw] About to call persist (void - not awaited)`)
121
+ void this.persist(appLogsToInsert)
122
+ DEBUG(`[WriteableThread.insertRaw] EXIT - returning ${appLogsToInsert.length} applogs`)
123
+ return appLogsToInsert
124
+ }
125
+
126
+ get readOnly() {
127
+ return false
128
+ }
129
+
130
+ protected abstract persist(logs: Applog[]): Promise<void>
131
+ }
132
+ export class ThreadInMemory extends WriteableThread {
133
+ static empty(name?: string) {
134
+ return ThreadInMemory.fromArray([], name ?? 'empty in-memory', false)
135
+ }
136
+ static fromArray(applogs: Applog[], name?: string, readOnly = false) {
137
+ return new ThreadInMemory(name ?? 'in-memory', applogs, [], readOnly)
138
+ }
139
+ static fromReadOnlyArray(applogs: readonly Applog[], name?: string) {
140
+ // @ts-expect-error readonly conditional drama
141
+ return new ThreadInMemory(name ?? 'in-memory', applogs, [], true)
142
+ }
143
+
144
+ constructor(
145
+ name: string,
146
+ applogs: Applog[],
147
+ filters: readonly string[],
148
+ readonly _readOnly: boolean,
149
+ ) {
150
+ super(name, applogs, filters)
151
+ }
152
+
153
+ get readOnly() {
154
+ return this._readOnly
155
+ }
156
+
157
+ protected async persist(logs: Applog[]) {
158
+ VERBOSE(`[InMem.persist] no persist for`, logs)
159
+ if (this.readOnly) {
160
+ throw ERROR(`[persist] called for readOnly thread`)
161
+ }
162
+ }
163
+ }
package/src/thread.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './thread/basic.ts'
2
+ export * from './thread/filters.ts'
3
+ export * from './thread/indexes.ts'
4
+ export * from './thread/mapped.ts'
5
+ export * from './thread/writeable.ts'
6
+ export * from './thread/utils.ts'
@@ -0,0 +1,64 @@
1
+ import { Type as T } from '@sinclair/typebox'
2
+ // import { Thread } from '../thread/basic.ts'
3
+
4
+ // ! circular import
5
+ // export const ThreadTB = TypeSystem.Type<Thread>('Thread', (options, value) => {
6
+ // return value instanceof Thread
7
+ // })()
8
+ const { String: StringTB, Optional: OptionalTB, Boolean: BooleanTB, Object: ObjectTB, Number: NumberTB } = T
9
+ export const Str: typeof StringTB = StringTB.bind(T)
10
+ export const Num: typeof NumberTB = NumberTB.bind(T)
11
+ export const Obj: typeof ObjectTB = ObjectTB.bind(T)
12
+ export const Opt: typeof OptionalTB = OptionalTB.bind(T)
13
+ export const Bool: typeof BooleanTB = BooleanTB.bind(T)
14
+
15
+ export const STR: ReturnType<typeof T.String> = Str()
16
+ export const NUM: ReturnType<typeof T.Number> = Num()
17
+ export const BOOL: ReturnType<typeof T.Boolean> = Bool()
18
+
19
+ export type GenericObject = Record<string, any>
20
+ export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
21
+ export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
22
+ export type PromiseType<T extends Promise<any>> = T extends Promise<infer U> ? U : never
23
+
24
+ export type CoerceToString<T> = T extends string ? T : never
25
+
26
+ /**
27
+ * Define nominal type of U based on type of T. Similar to Opaque types in Flow
28
+ */
29
+ export type Tagged<T, Tag> = T & { tag?: Tag }
30
+
31
+ // export interface Service {
32
+ // endpoint?: URL
33
+ // token: string
34
+ // rateLimiter?: RateLimiter
35
+ // fetch?: typeof _fetch
36
+ // }
37
+
38
+ // https://stackoverflow.com/a/76276541
39
+ export type LastElementOf<T extends readonly unknown[]> = T extends readonly [...unknown[], infer Last] ? Last : never
40
+
41
+ export function checkParityTB() {
42
+ /* Most examples are constantly calling Type.*() - needed to check if its really needed
43
+ https://github.com/sinclairzx81/typebox/issues/587#issuecomment-1712457623
44
+ */
45
+ const s1 = Str()
46
+ const s2 = Str()
47
+ const n1 = Num()
48
+ const n2 = Num()
49
+ console.log({ s1, s2, n1, n2 })
50
+ }
51
+
52
+ /** solidjs Setter requires returning something, which I often don't */
53
+ export type GenericSetter<T> = (newValue: T) => void
54
+
55
+ export type ArrayOrSingle<T> = T | T[] | readonly T[]
56
+ export function arrayIfSingle<T>(arrOrSingle: ArrayOrSingle<T>): readonly T[] {
57
+ if (Array.isArray(arrOrSingle)) return arrOrSingle
58
+ else return [arrOrSingle] as readonly T[]
59
+ }
60
+ export type ArrayType<T> = T extends (infer U)[] ? U : T
61
+ export type ArrayElementType<T> = T extends readonly (infer U)[] ? Extract<U, string> : never
62
+ export type ConstructorType<T, S = {}> = {
63
+ new(...args: any[]): T
64
+ } & S
package/src/types.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './types/typescript-utils.ts'
@@ -0,0 +1,54 @@
1
+ import stringify from 'safe-stable-stringify'
2
+ import type { Applog, DatalogQueryPattern } from '../applog/datom-types.ts'
3
+ import type { Thread } from '../thread/basic.ts'
4
+
5
+ export const createDebugName = ({ caller, thread, pattern, args }: {
6
+ caller?: string
7
+ thread?: Thread | Applog[]
8
+ pattern?: DatalogQueryPattern | DatalogQueryPattern[] | string
9
+ args?: any
10
+ }) => {
11
+ args = args || pattern
12
+ const str = `${(!Array.isArray(thread) && thread?.name) ? thread.name + ' | ' : ''}`
13
+ + `${caller ?? 'caller?'}`
14
+ + `${args ? `{${typeof args === 'string' ? args : stringify(args)}}` : ''}`
15
+ return str
16
+ }
17
+
18
+ export const createDebugNameObj = (args: Parameters<typeof createDebugName>[0]) => {
19
+ return { name: createDebugName(args) } as const
20
+ }
21
+
22
+ export function prettifyThreadName(input: string): string {
23
+ let depth = 0
24
+ let result = ''
25
+ let insideCurlyBraces = 0
26
+
27
+ for (let i = 0; i < input.length; i++) {
28
+ const char = input[i]
29
+
30
+ if (char === '(') {
31
+ result += char + '\n' + '\t'.repeat(++depth)
32
+ } else if (char === ')') {
33
+ result += '\n' + '\t'.repeat(--depth) + char
34
+ } else if (char === ',' && insideCurlyBraces === 0) {
35
+ result += char + '\n' + '\t'.repeat(depth)
36
+ } else if (char === '{' && insideCurlyBraces === 0) {
37
+ insideCurlyBraces++
38
+ result += char + '\n' + '\t'.repeat(depth + 1)
39
+ } else if (char === '}' && insideCurlyBraces === 1) {
40
+ insideCurlyBraces--
41
+ result += '\n' + '\t'.repeat(depth) + char
42
+ } else if (char === '{' && insideCurlyBraces > 0) {
43
+ insideCurlyBraces++
44
+ result += char
45
+ } else if (char === '}' && insideCurlyBraces > 1) {
46
+ insideCurlyBraces--
47
+ result += char
48
+ } else {
49
+ result += char
50
+ }
51
+ }
52
+
53
+ return result
54
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { Applog, ApplogEncNoCid } from './applog/datom-types.ts'
2
+
3
+ export const isTruthy = (l: Applog | ApplogEncNoCid): boolean => !!l
4
+ export const keepTruthy = (arr: readonly any[]): any[] => arr.filter(isTruthy)
@@ -1,65 +0,0 @@
1
- import {
2
- ThreadInMemory,
3
- computedFnDeepCompare,
4
- createDebugName,
5
- g,
6
- observableArrayMap
7
- } from "./chunk-GDX2OO7L.min.js";
8
- import {
9
- autorun,
10
- comparer,
11
- toJS
12
- } from "./chunk-KEHU7HGZ.min.js";
13
-
14
- // src/query/divergences.ts
15
- var { WARN, LOG, DEBUG, VERBOSE, ERROR } = g.setup(g.INFO);
16
- var queryDivergencesByPrev = computedFnDeepCompare("queryDivergencesByPrev", function queryConflictingByPrev(sourceThread) {
17
- DEBUG(`queryDivergencesByPrev<${sourceThread.nameAndSizeUntracked}>`);
18
- if (sourceThread.filters.includes("lastWriteWins")) WARN(`queryDivergencesByPrev on thread lastWriteWins`, sourceThread);
19
- const divergences = observableArrayMap(() => {
20
- const logsForNode = /* @__PURE__ */ new Map();
21
- const leafs = /* @__PURE__ */ new Set();
22
- VERBOSE("all applogs:", sourceThread.applogs);
23
- for (const log of sourceThread.applogs) {
24
- let prevLogs;
25
- if (log.pv) {
26
- prevLogs = log.pv && logsForNode.get(log.pv.toString());
27
- leafs.delete(log.pv.toString());
28
- }
29
- VERBOSE("traversing log", { log, prevLogs, leafs: Array.from(leafs) });
30
- logsForNode.set(log.cid, prevLogs ? [...prevLogs, log] : [log]);
31
- leafs.add(log.cid);
32
- }
33
- return Array.from(leafs).map((leafID) => {
34
- const thread = new ThreadInMemory(
35
- createDebugName({
36
- caller: "DivergenceLeaf",
37
- thread: sourceThread,
38
- pattern: `leaf: ${leafID}`
39
- }),
40
- logsForNode.get(leafID),
41
- sourceThread.filters,
42
- true
43
- // TODO: sourceThread,
44
- );
45
- return { log: thread.latestLog, thread };
46
- });
47
- }, { name: createDebugName({ caller: "queryDivergencesByPrev", thread: sourceThread }) });
48
- VERBOSE.isDisabled || autorun(() => VERBOSE(`[queryDivergencesByPrev] result:`, toJS(divergences)));
49
- return divergences;
50
- }, { equals: comparer.structural });
51
-
52
- // src/query/matchers.ts
53
- function includes(str) {
54
- return (vl) => vl?.includes?.(str);
55
- }
56
- function includedIn(arr) {
57
- return (vl) => arr?.includes?.(vl);
58
- }
59
-
60
- export {
61
- queryDivergencesByPrev,
62
- includes,
63
- includedIn
64
- };
65
- //# sourceMappingURL=chunk-2Y2PYHGR.min.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/query/divergences.ts","../src/query/matchers.ts"],"sourcesContent":["import { Logger } from 'besonders-logger'\nimport { autorun, comparer, toJS } from 'mobx'\nimport stringify from 'safe-stable-stringify'\nimport { Applog, CidString } from '../applog/datom-types'\nimport { computedFnDeepCompare, createDebugName, observableArrayMap } from '../mobx/mobx-utils'\nimport { Thread } from '../thread/basic'\nimport { ThreadInMemory } from '../thread/writeable'\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 = computedFnDeepCompare('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 divergences = observableArrayMap(() => {\n\t\tconst logsForNode = new Map<CidString, Applog[]>()\n\t\tconst leafs = new Set<CidString>()\n\t\tVERBOSE('all applogs:', sourceThread.applogs)\n\t\tfor (const log of sourceThread.applogs) {\n\t\t\tlet prevLogs\n\t\t\tif (log.pv) {\n\t\t\t\tprevLogs = log.pv && logsForNode.get(log.pv.toString())\n\t\t\t\tleafs.delete(log.pv.toString())\n\t\t\t}\n\t\t\tVERBOSE('traversing log', { log, prevLogs, leafs: Array.from(leafs) })\n\t\t\tlogsForNode.set(log.cid, prevLogs ? [...prevLogs, log] : [log])\n\t\t\tleafs.add(log.cid)\n\t\t}\n\t\treturn Array.from(leafs).map(leafID => {\n\t\t\t// TODO use MappedThread?\n\t\t\tconst thread = new ThreadInMemory(\n\t\t\t\tcreateDebugName({\n\t\t\t\t\tcaller: 'DivergenceLeaf',\n\t\t\t\t\tthread: sourceThread,\n\t\t\t\t\tpattern: `leaf: ${leafID}`,\n\t\t\t\t}),\n\t\t\t\tlogsForNode.get(leafID),\n\t\t\t\tsourceThread.filters,\n\t\t\t\ttrue,\n\t\t\t\t// TODO: sourceThread,\n\t\t\t)\n\t\t\treturn ({ log: thread.latestLog, thread })\n\t\t})\n\t}, { name: createDebugName({ caller: 'queryDivergencesByPrev', thread: sourceThread }) })\n\tVERBOSE.isDisabled || autorun(() => VERBOSE(`[queryDivergencesByPrev] result:`, toJS(divergences)))\n\treturn divergences\n}, { equals: comparer.structural })\n\n// export const queryDivergencesOfEnAtByPrev = computedFnDeepCompare('queryDivergencesOfEnAtByPrev', function queryDivergencesOfEnAtByPrev(\n// \tsourceThread: Thread,\n// ) {\n// \tDEBUG(`queryDivergencesOfEnAtByPrev<${sourceThread.nameAndSizeUntracked}>`)\n// \tif (sourceThread.filters.includes('lastWriteWins')) WARN(`queryDivergencesOfEnAtByPrevFon thread lastWriteWins`, sourceThread)\n\n// \tconst divergences = observableArrayMap(() => {\n// \t\tconst logsForNode = new Map<CidString, Applog[]>()\n// \t\tconst leafs = new Map<string, Set<CidString>>() // [en,at]\n// \t\tVERBOSE('all applogs:', sourceThread.applogs)\n// \t\tfor (const log of sourceThread.applogs) {\n// \t\t\tconst key = stringify([log.en, log.at])\n// \t\t\tif (!leafs.has(key)) leafs.set(key, new Set())\n// \t\t\tlet prevLogs\n// \t\t\tif (log.pv) {\n// \t\t\t\tprevLogs = log.pv && logsForNode.get(log.pv.toString())\n// \t\t\t\tleafs.get(key).delete(log.pv.toString())\n// \t\t\t}\n// \t\t\tVERBOSE('traversing log', { key, log, prevLogs, leafs: Array.from(leafs) })\n// \t\t\tlogsForNode.set(log.cid, prevLogs ? [...prevLogs, log] : [log])\n// \t\t\tleafs.get(key).add(log.cid)\n// \t\t}\n// \t\treturn Array.from(leafs.entries()).map(([_enAt, leafs]) => {\n// \t\t\t// TODO use MappedThread?\n// \t\t\tconst thread = new ThreadInMemory(\n// \t\t\t\tcreateDebugName({\n// \t\t\t\t\tcaller: 'DivergenceLeaf',\n// \t\t\t\t\tthread: sourceThread,\n// \t\t\t\t\tpattern: `leaf: ${leafID}`,\n// \t\t\t\t}),\n// \t\t\t\tlogsForNode.get(leafID),\n// \t\t\t\tsourceThread.filters,\n// \t\t\t\ttrue,\n// \t\t\t\t// TODO: sourceThread,\n// \t\t\t)\n// \t\t\treturn ({ log: thread.latestLog, thread })\n// \t\t})\n// \t}, { name: createDebugName({ caller: 'queryDivergencesOfEnAtByPrev', thread: sourceThread }) })\n// \tVERBOSE.isDisabled || autorun(() => VERBOSE(`[queryDivergencesOfEnAtByPrev] result:`, toJS(divergences)))\n// \treturn divergences\n// }, { equals: comparer.structural })\n","import { DatomPart } from '../applog/datom-types'\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"],"mappings":";;;;;;;;;;;;;;AAQA,IAAM,EAAE,MAAM,KAAK,OAAO,SAAS,MAAM,IAAI,EAAO,MAAM,EAAO,IAAI;AAO9D,IAAM,yBAAyB,sBAAsB,0BAA0B,SAAS,uBAC9F,cACC;AACD,QAAM,0BAA0B,aAAa,oBAAoB,GAAG;AACpE,MAAI,aAAa,QAAQ,SAAS,eAAe,EAAG,MAAK,kDAAkD,YAAY;AAEvH,QAAM,cAAc,mBAAmB,MAAM;AAC5C,UAAM,cAAc,oBAAI,IAAyB;AACjD,UAAM,QAAQ,oBAAI,IAAe;AACjC,YAAQ,gBAAgB,aAAa,OAAO;AAC5C,eAAW,OAAO,aAAa,SAAS;AACvC,UAAI;AACJ,UAAI,IAAI,IAAI;AACX,mBAAW,IAAI,MAAM,YAAY,IAAI,IAAI,GAAG,SAAS,CAAC;AACtD,cAAM,OAAO,IAAI,GAAG,SAAS,CAAC;AAAA,MAC/B;AACA,cAAQ,kBAAkB,EAAE,KAAK,UAAU,OAAO,MAAM,KAAK,KAAK,EAAE,CAAC;AACrE,kBAAY,IAAI,IAAI,KAAK,WAAW,CAAC,GAAG,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC;AAC9D,YAAM,IAAI,IAAI,GAAG;AAAA,IAClB;AACA,WAAO,MAAM,KAAK,KAAK,EAAE,IAAI,YAAU;AAEtC,YAAM,SAAS,IAAI;AAAA,QAClB,gBAAgB;AAAA,UACf,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,SAAS,SAAS,MAAM;AAAA,QACzB,CAAC;AAAA,QACD,YAAY,IAAI,MAAM;AAAA,QACtB,aAAa;AAAA,QACb;AAAA;AAAA,MAED;AACA,aAAQ,EAAE,KAAK,OAAO,WAAW,OAAO;AAAA,IACzC,CAAC;AAAA,EACF,GAAG,EAAE,MAAM,gBAAgB,EAAE,QAAQ,0BAA0B,QAAQ,aAAa,CAAC,EAAE,CAAC;AACxF,UAAQ,cAAc,QAAQ,MAAM,QAAQ,oCAAoC,KAAK,WAAW,CAAC,CAAC;AAClG,SAAO;AACR,GAAG,EAAE,QAAQ,SAAS,WAAW,CAAC;;;ACnD3B,SAAS,SAAS,KAAa;AACrC,SAAO,CAAC,OAAkB,IAAI,WAAW,GAAG;AAC7C;AACO,SAAS,WAAW,KAAe;AACzC,SAAO,CAAC,OAAkB,KAAK,WAAW,EAAE;AAC7C;","names":[]}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=chunk-5MMGBK2U.min.js.map
@@ -1 +0,0 @@
1
- //# sourceMappingURL=chunk-7IDQIMQO.min.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pubsub/pub-pull.ts","../src/pubsub/pubsub-types.ts"],"sourcesContent":["import { Logger } from 'besonders-logger'\nimport { CID } from 'multiformats'\nimport { ensureTsPvAndFinalizeApplog } from '../applog/applog-helpers'\nimport { EntityID } from '../applog/datom-types'\nimport { Thread } from '../thread'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport type PubPullData = {\n\tcid: CID\n\tthread: Thread\n}\n\nexport function integratePub({ targetThread, agentHash, subID, pubData }: {\n\ttargetThread: Thread\n\tagentHash: EntityID\n\tpubData: PubPullData\n\tsubID?: EntityID\n}) {\n\tconst newLogs = pubData.thread.applogs.filter(log => !targetThread.hasApplog(log, false))\n\tDEBUG(`[integratePub] integrating ${newLogs.length} logs`, { targetThread, subID, pubData })\n\tlet toInsert = newLogs\n\tif (subID) {\n\t\ttoInsert = toInsert.concat(ensureTsPvAndFinalizeApplog(\n\t\t\t{ en: subID, at: 'subscription/cid', vl: pubData.cid.toString(), ag: agentHash },\n\t\t\ttargetThread,\n\t\t))\n\t}\n\ttargetThread.insertRaw(toInsert)\n\treturn newLogs\n}\n","import { CID } from 'multiformats/cid'\nimport { cyrb53hash } from './../applog/applog-utils'\nimport { AgentHash, AgentID, CidString } from '../applog/datom-types'\nimport { Tagged } from '../types'\nimport { UCANCapMap } from './ucan'\ntype AgentString = Tagged<string, 'AgentString'>\ntype DIDString = Tagged<string, 'DID'>\nexport type { AgentHash, AgentString, DIDString }\n\n\nexport interface AppAgent {\n\tag: AgentHash\n\tagentString: AgentString\n\tdid: DIDString\n\tsign? (data: Uint8Array): Promise<Uint8Array>\n\tucan?: UCANCapMap\n}\nexport interface AppAgentForWorker extends AppAgent {\n\tsignerSecret?: Uint8Array\n}\nexport interface SnapRootBlock {\n\tapplogs: CID\n\tapplogsSignature: Uint8Array\n\tinfo: CID\n\tinfoSignature: Uint8Array\n\tprev?: CID\n\tprevCounter?: number | null // Sequential counter: 0 for first, then +1 for each. null = unknown (legacy/error).\n}\nexport interface SnapBlockLogs {\n\tlogs: CID[]\n}\nexport interface SnapBlockChunks {\n\tchunks: CID[]\n}\nexport type SnapBlockLogsOrChunks = SnapBlockLogs | SnapBlockChunks\n\n// HACK: this is actually note3 types, not wovin\nexport interface IShare {\n\tid?: string // string hash of pub (used as unique id in IDB) `W3Name.create().toString()` starts with k51qzi5uqu5d\n\tcreatedAt: string // ISO timestamp of creation\n\tname: string // nick name for the pub\n\tisDeleted?: boolean\n\tpurgeBeforePush?: boolean\n\n\tpk: Uint8Array // exported privatekey - needed to create WritableName for publishing //TODO: store as non-extractable / encrypted?\n\n\tautopush: boolean\n\tlastPush: string | null\n\tlastCID?: string\n\tlatestLogTs?: string\n\tpubCounter?: number\n\n\tpublishedBy: string // local user appAgent\n\tselectors?: string[] // to be used as a filter for which applogs to pub\n\tencryptedFor?: string | null // short agentHash\n\tencryptedWith?: CryptoKey | null // AES-GCM derived key from ECDH keys (local private and remote public)\n\n\t// HACK WIP #39 - shared encryption\n\tsharedKey?: CryptoKey | null // AES-GCM derived key from ECDH keys (local private and ipns public)\n\tsharedAgents?: AgentID[] | null // array of string EntityIDs for the chosen agents (we need public jwkd atoms for each of them)\n\tsharedKeyMap?: Map<AgentID, string> | null // uses public key from each agent to derive an aes key that is used to encrypt and btoa the sharedKey that is actually used to encrypt and decrypt the applogs\n}\nexport interface ISubscription {\n\tid: string // string hash of pub (used as unique id in IDB) `W3Name.create().toString()` starts with k51qzi5uqu5d\n\tcreatedAt: string // ISO timestamp of creation\n\tname: string // nick name for the pub\n\tisDeleted: boolean\n\n\tlastPull?: string | null\n\tlastPullAttempt?: string | null\n\tautopull: boolean\n\trealtime?: boolean // enable real-time WebSocket updates via IPNS watcher\n\tlastCID?: string // ? why not CidString\n\tlastApplogCID?: string\n\tpublishedBy?: string // remote publisher short agentHash\n\tencryptedFor?: string | undefined // short agentHash\n\tencryptedWith?: CryptoKey | undefined // AES-GCM derived key from ECDH keys (local private and remote public)\n}\nexport function isShare(obj: any): obj is IShare {\n\treturn obj?.pk !== undefined && obj?.lastPush !== undefined\n}\nexport function isSubscription(obj: any): obj is ISubscription {\n\treturn obj?.lastPull !== undefined\n}\n\nexport type TShareSub = IShare | ISubscription\n\nexport function agentToShortHash(agentString: string) {\n\treturn cyrb53hash(agentString, 31, 7) as string\n}\n"],"mappings":";;;;;;;AAMA,IAAM,EAAE,MAAM,KAAK,OAAO,SAAS,MAAM,IAAI,EAAO,MAAM,EAAO,IAAI;AAO9D,SAAS,aAAa,EAAE,cAAc,WAAW,OAAO,QAAQ,GAKpE;AACF,QAAM,UAAU,QAAQ,OAAO,QAAQ,OAAO,SAAO,CAAC,aAAa,UAAU,KAAK,KAAK,CAAC;AACxF,QAAM,8BAA8B,QAAQ,MAAM,SAAS,EAAE,cAAc,OAAO,QAAQ,CAAC;AAC3F,MAAI,WAAW;AACf,MAAI,OAAO;AACV,eAAW,SAAS,OAAO;AAAA,MAC1B,EAAE,IAAI,OAAO,IAAI,oBAAoB,IAAI,QAAQ,IAAI,SAAS,GAAG,IAAI,UAAU;AAAA,MAC/E;AAAA,IACD,CAAC;AAAA,EACF;AACA,eAAa,UAAU,QAAQ;AAC/B,SAAO;AACR;;;ACgDO,SAAS,QAAQ,KAAyB;AAChD,SAAO,KAAK,OAAO,UAAa,KAAK,aAAa;AACnD;AACO,SAAS,eAAe,KAAgC;AAC9D,SAAO,KAAK,aAAa;AAC1B;AAIO,SAAS,iBAAiB,aAAqB;AACrD,SAAO,WAAW,aAAa,IAAI,CAAC;AACrC;","names":[]}