mcard-js 2.1.49 → 2.1.50

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.
@@ -0,0 +1,299 @@
1
+ import {
2
+ MCard
3
+ } from "./chunk-GGQCF7ZK.js";
4
+ import {
5
+ DEFAULT_PAGE_SIZE
6
+ } from "./chunk-ETJWXHKZ.js";
7
+
8
+ // src/monads/Maybe.ts
9
+ var Maybe = class _Maybe {
10
+ constructor(_value, _isNothing) {
11
+ this._value = _value;
12
+ this._isNothing = _isNothing;
13
+ }
14
+ /**
15
+ * Create a Just (has value)
16
+ */
17
+ static just(value) {
18
+ return new _Maybe(value, false);
19
+ }
20
+ /**
21
+ * Create a Nothing (no value)
22
+ */
23
+ static nothing() {
24
+ return new _Maybe(null, true);
25
+ }
26
+ /**
27
+ * Check if this is Nothing
28
+ */
29
+ get isNothing() {
30
+ return this._isNothing;
31
+ }
32
+ /**
33
+ * Check if this is Just
34
+ */
35
+ get isJust() {
36
+ return !this._isNothing;
37
+ }
38
+ /**
39
+ * Get the value (throws if Nothing)
40
+ */
41
+ get value() {
42
+ if (this._isNothing) {
43
+ throw new Error("Cannot get value from Nothing");
44
+ }
45
+ return this._value;
46
+ }
47
+ /**
48
+ * Monadic bind - chain operations
49
+ * Short-circuits on Nothing
50
+ */
51
+ bind(fn) {
52
+ if (this._isNothing) {
53
+ return _Maybe.nothing();
54
+ }
55
+ return fn(this._value);
56
+ }
57
+ /**
58
+ * Map a function over the value
59
+ */
60
+ map(fn) {
61
+ if (this._isNothing) {
62
+ return _Maybe.nothing();
63
+ }
64
+ return _Maybe.just(fn(this._value));
65
+ }
66
+ /**
67
+ * Get value or default
68
+ */
69
+ getOrElse(defaultValue) {
70
+ return this._isNothing ? defaultValue : this._value;
71
+ }
72
+ };
73
+
74
+ // src/model/CardCollection.ts
75
+ var CardCollection = class {
76
+ engine;
77
+ constructor(engine) {
78
+ this.engine = engine;
79
+ }
80
+ // =========== Standard Operations ===========
81
+ /**
82
+ * Add a card to the collection
83
+ * Handles duplicates (same content, same hash) and collisions (diff content, same hash)
84
+ */
85
+ async add(card) {
86
+ const existingCard = await this.engine.get(card.hash);
87
+ if (existingCard) {
88
+ const isDuplicate = this.areContentsEqual(existingCard.content, card.content);
89
+ if (isDuplicate) {
90
+ const { generateDuplicationEvent } = await import("./EventProducer-VFDOM5W2.js");
91
+ const eventStr = generateDuplicationEvent(card);
92
+ const eventCard = await MCard.create(eventStr);
93
+ await this.engine.add(eventCard);
94
+ return card.hash;
95
+ } else {
96
+ const { generateCollisionEvent } = await import("./EventProducer-VFDOM5W2.js");
97
+ const eventStr = await generateCollisionEvent(card);
98
+ const eventCard = await MCard.create(eventStr);
99
+ await this.engine.add(eventCard);
100
+ const eventObj = JSON.parse(eventStr);
101
+ const nextAlgo = eventObj.upgraded_function;
102
+ if (!nextAlgo) {
103
+ throw new Error("Failed to determine next hash algorithm for collision");
104
+ }
105
+ const upgradedCard = await MCard.create(card.content, nextAlgo);
106
+ return this.engine.add(upgradedCard);
107
+ }
108
+ }
109
+ return this.engine.add(card);
110
+ }
111
+ areContentsEqual(a, b) {
112
+ if (a.length !== b.length) return false;
113
+ for (let i = 0; i < a.length; i++) {
114
+ if (a[i] !== b[i]) return false;
115
+ }
116
+ return true;
117
+ }
118
+ /**
119
+ * Get a card by hash
120
+ */
121
+ async get(hash) {
122
+ return this.engine.get(hash);
123
+ }
124
+ /**
125
+ * Delete a card by hash
126
+ */
127
+ async delete(hash) {
128
+ return this.engine.delete(hash);
129
+ }
130
+ /**
131
+ * Get a page of cards
132
+ */
133
+ async getPage(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
134
+ return this.engine.getPage(pageNumber, pageSize);
135
+ }
136
+ /**
137
+ * Count total cards
138
+ */
139
+ async count() {
140
+ return this.engine.count();
141
+ }
142
+ // =========== Handle Operations ===========
143
+ /**
144
+ * Add a card and register a handle for it
145
+ */
146
+ async addWithHandle(card, handle) {
147
+ const hash = await this.add(card);
148
+ await this.engine.registerHandle(handle, hash);
149
+ return hash;
150
+ }
151
+ /**
152
+ * Get card by handle
153
+ */
154
+ async getByHandle(handle) {
155
+ return this.engine.getByHandle(handle);
156
+ }
157
+ /**
158
+ * Resolve handle to hash
159
+ */
160
+ async resolveHandle(handle) {
161
+ return this.engine.resolveHandle(handle);
162
+ }
163
+ /**
164
+ * Update handle to point to new card
165
+ */
166
+ async updateHandle(handle, newCard) {
167
+ const hash = await this.add(newCard);
168
+ await this.engine.updateHandle(handle, hash);
169
+ return hash;
170
+ }
171
+ /**
172
+ * Get version history for a handle
173
+ */
174
+ async getHandleHistory(handle) {
175
+ return this.engine.getHandleHistory(handle);
176
+ }
177
+ // =========== Monadic Operations ===========
178
+ /**
179
+ * Monadic get - returns Maybe<MCard>
180
+ */
181
+ async getM(hash) {
182
+ const card = await this.get(hash);
183
+ return card ? Maybe.just(card) : Maybe.nothing();
184
+ }
185
+ /**
186
+ * Monadic getByHandle - returns Maybe<MCard>
187
+ */
188
+ async getByHandleM(handle) {
189
+ const card = await this.getByHandle(handle);
190
+ return card ? Maybe.just(card) : Maybe.nothing();
191
+ }
192
+ /**
193
+ * Monadic resolveHandle - returns Maybe<string>
194
+ */
195
+ async resolveHandleM(handle) {
196
+ const hash = await this.resolveHandle(handle);
197
+ return hash ? Maybe.just(hash) : Maybe.nothing();
198
+ }
199
+ /**
200
+ * Resolve handle and get card in one monadic operation
201
+ */
202
+ async resolveAndGetM(handle) {
203
+ const maybeHash = await this.resolveHandleM(handle);
204
+ if (maybeHash.isNothing) return Maybe.nothing();
205
+ return this.getM(maybeHash.value);
206
+ }
207
+ /**
208
+ * Prune version history for a handle.
209
+ * @param handle The handle string.
210
+ * @param options Options for pruning (olderThan date, or deleteAll).
211
+ * @returns Number of deleted entries.
212
+ */
213
+ async pruneHandleHistory(handle, options = {}) {
214
+ if (this.engine.pruneHandleHistory) {
215
+ return this.engine.pruneHandleHistory(handle, options);
216
+ }
217
+ return 0;
218
+ }
219
+ // =========== Search & Bulk Operations ===========
220
+ async clear() {
221
+ return this.engine.clear();
222
+ }
223
+ async searchByString(query, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
224
+ return this.engine.search(query, pageNumber, pageSize);
225
+ }
226
+ async searchByContent(query, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
227
+ return this.engine.search(query, pageNumber, pageSize);
228
+ }
229
+ async searchByHash(hashPrefix) {
230
+ return this.engine.searchByHash(hashPrefix);
231
+ }
232
+ async getAllMCardsRaw() {
233
+ return this.engine.getAll();
234
+ }
235
+ async getAllCards(pageSize = DEFAULT_PAGE_SIZE, processCallback) {
236
+ const cards = [];
237
+ let pageNumber = 1;
238
+ let total = 0;
239
+ while (true) {
240
+ const page = await this.getPage(pageNumber, pageSize);
241
+ if (!page.items || page.items.length === 0) break;
242
+ for (const card of page.items) {
243
+ if (processCallback) {
244
+ processCallback(card);
245
+ }
246
+ cards.push(card);
247
+ }
248
+ total = page.totalItems;
249
+ if (!page.hasNext) break;
250
+ pageNumber++;
251
+ }
252
+ return { cards, total };
253
+ }
254
+ async printAllCards() {
255
+ const cards = await this.getAllMCardsRaw();
256
+ cards.forEach((card) => {
257
+ console.log(`Hash: ${card.hash}`);
258
+ try {
259
+ const text = new TextDecoder().decode(card.content);
260
+ const preview = text.slice(0, 100).replace(/\n/g, " ");
261
+ console.log(`Content: ${preview}${text.length > 100 ? "..." : ""}`);
262
+ } catch {
263
+ console.log(`Content (binary): ${card.content.length} bytes`);
264
+ }
265
+ console.log("---");
266
+ });
267
+ }
268
+ // =========== Handle Management Operations ===========
269
+ /**
270
+ * List all registered handles with their current hashes.
271
+ */
272
+ async getAllHandles() {
273
+ return this.engine.getAllHandles();
274
+ }
275
+ /**
276
+ * Remove a handle and all its history entries.
277
+ * Does NOT delete the underlying card(s).
278
+ */
279
+ async removeHandle(handle) {
280
+ return this.engine.removeHandle(handle);
281
+ }
282
+ /**
283
+ * Rename a handle atomically: updates handle registry and all history entries.
284
+ */
285
+ async renameHandle(oldHandle, newHandle) {
286
+ return this.engine.renameHandle(oldHandle, newHandle);
287
+ }
288
+ /**
289
+ * Delete a single history entry by handle + previousHash, stitching the chain.
290
+ */
291
+ async deleteHistoryEntry(handle, previousHash) {
292
+ return this.engine.deleteHistoryEntry(handle, previousHash);
293
+ }
294
+ };
295
+
296
+ export {
297
+ Maybe,
298
+ CardCollection
299
+ };
@@ -0,0 +1,74 @@
1
+ // src/storage/EngineRegistry.ts
2
+ var EngineType = /* @__PURE__ */ ((EngineType2) => {
3
+ EngineType2["INDEXED_DB"] = "indexeddb";
4
+ EngineType2["SQLITE_NODE"] = "sqlite-node";
5
+ EngineType2["SQLITE_WASM"] = "sqlite-wasm";
6
+ return EngineType2;
7
+ })(EngineType || {});
8
+ var ENGINE_INFO = {
9
+ ["indexeddb" /* INDEXED_DB */]: {
10
+ type: "indexeddb" /* INDEXED_DB */,
11
+ displayName: "IndexedDB",
12
+ environment: "browser",
13
+ package: null,
14
+ description: "Browser-native IndexedDB key-value store"
15
+ },
16
+ ["sqlite-node" /* SQLITE_NODE */]: {
17
+ type: "sqlite-node" /* SQLITE_NODE */,
18
+ displayName: "SQLite (Node.js)",
19
+ environment: "node",
20
+ package: "better-sqlite3",
21
+ description: "SQLite via native better-sqlite3 bindings"
22
+ },
23
+ ["sqlite-wasm" /* SQLITE_WASM */]: {
24
+ type: "sqlite-wasm" /* SQLITE_WASM */,
25
+ displayName: "SQLite (WASM)",
26
+ environment: "browser",
27
+ package: "sql.js",
28
+ description: "SQLite via sql.js WebAssembly"
29
+ }
30
+ };
31
+ async function createEngine(type, options = {}) {
32
+ switch (type) {
33
+ case "indexeddb" /* INDEXED_DB */: {
34
+ const { IndexedDBEngine } = await import("./IndexedDBEngine-RD4447IS.js");
35
+ const engine = new IndexedDBEngine();
36
+ await engine.init();
37
+ return engine;
38
+ }
39
+ case "sqlite-node" /* SQLITE_NODE */: {
40
+ const { SqliteNodeEngine } = await import("./storage/SqliteNodeEngine.js");
41
+ return SqliteNodeEngine.create(options.dbPath || ":memory:");
42
+ }
43
+ case "sqlite-wasm" /* SQLITE_WASM */: {
44
+ const { SqliteWasmEngine } = await import("./storage/SqliteWasmEngine.js");
45
+ const engine = new SqliteWasmEngine();
46
+ await engine.init(options.wasmUrl, options.existingData);
47
+ return engine;
48
+ }
49
+ default: {
50
+ const validTypes = Object.values(EngineType).join(", ");
51
+ throw new Error(
52
+ `Unknown engine type: "${type}". Valid types: ${validTypes}`
53
+ );
54
+ }
55
+ }
56
+ }
57
+ function getAvailableEngines() {
58
+ return Object.values(EngineType);
59
+ }
60
+ function getEngineInfo(type) {
61
+ return ENGINE_INFO[type];
62
+ }
63
+ function getEnginesByEnvironment(env) {
64
+ return Object.values(ENGINE_INFO).filter((info) => info.environment === env);
65
+ }
66
+
67
+ export {
68
+ EngineType,
69
+ ENGINE_INFO,
70
+ createEngine,
71
+ getAvailableEngines,
72
+ getEngineInfo,
73
+ getEnginesByEnvironment
74
+ };
@@ -0,0 +1,112 @@
1
+ import {
2
+ AbstractSqlEngine,
3
+ CORE_SCHEMAS
4
+ } from "./chunk-GIKMCG4D.js";
5
+ import {
6
+ MCard
7
+ } from "./chunk-GGQCF7ZK.js";
8
+ import {
9
+ DEFAULT_SQLJS_WASM_URL
10
+ } from "./chunk-ETJWXHKZ.js";
11
+
12
+ // src/storage/engines/SqliteWasmEngine.ts
13
+ var SqliteWasmEngine = class extends AbstractSqlEngine {
14
+ db = null;
15
+ SQL = null;
16
+ /**
17
+ * Initialize the database
18
+ * @param wasmUrl URL to sql-wasm.wasm file (optional, defaults to CDN)
19
+ * @param existingData Optional existing database as Uint8Array
20
+ */
21
+ async init(wasmUrl, existingData) {
22
+ const initSqlJs = (await import("sql.js")).default;
23
+ const SQL = await initSqlJs({
24
+ locateFile: (file) => wasmUrl || `${DEFAULT_SQLJS_WASM_URL}${file}`
25
+ });
26
+ this.SQL = SQL;
27
+ this.db = existingData ? new SQL.Database(existingData) : new SQL.Database();
28
+ this.db.run(CORE_SCHEMAS.card);
29
+ this.db.run(CORE_SCHEMAS.handleRegistry);
30
+ this.db.run(CORE_SCHEMAS.handleHistory);
31
+ this.db.run(CORE_SCHEMAS.handleIndex);
32
+ }
33
+ ensureDb() {
34
+ if (!this.db) throw new Error("Database not initialized. Call init() first.");
35
+ return this.db;
36
+ }
37
+ // ======================================================================
38
+ // AbstractSqlEngine primitives
39
+ // ======================================================================
40
+ async queryRows(sql, ...params) {
41
+ const db = this.ensureDb();
42
+ const stmt = db.prepare(sql);
43
+ if (params.length > 0) stmt.bind(params);
44
+ const results = [];
45
+ while (stmt.step()) {
46
+ const row = stmt.getAsObject();
47
+ results.push(row);
48
+ }
49
+ stmt.free();
50
+ return results;
51
+ }
52
+ async execSql(sql, ...params) {
53
+ const db = this.ensureDb();
54
+ if (params.length === 0) {
55
+ db.run(sql);
56
+ } else {
57
+ db.run(sql, params);
58
+ }
59
+ return 0;
60
+ }
61
+ // ======================================================================
62
+ // Row → MCard conversion (sql.js returns Uint8Array for BLOBs)
63
+ // ======================================================================
64
+ rowToCard(row) {
65
+ const rawContent = row.content;
66
+ const content = rawContent instanceof Uint8Array ? rawContent : typeof rawContent === "string" ? new TextEncoder().encode(rawContent) : new Uint8Array(0);
67
+ return MCard.fromData(content, String(row.hash), String(row.g_time));
68
+ }
69
+ // ======================================================================
70
+ // sql.js-specific helpers
71
+ // ======================================================================
72
+ /**
73
+ * Export database as Uint8Array (for persistence)
74
+ */
75
+ export() {
76
+ return this.ensureDb().export();
77
+ }
78
+ /**
79
+ * Get raw sql.js Database for use with VectorStore adapter.
80
+ */
81
+ getRawDb() {
82
+ return this.ensureDb();
83
+ }
84
+ // =========== pruneHandleHistory override (needs count before delete) ===========
85
+ async pruneHandleHistory(handle, options = {}) {
86
+ const { validateHandle } = await import("./Handle-3N4QOA3U.js");
87
+ const db = this.ensureDb();
88
+ const normalized = validateHandle(handle);
89
+ if (options.deleteAll) {
90
+ const stmt = db.prepare("SELECT COUNT(*) FROM handle_history WHERE handle = ?");
91
+ stmt.bind([normalized]);
92
+ stmt.step();
93
+ const count = stmt.get()[0];
94
+ stmt.free();
95
+ db.run("DELETE FROM handle_history WHERE handle = ?", [normalized]);
96
+ return count;
97
+ } else if (options.olderThan) {
98
+ const stmt = db.prepare("SELECT COUNT(*) FROM handle_history WHERE handle = ? AND changed_at < ?");
99
+ stmt.bind([normalized, options.olderThan]);
100
+ stmt.step();
101
+ const count = stmt.get()[0];
102
+ stmt.free();
103
+ db.run("DELETE FROM handle_history WHERE handle = ? AND changed_at < ?", [normalized, options.olderThan]);
104
+ return count;
105
+ }
106
+ return 0;
107
+ }
108
+ };
109
+
110
+ export {
111
+ SqliteWasmEngine
112
+ };