mcard-js 2.1.49 → 2.1.51

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 (109) hide show
  1. package/dist/CardCollection-EMSBVZP3.js +10 -0
  2. package/dist/CardCollection-KQWR4PCV.js +10 -0
  3. package/dist/CardCollection-ORGE2XBG.js +10 -0
  4. package/dist/EngineRegistry-ABZXHZWO.js +17 -0
  5. package/dist/EngineRegistry-EIOT4MUZ.js +17 -0
  6. package/dist/EngineRegistry-IQ6EVO72.js +17 -0
  7. package/dist/EngineRegistry-PHRFXEOE.js +17 -0
  8. package/dist/IndexedDBEngine-EWA3SLAO.js +12 -0
  9. package/dist/IndexedDBEngine-FXAD42F3.js +12 -0
  10. package/dist/IndexedDBEngine-RD4447IS.js +12 -0
  11. package/dist/LLMRuntime-ARUWOX52.js +17 -0
  12. package/dist/LLMRuntime-C3XCO7WF.js +17 -0
  13. package/dist/LLMRuntime-CQ7X43QR.js +17 -0
  14. package/dist/LLMRuntime-PD45COKE.js +17 -0
  15. package/dist/LLMRuntime-QOUMLT33.js +17 -0
  16. package/dist/LLMRuntime-SZNLTHD7.js +17 -0
  17. package/dist/LLMRuntime-TVJGK2BG.js +17 -0
  18. package/dist/LambdaRuntime-25GMEJCU.js +19 -0
  19. package/dist/LambdaRuntime-7KQUMHPI.js +19 -0
  20. package/dist/LambdaRuntime-DRT7ODPC.js +19 -0
  21. package/dist/LambdaRuntime-HSREEYQG.js +19 -0
  22. package/dist/LambdaRuntime-IH7NVG6Z.js +19 -0
  23. package/dist/LambdaRuntime-MPG27FM2.js +19 -0
  24. package/dist/LambdaRuntime-ODSWIMNM.js +19 -0
  25. package/dist/LambdaRuntime-PHGRZYAW.js +19 -0
  26. package/dist/LambdaRuntime-QOEYR37L.js +19 -0
  27. package/dist/LambdaRuntime-RT33TFN2.js +19 -0
  28. package/dist/LambdaRuntime-W6TQBP5O.js +19 -0
  29. package/dist/Loader-35WSUC53.js +14 -0
  30. package/dist/Loader-STS3G4OQ.js +16 -0
  31. package/dist/Loader-W22AEM6F.js +12 -0
  32. package/dist/Loader-YBPWP43S.js +12 -0
  33. package/dist/Loader-ZYSS7B4D.js +12 -0
  34. package/dist/NetworkRuntime-KR2QITXV.js +987 -0
  35. package/dist/NetworkRuntime-S6V2CMZV.js +1575 -0
  36. package/dist/OllamaProvider-2ANW6EB2.js +9 -0
  37. package/dist/OllamaProvider-5QFJKYAC.js +9 -0
  38. package/dist/OllamaProvider-6QXJGR7V.js +9 -0
  39. package/dist/OllamaProvider-ABEEFX7M.js +9 -0
  40. package/dist/OllamaProvider-Z2CGY5LY.js +9 -0
  41. package/dist/VCard-225X42W7.js +25 -0
  42. package/dist/chunk-2APJYBH4.js +368 -0
  43. package/dist/chunk-4DFTWDRB.js +497 -0
  44. package/dist/chunk-4PBRTFSY.js +112 -0
  45. package/dist/chunk-4T3H25AP.js +299 -0
  46. package/dist/chunk-5DFXPIRL.js +42 -0
  47. package/dist/chunk-5HRZV4R3.js +217 -0
  48. package/dist/chunk-6ZRJXVJ3.js +529 -0
  49. package/dist/chunk-7N7JYGN2.js +364 -0
  50. package/dist/chunk-7QTJUGYQ.js +74 -0
  51. package/dist/chunk-7TXIPJI2.js +2360 -0
  52. package/dist/chunk-BFJUD527.js +2369 -0
  53. package/dist/chunk-CHXIVTQV.js +364 -0
  54. package/dist/chunk-DM2ABCA4.js +497 -0
  55. package/dist/chunk-DTPHGTBQ.js +275 -0
  56. package/dist/chunk-EDAJ5FO6.js +405 -0
  57. package/dist/chunk-ETJWXHKZ.js +246 -0
  58. package/dist/chunk-FLYGNPUC.js +2369 -0
  59. package/dist/chunk-FSDRDWOP.js +34 -0
  60. package/dist/chunk-GIKMCG4D.js +497 -0
  61. package/dist/chunk-IJKS3LGK.js +428 -0
  62. package/dist/chunk-JUQ2VQZA.js +428 -0
  63. package/dist/chunk-JVW4J7BY.js +2369 -0
  64. package/dist/chunk-JWTRVEC3.js +2369 -0
  65. package/dist/chunk-KJM4C65U.js +299 -0
  66. package/dist/chunk-KMC566CN.js +591 -0
  67. package/dist/chunk-KMNP6DBL.js +455 -0
  68. package/dist/chunk-LVU7O5IY.js +597 -0
  69. package/dist/chunk-M4C6RWLA.js +373 -0
  70. package/dist/chunk-NAAAKSEO.js +541 -0
  71. package/dist/chunk-NKIXLPHL.js +373 -0
  72. package/dist/chunk-NOEDMK7I.js +428 -0
  73. package/dist/chunk-NOPYSBOQ.js +2360 -0
  74. package/dist/chunk-P4G42QCY.js +2369 -0
  75. package/dist/chunk-PKLONZCF.js +253 -0
  76. package/dist/chunk-PNGECWPN.js +597 -0
  77. package/dist/chunk-PYP6T64W.js +217 -0
  78. package/dist/chunk-QFT3COE2.js +217 -0
  79. package/dist/chunk-QFZFXMNX.js +275 -0
  80. package/dist/chunk-QZGRQRJP.js +2369 -0
  81. package/dist/chunk-R3XRBAM7.js +253 -0
  82. package/dist/chunk-RYP66UMH.js +74 -0
  83. package/dist/chunk-RZIZYRLF.js +112 -0
  84. package/dist/chunk-T43V44RS.js +2369 -0
  85. package/dist/chunk-UCNVX5BZ.js +74 -0
  86. package/dist/chunk-UDF7HS4V.js +368 -0
  87. package/dist/chunk-VJPXJVEH.js +299 -0
  88. package/dist/chunk-VW3KBDK5.js +74 -0
  89. package/dist/chunk-X72XIYSN.js +364 -0
  90. package/dist/chunk-XETU7TV4.js +112 -0
  91. package/dist/chunk-Y4BT6LHA.js +368 -0
  92. package/dist/chunk-YQGB6BIA.js +2369 -0
  93. package/dist/chunk-ZEQPO3XV.js +217 -0
  94. package/dist/chunk-ZKRKWXEQ.js +2369 -0
  95. package/dist/chunk-ZMK2HTZ5.js +275 -0
  96. package/dist/constants-CLB7B6MN.js +101 -0
  97. package/dist/constants-O343SMHL.js +103 -0
  98. package/dist/constants-YPGDEX5X.js +103 -0
  99. package/dist/index.browser.cjs +11 -5
  100. package/dist/index.browser.js +12 -12
  101. package/dist/index.cjs +2358 -1896
  102. package/dist/index.d.cts +934 -776
  103. package/dist/index.d.ts +934 -776
  104. package/dist/index.js +1353 -1271
  105. package/dist/storage/SqliteNodeEngine.cjs +12 -6
  106. package/dist/storage/SqliteNodeEngine.js +4 -4
  107. package/dist/storage/SqliteWasmEngine.cjs +11 -5
  108. package/dist/storage/SqliteWasmEngine.js +4 -4
  109. package/package.json +5 -3
@@ -0,0 +1,217 @@
1
+ import {
2
+ AbstractSqlEngine,
3
+ initCoreSchemas
4
+ } from "./chunk-DM2ABCA4.js";
5
+ import {
6
+ createPage
7
+ } from "./chunk-3EIBJPNF.js";
8
+ import {
9
+ MCard
10
+ } from "./chunk-GGQCF7ZK.js";
11
+ import {
12
+ Handle_exports,
13
+ init_Handle
14
+ } from "./chunk-ADV52544.js";
15
+ import {
16
+ DEFAULT_PAGE_SIZE,
17
+ SQLITE_BUSY_TIMEOUT_MS
18
+ } from "./chunk-R3XRBAM7.js";
19
+ import {
20
+ __toCommonJS
21
+ } from "./chunk-PNKVD2UK.js";
22
+
23
+ // src/storage/engines/SqliteNodeEngine.ts
24
+ var SqliteNodeEngine = class _SqliteNodeEngine extends AbstractSqlEngine {
25
+ db;
26
+ dbPath;
27
+ /**
28
+ * Convert a database row into an MCard instance.
29
+ */
30
+ rowToCard(row) {
31
+ const rawContent = row.content;
32
+ const content = rawContent instanceof Buffer ? new Uint8Array(rawContent) : new Uint8Array(rawContent);
33
+ return MCard.fromData(content, String(row.hash), String(row.g_time));
34
+ }
35
+ /**
36
+ * Create a new SqliteNodeEngine via async factory.
37
+ * @param dbPath Path to database file, or ':memory:' for in-memory database
38
+ */
39
+ static async create(dbPath = ":memory:") {
40
+ const engine = new _SqliteNodeEngine(dbPath);
41
+ await engine.init();
42
+ return engine;
43
+ }
44
+ constructor(dbPath) {
45
+ super();
46
+ this.dbPath = dbPath;
47
+ }
48
+ async init() {
49
+ try {
50
+ const mod = await import("better-sqlite3");
51
+ const Database = mod.default || mod;
52
+ this.db = new Database(this.dbPath);
53
+ this.setupDatabase();
54
+ } catch (e) {
55
+ console.error(`SqliteNodeEngine: Failed to load better-sqlite3: ${e.message}`);
56
+ throw e;
57
+ }
58
+ }
59
+ /**
60
+ * Initialize database schema
61
+ */
62
+ setupDatabase() {
63
+ this.db.pragma("journal_mode = WAL");
64
+ this.db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);
65
+ this.db.pragma("synchronous = NORMAL");
66
+ initCoreSchemas(this.db);
67
+ }
68
+ // ======================================================================
69
+ // AbstractSqlEngine primitives
70
+ // ======================================================================
71
+ async queryRows(sql, ...params) {
72
+ const stmt = this.db.prepare(sql);
73
+ return stmt.all(...params);
74
+ }
75
+ async execSql(sql, ...params) {
76
+ if (params.length === 0) {
77
+ this.db.exec(sql);
78
+ return 0;
79
+ }
80
+ const stmt = this.db.prepare(sql);
81
+ const result = stmt.run(...params);
82
+ return result.changes;
83
+ }
84
+ /**
85
+ * Close the database connection
86
+ */
87
+ close() {
88
+ this.db.close();
89
+ }
90
+ /**
91
+ * Get the database path
92
+ */
93
+ getDbPath() {
94
+ return this.dbPath;
95
+ }
96
+ // =========== Card Operations (overrides to use Buffer.from for better-sqlite3) ===========
97
+ async add(card) {
98
+ const stmt = this.db.prepare(
99
+ "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)"
100
+ );
101
+ stmt.run(card.hash, Buffer.from(card.content), card.g_time);
102
+ return card.hash;
103
+ }
104
+ // =========== Sync card operations (for performance-critical callers) ===========
105
+ addSync(card) {
106
+ const stmt = this.db.prepare(
107
+ "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)"
108
+ );
109
+ stmt.run(card.hash, Buffer.from(card.content), card.g_time);
110
+ return card.hash;
111
+ }
112
+ getSync(hash) {
113
+ const stmt = this.db.prepare("SELECT hash, content, g_time FROM card WHERE hash = ?");
114
+ const row = stmt.get(hash);
115
+ if (!row) return null;
116
+ return this.rowToCard(row);
117
+ }
118
+ deleteSync(hash) {
119
+ const stmt = this.db.prepare("DELETE FROM card WHERE hash = ?");
120
+ const result = stmt.run(hash);
121
+ return result.changes > 0;
122
+ }
123
+ getPageSync(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
124
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
125
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
126
+ const totalItems = this.countSync();
127
+ const offset = (pageNumber - 1) * pageSize;
128
+ const stmt = this.db.prepare(
129
+ "SELECT hash, content, g_time FROM card ORDER BY g_time DESC LIMIT ? OFFSET ?"
130
+ );
131
+ const rows = stmt.all(pageSize, offset);
132
+ const items = rows.map((row) => this.rowToCard(row));
133
+ return createPage(items, totalItems, pageNumber, pageSize);
134
+ }
135
+ countSync() {
136
+ const stmt = this.db.prepare("SELECT COUNT(*) as cnt FROM card");
137
+ const row = stmt.get();
138
+ return row.cnt;
139
+ }
140
+ clearSync() {
141
+ this.db.exec("DELETE FROM handle_history");
142
+ this.db.exec("DELETE FROM handle_registry");
143
+ this.db.exec("DELETE FROM card");
144
+ }
145
+ // =========== Additional sync search operations ===========
146
+ searchByString(searchString, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
147
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
148
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
149
+ const pattern = `%${searchString}%`;
150
+ const offset = (pageNumber - 1) * pageSize;
151
+ const countStmt = this.db.prepare(`
152
+ SELECT COUNT(*) as cnt FROM card
153
+ WHERE hash LIKE ? OR g_time LIKE ? OR CAST(content AS TEXT) LIKE ?
154
+ `);
155
+ const countRow = countStmt.get(pattern, pattern, pattern);
156
+ const totalItems = countRow.cnt;
157
+ const stmt = this.db.prepare(`
158
+ SELECT hash, content, g_time FROM card
159
+ WHERE hash LIKE ? OR g_time LIKE ? OR CAST(content AS TEXT) LIKE ?
160
+ ORDER BY g_time DESC LIMIT ? OFFSET ?
161
+ `);
162
+ const rows = stmt.all(pattern, pattern, pattern, pageSize, offset);
163
+ const items = rows.map((row) => this.rowToCard(row));
164
+ return createPage(items, totalItems, pageNumber, pageSize);
165
+ }
166
+ searchByContent(searchPattern, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
167
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
168
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
169
+ if (!searchPattern || typeof searchPattern === "string" && searchPattern.length === 0) {
170
+ throw new Error("Search pattern cannot be empty");
171
+ }
172
+ const searchBytes = typeof searchPattern === "string" ? Buffer.from(searchPattern, "utf-8") : Buffer.from(searchPattern);
173
+ const offset = (pageNumber - 1) * pageSize;
174
+ const countStmt = this.db.prepare("SELECT COUNT(*) as cnt FROM card WHERE INSTR(content, ?) > 0");
175
+ const countRow = countStmt.get(searchBytes);
176
+ const totalItems = countRow.cnt;
177
+ const stmt = this.db.prepare(`
178
+ SELECT hash, content, g_time FROM card
179
+ WHERE INSTR(content, ?) > 0
180
+ ORDER BY g_time DESC LIMIT ? OFFSET ?
181
+ `);
182
+ const rows = stmt.all(searchBytes, pageSize, offset);
183
+ const items = rows.map((row) => this.rowToCard(row));
184
+ return createPage(items, totalItems, pageNumber, pageSize);
185
+ }
186
+ getAllCards() {
187
+ const stmt = this.db.prepare("SELECT hash, content, g_time FROM card ORDER BY g_time DESC");
188
+ const rows = stmt.all();
189
+ const items = rows.map((row) => this.rowToCard(row));
190
+ return createPage(items, items.length, 1, items.length || 1);
191
+ }
192
+ // =========== Unique sync method (not in AbstractSqlEngine) ===========
193
+ deleteHistoryEntrySync(handle, previousHash) {
194
+ const { validateHandle } = (init_Handle(), __toCommonJS(Handle_exports));
195
+ const normalized = validateHandle(handle);
196
+ const performStitch = this.db.transaction(() => {
197
+ const rOut = this.db.prepare(
198
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND previous_hash = ? ORDER BY id DESC LIMIT 1"
199
+ ).get(normalized, previousHash);
200
+ if (!rOut) return;
201
+ const rIn = this.db.prepare(
202
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND id < ? ORDER BY id DESC LIMIT 1"
203
+ ).get(normalized, rOut.id);
204
+ if (rIn) {
205
+ this.db.prepare("UPDATE handle_history SET previous_hash = ? WHERE id = ?").run(rIn.previous_hash, rOut.id);
206
+ this.db.prepare("DELETE FROM handle_history WHERE id = ?").run(rIn.id);
207
+ } else {
208
+ this.db.prepare("DELETE FROM handle_history WHERE id = ?").run(rOut.id);
209
+ }
210
+ });
211
+ performStitch();
212
+ }
213
+ };
214
+
215
+ export {
216
+ SqliteNodeEngine
217
+ };
@@ -0,0 +1,217 @@
1
+ import {
2
+ AbstractSqlEngine,
3
+ initCoreSchemas
4
+ } from "./chunk-DM2ABCA4.js";
5
+ import {
6
+ createPage
7
+ } from "./chunk-3EIBJPNF.js";
8
+ import {
9
+ MCard
10
+ } from "./chunk-GGQCF7ZK.js";
11
+ import {
12
+ Handle_exports,
13
+ init_Handle
14
+ } from "./chunk-ADV52544.js";
15
+ import {
16
+ DEFAULT_PAGE_SIZE,
17
+ SQLITE_BUSY_TIMEOUT_MS
18
+ } from "./chunk-R3XRBAM7.js";
19
+ import {
20
+ __toCommonJS
21
+ } from "./chunk-PNKVD2UK.js";
22
+
23
+ // src/storage/engines/SqliteNodeEngine.ts
24
+ var SqliteNodeEngine = class _SqliteNodeEngine extends AbstractSqlEngine {
25
+ db;
26
+ dbPath;
27
+ /**
28
+ * Convert a database row into an MCard instance.
29
+ */
30
+ rowToCard(row) {
31
+ const rawContent = row.content;
32
+ const content = rawContent instanceof Buffer ? new Uint8Array(rawContent) : new Uint8Array(rawContent);
33
+ return MCard.fromData(content, String(row.hash), String(row.g_time));
34
+ }
35
+ /**
36
+ * Create a new SqliteNodeEngine via async factory.
37
+ * @param dbPath Path to database file, or ':memory:' for in-memory database
38
+ */
39
+ static async create(dbPath = ":memory:") {
40
+ const engine = new _SqliteNodeEngine(dbPath);
41
+ await engine.init();
42
+ return engine;
43
+ }
44
+ constructor(dbPath) {
45
+ super();
46
+ this.dbPath = dbPath;
47
+ }
48
+ async init() {
49
+ try {
50
+ const mod = await import("better-sqlite3");
51
+ const Database = mod.default || mod;
52
+ this.db = new Database(this.dbPath);
53
+ this.setupDatabase();
54
+ } catch (e) {
55
+ console.error(`SqliteNodeEngine: Failed to load better-sqlite3: ${e.message}`);
56
+ throw e;
57
+ }
58
+ }
59
+ /**
60
+ * Initialize database schema
61
+ */
62
+ setupDatabase() {
63
+ this.db.pragma("journal_mode = DELETE");
64
+ this.db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);
65
+ this.db.pragma("synchronous = NORMAL");
66
+ initCoreSchemas(this.db);
67
+ }
68
+ // ======================================================================
69
+ // AbstractSqlEngine primitives
70
+ // ======================================================================
71
+ async queryRows(sql, ...params) {
72
+ const stmt = this.db.prepare(sql);
73
+ return stmt.all(...params);
74
+ }
75
+ async execSql(sql, ...params) {
76
+ if (params.length === 0) {
77
+ this.db.exec(sql);
78
+ return 0;
79
+ }
80
+ const stmt = this.db.prepare(sql);
81
+ const result = stmt.run(...params);
82
+ return result.changes;
83
+ }
84
+ /**
85
+ * Close the database connection
86
+ */
87
+ close() {
88
+ this.db.close();
89
+ }
90
+ /**
91
+ * Get the database path
92
+ */
93
+ getDbPath() {
94
+ return this.dbPath;
95
+ }
96
+ // =========== Card Operations (overrides to use Buffer.from for better-sqlite3) ===========
97
+ async add(card) {
98
+ const stmt = this.db.prepare(
99
+ "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)"
100
+ );
101
+ stmt.run(card.hash, Buffer.from(card.content), card.g_time);
102
+ return card.hash;
103
+ }
104
+ // =========== Sync card operations (for performance-critical callers) ===========
105
+ addSync(card) {
106
+ const stmt = this.db.prepare(
107
+ "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)"
108
+ );
109
+ stmt.run(card.hash, Buffer.from(card.content), card.g_time);
110
+ return card.hash;
111
+ }
112
+ getSync(hash) {
113
+ const stmt = this.db.prepare("SELECT hash, content, g_time FROM card WHERE hash = ?");
114
+ const row = stmt.get(hash);
115
+ if (!row) return null;
116
+ return this.rowToCard(row);
117
+ }
118
+ deleteSync(hash) {
119
+ const stmt = this.db.prepare("DELETE FROM card WHERE hash = ?");
120
+ const result = stmt.run(hash);
121
+ return result.changes > 0;
122
+ }
123
+ getPageSync(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
124
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
125
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
126
+ const totalItems = this.countSync();
127
+ const offset = (pageNumber - 1) * pageSize;
128
+ const stmt = this.db.prepare(
129
+ "SELECT hash, content, g_time FROM card ORDER BY g_time DESC LIMIT ? OFFSET ?"
130
+ );
131
+ const rows = stmt.all(pageSize, offset);
132
+ const items = rows.map((row) => this.rowToCard(row));
133
+ return createPage(items, totalItems, pageNumber, pageSize);
134
+ }
135
+ countSync() {
136
+ const stmt = this.db.prepare("SELECT COUNT(*) as cnt FROM card");
137
+ const row = stmt.get();
138
+ return row.cnt;
139
+ }
140
+ clearSync() {
141
+ this.db.exec("DELETE FROM handle_history");
142
+ this.db.exec("DELETE FROM handle_registry");
143
+ this.db.exec("DELETE FROM card");
144
+ }
145
+ // =========== Additional sync search operations ===========
146
+ searchByString(searchString, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
147
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
148
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
149
+ const pattern = `%${searchString}%`;
150
+ const offset = (pageNumber - 1) * pageSize;
151
+ const countStmt = this.db.prepare(`
152
+ SELECT COUNT(*) as cnt FROM card
153
+ WHERE hash LIKE ? OR g_time LIKE ? OR CAST(content AS TEXT) LIKE ?
154
+ `);
155
+ const countRow = countStmt.get(pattern, pattern, pattern);
156
+ const totalItems = countRow.cnt;
157
+ const stmt = this.db.prepare(`
158
+ SELECT hash, content, g_time FROM card
159
+ WHERE hash LIKE ? OR g_time LIKE ? OR CAST(content AS TEXT) LIKE ?
160
+ ORDER BY g_time DESC LIMIT ? OFFSET ?
161
+ `);
162
+ const rows = stmt.all(pattern, pattern, pattern, pageSize, offset);
163
+ const items = rows.map((row) => this.rowToCard(row));
164
+ return createPage(items, totalItems, pageNumber, pageSize);
165
+ }
166
+ searchByContent(searchPattern, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
167
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
168
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
169
+ if (!searchPattern || typeof searchPattern === "string" && searchPattern.length === 0) {
170
+ throw new Error("Search pattern cannot be empty");
171
+ }
172
+ const searchBytes = typeof searchPattern === "string" ? Buffer.from(searchPattern, "utf-8") : Buffer.from(searchPattern);
173
+ const offset = (pageNumber - 1) * pageSize;
174
+ const countStmt = this.db.prepare("SELECT COUNT(*) as cnt FROM card WHERE INSTR(content, ?) > 0");
175
+ const countRow = countStmt.get(searchBytes);
176
+ const totalItems = countRow.cnt;
177
+ const stmt = this.db.prepare(`
178
+ SELECT hash, content, g_time FROM card
179
+ WHERE INSTR(content, ?) > 0
180
+ ORDER BY g_time DESC LIMIT ? OFFSET ?
181
+ `);
182
+ const rows = stmt.all(searchBytes, pageSize, offset);
183
+ const items = rows.map((row) => this.rowToCard(row));
184
+ return createPage(items, totalItems, pageNumber, pageSize);
185
+ }
186
+ getAllCards() {
187
+ const stmt = this.db.prepare("SELECT hash, content, g_time FROM card ORDER BY g_time DESC");
188
+ const rows = stmt.all();
189
+ const items = rows.map((row) => this.rowToCard(row));
190
+ return createPage(items, items.length, 1, items.length || 1);
191
+ }
192
+ // =========== Unique sync method (not in AbstractSqlEngine) ===========
193
+ deleteHistoryEntrySync(handle, previousHash) {
194
+ const { validateHandle } = (init_Handle(), __toCommonJS(Handle_exports));
195
+ const normalized = validateHandle(handle);
196
+ const performStitch = this.db.transaction(() => {
197
+ const rOut = this.db.prepare(
198
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND previous_hash = ? ORDER BY id DESC LIMIT 1"
199
+ ).get(normalized, previousHash);
200
+ if (!rOut) return;
201
+ const rIn = this.db.prepare(
202
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND id < ? ORDER BY id DESC LIMIT 1"
203
+ ).get(normalized, rOut.id);
204
+ if (rIn) {
205
+ this.db.prepare("UPDATE handle_history SET previous_hash = ? WHERE id = ?").run(rIn.previous_hash, rOut.id);
206
+ this.db.prepare("DELETE FROM handle_history WHERE id = ?").run(rIn.id);
207
+ } else {
208
+ this.db.prepare("DELETE FROM handle_history WHERE id = ?").run(rOut.id);
209
+ }
210
+ });
211
+ performStitch();
212
+ }
213
+ };
214
+
215
+ export {
216
+ SqliteNodeEngine
217
+ };
@@ -0,0 +1,275 @@
1
+ import {
2
+ createPage
3
+ } from "./chunk-3EIBJPNF.js";
4
+ import {
5
+ MCard
6
+ } from "./chunk-GGQCF7ZK.js";
7
+ import {
8
+ init_Handle,
9
+ validateHandle
10
+ } from "./chunk-ADV52544.js";
11
+ import {
12
+ DEFAULT_PAGE_SIZE,
13
+ INDEXEDDB_DEFAULT_DB_NAME,
14
+ INDEXEDDB_DEFAULT_DB_VERSION
15
+ } from "./chunk-R3XRBAM7.js";
16
+
17
+ // src/storage/engines/IndexedDBEngine.ts
18
+ import { openDB } from "idb";
19
+ init_Handle();
20
+ var IndexedDBEngine = class {
21
+ db = null;
22
+ dbName;
23
+ constructor(dbName = INDEXEDDB_DEFAULT_DB_NAME) {
24
+ this.dbName = dbName;
25
+ }
26
+ /**
27
+ * Initialize the database connection
28
+ */
29
+ async init() {
30
+ this.db = await openDB(this.dbName, INDEXEDDB_DEFAULT_DB_VERSION, {
31
+ upgrade(db) {
32
+ if (!db.objectStoreNames.contains("cards")) {
33
+ db.createObjectStore("cards", { keyPath: "hash" });
34
+ }
35
+ if (!db.objectStoreNames.contains("handles")) {
36
+ const handleStore = db.createObjectStore("handles", { keyPath: "handle" });
37
+ handleStore.createIndex("by-hash", "currentHash");
38
+ }
39
+ if (!db.objectStoreNames.contains("handleHistory")) {
40
+ const historyStore = db.createObjectStore("handleHistory", {
41
+ keyPath: "id",
42
+ autoIncrement: true
43
+ });
44
+ historyStore.createIndex("by-handle", "handle");
45
+ }
46
+ }
47
+ });
48
+ }
49
+ ensureDb() {
50
+ if (!this.db) {
51
+ throw new Error("Database not initialized. Call init() first.");
52
+ }
53
+ return this.db;
54
+ }
55
+ // =========== Card Operations ===========
56
+ async add(card) {
57
+ const db = this.ensureDb();
58
+ await db.put("cards", {
59
+ hash: card.hash,
60
+ content: card.content,
61
+ g_time: card.g_time
62
+ });
63
+ return card.hash;
64
+ }
65
+ async get(hash) {
66
+ const db = this.ensureDb();
67
+ const record = await db.get("cards", hash);
68
+ if (!record) return null;
69
+ return MCard.fromData(record.content, record.hash, record.g_time);
70
+ }
71
+ async delete(hash) {
72
+ const db = this.ensureDb();
73
+ await db.delete("cards", hash);
74
+ }
75
+ async getPage(pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
76
+ const db = this.ensureDb();
77
+ const totalItems = await db.count("cards");
78
+ const allCards = await db.getAll("cards");
79
+ const start = (pageNumber - 1) * pageSize;
80
+ const pageRecords = allCards.slice(start, start + pageSize);
81
+ const items = pageRecords.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
82
+ return createPage(items, totalItems, pageNumber, pageSize);
83
+ }
84
+ async count() {
85
+ const db = this.ensureDb();
86
+ return db.count("cards");
87
+ }
88
+ async searchByHash(hashPrefix) {
89
+ const db = this.ensureDb();
90
+ const start = hashPrefix;
91
+ const end = hashPrefix + "\uFFFF";
92
+ const range = IDBKeyRange.bound(start, end);
93
+ const records = await db.getAll("cards", range);
94
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
95
+ }
96
+ async search(query, pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
97
+ const db = this.ensureDb();
98
+ const records = await db.getAll("cards");
99
+ const decoder = new TextDecoder();
100
+ const filtered = records.filter((r) => {
101
+ try {
102
+ const text = decoder.decode(r.content);
103
+ return text.includes(query);
104
+ } catch {
105
+ return false;
106
+ }
107
+ });
108
+ const totalItems = filtered.length;
109
+ const start = (pageNumber - 1) * pageSize;
110
+ const pageItems = filtered.slice(start, start + pageSize).map((r) => MCard.fromData(r.content, r.hash, r.g_time));
111
+ return createPage(pageItems, totalItems, pageNumber, pageSize);
112
+ }
113
+ async getAll() {
114
+ const db = this.ensureDb();
115
+ const records = await db.getAll("cards");
116
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
117
+ }
118
+ async clear() {
119
+ const db = this.ensureDb();
120
+ await db.clear("cards");
121
+ await db.clear("handles");
122
+ await db.clear("handleHistory");
123
+ }
124
+ // =========== Handle Operations ===========
125
+ async registerHandle(handle, hash) {
126
+ const db = this.ensureDb();
127
+ const normalized = validateHandle(handle);
128
+ const existing = await db.get("handles", normalized);
129
+ if (existing) {
130
+ throw new Error(`Handle '${handle}' already exists.`);
131
+ }
132
+ const now = (/* @__PURE__ */ new Date()).toISOString();
133
+ await db.put("handles", {
134
+ handle: normalized,
135
+ currentHash: hash,
136
+ createdAt: now,
137
+ updatedAt: now
138
+ });
139
+ }
140
+ async resolveHandle(handle) {
141
+ const db = this.ensureDb();
142
+ const normalized = validateHandle(handle);
143
+ const record = await db.get("handles", normalized);
144
+ return record?.currentHash ?? null;
145
+ }
146
+ async getByHandle(handle) {
147
+ const hash = await this.resolveHandle(handle);
148
+ if (!hash) return null;
149
+ return this.get(hash);
150
+ }
151
+ async updateHandle(handle, newHash) {
152
+ const db = this.ensureDb();
153
+ const normalized = validateHandle(handle);
154
+ const existing = await db.get("handles", normalized);
155
+ if (!existing) {
156
+ throw new Error(`Handle '${handle}' not found.`);
157
+ }
158
+ const previousHash = existing.currentHash;
159
+ const now = (/* @__PURE__ */ new Date()).toISOString();
160
+ await db.add("handleHistory", {
161
+ handle: normalized,
162
+ previousHash,
163
+ changedAt: now
164
+ });
165
+ await db.put("handles", {
166
+ ...existing,
167
+ currentHash: newHash,
168
+ updatedAt: now
169
+ });
170
+ return previousHash;
171
+ }
172
+ async getHandleHistory(handle) {
173
+ const db = this.ensureDb();
174
+ const normalized = validateHandle(handle);
175
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
176
+ return records.map((r) => ({ previousHash: r.previousHash, changedAt: r.changedAt })).reverse();
177
+ }
178
+ async pruneHandleHistory(handle, options = {}) {
179
+ const db = this.ensureDb();
180
+ const normalized = validateHandle(handle);
181
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
182
+ let toDelete;
183
+ if (options.deleteAll) {
184
+ toDelete = records;
185
+ } else if (options.olderThan) {
186
+ toDelete = records.filter((r) => r.changedAt < options.olderThan);
187
+ } else {
188
+ return 0;
189
+ }
190
+ const tx = db.transaction("handleHistory", "readwrite");
191
+ for (const record of toDelete) {
192
+ await tx.store.delete(record.id);
193
+ }
194
+ await tx.done;
195
+ return toDelete.length;
196
+ }
197
+ // =========== Handle Management Operations ===========
198
+ async getAllHandles() {
199
+ const db = this.ensureDb();
200
+ const records = await db.getAll("handles");
201
+ return records.map((r) => ({ handle: r.handle, hash: r.currentHash }));
202
+ }
203
+ async removeHandle(handle) {
204
+ const db = this.ensureDb();
205
+ const normalized = validateHandle(handle);
206
+ const keysToTry = normalized !== handle.trim() ? [normalized, handle.trim()] : [normalized];
207
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
208
+ const handleStore = tx.objectStore("handles");
209
+ const historyStore = tx.objectStore("handleHistory");
210
+ for (const key of keysToTry) {
211
+ await handleStore.delete(key);
212
+ }
213
+ const historyIndex = historyStore.index("by-handle");
214
+ for (const key of keysToTry) {
215
+ let cursor = await historyIndex.openCursor(key);
216
+ while (cursor) {
217
+ await cursor.delete();
218
+ cursor = await cursor.continue();
219
+ }
220
+ }
221
+ await tx.done;
222
+ }
223
+ async renameHandle(oldHandle, newHandle) {
224
+ const db = this.ensureDb();
225
+ const normalizedOld = validateHandle(oldHandle);
226
+ const normalizedNew = validateHandle(newHandle);
227
+ if (normalizedOld === normalizedNew) return;
228
+ const oldEntry = await db.get("handles", normalizedOld);
229
+ if (!oldEntry) throw new Error(`Handle '${oldHandle}' not found.`);
230
+ const newEntry = await db.get("handles", normalizedNew);
231
+ if (newEntry) throw new Error(`Handle '${newHandle}' already exists.`);
232
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
233
+ const handleStore = tx.objectStore("handles");
234
+ const historyStore = tx.objectStore("handleHistory");
235
+ const now = (/* @__PURE__ */ new Date()).toISOString();
236
+ await handleStore.put({
237
+ ...oldEntry,
238
+ handle: normalizedNew,
239
+ updatedAt: now
240
+ });
241
+ await handleStore.delete(normalizedOld);
242
+ const historyIndex = historyStore.index("by-handle");
243
+ let cursor = await historyIndex.openCursor(normalizedOld);
244
+ while (cursor) {
245
+ const record = cursor.value;
246
+ record.handle = normalizedNew;
247
+ await cursor.update(record);
248
+ cursor = await cursor.continue();
249
+ }
250
+ await tx.done;
251
+ }
252
+ async deleteHistoryEntry(handle, previousHash) {
253
+ const db = this.ensureDb();
254
+ const normalized = validateHandle(handle);
255
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
256
+ const entries = records.sort((a, b) => a.id - b.id);
257
+ const targetIdx = entries.findIndex((e) => e.previousHash === previousHash);
258
+ if (targetIdx === -1) return;
259
+ const target = entries[targetIdx];
260
+ const successor = entries[targetIdx + 1];
261
+ const tx = db.transaction("handleHistory", "readwrite");
262
+ const store = tx.objectStore("handleHistory");
263
+ if (successor && targetIdx > 0) {
264
+ const predecessor = entries[targetIdx - 1];
265
+ successor.previousHash = predecessor.previousHash;
266
+ await store.put(successor);
267
+ }
268
+ await store.delete(target.id);
269
+ await tx.done;
270
+ }
271
+ };
272
+
273
+ export {
274
+ IndexedDBEngine
275
+ };