@wovin/core 0.2.0 → 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 (45) 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/{chunk-CPSDKFBG.js → chunk-22WDFLXO.js} +5 -14
  7. package/dist/chunk-22WDFLXO.js.map +1 -0
  8. package/dist/{chunk-QZXKQCAY.js → chunk-3SUFNJEZ.js} +2 -2
  9. package/dist/{chunk-3WZVG277.js → chunk-6ALNRM3J.js} +5 -4
  10. package/dist/chunk-6ALNRM3J.js.map +1 -0
  11. package/dist/{chunk-3JZMOEOD.js → chunk-BLF5MAWU.js} +2 -2
  12. package/dist/{chunk-J2FDHGOZ.js → chunk-HUIQ54TT.js} +3 -3
  13. package/dist/{chunk-PD3C7XUM.js → chunk-OC6Z6CQW.js} +2 -2
  14. package/dist/{chunk-L5EEEGE6.js → chunk-SHUHRHOT.js} +738 -677
  15. package/dist/chunk-SHUHRHOT.js.map +1 -0
  16. package/dist/index.js +17 -9
  17. package/dist/ipfs.js +4 -4
  18. package/dist/pubsub/snap-push.d.ts.map +1 -1
  19. package/dist/pubsub.js +4 -4
  20. package/dist/query/basic.d.ts +3 -3
  21. package/dist/query/basic.d.ts.map +1 -1
  22. package/dist/query/entity-collection.d.ts.map +1 -1
  23. package/dist/query/matchers.d.ts +12 -1
  24. package/dist/query/matchers.d.ts.map +1 -1
  25. package/dist/query.js +7 -5
  26. package/dist/retrieve.js +4 -4
  27. package/dist/thread/indexes.d.ts +3 -2
  28. package/dist/thread/indexes.d.ts.map +1 -1
  29. package/dist/thread.js +1 -1
  30. package/package.json +1 -1
  31. package/src/applog/applog-utils.ts +48 -4
  32. package/src/applog/datom-types.ts +22 -3
  33. package/src/applog/object-values.test.ts +106 -0
  34. package/src/pubsub/snap-push.ts +2 -1
  35. package/src/query/entity-collection.ts +2 -1
  36. package/src/query/matchers.ts +23 -1
  37. package/src/thread/basic.ts +2 -2
  38. package/src/thread/indexes.ts +15 -9
  39. package/dist/chunk-3WZVG277.js.map +0 -1
  40. package/dist/chunk-CPSDKFBG.js.map +0 -1
  41. package/dist/chunk-L5EEEGE6.js.map +0 -1
  42. /package/dist/{chunk-QZXKQCAY.js.map → chunk-3SUFNJEZ.js.map} +0 -0
  43. /package/dist/{chunk-3JZMOEOD.js.map → chunk-BLF5MAWU.js.map} +0 -0
  44. /package/dist/{chunk-J2FDHGOZ.js.map → chunk-HUIQ54TT.js.map} +0 -0
  45. /package/dist/{chunk-PD3C7XUM.js.map → chunk-OC6Z6CQW.js.map} +0 -0
@@ -3,265 +3,643 @@ import {
3
3
  } from "./chunk-ZAADLBSB.js";
4
4
 
5
5
  // src/thread/basic.ts
6
- import { Logger } from "besonders-logger";
6
+ import { Logger as Logger2 } from "besonders-logger";
7
7
 
8
- // src/query/subscribable.ts
9
- var SubscribableImpl = class {
10
- _value;
11
- _derivedSubscribers = [];
12
- _subscribers = [];
13
- _upstreamActive = false;
14
- _activateUpstream;
15
- _deactivateUpstream = null;
16
- _equals;
17
- constructor(initialValue, activateUpstream, opts) {
18
- this._value = initialValue;
19
- this._activateUpstream = activateUpstream ?? null;
20
- this._equals = opts?.equals === false ? () => false : opts?.equals ?? ((a, b) => a === b);
8
+ // src/applog/applog-utils.ts
9
+ import { Logger } from "besonders-logger";
10
+ import { isBefore } from "date-fns";
11
+ import { partial, pick } from "lodash-es";
12
+ import { isEqual } from "lodash-es";
13
+ import stringify from "safe-stable-stringify";
14
+ var { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO);
15
+ var isoDateStrCompare = (strA, strB, dir = "asc") => dir === "asc" ? strA.localeCompare(strB, "en-US") : strB.localeCompare(strA, "en-US");
16
+ var objEqualByKeys = (keys, objA, objB) => {
17
+ return isEqual(pick(objA, keys), pick(objB, keys));
18
+ };
19
+ var valueEq = (a, b) => isEqual(a, b);
20
+ var valueKey = (vl) => {
21
+ switch (typeof vl) {
22
+ case "string":
23
+ case "number":
24
+ case "boolean":
25
+ return vl;
26
+ default:
27
+ return vl === null ? null : "\0obj:" + stringify(vl);
21
28
  }
22
- get value() {
23
- return this._value;
29
+ };
30
+ var compareApplogsByTs = (logA, logB, dir = "asc") => {
31
+ const tsCmp = isoDateStrCompare(logA.ts, logB.ts, dir);
32
+ if (tsCmp !== 0) return tsCmp;
33
+ return dir === "asc" ? logA.cid.localeCompare(logB.cid) : logB.cid.localeCompare(logA.cid);
34
+ };
35
+ var compareApplogsByEnAt = partial(objEqualByKeys, ["en", "at"]);
36
+ function isLaterByTsAndPv(a, b) {
37
+ const tsCmp = isoDateStrCompare(a.ts, b.ts);
38
+ if (tsCmp !== 0) return tsCmp > 0;
39
+ if (a.en === b.en && a.at === b.at) {
40
+ if (a.pv === b.cid) return true;
41
+ if (b.pv === a.cid) return false;
24
42
  }
25
- subscribe(cb, type) {
26
- if (!this._upstreamActive && this._activateUpstream) {
27
- this._deactivateUpstream = this._activateUpstream();
28
- this._upstreamActive = true;
29
- }
30
- const list = type === "derived" ? this._derivedSubscribers : this._subscribers;
31
- list.push(cb);
32
- return () => {
33
- const idx = list.indexOf(cb);
34
- if (idx >= 0) list.splice(idx, 1);
35
- if (this._derivedSubscribers.length === 0 && this._subscribers.length === 0 && this._upstreamActive) {
36
- this._deactivateUpstream?.();
37
- this._deactivateUpstream = null;
38
- this._upstreamActive = false;
39
- }
40
- };
43
+ return a.cid.localeCompare(b.cid) > 0;
44
+ }
45
+ function sortApplogsByTs(appLogArray, dir = "asc") {
46
+ appLogArray.sort((a, b) => compareApplogsByTs(a, b, dir));
47
+ let i = 0;
48
+ while (i < appLogArray.length) {
49
+ let j = i + 1;
50
+ while (j < appLogArray.length && appLogArray[j].ts === appLogArray[i].ts) j++;
51
+ if (j - i > 1) chainStabilizeCluster(appLogArray, i, j, dir);
52
+ i = j;
41
53
  }
42
- /** Update value and notify subscribers (skips if equals check passes) */
43
- _set(value) {
44
- if (this._equals(value, this._value)) return;
45
- this._value = value;
46
- this._notify();
54
+ return appLogArray;
55
+ }
56
+ function chainStabilizeCluster(applogs, from, to, dir) {
57
+ const groups = /* @__PURE__ */ new Map();
58
+ for (let k = from; k < to; k++) {
59
+ const log = applogs[k];
60
+ const key = log.en + "|" + log.at;
61
+ const existing = groups.get(key);
62
+ if (existing) existing.push(log);
63
+ else groups.set(key, [log]);
47
64
  }
48
- _notify() {
49
- const derived = [...this._derivedSubscribers];
50
- for (const sub of derived) sub();
51
- const subs = [...this._subscribers];
52
- for (const sub of subs) sub();
65
+ if (groups.size === to - from) return;
66
+ const orderedByGroup = /* @__PURE__ */ new Map();
67
+ for (const [key, logs] of groups) {
68
+ orderedByGroup.set(key, logs.length === 1 ? logs : topoSortByPv(logs, dir));
53
69
  }
54
- dispose() {
55
- this._deactivateUpstream?.();
56
- this._deactivateUpstream = null;
57
- this._derivedSubscribers.length = 0;
58
- this._subscribers.length = 0;
59
- this._upstreamActive = false;
70
+ const cursors = /* @__PURE__ */ new Map();
71
+ for (let k = from; k < to; k++) {
72
+ const key = applogs[k].en + "|" + applogs[k].at;
73
+ const cursor = cursors.get(key) ?? 0;
74
+ applogs[k] = orderedByGroup.get(key)[cursor];
75
+ cursors.set(key, cursor + 1);
60
76
  }
61
- };
62
- function isArrayInitEvent(event) {
63
- return event.init !== void 0;
64
77
  }
65
- var SubscribableArrayImpl = class {
66
- _items;
67
- _derivedSubscribers = [];
68
- _subscribers = [];
69
- _upstreamActive = false;
70
- _activateUpstream;
71
- _deactivateUpstream = null;
72
- constructor(initialItems, activateUpstream) {
73
- this._items = initialItems;
74
- this._activateUpstream = activateUpstream ?? null;
78
+ function topoSortByPv(logs, dir) {
79
+ const cidSet = new Set(logs.map((l) => l.cid));
80
+ const childrenByPv = /* @__PURE__ */ new Map();
81
+ const roots = [];
82
+ for (const log of logs) {
83
+ if (log.pv && cidSet.has(log.pv)) {
84
+ const children = childrenByPv.get(log.pv);
85
+ if (children) children.push(log);
86
+ else childrenByPv.set(log.pv, [log]);
87
+ } else {
88
+ roots.push(log);
89
+ }
75
90
  }
76
- get items() {
77
- return this._items;
91
+ const lexCmp = (a, b) => a.cid.localeCompare(b.cid);
92
+ roots.sort(lexCmp);
93
+ for (const children of childrenByPv.values()) children.sort(lexCmp);
94
+ const result = [];
95
+ const visited = /* @__PURE__ */ new Set();
96
+ const stack = [...roots].reverse();
97
+ while (stack.length > 0) {
98
+ const log = stack.pop();
99
+ if (visited.has(log.cid)) continue;
100
+ visited.add(log.cid);
101
+ result.push(log);
102
+ const children = childrenByPv.get(log.cid);
103
+ if (children) for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]);
78
104
  }
79
- get length() {
80
- return this._items.length;
105
+ if (result.length < logs.length) {
106
+ for (const log of logs) if (!visited.has(log.cid)) result.push(log);
81
107
  }
82
- subscribe(cb, type) {
83
- if (!this._upstreamActive && this._activateUpstream) {
84
- this._deactivateUpstream = this._activateUpstream();
85
- this._upstreamActive = true;
108
+ return dir === "desc" ? result.reverse() : result;
109
+ }
110
+ var isTsBefore = (log, logToCompare) => isBefore(new Date(log.ts), new Date(logToCompare.ts));
111
+ var uniqueEnFromAppLogs = (appLogArray) => [...new Set(appLogArray.map((eachLog) => eachLog.en))];
112
+ var areApplogsEqual = (logA, logB) => isEqual(logA, logB);
113
+ var warnMissingRemoveDuplicateMode = () => {
114
+ WARN(`[removeDuplicateAppLogs] mode not set; pass 'safety' or 'cleanup' for optimal behavior`);
115
+ };
116
+ var removeDuplicateAppLogsCleanup = (appLogArray) => {
117
+ const logMap = /* @__PURE__ */ new Map();
118
+ const verboseEnabled = VERBOSE.isEnabled;
119
+ for (const eachLog of appLogArray) {
120
+ if (!eachLog) {
121
+ ERROR(`falsy entry in applogs`, appLogArray);
122
+ throw new Error(`falsy entry in applogs`);
86
123
  }
87
- const list = type === "derived" ? this._derivedSubscribers : this._subscribers;
88
- list.push(cb);
89
- return () => {
90
- const idx = list.indexOf(cb);
91
- if (idx >= 0) list.splice(idx, 1);
92
- if (this._derivedSubscribers.length === 0 && this._subscribers.length === 0 && this._upstreamActive) {
93
- this._deactivateUpstream?.();
94
- this._deactivateUpstream = null;
95
- this._upstreamActive = false;
96
- }
97
- };
98
- }
99
- /** Push items and notify subscribers */
100
- _push(...items) {
101
- this._items.push(...items);
102
- this._notify({ added: items, removed: null });
103
- }
104
- /** Remove items and notify subscribers */
105
- _remove(items) {
106
- for (const item of items) {
107
- const idx = this._items.indexOf(item);
108
- if (idx >= 0) this._items.splice(idx, 1);
124
+ if (!eachLog.cid) {
125
+ ERROR(`applog with missing CID`, eachLog);
126
+ throw new Error(`applog with missing CID`);
127
+ }
128
+ const key = eachLog.cid;
129
+ const existing = logMap.get(key);
130
+ if (existing) {
131
+ if (verboseEnabled) VERBOSE(`Skipping duplicate applog:`, [existing, eachLog]);
132
+ } else {
133
+ logMap.set(key, eachLog);
109
134
  }
110
- this._notify({ added: [], removed: items });
111
- }
112
- /** Full reset — replace all items */
113
- _reset(items) {
114
- this._items = items;
115
- this._notify({ init: [...this._items] });
116
- }
117
- _notify(event) {
118
- const derived = [...this._derivedSubscribers];
119
- for (const sub of derived) sub(event);
120
- const subs = [...this._subscribers];
121
- for (const sub of subs) sub(event);
122
- }
123
- dispose() {
124
- this._deactivateUpstream?.();
125
- this._deactivateUpstream = null;
126
- this._derivedSubscribers.length = 0;
127
- this._subscribers.length = 0;
128
- this._upstreamActive = false;
129
135
  }
136
+ return Array.from(logMap.values());
130
137
  };
131
-
132
- // src/utils/debug-name.ts
133
- import stringify from "safe-stable-stringify";
134
- var createDebugName = ({ caller, thread, pattern, args }) => {
135
- args = args || pattern;
136
- const str = `${!Array.isArray(thread) && thread?.name ? thread.name + " | " : ""}${caller ?? "caller?"}${args ? `{${typeof args === "string" ? args : stringify(args)}}` : ""}`;
137
- return str;
138
+ var removeDuplicateAppLogsSafety = (appLogArray) => {
139
+ const seen = /* @__PURE__ */ new Set();
140
+ const verboseEnabled = VERBOSE.isEnabled;
141
+ const existingByCid = verboseEnabled ? /* @__PURE__ */ new Map() : null;
142
+ let result = null;
143
+ let index = 0;
144
+ for (const eachLog of appLogArray) {
145
+ if (!eachLog) {
146
+ ERROR(`falsy entry in applogs`, appLogArray);
147
+ throw new Error(`falsy entry in applogs`);
148
+ }
149
+ if (!eachLog.cid) {
150
+ ERROR(`applog with missing CID`, eachLog);
151
+ throw new Error(`applog with missing CID`);
152
+ }
153
+ const key = eachLog.cid;
154
+ if (seen.has(key)) {
155
+ if (!result) {
156
+ result = appLogArray.slice(0, index);
157
+ }
158
+ if (verboseEnabled) VERBOSE(`Skipping duplicate applog:`, [existingByCid?.get(key), eachLog]);
159
+ } else {
160
+ seen.add(key);
161
+ if (existingByCid) existingByCid.set(key, eachLog);
162
+ if (result) result.push(eachLog);
163
+ }
164
+ index++;
165
+ }
166
+ return result ?? appLogArray;
138
167
  };
139
- var createDebugNameObj = (args) => {
140
- return { name: createDebugName(args) };
168
+ var removeDuplicateAppLogs = (appLogArray, mode) => {
169
+ if (!mode) {
170
+ warnMissingRemoveDuplicateMode();
171
+ return removeDuplicateAppLogsCleanup(appLogArray);
172
+ }
173
+ return mode === "safety" ? removeDuplicateAppLogsSafety(appLogArray) : removeDuplicateAppLogsCleanup(appLogArray);
141
174
  };
142
- function prettifyThreadName(input) {
143
- let depth = 0;
144
- let result = "";
145
- let insideCurlyBraces = 0;
146
- for (let i = 0; i < input.length; i++) {
147
- const char = input[i];
148
- if (char === "(") {
149
- result += char + "\n" + " ".repeat(++depth);
150
- } else if (char === ")") {
151
- result += "\n" + " ".repeat(--depth) + char;
152
- } else if (char === "," && insideCurlyBraces === 0) {
153
- result += char + "\n" + " ".repeat(depth);
154
- } else if (char === "{" && insideCurlyBraces === 0) {
155
- insideCurlyBraces++;
156
- result += char + "\n" + " ".repeat(depth + 1);
157
- } else if (char === "}" && insideCurlyBraces === 1) {
158
- insideCurlyBraces--;
159
- result += "\n" + " ".repeat(depth) + char;
160
- } else if (char === "{" && insideCurlyBraces > 0) {
161
- insideCurlyBraces++;
162
- result += char;
163
- } else if (char === "}" && insideCurlyBraces > 1) {
164
- insideCurlyBraces--;
165
- result += char;
175
+ var getHashID = (stringifiable, lngth = 8) => cyrb53hash(stringify(stringifiable), 31, lngth);
176
+ function isVariable(x) {
177
+ return typeof x === "string" && x.startsWith("?");
178
+ }
179
+ function variableNameWithoutQuestionmark(str) {
180
+ return str.slice(1);
181
+ }
182
+ function isStaticPattern(x) {
183
+ if (!["string", "boolean", "number", "function"].includes(typeof x)) WARN(`Unhandled pattern value type:`, typeof x, x);
184
+ return !isVariable(x) && ["string", "boolean", "number"].includes(typeof x);
185
+ }
186
+ function resolveOrRemoveVariables(pattern, candidate) {
187
+ let variablesToFill = {};
188
+ const newPattern = {};
189
+ for (const [patternKey, patternValue] of Object.entries(pattern)) {
190
+ if (isVariable(patternValue)) {
191
+ const varName = variableNameWithoutQuestionmark(patternValue);
192
+ const candidateValue = candidate[varName];
193
+ if (candidateValue) {
194
+ newPattern[patternKey] = candidateValue;
195
+ } else {
196
+ variablesToFill[patternKey] = varName;
197
+ }
166
198
  } else {
167
- result += char;
199
+ newPattern[patternKey] = patternValue;
168
200
  }
169
201
  }
170
- return result;
202
+ return [newPattern, variablesToFill];
171
203
  }
172
-
173
- // src/thread/basic.ts
174
- var { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO, { prefix: "[thread]" });
175
- var isInitEvent = isArrayInitEvent;
176
- var Thread = class {
177
- constructor(name, parents, filters, _applogs = []) {
178
- this.name = name;
179
- this._applogs = _applogs;
180
- this.parents = parents === null ? null : arrayIfSingle(parents);
181
- this.filters = filters;
182
- if (this.parents?.length === 0) {
183
- WARN(`[Thread] empty parents array`, name);
184
- }
185
- }
186
- filters;
187
- parents;
188
- _derivedSubscribers = [];
189
- _subscribers = [];
190
- /** Monotonic counter incremented on every mutation. Used by memoizedFn to invalidate caches. */
191
- _version = 0;
192
- get readOnly() {
193
- if (this.parents.length !== 1) return true;
194
- return this.parents[0].readOnly;
204
+ function matchVariable(variable, triplePart, context) {
205
+ if (context.hasOwnProperty(variable)) {
206
+ const bound = context[variable];
207
+ const match = matchPart(bound, triplePart, context);
208
+ return match;
195
209
  }
196
- insert(appLogsToInsert) {
197
- if (this.readOnly) throw ERROR(`[Thread] insert() called on read-only thread:`, this.nameAndSizeUntracked);
198
- if (!this.parents) throw ERROR(`[Thread] insert() called on non-writable thread without parents:`, this.nameAndSizeUntracked);
199
- if (this.parents?.length !== 1) throw ERROR(`[Thread] insert() called on thread with multiple parents:`, this.nameAndSizeUntracked);
200
- return this.parents[0].insert(appLogsToInsert);
210
+ return { ...context, [variable]: triplePart };
211
+ }
212
+ function matchPartStatic(field, patternPart, atomPart) {
213
+ let result;
214
+ if (patternPart) {
215
+ const typ = typeof patternPart;
216
+ if (typ === "string") {
217
+ result = patternPart === atomPart;
218
+ } else if (typ === "function") {
219
+ result = patternPart(atomPart);
220
+ } else if (Array.isArray(patternPart)) {
221
+ throw ERROR(
222
+ `[matchPartStatic] a bare array is not a valid matcher for field '${field}'. Use anyOf(...) for set-membership, or a predicate (v) => isEqual(v, [...]) to match a literal array value.`,
223
+ patternPart
224
+ );
225
+ } else if (typeof patternPart.has === "function") {
226
+ result = patternPart.has(atomPart);
227
+ } else {
228
+ result = valueEq(patternPart, atomPart);
229
+ }
230
+ } else {
231
+ result = patternPart === atomPart;
201
232
  }
202
- insertRaw(appLogsToInsert) {
203
- if (this.readOnly) throw ERROR(`[Thread] insertRaw() called on read-only thread:`, this.nameAndSizeUntracked);
204
- if (!this.parents) throw ERROR(`[Thread] insertRaw() called on non-writable thread without parents:`, this.nameAndSizeUntracked);
205
- if (this.parents?.length !== 1) throw ERROR(`[Thread] insertRaw() called on thread with multiple parents:`, this.nameAndSizeUntracked);
206
- return this.parents[0].insertRaw(appLogsToInsert);
233
+ if (field.charAt(0) === "!") {
234
+ return !result;
235
+ } else {
236
+ return result;
207
237
  }
208
- subscribe(callback, type) {
209
- const list = type === "derived" ? this._derivedSubscribers : this._subscribers;
210
- list.push(callback);
211
- return () => {
212
- const idx = list.indexOf(callback);
213
- if (idx >= 0) list.splice(idx, 1);
214
- };
238
+ }
239
+ function matchPart(patternPart, atomPart, context) {
240
+ if (!context) {
241
+ return null;
215
242
  }
216
- notifySubscribers(event) {
217
- this._version++;
218
- DEBUG(`[thread: ${this.name}] notifying`, this._derivedSubscribers.length, "derived +", this._subscribers.length, "subscribers of", { ...event, subs: this._subscribers });
219
- const derived = [...this._derivedSubscribers];
220
- for (const subscriber of derived) {
221
- subscriber(event);
222
- }
223
- const subs = [...this._subscribers];
224
- for (const subscriber of subs) {
225
- subscriber(event);
243
+ if (typeof patternPart === "string") {
244
+ if (isVariable(patternPart)) {
245
+ return matchVariable(patternPart, atomPart, context);
226
246
  }
227
247
  }
228
- // ── SubscribableArray<Applog> ──
229
- get items() {
230
- return this._applogs;
231
- }
232
- dispose() {
233
- this._derivedSubscribers.length = 0;
234
- this._subscribers.length = 0;
248
+ if (typeof patternPart === "function") {
249
+ return patternPart(atomPart) ? context : null;
235
250
  }
236
- get applogs() {
237
- return this._applogs;
251
+ if (Array.isArray(patternPart)) {
252
+ throw ERROR(
253
+ `[matchPart] a bare array is not a valid matcher. Use anyOf(...) for set-membership, or a predicate to match a literal array value.`,
254
+ patternPart
255
+ );
238
256
  }
239
- get applogsCids() {
240
- return this._applogs.map((l) => l.cid);
257
+ if (patternPart && typeof patternPart.has === "function") {
258
+ return patternPart.has(atomPart) ? context : null;
241
259
  }
242
- get applogsCidSet() {
243
- return new Set(this._applogs.map((l) => l.cid));
260
+ return valueEq(patternPart, atomPart) ? context : null;
261
+ }
262
+ function matchPattern(pattern, applog, context) {
263
+ return Object.entries(pattern).reduce((context2, [field, patternValue]) => {
264
+ const applogValue = applog[field];
265
+ const patternValT = patternValue;
266
+ return matchPart(patternValT, applogValue, context2);
267
+ }, context);
268
+ }
269
+ function actualize(context, find) {
270
+ return Object.fromEntries(find.map((findField) => {
271
+ if (context === null) {
272
+ throw new Error(`actualize context is null ${find}`);
273
+ }
274
+ return [
275
+ isVariable(findField) ? findField.replace(/^\?/, "") : findField,
276
+ isVariable(findField) ? context[findField] : findField
277
+ ];
278
+ }));
279
+ }
280
+ var sum = function sum2(array) {
281
+ var num = 0;
282
+ for (var i = 0, l = array.length; i < l; i++) num += array[i];
283
+ return num;
284
+ };
285
+ var mean = function mean2(array) {
286
+ return sum(array) / array.length;
287
+ };
288
+ var arrStats = {
289
+ max: function(array) {
290
+ return Math.max.apply(null, array);
291
+ },
292
+ min: function(array) {
293
+ return Math.min.apply(null, array);
294
+ },
295
+ range: function(array) {
296
+ return arrStats.max(array) - arrStats.min(array);
297
+ },
298
+ midrange: function(array) {
299
+ return arrStats.range(array) / 2;
300
+ },
301
+ sum,
302
+ mean,
303
+ average: mean,
304
+ median: function(array) {
305
+ array.sort(function(a, b) {
306
+ return a - b;
307
+ });
308
+ var mid = array.length / 2;
309
+ return mid % 1 ? array[mid - 0.5] : (array[mid - 1] + array[mid]) / 2;
310
+ },
311
+ modes: function(array) {
312
+ if (!array.length) return [];
313
+ var modeMap = {}, maxCount = 0, modes = [];
314
+ array.forEach(function(val) {
315
+ if (!modeMap[val]) modeMap[val] = 1;
316
+ else modeMap[val]++;
317
+ if (modeMap[val] > maxCount) {
318
+ modes = [val];
319
+ maxCount = modeMap[val];
320
+ } else if (modeMap[val] === maxCount) {
321
+ modes.push(val);
322
+ maxCount = modeMap[val];
323
+ }
324
+ });
325
+ return modes;
326
+ },
327
+ variance: function(array) {
328
+ var mean3 = arrStats.mean(array);
329
+ return arrStats.mean(array.map(function(num) {
330
+ return Math.pow(num - mean3, 2);
331
+ }));
332
+ },
333
+ standardDeviation: function(array) {
334
+ return Math.sqrt(arrStats.variance(array));
335
+ },
336
+ meanAbsoluteDeviation: function(array) {
337
+ var mean3 = arrStats.mean(array);
338
+ return arrStats.mean(array.map(function(num) {
339
+ return Math.abs(num - mean3);
340
+ }));
341
+ },
342
+ zScores: function(array) {
343
+ var mean3 = arrStats.mean(array);
344
+ var standardDeviation = arrStats.standardDeviation(array);
345
+ return array.map(function(num) {
346
+ return (num - mean3) / standardDeviation;
347
+ });
244
348
  }
245
- map(fn) {
246
- return this.applogs.map(fn);
349
+ };
350
+ arrStats.average = arrStats.mean;
351
+ var tsNearlySame = (timeA, timeB) => timeB.startsWith(timeA.slice(0, timeA.length - 4));
352
+ var cyrb53hash = function(str, seed = 13, strLength) {
353
+ if (!str?.length) {
354
+ throw new Error(`Empty string: ${str}`);
247
355
  }
248
- get findLast() {
249
- return this.applogs.findLast.bind(this.applogs);
356
+ let h1 = 3735928559 ^ seed;
357
+ let h2 = 1103547991 ^ seed;
358
+ for (let i = 0, ch; i < str.length; i++) {
359
+ ch = str.charCodeAt(i);
360
+ h1 = Math.imul(h1 ^ ch, 2654435761);
361
+ h2 = Math.imul(h2 ^ ch, 1597334677);
250
362
  }
251
- get findFirst() {
252
- return this.applogs.find.bind(this.applogs);
363
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
364
+ h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
365
+ const asHex = (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16);
366
+ return asHex.slice(-strLength).padStart(strLength, "0");
367
+ };
368
+ function arraysContainSameElements(arr1, arr2) {
369
+ if (arr1.length !== arr2.length) {
370
+ return false;
253
371
  }
254
- get firstLog() {
255
- return this.applogs[0];
372
+ const sortedArr1 = [...arr1].sort();
373
+ const sortedArr2 = [...arr2].sort();
374
+ for (let i = 0; i < sortedArr1.length; i++) {
375
+ if (sortedArr1[i] !== sortedArr2[i]) {
376
+ return false;
377
+ }
256
378
  }
257
- get latestLog() {
379
+ return true;
380
+ }
381
+ function dateNowIso() {
382
+ const now = /* @__PURE__ */ new Date();
383
+ return now.toISOString();
384
+ }
385
+
386
+ // src/query/subscribable.ts
387
+ var SubscribableImpl = class {
388
+ _value;
389
+ _derivedSubscribers = [];
390
+ _subscribers = [];
391
+ _upstreamActive = false;
392
+ _activateUpstream;
393
+ _deactivateUpstream = null;
394
+ _equals;
395
+ constructor(initialValue, activateUpstream, opts) {
396
+ this._value = initialValue;
397
+ this._activateUpstream = activateUpstream ?? null;
398
+ this._equals = opts?.equals === false ? () => false : opts?.equals ?? ((a, b) => a === b);
399
+ }
400
+ get value() {
401
+ return this._value;
402
+ }
403
+ subscribe(cb, type) {
404
+ if (!this._upstreamActive && this._activateUpstream) {
405
+ this._deactivateUpstream = this._activateUpstream();
406
+ this._upstreamActive = true;
407
+ }
408
+ const list = type === "derived" ? this._derivedSubscribers : this._subscribers;
409
+ list.push(cb);
410
+ return () => {
411
+ const idx = list.indexOf(cb);
412
+ if (idx >= 0) list.splice(idx, 1);
413
+ if (this._derivedSubscribers.length === 0 && this._subscribers.length === 0 && this._upstreamActive) {
414
+ this._deactivateUpstream?.();
415
+ this._deactivateUpstream = null;
416
+ this._upstreamActive = false;
417
+ }
418
+ };
419
+ }
420
+ /** Update value and notify subscribers (skips if equals check passes) */
421
+ _set(value) {
422
+ if (this._equals(value, this._value)) return;
423
+ this._value = value;
424
+ this._notify();
425
+ }
426
+ _notify() {
427
+ const derived = [...this._derivedSubscribers];
428
+ for (const sub of derived) sub();
429
+ const subs = [...this._subscribers];
430
+ for (const sub of subs) sub();
431
+ }
432
+ dispose() {
433
+ this._deactivateUpstream?.();
434
+ this._deactivateUpstream = null;
435
+ this._derivedSubscribers.length = 0;
436
+ this._subscribers.length = 0;
437
+ this._upstreamActive = false;
438
+ }
439
+ };
440
+ function isArrayInitEvent(event) {
441
+ return event.init !== void 0;
442
+ }
443
+ var SubscribableArrayImpl = class {
444
+ _items;
445
+ _derivedSubscribers = [];
446
+ _subscribers = [];
447
+ _upstreamActive = false;
448
+ _activateUpstream;
449
+ _deactivateUpstream = null;
450
+ constructor(initialItems, activateUpstream) {
451
+ this._items = initialItems;
452
+ this._activateUpstream = activateUpstream ?? null;
453
+ }
454
+ get items() {
455
+ return this._items;
456
+ }
457
+ get length() {
458
+ return this._items.length;
459
+ }
460
+ subscribe(cb, type) {
461
+ if (!this._upstreamActive && this._activateUpstream) {
462
+ this._deactivateUpstream = this._activateUpstream();
463
+ this._upstreamActive = true;
464
+ }
465
+ const list = type === "derived" ? this._derivedSubscribers : this._subscribers;
466
+ list.push(cb);
467
+ return () => {
468
+ const idx = list.indexOf(cb);
469
+ if (idx >= 0) list.splice(idx, 1);
470
+ if (this._derivedSubscribers.length === 0 && this._subscribers.length === 0 && this._upstreamActive) {
471
+ this._deactivateUpstream?.();
472
+ this._deactivateUpstream = null;
473
+ this._upstreamActive = false;
474
+ }
475
+ };
476
+ }
477
+ /** Push items and notify subscribers */
478
+ _push(...items) {
479
+ this._items.push(...items);
480
+ this._notify({ added: items, removed: null });
481
+ }
482
+ /** Remove items and notify subscribers */
483
+ _remove(items) {
484
+ for (const item of items) {
485
+ const idx = this._items.indexOf(item);
486
+ if (idx >= 0) this._items.splice(idx, 1);
487
+ }
488
+ this._notify({ added: [], removed: items });
489
+ }
490
+ /** Full reset — replace all items */
491
+ _reset(items) {
492
+ this._items = items;
493
+ this._notify({ init: [...this._items] });
494
+ }
495
+ _notify(event) {
496
+ const derived = [...this._derivedSubscribers];
497
+ for (const sub of derived) sub(event);
498
+ const subs = [...this._subscribers];
499
+ for (const sub of subs) sub(event);
500
+ }
501
+ dispose() {
502
+ this._deactivateUpstream?.();
503
+ this._deactivateUpstream = null;
504
+ this._derivedSubscribers.length = 0;
505
+ this._subscribers.length = 0;
506
+ this._upstreamActive = false;
507
+ }
508
+ };
509
+
510
+ // src/utils/debug-name.ts
511
+ import stringify2 from "safe-stable-stringify";
512
+ var createDebugName = ({ caller, thread, pattern, args }) => {
513
+ args = args || pattern;
514
+ const str = `${!Array.isArray(thread) && thread?.name ? thread.name + " | " : ""}${caller ?? "caller?"}${args ? `{${typeof args === "string" ? args : stringify2(args)}}` : ""}`;
515
+ return str;
516
+ };
517
+ var createDebugNameObj = (args) => {
518
+ return { name: createDebugName(args) };
519
+ };
520
+ function prettifyThreadName(input) {
521
+ let depth = 0;
522
+ let result = "";
523
+ let insideCurlyBraces = 0;
524
+ for (let i = 0; i < input.length; i++) {
525
+ const char = input[i];
526
+ if (char === "(") {
527
+ result += char + "\n" + " ".repeat(++depth);
528
+ } else if (char === ")") {
529
+ result += "\n" + " ".repeat(--depth) + char;
530
+ } else if (char === "," && insideCurlyBraces === 0) {
531
+ result += char + "\n" + " ".repeat(depth);
532
+ } else if (char === "{" && insideCurlyBraces === 0) {
533
+ insideCurlyBraces++;
534
+ result += char + "\n" + " ".repeat(depth + 1);
535
+ } else if (char === "}" && insideCurlyBraces === 1) {
536
+ insideCurlyBraces--;
537
+ result += "\n" + " ".repeat(depth) + char;
538
+ } else if (char === "{" && insideCurlyBraces > 0) {
539
+ insideCurlyBraces++;
540
+ result += char;
541
+ } else if (char === "}" && insideCurlyBraces > 1) {
542
+ insideCurlyBraces--;
543
+ result += char;
544
+ } else {
545
+ result += char;
546
+ }
547
+ }
548
+ return result;
549
+ }
550
+
551
+ // src/thread/basic.ts
552
+ var { WARN: WARN2, LOG: LOG2, DEBUG: DEBUG2, VERBOSE: VERBOSE2, ERROR: ERROR2 } = Logger2.setup(Logger2.INFO, { prefix: "[thread]" });
553
+ var isInitEvent = isArrayInitEvent;
554
+ var Thread = class {
555
+ constructor(name, parents, filters, _applogs = []) {
556
+ this.name = name;
557
+ this._applogs = _applogs;
558
+ this.parents = parents === null ? null : arrayIfSingle(parents);
559
+ this.filters = filters;
560
+ if (this.parents?.length === 0) {
561
+ WARN2(`[Thread] empty parents array`, name);
562
+ }
563
+ }
564
+ filters;
565
+ parents;
566
+ _derivedSubscribers = [];
567
+ _subscribers = [];
568
+ /** Monotonic counter incremented on every mutation. Used by memoizedFn to invalidate caches. */
569
+ _version = 0;
570
+ get readOnly() {
571
+ if (this.parents.length !== 1) return true;
572
+ return this.parents[0].readOnly;
573
+ }
574
+ insert(appLogsToInsert) {
575
+ if (this.readOnly) throw ERROR2(`[Thread] insert() called on read-only thread:`, this.nameAndSizeUntracked);
576
+ if (!this.parents) throw ERROR2(`[Thread] insert() called on non-writable thread without parents:`, this.nameAndSizeUntracked);
577
+ if (this.parents?.length !== 1) throw ERROR2(`[Thread] insert() called on thread with multiple parents:`, this.nameAndSizeUntracked);
578
+ return this.parents[0].insert(appLogsToInsert);
579
+ }
580
+ insertRaw(appLogsToInsert) {
581
+ if (this.readOnly) throw ERROR2(`[Thread] insertRaw() called on read-only thread:`, this.nameAndSizeUntracked);
582
+ if (!this.parents) throw ERROR2(`[Thread] insertRaw() called on non-writable thread without parents:`, this.nameAndSizeUntracked);
583
+ if (this.parents?.length !== 1) throw ERROR2(`[Thread] insertRaw() called on thread with multiple parents:`, this.nameAndSizeUntracked);
584
+ return this.parents[0].insertRaw(appLogsToInsert);
585
+ }
586
+ subscribe(callback, type) {
587
+ const list = type === "derived" ? this._derivedSubscribers : this._subscribers;
588
+ list.push(callback);
589
+ return () => {
590
+ const idx = list.indexOf(callback);
591
+ if (idx >= 0) list.splice(idx, 1);
592
+ };
593
+ }
594
+ notifySubscribers(event) {
595
+ this._version++;
596
+ DEBUG2(`[thread: ${this.name}] notifying`, this._derivedSubscribers.length, "derived +", this._subscribers.length, "subscribers of", { ...event, subs: this._subscribers });
597
+ const derived = [...this._derivedSubscribers];
598
+ for (const subscriber of derived) {
599
+ subscriber(event);
600
+ }
601
+ const subs = [...this._subscribers];
602
+ for (const subscriber of subs) {
603
+ subscriber(event);
604
+ }
605
+ }
606
+ // ── SubscribableArray<Applog> ──
607
+ get items() {
608
+ return this._applogs;
609
+ }
610
+ dispose() {
611
+ this._derivedSubscribers.length = 0;
612
+ this._subscribers.length = 0;
613
+ }
614
+ get applogs() {
615
+ return this._applogs;
616
+ }
617
+ get applogsCids() {
618
+ return this._applogs.map((l) => l.cid);
619
+ }
620
+ get applogsCidSet() {
621
+ return new Set(this._applogs.map((l) => l.cid));
622
+ }
623
+ map(fn) {
624
+ return this.applogs.map(fn);
625
+ }
626
+ get findLast() {
627
+ return this.applogs.findLast.bind(this.applogs);
628
+ }
629
+ get findFirst() {
630
+ return this.applogs.find.bind(this.applogs);
631
+ }
632
+ get firstLog() {
633
+ return this.applogs[0];
634
+ }
635
+ get latestLog() {
258
636
  return this.applogs[this.applogs.length - 1];
259
637
  }
260
638
  hasApplog(applog, byRef) {
261
639
  if (byRef) {
262
640
  return this.applogs.includes(applog);
263
641
  } else {
264
- if (!applog.cid) throw ERROR(`[hasApplogs] applog without CID:`, applog);
642
+ if (!applog.cid) throw ERROR2(`[hasApplogs] applog without CID:`, applog);
265
643
  return this.hasApplogCid(applog.cid);
266
644
  }
267
645
  }
@@ -275,7 +653,7 @@ var Thread = class {
275
653
  return this.applogsByCid.get(cid.toString());
276
654
  }
277
655
  hasApplogWithDiffTs(applog) {
278
- return this.applogs.find((existing) => existing.en === applog.en && existing.at === applog.at && existing.vl === applog.vl && existing.ag === applog.ag);
656
+ return this.applogs.find((existing) => existing.en === applog.en && existing.at === applog.at && valueEq(existing.vl, applog.vl) && existing.ag === applog.ag);
279
657
  }
280
658
  // get stateHash() {
281
659
  // blakeHasher.init()
@@ -329,7 +707,7 @@ import { Logger as Logger4 } from "besonders-logger";
329
707
  // src/ipfs/ipfs-utils.ts
330
708
  import * as dagJson from "@ipld/dag-json";
331
709
  import { sha256 } from "@noble/hashes/sha2.js";
332
- import { Logger as Logger2 } from "besonders-logger";
710
+ import { Logger as Logger3 } from "besonders-logger";
333
711
  import { CID, digest as Digest } from "multiformats";
334
712
  import { encode as multiformatsEncode } from "multiformats/block";
335
713
 
@@ -348,13 +726,23 @@ var CIDTB = Type.String({ format: "CID" });
348
726
  var isURL = /^http([s]?):\/\/.*\..*/;
349
727
  FormatRegistry.Set("URL", (value) => !!value.match(isURL));
350
728
  var URL = Type.String({ format: "URL" });
729
+ var JsonValueTB = Type.Recursive(
730
+ (This) => Type.Union([
731
+ Type.String(),
732
+ Type.Number(),
733
+ Type.Boolean(),
734
+ Type.Null(),
735
+ Type.Array(This),
736
+ Type.Record(Type.String(), This)
737
+ ])
738
+ );
351
739
  var AppLogNoCidTB = Type.Object({
352
740
  en: EntityID,
353
741
  // EntityID
354
742
  at: Type.String(),
355
743
  // Attribute
356
- vl: Nullable(Type.Union([Type.String(), Type.Boolean(), Type.Number()])),
357
- // TODO refactor to semantic typesafe ApplogValue
744
+ vl: JsonValueTB,
745
+ // ApplogValue (JSON-serializable: primitives, arrays, objects)
358
746
  ts: Type.String(),
359
747
  // Timestamp
360
748
  ag: Type.String(),
@@ -378,466 +766,111 @@ var isValidApplog = AppLogTBC.Check.bind(AppLogTBC);
378
766
  // src/ipfs/ipfs-utils.ts
379
767
  import { base36 } from "multiformats/bases/base36";
380
768
  import { sha256 as sha265Hasher } from "multiformats/hashes/sha2";
381
- var { WARN: WARN2, LOG: LOG2, DEBUG: DEBUG2, VERBOSE: VERBOSE2, ERROR: ERROR2 } = Logger2.setup(Logger2.INFO);
769
+ var { WARN: WARN3, LOG: LOG3, DEBUG: DEBUG3, VERBOSE: VERBOSE3, ERROR: ERROR3 } = Logger3.setup(Logger3.INFO);
382
770
  var MULTICODEC_IPNS_KEY = 114;
383
771
  function prepareForPub(log, without = ["cid"]) {
384
- if (!log) throw ERROR2("falsy log", log);
772
+ if (!log) throw ERROR3("falsy log", log);
385
773
  let cid = log.cid;
386
774
  if (isEncryptedApplog(log)) {
387
775
  if (!cid) cid = getCidSync(encodeBlock(log).bytes).toString();
388
- WARN2("preparing an encrypted applog - really?");
389
- return { log, cid };
390
- }
391
- const logWithout = {};
392
- for (let [key, val] of Object.entries(log)) {
393
- if (val === void 0) {
394
- WARN2(`log.${key} is undefined, which is not allowed - encoding as null`, log);
395
- val = null;
396
- }
397
- if (!without.includes(key)) {
398
- logWithout[key] = val;
399
- } else {
400
- VERBOSE2("excluding app log", { key, val });
401
- }
402
- }
403
- return { log: logWithout, cid };
404
- }
405
- function encodeApplogAndGetCid(log) {
406
- return getCidSync(encodeApplog(log).bytes);
407
- }
408
- function encodeApplog(log) {
409
- return encodeBlock(prepareForPub(log)?.log);
410
- }
411
- function getCidSync(bytes) {
412
- const hash = sha256(bytes);
413
- const digest = Digest.create(sha265Hasher.code, hash);
414
- const cid = CID.create(1, dagJson.code, digest);
415
- VERBOSE2(`[getCidSync]`, { bytes, hash, digest, cid });
416
- return cid;
417
- }
418
- function encodeBlock(jsonObject) {
419
- DEBUG2("[encodeBlock]", jsonObject);
420
- try {
421
- const byteView = dagJson.encode(jsonObject);
422
- return { bytes: byteView, cid: getCidSync(byteView) };
423
- } catch (err) {
424
- throw ERROR2("[encodeBlock] failed to encode:", jsonObject, err);
425
- }
426
- }
427
- async function encodeBlockOriginal(jsonObject) {
428
- const encoded = await multiformatsEncode({ value: jsonObject, codec: dagJson, hasher: sha265Hasher });
429
- const syncVariant = encodeBlock(jsonObject);
430
- if (syncVariant.cid.toString() !== encoded.cid.toString()) {
431
- ERROR2(`[encodeBlockOriginal] sync cid mismatch`, { jsonObject, encoded, syncVariant });
432
- }
433
- return encoded;
434
- }
435
- function tryParseCID(cidString) {
436
- let cid = null;
437
- let errors = [];
438
- try {
439
- cid = CID.parse(cidString);
440
- } catch (err) {
441
- VERBOSE2(`[retrieveThread] couldn't parse pubID with default base`);
442
- errors.push(err);
443
- }
444
- if (!cid) {
445
- try {
446
- cid = CID.parse(cidString, base36);
447
- } catch (err) {
448
- VERBOSE2(`[retrieveThread] couldn't parse pubID with base36`);
449
- errors.push(err);
450
- }
451
- }
452
- return {
453
- cid,
454
- errors: cid ? null : errors,
455
- // we only care about errors if we failed to parse
456
- isIpns: cid && isIpnsKeyCid(cid)
457
- };
458
- }
459
- function isIpnsKeyCid(cid) {
460
- return cid.code === MULTICODEC_IPNS_KEY;
461
- }
462
- function cidToString(cid) {
463
- if (cid.code == MULTICODEC_IPNS_KEY) {
464
- return toIpnsString(cid);
465
- } else {
466
- return cid.toString();
467
- }
468
- }
469
- function toIpnsString(cid) {
470
- if (cid.code !== MULTICODEC_IPNS_KEY) throw ERROR2(`Not an IPNS cid (${cid.code}):`, cid.toString());
471
- return cid.toString(base36);
472
- }
473
- function ensureValidCIDinstance(cidOrStringA) {
474
- return typeof cidOrStringA === "string" ? CID.parse(cidOrStringA) : typeof cidOrStringA.toV1 != "function" ? CID.decode(cidOrStringA.bytes) : cidOrStringA;
475
- }
476
- function areCidsEqual(cidOrStringA, cidOrStringB) {
477
- if (!cidOrStringA || !cidOrStringB) throw new Error(`[areCidsEqual] invalid params: ${cidOrStringA}, ${cidOrStringB}`);
478
- if (cidOrStringA === cidOrStringB) return true;
479
- const cidA = ensureValidCIDinstance(cidOrStringA);
480
- const cidB = ensureValidCIDinstance(cidOrStringB);
481
- return cidA.toV1().toString() === cidB.toV1().toString();
482
- }
483
- function containsCid(list, needle) {
484
- if (list instanceof Set) return list.has(typeof needle === "string" ? needle : needle.toV1().toString());
485
- return list.some((cidOrString) => areCidsEqual(cidOrString, needle));
486
- }
487
-
488
- // src/applog/applog-utils.ts
489
- import { Logger as Logger3 } from "besonders-logger";
490
- import { isBefore } from "date-fns";
491
- import { partial, pick } from "lodash-es";
492
- import { isEqual } from "lodash-es";
493
- import stringify2 from "safe-stable-stringify";
494
- var { WARN: WARN3, LOG: LOG3, DEBUG: DEBUG3, VERBOSE: VERBOSE3, ERROR: ERROR3 } = Logger3.setup(Logger3.INFO);
495
- var isoDateStrCompare = (strA, strB, dir = "asc") => dir === "asc" ? strA.localeCompare(strB, "en-US") : strB.localeCompare(strA, "en-US");
496
- var objEqualByKeys = (keys, objA, objB) => {
497
- return isEqual(pick(objA, keys), pick(objB, keys));
498
- };
499
- var compareApplogsByTs = (logA, logB, dir = "asc") => {
500
- const tsCmp = isoDateStrCompare(logA.ts, logB.ts, dir);
501
- if (tsCmp !== 0) return tsCmp;
502
- return dir === "asc" ? logA.cid.localeCompare(logB.cid) : logB.cid.localeCompare(logA.cid);
503
- };
504
- var compareApplogsByEnAt = partial(objEqualByKeys, ["en", "at"]);
505
- function isLaterByTsAndPv(a, b) {
506
- const tsCmp = isoDateStrCompare(a.ts, b.ts);
507
- if (tsCmp !== 0) return tsCmp > 0;
508
- if (a.en === b.en && a.at === b.at) {
509
- if (a.pv === b.cid) return true;
510
- if (b.pv === a.cid) return false;
511
- }
512
- return a.cid.localeCompare(b.cid) > 0;
513
- }
514
- function sortApplogsByTs(appLogArray, dir = "asc") {
515
- appLogArray.sort((a, b) => compareApplogsByTs(a, b, dir));
516
- let i = 0;
517
- while (i < appLogArray.length) {
518
- let j = i + 1;
519
- while (j < appLogArray.length && appLogArray[j].ts === appLogArray[i].ts) j++;
520
- if (j - i > 1) chainStabilizeCluster(appLogArray, i, j, dir);
521
- i = j;
522
- }
523
- return appLogArray;
524
- }
525
- function chainStabilizeCluster(applogs, from, to, dir) {
526
- const groups = /* @__PURE__ */ new Map();
527
- for (let k = from; k < to; k++) {
528
- const log = applogs[k];
529
- const key = log.en + "|" + log.at;
530
- const existing = groups.get(key);
531
- if (existing) existing.push(log);
532
- else groups.set(key, [log]);
533
- }
534
- if (groups.size === to - from) return;
535
- const orderedByGroup = /* @__PURE__ */ new Map();
536
- for (const [key, logs] of groups) {
537
- orderedByGroup.set(key, logs.length === 1 ? logs : topoSortByPv(logs, dir));
538
- }
539
- const cursors = /* @__PURE__ */ new Map();
540
- for (let k = from; k < to; k++) {
541
- const key = applogs[k].en + "|" + applogs[k].at;
542
- const cursor = cursors.get(key) ?? 0;
543
- applogs[k] = orderedByGroup.get(key)[cursor];
544
- cursors.set(key, cursor + 1);
545
- }
546
- }
547
- function topoSortByPv(logs, dir) {
548
- const cidSet = new Set(logs.map((l) => l.cid));
549
- const childrenByPv = /* @__PURE__ */ new Map();
550
- const roots = [];
551
- for (const log of logs) {
552
- if (log.pv && cidSet.has(log.pv)) {
553
- const children = childrenByPv.get(log.pv);
554
- if (children) children.push(log);
555
- else childrenByPv.set(log.pv, [log]);
556
- } else {
557
- roots.push(log);
558
- }
559
- }
560
- const lexCmp = (a, b) => a.cid.localeCompare(b.cid);
561
- roots.sort(lexCmp);
562
- for (const children of childrenByPv.values()) children.sort(lexCmp);
563
- const result = [];
564
- const visited = /* @__PURE__ */ new Set();
565
- const stack = [...roots].reverse();
566
- while (stack.length > 0) {
567
- const log = stack.pop();
568
- if (visited.has(log.cid)) continue;
569
- visited.add(log.cid);
570
- result.push(log);
571
- const children = childrenByPv.get(log.cid);
572
- if (children) for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]);
573
- }
574
- if (result.length < logs.length) {
575
- for (const log of logs) if (!visited.has(log.cid)) result.push(log);
576
- }
577
- return dir === "desc" ? result.reverse() : result;
578
- }
579
- var isTsBefore = (log, logToCompare) => isBefore(new Date(log.ts), new Date(logToCompare.ts));
580
- var uniqueEnFromAppLogs = (appLogArray) => [...new Set(appLogArray.map((eachLog) => eachLog.en))];
581
- var areApplogsEqual = (logA, logB) => isEqual(logA, logB);
582
- var warnMissingRemoveDuplicateMode = () => {
583
- WARN3(`[removeDuplicateAppLogs] mode not set; pass 'safety' or 'cleanup' for optimal behavior`);
584
- };
585
- var removeDuplicateAppLogsCleanup = (appLogArray) => {
586
- const logMap = /* @__PURE__ */ new Map();
587
- const verboseEnabled = VERBOSE3.isEnabled;
588
- for (const eachLog of appLogArray) {
589
- if (!eachLog) {
590
- ERROR3(`falsy entry in applogs`, appLogArray);
591
- throw new Error(`falsy entry in applogs`);
592
- }
593
- if (!eachLog.cid) {
594
- ERROR3(`applog with missing CID`, eachLog);
595
- throw new Error(`applog with missing CID`);
596
- }
597
- const key = eachLog.cid;
598
- const existing = logMap.get(key);
599
- if (existing) {
600
- if (verboseEnabled) VERBOSE3(`Skipping duplicate applog:`, [existing, eachLog]);
601
- } else {
602
- logMap.set(key, eachLog);
603
- }
604
- }
605
- return Array.from(logMap.values());
606
- };
607
- var removeDuplicateAppLogsSafety = (appLogArray) => {
608
- const seen = /* @__PURE__ */ new Set();
609
- const verboseEnabled = VERBOSE3.isEnabled;
610
- const existingByCid = verboseEnabled ? /* @__PURE__ */ new Map() : null;
611
- let result = null;
612
- let index = 0;
613
- for (const eachLog of appLogArray) {
614
- if (!eachLog) {
615
- ERROR3(`falsy entry in applogs`, appLogArray);
616
- throw new Error(`falsy entry in applogs`);
617
- }
618
- if (!eachLog.cid) {
619
- ERROR3(`applog with missing CID`, eachLog);
620
- throw new Error(`applog with missing CID`);
621
- }
622
- const key = eachLog.cid;
623
- if (seen.has(key)) {
624
- if (!result) {
625
- result = appLogArray.slice(0, index);
626
- }
627
- if (verboseEnabled) VERBOSE3(`Skipping duplicate applog:`, [existingByCid?.get(key), eachLog]);
628
- } else {
629
- seen.add(key);
630
- if (existingByCid) existingByCid.set(key, eachLog);
631
- if (result) result.push(eachLog);
632
- }
633
- index++;
634
- }
635
- return result ?? appLogArray;
636
- };
637
- var removeDuplicateAppLogs = (appLogArray, mode) => {
638
- if (!mode) {
639
- warnMissingRemoveDuplicateMode();
640
- return removeDuplicateAppLogsCleanup(appLogArray);
641
- }
642
- return mode === "safety" ? removeDuplicateAppLogsSafety(appLogArray) : removeDuplicateAppLogsCleanup(appLogArray);
643
- };
644
- var getHashID = (stringifiable, lngth = 8) => cyrb53hash(stringify2(stringifiable), 31, lngth);
645
- function isVariable(x) {
646
- return typeof x === "string" && x.startsWith("?");
647
- }
648
- function variableNameWithoutQuestionmark(str) {
649
- return str.slice(1);
650
- }
651
- function isStaticPattern(x) {
652
- if (!["string", "boolean", "number", "function"].includes(typeof x)) WARN3(`Unhandled pattern value type:`, typeof x, x);
653
- return !isVariable(x) && ["string", "boolean", "number"].includes(typeof x);
654
- }
655
- function resolveOrRemoveVariables(pattern, candidate) {
656
- let variablesToFill = {};
657
- const newPattern = {};
658
- for (const [patternKey, patternValue] of Object.entries(pattern)) {
659
- if (isVariable(patternValue)) {
660
- const varName = variableNameWithoutQuestionmark(patternValue);
661
- const candidateValue = candidate[varName];
662
- if (candidateValue) {
663
- newPattern[patternKey] = candidateValue;
664
- } else {
665
- variablesToFill[patternKey] = varName;
666
- }
776
+ WARN3("preparing an encrypted applog - really?");
777
+ return { log, cid };
778
+ }
779
+ const logWithout = {};
780
+ for (let [key, val] of Object.entries(log)) {
781
+ if (val === void 0) {
782
+ WARN3(`log.${key} is undefined, which is not allowed - encoding as null`, log);
783
+ val = null;
784
+ }
785
+ if (!without.includes(key)) {
786
+ logWithout[key] = val;
667
787
  } else {
668
- newPattern[patternKey] = patternValue;
788
+ VERBOSE3("excluding app log", { key, val });
669
789
  }
670
790
  }
671
- return [newPattern, variablesToFill];
791
+ return { log: logWithout, cid };
672
792
  }
673
- function matchVariable(variable, triplePart, context) {
674
- if (context.hasOwnProperty(variable)) {
675
- const bound = context[variable];
676
- const match = matchPart(bound, triplePart, context);
677
- return match;
678
- }
679
- return { ...context, [variable]: triplePart };
793
+ function encodeApplogAndGetCid(log) {
794
+ return getCidSync(encodeApplog(log).bytes);
680
795
  }
681
- function matchPartStatic(field, patternPart, atomPart) {
682
- let result;
683
- if (patternPart) {
684
- const typ = typeof patternPart;
685
- if (typ === "string") {
686
- result = patternPart === atomPart;
687
- } else if (typ === "function") {
688
- result = patternPart(atomPart);
689
- } else if (typeof patternPart.has === "function") {
690
- result = patternPart.has(atomPart);
691
- } else if (Array.isArray(patternPart) && !Array.isArray(atomPart)) {
692
- result = patternPart.includes(atomPart);
693
- } else {
694
- result = patternPart === atomPart;
695
- }
696
- } else {
697
- result = patternPart === atomPart;
796
+ function encodeApplog(log) {
797
+ return encodeBlock(prepareForPub(log)?.log);
798
+ }
799
+ function getCidSync(bytes) {
800
+ const hash = sha256(bytes);
801
+ const digest = Digest.create(sha265Hasher.code, hash);
802
+ const cid = CID.create(1, dagJson.code, digest);
803
+ VERBOSE3(`[getCidSync]`, { bytes, hash, digest, cid });
804
+ return cid;
805
+ }
806
+ function encodeBlock(jsonObject) {
807
+ DEBUG3("[encodeBlock]", jsonObject);
808
+ try {
809
+ const byteView = dagJson.encode(jsonObject);
810
+ return { bytes: byteView, cid: getCidSync(byteView) };
811
+ } catch (err) {
812
+ throw ERROR3("[encodeBlock] failed to encode:", jsonObject, err);
698
813
  }
699
- if (field.charAt(0) === "!") {
700
- return !result;
701
- } else {
702
- return result;
814
+ }
815
+ async function encodeBlockOriginal(jsonObject) {
816
+ const encoded = await multiformatsEncode({ value: jsonObject, codec: dagJson, hasher: sha265Hasher });
817
+ const syncVariant = encodeBlock(jsonObject);
818
+ if (syncVariant.cid.toString() !== encoded.cid.toString()) {
819
+ ERROR3(`[encodeBlockOriginal] sync cid mismatch`, { jsonObject, encoded, syncVariant });
703
820
  }
821
+ return encoded;
704
822
  }
705
- function matchPart(patternPart, atomPart, context) {
706
- if (!context) {
707
- return null;
823
+ function tryParseCID(cidString) {
824
+ let cid = null;
825
+ let errors = [];
826
+ try {
827
+ cid = CID.parse(cidString);
828
+ } catch (err) {
829
+ VERBOSE3(`[retrieveThread] couldn't parse pubID with default base`);
830
+ errors.push(err);
708
831
  }
709
- if (typeof patternPart === "string") {
710
- if (isVariable(patternPart)) {
711
- return matchVariable(patternPart, atomPart, context);
832
+ if (!cid) {
833
+ try {
834
+ cid = CID.parse(cidString, base36);
835
+ } catch (err) {
836
+ VERBOSE3(`[retrieveThread] couldn't parse pubID with base36`);
837
+ errors.push(err);
712
838
  }
713
839
  }
714
- if (typeof patternPart === "function") {
715
- return patternPart(atomPart) ? context : null;
840
+ return {
841
+ cid,
842
+ errors: cid ? null : errors,
843
+ // we only care about errors if we failed to parse
844
+ isIpns: cid && isIpnsKeyCid(cid)
845
+ };
846
+ }
847
+ function isIpnsKeyCid(cid) {
848
+ return cid.code === MULTICODEC_IPNS_KEY;
849
+ }
850
+ function cidToString(cid) {
851
+ if (cid.code == MULTICODEC_IPNS_KEY) {
852
+ return toIpnsString(cid);
853
+ } else {
854
+ return cid.toString();
716
855
  }
717
- return patternPart === atomPart ? context : null;
718
856
  }
719
- function matchPattern(pattern, applog, context) {
720
- return Object.entries(pattern).reduce((context2, [field, patternValue]) => {
721
- const applogValue = applog[field];
722
- const patternValT = patternValue;
723
- return matchPart(patternValT, applogValue, context2);
724
- }, context);
857
+ function toIpnsString(cid) {
858
+ if (cid.code !== MULTICODEC_IPNS_KEY) throw ERROR3(`Not an IPNS cid (${cid.code}):`, cid.toString());
859
+ return cid.toString(base36);
725
860
  }
726
- function actualize(context, find) {
727
- return Object.fromEntries(find.map((findField) => {
728
- if (context === null) {
729
- throw new Error(`actualize context is null ${find}`);
730
- }
731
- return [
732
- isVariable(findField) ? findField.replace(/^\?/, "") : findField,
733
- isVariable(findField) ? context[findField] : findField
734
- ];
735
- }));
861
+ function ensureValidCIDinstance(cidOrStringA) {
862
+ return typeof cidOrStringA === "string" ? CID.parse(cidOrStringA) : typeof cidOrStringA.toV1 != "function" ? CID.decode(cidOrStringA.bytes) : cidOrStringA;
736
863
  }
737
- var sum = function sum2(array) {
738
- var num = 0;
739
- for (var i = 0, l = array.length; i < l; i++) num += array[i];
740
- return num;
741
- };
742
- var mean = function mean2(array) {
743
- return sum(array) / array.length;
744
- };
745
- var arrStats = {
746
- max: function(array) {
747
- return Math.max.apply(null, array);
748
- },
749
- min: function(array) {
750
- return Math.min.apply(null, array);
751
- },
752
- range: function(array) {
753
- return arrStats.max(array) - arrStats.min(array);
754
- },
755
- midrange: function(array) {
756
- return arrStats.range(array) / 2;
757
- },
758
- sum,
759
- mean,
760
- average: mean,
761
- median: function(array) {
762
- array.sort(function(a, b) {
763
- return a - b;
764
- });
765
- var mid = array.length / 2;
766
- return mid % 1 ? array[mid - 0.5] : (array[mid - 1] + array[mid]) / 2;
767
- },
768
- modes: function(array) {
769
- if (!array.length) return [];
770
- var modeMap = {}, maxCount = 0, modes = [];
771
- array.forEach(function(val) {
772
- if (!modeMap[val]) modeMap[val] = 1;
773
- else modeMap[val]++;
774
- if (modeMap[val] > maxCount) {
775
- modes = [val];
776
- maxCount = modeMap[val];
777
- } else if (modeMap[val] === maxCount) {
778
- modes.push(val);
779
- maxCount = modeMap[val];
780
- }
781
- });
782
- return modes;
783
- },
784
- variance: function(array) {
785
- var mean3 = arrStats.mean(array);
786
- return arrStats.mean(array.map(function(num) {
787
- return Math.pow(num - mean3, 2);
788
- }));
789
- },
790
- standardDeviation: function(array) {
791
- return Math.sqrt(arrStats.variance(array));
792
- },
793
- meanAbsoluteDeviation: function(array) {
794
- var mean3 = arrStats.mean(array);
795
- return arrStats.mean(array.map(function(num) {
796
- return Math.abs(num - mean3);
797
- }));
798
- },
799
- zScores: function(array) {
800
- var mean3 = arrStats.mean(array);
801
- var standardDeviation = arrStats.standardDeviation(array);
802
- return array.map(function(num) {
803
- return (num - mean3) / standardDeviation;
804
- });
805
- }
806
- };
807
- arrStats.average = arrStats.mean;
808
- var tsNearlySame = (timeA, timeB) => timeB.startsWith(timeA.slice(0, timeA.length - 4));
809
- var cyrb53hash = function(str, seed = 13, strLength) {
810
- if (!str?.length) {
811
- throw new Error(`Empty string: ${str}`);
812
- }
813
- let h1 = 3735928559 ^ seed;
814
- let h2 = 1103547991 ^ seed;
815
- for (let i = 0, ch; i < str.length; i++) {
816
- ch = str.charCodeAt(i);
817
- h1 = Math.imul(h1 ^ ch, 2654435761);
818
- h2 = Math.imul(h2 ^ ch, 1597334677);
819
- }
820
- h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
821
- h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
822
- const asHex = (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16);
823
- return asHex.slice(-strLength).padStart(strLength, "0");
824
- };
825
- function arraysContainSameElements(arr1, arr2) {
826
- if (arr1.length !== arr2.length) {
827
- return false;
828
- }
829
- const sortedArr1 = [...arr1].sort();
830
- const sortedArr2 = [...arr2].sort();
831
- for (let i = 0; i < sortedArr1.length; i++) {
832
- if (sortedArr1[i] !== sortedArr2[i]) {
833
- return false;
834
- }
835
- }
836
- return true;
864
+ function areCidsEqual(cidOrStringA, cidOrStringB) {
865
+ if (!cidOrStringA || !cidOrStringB) throw new Error(`[areCidsEqual] invalid params: ${cidOrStringA}, ${cidOrStringB}`);
866
+ if (cidOrStringA === cidOrStringB) return true;
867
+ const cidA = ensureValidCIDinstance(cidOrStringA);
868
+ const cidB = ensureValidCIDinstance(cidOrStringB);
869
+ return cidA.toV1().toString() === cidB.toV1().toString();
837
870
  }
838
- function dateNowIso() {
839
- const now = /* @__PURE__ */ new Date();
840
- return now.toISOString();
871
+ function containsCid(list, needle) {
872
+ if (list instanceof Set) return list.has(typeof needle === "string" ? needle : needle.toV1().toString());
873
+ return list.some((cidOrString) => areCidsEqual(cidOrString, needle));
841
874
  }
842
875
 
843
876
  // src/applog/applog-helpers.ts
@@ -1363,6 +1396,26 @@ var simpleApplogMapper = function simpleApplogMapper2(thread, logMapper, opts =
1363
1396
 
1364
1397
  // src/thread/indexes.ts
1365
1398
  import { Logger as Logger7 } from "besonders-logger";
1399
+
1400
+ // src/query/matchers.ts
1401
+ function includes(str) {
1402
+ return (vl) => vl?.includes?.(str);
1403
+ }
1404
+ function includedIn(arr) {
1405
+ return (vl) => arr?.includes?.(vl);
1406
+ }
1407
+ function anyOf(...vals) {
1408
+ for (const v of vals) {
1409
+ if (v !== null && typeof v === "object") {
1410
+ throw new Error(
1411
+ `[anyOf] object/array members are not supported (referential Set membership would silently never match). Use a predicate matcher instead, e.g. (v) => members.some(m => isEqual(v, m)).`
1412
+ );
1413
+ }
1414
+ }
1415
+ return new Set(vals);
1416
+ }
1417
+
1418
+ // src/thread/indexes.ts
1366
1419
  var { WARN: WARN7, LOG: LOG7, DEBUG: DEBUG7, VERBOSE: VERBOSE7, ERROR: ERROR7 } = Logger7.setup(Logger7.INFO);
1367
1420
  var applogsByEntity = memoizedFn(
1368
1421
  "applogsByEntity",
@@ -1401,19 +1454,21 @@ var applogsByAttrValue = memoizedFn(
1401
1454
  function applogsByAttrValue2(thread, attr) {
1402
1455
  const map = /* @__PURE__ */ new Map();
1403
1456
  const add = (log) => {
1404
- let arr = map.get(log.vl);
1457
+ const key = valueKey(log.vl);
1458
+ let arr = map.get(key);
1405
1459
  if (!arr) {
1406
1460
  arr = [];
1407
- map.set(log.vl, arr);
1461
+ map.set(key, arr);
1408
1462
  }
1409
1463
  arr.push(log);
1410
1464
  };
1411
1465
  const remove = (log) => {
1412
- const arr = map.get(log.vl);
1466
+ const key = valueKey(log.vl);
1467
+ const arr = map.get(key);
1413
1468
  if (!arr) return;
1414
1469
  const idx = arr.indexOf(log);
1415
1470
  if (idx >= 0) arr.splice(idx, 1);
1416
- if (arr.length === 0) map.delete(log.vl);
1471
+ if (arr.length === 0) map.delete(key);
1417
1472
  };
1418
1473
  const filtered = rollingFilter2(thread, { at: attr });
1419
1474
  for (const log of filtered.applogs) add(log);
@@ -1509,7 +1564,7 @@ var entityLinkIndex = memoizedFn(
1509
1564
  bByLink.clear();
1510
1565
  for (const log of applogs) processLog(log);
1511
1566
  }
1512
- const filtered = rollingFilter2(thread, { at: [attrA, attrB] });
1567
+ const filtered = rollingFilter2(thread, { at: anyOf(attrA, attrB) });
1513
1568
  buildFull(filtered.applogs);
1514
1569
  const value = { byA, byB };
1515
1570
  const result = new SubscribableImpl(
@@ -1767,6 +1822,7 @@ export {
1767
1822
  isEncryptedApplog,
1768
1823
  CIDTB,
1769
1824
  URL,
1825
+ JsonValueTB,
1770
1826
  AppLogNoCidTB,
1771
1827
  AppLogNoCidTBC,
1772
1828
  getApplogNoCidTypeErrors,
@@ -1789,18 +1845,10 @@ export {
1789
1845
  ensureValidCIDinstance,
1790
1846
  areCidsEqual,
1791
1847
  containsCid,
1792
- SubscribableImpl,
1793
- isArrayInitEvent,
1794
- SubscribableArrayImpl,
1795
- createDebugName,
1796
- createDebugNameObj,
1797
- prettifyThreadName,
1798
- isInitEvent,
1799
- Thread,
1800
- getLogsFromThread,
1801
- StaticThread,
1802
1848
  isoDateStrCompare,
1803
1849
  objEqualByKeys,
1850
+ valueEq,
1851
+ valueKey,
1804
1852
  compareApplogsByTs,
1805
1853
  compareApplogsByEnAt,
1806
1854
  isLaterByTsAndPv,
@@ -1823,6 +1871,16 @@ export {
1823
1871
  cyrb53hash,
1824
1872
  arraysContainSameElements,
1825
1873
  dateNowIso,
1874
+ SubscribableImpl,
1875
+ isArrayInitEvent,
1876
+ SubscribableArrayImpl,
1877
+ createDebugName,
1878
+ createDebugNameObj,
1879
+ prettifyThreadName,
1880
+ isInitEvent,
1881
+ Thread,
1882
+ getLogsFromThread,
1883
+ StaticThread,
1826
1884
  memoizedFn,
1827
1885
  refCountedMemoizedFn,
1828
1886
  MappedThread,
@@ -1837,6 +1895,9 @@ export {
1837
1895
  assertOnlyCurrent,
1838
1896
  asReadOnly,
1839
1897
  simpleApplogMapper,
1898
+ includes,
1899
+ includedIn,
1900
+ anyOf,
1840
1901
  applogsByEntity,
1841
1902
  applogsByAttrValue,
1842
1903
  entityLinkIndex,
@@ -1859,4 +1920,4 @@ export {
1859
1920
  withPvFrom,
1860
1921
  joinThreads
1861
1922
  };
1862
- //# sourceMappingURL=chunk-L5EEEGE6.js.map
1923
+ //# sourceMappingURL=chunk-SHUHRHOT.js.map