mcard-js 2.1.39 → 2.1.41

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 (40) hide show
  1. package/dist/AbstractSqlEngine-BSfp8S_Y.d.cts +451 -0
  2. package/dist/AbstractSqlEngine-BSfp8S_Y.d.ts +451 -0
  3. package/dist/CardCollection-MXTUJV4J.js +9 -0
  4. package/dist/EventProducer-AWD6YMZR.js +47 -0
  5. package/dist/Handle-3N4QOA3U.js +13 -0
  6. package/dist/IndexedDBEngine-2G5KCISA.js +11 -0
  7. package/dist/LLMRuntime-LBWUJ7ON.js +16 -0
  8. package/dist/LambdaRuntime-B6D6IQKZ.js +18 -0
  9. package/dist/Loader-3LSJXJQG.js +11 -0
  10. package/dist/MCard-H56VOJLR.js +8 -0
  11. package/dist/NetworkRuntime-IAFHPQSX.js +1570 -0
  12. package/dist/OllamaProvider-QPX2JXL2.js +8 -0
  13. package/dist/chunk-2R4ESMZB.js +110 -0
  14. package/dist/chunk-3EIBJPNF.js +17 -0
  15. package/dist/chunk-3LPY36OG.js +355 -0
  16. package/dist/chunk-3MMMJ7NH.js +1068 -0
  17. package/dist/chunk-42VF42KH.js +273 -0
  18. package/dist/chunk-4PDYHPR6.js +297 -0
  19. package/dist/chunk-ADV52544.js +95 -0
  20. package/dist/chunk-FIE4LAJG.js +215 -0
  21. package/dist/chunk-PNKVD2UK.js +26 -0
  22. package/dist/chunk-RSTKX7WM.js +907 -0
  23. package/dist/chunk-VXV35I5J.js +2315 -0
  24. package/dist/index.browser.cjs +375 -276
  25. package/dist/index.browser.d.cts +4 -4
  26. package/dist/index.browser.d.ts +4 -4
  27. package/dist/index.browser.js +18 -13
  28. package/dist/index.cjs +382 -453
  29. package/dist/index.d.cts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +26 -21
  32. package/dist/storage/SqliteNodeEngine.cjs +395 -270
  33. package/dist/storage/SqliteNodeEngine.d.cts +9 -94
  34. package/dist/storage/SqliteNodeEngine.d.ts +9 -94
  35. package/dist/storage/SqliteNodeEngine.js +6 -5
  36. package/dist/storage/SqliteWasmEngine.cjs +382 -252
  37. package/dist/storage/SqliteWasmEngine.d.cts +8 -29
  38. package/dist/storage/SqliteWasmEngine.d.ts +8 -29
  39. package/dist/storage/SqliteWasmEngine.js +6 -5
  40. package/package.json +1 -1
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,6 +30,90 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // src/model/Handle.ts
34
+ var Handle_exports = {};
35
+ __export(Handle_exports, {
36
+ ContentHandle: () => ContentHandle,
37
+ HandleValidationError: () => HandleValidationError,
38
+ validateHandle: () => validateHandle
39
+ });
40
+ function isValidStartChar(char) {
41
+ return /^\p{L}$/u.test(char);
42
+ }
43
+ function isValidBodyChar(char) {
44
+ return /^[\p{L}\p{N}_./ -]$/u.test(char);
45
+ }
46
+ function validateHandle(handle) {
47
+ if (!handle) {
48
+ throw new HandleValidationError("Handle cannot be empty.");
49
+ }
50
+ const normalized = handle.trim().normalize("NFC");
51
+ if (normalized.length === 0) {
52
+ throw new HandleValidationError("Handle cannot be empty after normalization.");
53
+ }
54
+ if (normalized.length > MAX_HANDLE_LENGTH) {
55
+ throw new HandleValidationError(
56
+ `Handle '${handle}' is too long (${normalized.length} chars). Maximum is ${MAX_HANDLE_LENGTH}.`
57
+ );
58
+ }
59
+ if (!isValidStartChar(normalized[0])) {
60
+ throw new HandleValidationError(
61
+ `Invalid handle '${handle}'. Must start with a letter (any language).`
62
+ );
63
+ }
64
+ for (let i = 1; i < normalized.length; i++) {
65
+ if (!isValidBodyChar(normalized[i])) {
66
+ throw new HandleValidationError(
67
+ `Invalid character '${normalized[i]}' at position ${i} in handle '${handle}'.`
68
+ );
69
+ }
70
+ }
71
+ return normalized;
72
+ }
73
+ var MAX_HANDLE_LENGTH, HandleValidationError, ContentHandle;
74
+ var init_Handle = __esm({
75
+ "src/model/Handle.ts"() {
76
+ "use strict";
77
+ MAX_HANDLE_LENGTH = 255;
78
+ HandleValidationError = class extends Error {
79
+ constructor(message) {
80
+ super(message);
81
+ this.name = "HandleValidationError";
82
+ }
83
+ };
84
+ ContentHandle = class {
85
+ handle;
86
+ currentHash;
87
+ createdAt;
88
+ updatedAt;
89
+ constructor(handle, currentHash, createdAt, updatedAt) {
90
+ this.handle = validateHandle(handle);
91
+ this.currentHash = currentHash;
92
+ this.createdAt = createdAt ?? /* @__PURE__ */ new Date();
93
+ this.updatedAt = updatedAt ?? this.createdAt;
94
+ }
95
+ /**
96
+ * Update handle to point to new hash
97
+ * @returns Previous hash for history tracking
98
+ */
99
+ update(newHash) {
100
+ const previousHash = this.currentHash;
101
+ this.currentHash = newHash;
102
+ this.updatedAt = /* @__PURE__ */ new Date();
103
+ return previousHash;
104
+ }
105
+ toObject() {
106
+ return {
107
+ handle: this.handle,
108
+ currentHash: this.currentHash,
109
+ createdAt: this.createdAt.toISOString(),
110
+ updatedAt: this.updatedAt.toISOString()
111
+ };
112
+ }
113
+ };
114
+ }
115
+ });
116
+
30
117
  // src/storage/SqliteNodeEngine.ts
31
118
  var SqliteNodeEngine_exports = {};
32
119
  __export(SqliteNodeEngine_exports, {
@@ -905,6 +992,16 @@ var mime_extensions_default = {
905
992
  }
906
993
  };
907
994
 
995
+ // src/config/constants.ts
996
+ var DEFAULT_PAGE_SIZE = 10;
997
+ var DETECTION_SAMPLE_CAP = 8192;
998
+ var MAX_FILE_SIZE = 50 * 1024 * 1024;
999
+ var KNOWN_TYPE_SIZE_LIMIT = 1024 * 1024;
1000
+ var BINARY_CHECK_SAMPLE_SIZE = 32 * 1024;
1001
+ var CONTENT_DETECTION_SAMPLE_SIZE = 1024 * 1024;
1002
+ var DEFAULT_MAX_PROBLEM_BYTES = 2 * 1024 * 1024;
1003
+ var SQLITE_BUSY_TIMEOUT_MS = 5e3;
1004
+
908
1005
  // src/model/strategies/DetectionStrategy.ts
909
1006
  function loadSharedMimeData() {
910
1007
  return {
@@ -937,7 +1034,7 @@ var DefaultDetectionStrategy = class _DefaultDetectionStrategy {
937
1034
  return this.extensionsRegistry[mimeType] || "";
938
1035
  }
939
1036
  detect(content, fileExtension) {
940
- const contentSample = typeof content === "string" ? content.slice(0, 8192) : content.slice(0, 8192);
1037
+ const contentSample = typeof content === "string" ? content.slice(0, DETECTION_SAMPLE_CAP) : content.slice(0, DETECTION_SAMPLE_CAP);
941
1038
  const textSample = this.getTextSample(contentSample);
942
1039
  const lines = textSample.split("\n").slice(0, 20);
943
1040
  const firstLine = lines[0] || "";
@@ -971,9 +1068,9 @@ var DefaultDetectionStrategy = class _DefaultDetectionStrategy {
971
1068
  }
972
1069
  getTextSample(content) {
973
1070
  if (typeof content === "string") {
974
- return content.slice(0, 8192);
1071
+ return content.slice(0, DETECTION_SAMPLE_CAP);
975
1072
  }
976
- return new TextDecoder("utf-8", { fatal: false }).decode(content.slice(0, 8192));
1073
+ return new TextDecoder("utf-8", { fatal: false }).decode(content.slice(0, DETECTION_SAMPLE_CAP));
977
1074
  }
978
1075
  getExtension(mimeType) {
979
1076
  return _DefaultDetectionStrategy.getExtension(mimeType);
@@ -1191,48 +1288,6 @@ var MCard = class _MCard {
1191
1288
  }
1192
1289
  };
1193
1290
 
1194
- // src/model/Handle.ts
1195
- var MAX_HANDLE_LENGTH = 255;
1196
- function isValidStartChar(char) {
1197
- return /^\p{L}$/u.test(char);
1198
- }
1199
- function isValidBodyChar(char) {
1200
- return /^[\p{L}\p{N}_./ -]$/u.test(char);
1201
- }
1202
- var HandleValidationError = class extends Error {
1203
- constructor(message) {
1204
- super(message);
1205
- this.name = "HandleValidationError";
1206
- }
1207
- };
1208
- function validateHandle(handle) {
1209
- if (!handle) {
1210
- throw new HandleValidationError("Handle cannot be empty.");
1211
- }
1212
- const normalized = handle.trim().normalize("NFC").toLowerCase();
1213
- if (normalized.length === 0) {
1214
- throw new HandleValidationError("Handle cannot be empty after normalization.");
1215
- }
1216
- if (normalized.length > MAX_HANDLE_LENGTH) {
1217
- throw new HandleValidationError(
1218
- `Handle '${handle}' is too long (${normalized.length} chars). Maximum is ${MAX_HANDLE_LENGTH}.`
1219
- );
1220
- }
1221
- if (!isValidStartChar(normalized[0])) {
1222
- throw new HandleValidationError(
1223
- `Invalid handle '${handle}'. Must start with a letter (any language).`
1224
- );
1225
- }
1226
- for (let i = 1; i < normalized.length; i++) {
1227
- if (!isValidBodyChar(normalized[i])) {
1228
- throw new HandleValidationError(
1229
- `Invalid character '${normalized[i]}' at position ${i} in handle '${handle}'.`
1230
- );
1231
- }
1232
- }
1233
- return normalized;
1234
- }
1235
-
1236
1291
  // src/storage/StorageAdapter.ts
1237
1292
  function createPage(items, totalItems, pageNumber, pageSize) {
1238
1293
  const totalPages = Math.ceil(totalItems / pageSize) || 1;
@@ -1879,17 +1934,270 @@ function initCoreSchemas(db) {
1879
1934
  schema.initHandleTables(db);
1880
1935
  }
1881
1936
 
1937
+ // src/storage/engines/AbstractSqlEngine.ts
1938
+ init_Handle();
1939
+ var AbstractSqlEngine = class {
1940
+ /**
1941
+ * SQL expression for casting content to text in search queries.
1942
+ * Override in subclasses: SQLite uses 'TEXT', DuckDB uses 'VARCHAR'.
1943
+ */
1944
+ get castContentAs() {
1945
+ return "TEXT";
1946
+ }
1947
+ // ======================================================================
1948
+ // Concrete: Card Operations (shared across all SQL engines)
1949
+ // ======================================================================
1950
+ /**
1951
+ * Add a card. Default uses INSERT OR REPLACE (SQLite).
1952
+ * DuckDB overrides with DELETE + INSERT.
1953
+ */
1954
+ async add(card) {
1955
+ const contentBytes = card.content instanceof Uint8Array ? card.content : new TextEncoder().encode(String(card.content));
1956
+ await this.execSql(
1957
+ "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)",
1958
+ card.hash,
1959
+ contentBytes,
1960
+ card.g_time
1961
+ );
1962
+ return card.hash;
1963
+ }
1964
+ async get(hash) {
1965
+ const rows = await this.queryRows(
1966
+ "SELECT hash, content, g_time FROM card WHERE hash = ?",
1967
+ hash
1968
+ );
1969
+ if (rows.length === 0) return null;
1970
+ return this.rowToCard(rows[0]);
1971
+ }
1972
+ async delete(hash) {
1973
+ await this.execSql("DELETE FROM card WHERE hash = ?", hash);
1974
+ }
1975
+ async getPage(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
1976
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
1977
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
1978
+ const totalItems = await this.count();
1979
+ const offset = (pageNumber - 1) * pageSize;
1980
+ const rows = await this.queryRows(
1981
+ "SELECT hash, content, g_time FROM card ORDER BY g_time DESC LIMIT ? OFFSET ?",
1982
+ pageSize,
1983
+ offset
1984
+ );
1985
+ const items = rows.map((r) => this.rowToCard(r));
1986
+ return createPage(items, totalItems, pageNumber, pageSize);
1987
+ }
1988
+ async count() {
1989
+ const rows = await this.queryRows("SELECT COUNT(*) as cnt FROM card");
1990
+ return Number(rows[0]?.cnt ?? 0);
1991
+ }
1992
+ async searchByHash(hashPrefix) {
1993
+ const rows = await this.queryRows(
1994
+ "SELECT hash, content, g_time FROM card WHERE hash LIKE ?",
1995
+ `${hashPrefix}%`
1996
+ );
1997
+ return rows.map((r) => this.rowToCard(r));
1998
+ }
1999
+ async search(queryStr, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
2000
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
2001
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
2002
+ const offset = (pageNumber - 1) * pageSize;
2003
+ const pattern = `%${queryStr}%`;
2004
+ const cast = this.castContentAs;
2005
+ const countRows = await this.queryRows(
2006
+ `SELECT COUNT(*) as cnt FROM card WHERE CAST(content AS ${cast}) LIKE ?`,
2007
+ pattern
2008
+ );
2009
+ const totalItems = Number(countRows[0]?.cnt ?? 0);
2010
+ const rows = await this.queryRows(
2011
+ `SELECT hash, content, g_time FROM card WHERE CAST(content AS ${cast}) LIKE ? ORDER BY g_time DESC LIMIT ? OFFSET ?`,
2012
+ pattern,
2013
+ pageSize,
2014
+ offset
2015
+ );
2016
+ const items = rows.map((r) => this.rowToCard(r));
2017
+ return createPage(items, totalItems, pageNumber, pageSize);
2018
+ }
2019
+ async getAll() {
2020
+ const rows = await this.queryRows("SELECT hash, content, g_time FROM card ORDER BY g_time DESC");
2021
+ return rows.map((r) => this.rowToCard(r));
2022
+ }
2023
+ // ======================================================================
2024
+ // Concrete: clear (FK-safe delete order)
2025
+ // ======================================================================
2026
+ async clear() {
2027
+ await this.execSql("DELETE FROM handle_history");
2028
+ await this.execSql("DELETE FROM handle_registry");
2029
+ await this.execSql("DELETE FROM card");
2030
+ }
2031
+ // ======================================================================
2032
+ // Concrete: Handle Operations
2033
+ // ======================================================================
2034
+ async registerHandle(handle, hash) {
2035
+ const normalized = validateHandle(handle);
2036
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2037
+ const existing = await this.queryRows(
2038
+ "SELECT handle FROM handle_registry WHERE handle = ?",
2039
+ normalized
2040
+ );
2041
+ if (existing.length > 0) {
2042
+ throw new Error(`Handle '${handle}' already exists.`);
2043
+ }
2044
+ await this.execSql(
2045
+ "INSERT INTO handle_registry (handle, current_hash, created_at, updated_at) VALUES (?, ?, ?, ?)",
2046
+ normalized,
2047
+ hash,
2048
+ now,
2049
+ now
2050
+ );
2051
+ }
2052
+ async resolveHandle(handle) {
2053
+ const normalized = validateHandle(handle);
2054
+ const rows = await this.queryRows(
2055
+ "SELECT current_hash FROM handle_registry WHERE handle = ?",
2056
+ normalized
2057
+ );
2058
+ if (rows.length === 0) return null;
2059
+ return String(rows[0].current_hash);
2060
+ }
2061
+ async getByHandle(handle) {
2062
+ const hash = await this.resolveHandle(handle);
2063
+ if (!hash) return null;
2064
+ return this.get(hash);
2065
+ }
2066
+ async updateHandle(handle, newHash) {
2067
+ const normalized = validateHandle(handle);
2068
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2069
+ const rows = await this.queryRows(
2070
+ "SELECT current_hash FROM handle_registry WHERE handle = ?",
2071
+ normalized
2072
+ );
2073
+ if (rows.length === 0) {
2074
+ throw new Error(`Handle '${handle}' not found.`);
2075
+ }
2076
+ const previousHash = String(rows[0].current_hash);
2077
+ await this.execSql(
2078
+ "INSERT INTO handle_history (handle, previous_hash, changed_at) VALUES (?, ?, ?)",
2079
+ normalized,
2080
+ previousHash,
2081
+ now
2082
+ );
2083
+ await this.execSql(
2084
+ "UPDATE handle_registry SET current_hash = ?, updated_at = ? WHERE handle = ?",
2085
+ newHash,
2086
+ now,
2087
+ normalized
2088
+ );
2089
+ return previousHash;
2090
+ }
2091
+ async getHandleHistory(handle) {
2092
+ const normalized = validateHandle(handle);
2093
+ const rows = await this.queryRows(
2094
+ "SELECT previous_hash, changed_at FROM handle_history WHERE handle = ? ORDER BY id DESC",
2095
+ normalized
2096
+ );
2097
+ return rows.map((r) => ({
2098
+ previousHash: String(r.previous_hash),
2099
+ changedAt: String(r.changed_at)
2100
+ }));
2101
+ }
2102
+ async pruneHandleHistory(handle, options = {}) {
2103
+ const normalized = validateHandle(handle);
2104
+ if (options.deleteAll) {
2105
+ return this.execSql("DELETE FROM handle_history WHERE handle = ?", normalized);
2106
+ } else if (options.olderThan) {
2107
+ return this.execSql(
2108
+ "DELETE FROM handle_history WHERE handle = ? AND changed_at < ?",
2109
+ normalized,
2110
+ options.olderThan
2111
+ );
2112
+ }
2113
+ return 0;
2114
+ }
2115
+ // ======================================================================
2116
+ // Concrete: Handle Management Operations
2117
+ // ======================================================================
2118
+ async getAllHandles() {
2119
+ const rows = await this.queryRows("SELECT handle, current_hash FROM handle_registry");
2120
+ return rows.map((r) => ({
2121
+ handle: String(r.handle),
2122
+ hash: String(r.current_hash)
2123
+ }));
2124
+ }
2125
+ async removeHandle(handle) {
2126
+ const normalized = validateHandle(handle);
2127
+ await this.execSql("DELETE FROM handle_history WHERE handle = ?", normalized);
2128
+ await this.execSql("DELETE FROM handle_registry WHERE handle = ?", normalized);
2129
+ }
2130
+ async renameHandle(oldHandle, newHandle) {
2131
+ const normalizedOld = validateHandle(oldHandle);
2132
+ const normalizedNew = validateHandle(newHandle);
2133
+ if (normalizedOld === normalizedNew) return;
2134
+ const existsOld = await this.queryRows(
2135
+ "SELECT handle FROM handle_registry WHERE handle = ?",
2136
+ normalizedOld
2137
+ );
2138
+ if (existsOld.length === 0) throw new Error(`Handle '${oldHandle}' not found.`);
2139
+ const existsNew = await this.queryRows(
2140
+ "SELECT handle FROM handle_registry WHERE handle = ?",
2141
+ normalizedNew
2142
+ );
2143
+ if (existsNew.length > 0) throw new Error(`Handle '${newHandle}' already exists.`);
2144
+ const oldRow = await this.queryRows(
2145
+ "SELECT current_hash, created_at, updated_at FROM handle_registry WHERE handle = ?",
2146
+ normalizedOld
2147
+ );
2148
+ await this.execSql(
2149
+ "INSERT INTO handle_registry (handle, current_hash, created_at, updated_at) VALUES (?, ?, ?, ?)",
2150
+ normalizedNew,
2151
+ String(oldRow[0].current_hash),
2152
+ String(oldRow[0].created_at),
2153
+ String(oldRow[0].updated_at)
2154
+ );
2155
+ await this.execSql(
2156
+ "UPDATE handle_history SET handle = ? WHERE handle = ?",
2157
+ normalizedNew,
2158
+ normalizedOld
2159
+ );
2160
+ await this.execSql(
2161
+ "DELETE FROM handle_registry WHERE handle = ?",
2162
+ normalizedOld
2163
+ );
2164
+ }
2165
+ async deleteHistoryEntry(handle, previousHash) {
2166
+ const normalized = validateHandle(handle);
2167
+ const rOutRows = await this.queryRows(
2168
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND previous_hash = ? ORDER BY id DESC LIMIT 1",
2169
+ normalized,
2170
+ previousHash
2171
+ );
2172
+ if (rOutRows.length === 0) return;
2173
+ const rOutId = Number(rOutRows[0].id);
2174
+ const rInRows = await this.queryRows(
2175
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND id < ? ORDER BY id DESC LIMIT 1",
2176
+ normalized,
2177
+ rOutId
2178
+ );
2179
+ if (rInRows.length > 0) {
2180
+ const rInId = Number(rInRows[0].id);
2181
+ const rInPrevHash = String(rInRows[0].previous_hash);
2182
+ await this.execSql("UPDATE handle_history SET previous_hash = ? WHERE id = ?", rInPrevHash, rOutId);
2183
+ await this.execSql("DELETE FROM handle_history WHERE id = ?", rInId);
2184
+ } else {
2185
+ await this.execSql("DELETE FROM handle_history WHERE id = ?", rOutId);
2186
+ }
2187
+ }
2188
+ };
2189
+
1882
2190
  // src/storage/engines/SqliteNodeEngine.ts
1883
- var DEFAULT_PAGE_SIZE = 10;
1884
- var SqliteNodeEngine = class _SqliteNodeEngine {
2191
+ var SqliteNodeEngine = class _SqliteNodeEngine extends AbstractSqlEngine {
1885
2192
  db;
1886
2193
  dbPath;
1887
2194
  /**
1888
2195
  * Convert a database row into an MCard instance.
1889
2196
  */
1890
- static rowToCard(row) {
1891
- const content = row.content instanceof Buffer ? new Uint8Array(row.content) : new Uint8Array(row.content);
1892
- return MCard.fromData(content, row.hash, row.g_time);
2197
+ rowToCard(row) {
2198
+ const rawContent = row.content;
2199
+ const content = rawContent instanceof Buffer ? new Uint8Array(rawContent) : new Uint8Array(rawContent);
2200
+ return MCard.fromData(content, String(row.hash), String(row.g_time));
1893
2201
  }
1894
2202
  /**
1895
2203
  * Create a new SqliteNodeEngine via async factory.
@@ -1901,6 +2209,7 @@ var SqliteNodeEngine = class _SqliteNodeEngine {
1901
2209
  return engine;
1902
2210
  }
1903
2211
  constructor(dbPath) {
2212
+ super();
1904
2213
  this.dbPath = dbPath;
1905
2214
  }
1906
2215
  async init() {
@@ -1919,10 +2228,26 @@ var SqliteNodeEngine = class _SqliteNodeEngine {
1919
2228
  */
1920
2229
  setupDatabase() {
1921
2230
  this.db.pragma("journal_mode = WAL");
1922
- this.db.pragma("busy_timeout = 5000");
2231
+ this.db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);
1923
2232
  this.db.pragma("synchronous = NORMAL");
1924
2233
  initCoreSchemas(this.db);
1925
2234
  }
2235
+ // ======================================================================
2236
+ // AbstractSqlEngine primitives
2237
+ // ======================================================================
2238
+ async queryRows(sql, ...params) {
2239
+ const stmt = this.db.prepare(sql);
2240
+ return stmt.all(...params);
2241
+ }
2242
+ async execSql(sql, ...params) {
2243
+ if (params.length === 0) {
2244
+ this.db.exec(sql);
2245
+ return 0;
2246
+ }
2247
+ const stmt = this.db.prepare(sql);
2248
+ const result = stmt.run(...params);
2249
+ return result.changes;
2250
+ }
1926
2251
  /**
1927
2252
  * Close the database connection
1928
2253
  */
@@ -1935,7 +2260,7 @@ var SqliteNodeEngine = class _SqliteNodeEngine {
1935
2260
  getDbPath() {
1936
2261
  return this.dbPath;
1937
2262
  }
1938
- // =========== Card Operations ===========
2263
+ // =========== Card Operations (overrides to use Buffer.from for better-sqlite3) ===========
1939
2264
  async add(card) {
1940
2265
  const stmt = this.db.prepare(
1941
2266
  "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)"
@@ -1943,9 +2268,7 @@ var SqliteNodeEngine = class _SqliteNodeEngine {
1943
2268
  stmt.run(card.hash, Buffer.from(card.content), card.g_time);
1944
2269
  return card.hash;
1945
2270
  }
1946
- /**
1947
- * Add a card synchronously (for performance-critical paths)
1948
- */
2271
+ // =========== Sync card operations (for performance-critical callers) ===========
1949
2272
  addSync(card) {
1950
2273
  const stmt = this.db.prepare(
1951
2274
  "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)"
@@ -1953,35 +2276,17 @@ var SqliteNodeEngine = class _SqliteNodeEngine {
1953
2276
  stmt.run(card.hash, Buffer.from(card.content), card.g_time);
1954
2277
  return card.hash;
1955
2278
  }
1956
- async get(hash) {
1957
- return this.getSync(hash);
1958
- }
1959
- /**
1960
- * Get a card synchronously
1961
- */
1962
2279
  getSync(hash) {
1963
2280
  const stmt = this.db.prepare("SELECT hash, content, g_time FROM card WHERE hash = ?");
1964
2281
  const row = stmt.get(hash);
1965
2282
  if (!row) return null;
1966
- return _SqliteNodeEngine.rowToCard(row);
2283
+ return this.rowToCard(row);
1967
2284
  }
1968
- async delete(hash) {
1969
- this.deleteSync(hash);
1970
- }
1971
- /**
1972
- * Delete a card synchronously
1973
- */
1974
2285
  deleteSync(hash) {
1975
2286
  const stmt = this.db.prepare("DELETE FROM card WHERE hash = ?");
1976
2287
  const result = stmt.run(hash);
1977
2288
  return result.changes > 0;
1978
2289
  }
1979
- async getPage(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
1980
- return this.getPageSync(pageNumber, pageSize);
1981
- }
1982
- /**
1983
- * Get a page of cards synchronously
1984
- */
1985
2290
  getPageSync(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
1986
2291
  if (pageNumber < 1) throw new Error("Page number must be >= 1");
1987
2292
  if (pageSize < 1) throw new Error("Page size must be >= 1");
@@ -1991,76 +2296,40 @@ var SqliteNodeEngine = class _SqliteNodeEngine {
1991
2296
  "SELECT hash, content, g_time FROM card ORDER BY g_time DESC LIMIT ? OFFSET ?"
1992
2297
  );
1993
2298
  const rows = stmt.all(pageSize, offset);
1994
- const items = rows.map((row) => _SqliteNodeEngine.rowToCard(row));
2299
+ const items = rows.map((row) => this.rowToCard(row));
1995
2300
  return createPage(items, totalItems, pageNumber, pageSize);
1996
2301
  }
1997
- async count() {
1998
- return this.countSync();
1999
- }
2000
- /**
2001
- * Count cards synchronously
2002
- */
2003
2302
  countSync() {
2004
- const stmt = this.db.prepare("SELECT COUNT(*) as count FROM card");
2303
+ const stmt = this.db.prepare("SELECT COUNT(*) as cnt FROM card");
2005
2304
  const row = stmt.get();
2006
- return row.count;
2007
- }
2008
- async searchByHash(hashPrefix) {
2009
- const rows = this.db.prepare("SELECT hash, content, g_time FROM card WHERE hash LIKE ?").all(`${hashPrefix}%`);
2010
- return rows.map((row) => _SqliteNodeEngine.rowToCard(row));
2011
- }
2012
- async search(query, pageNumber, pageSize) {
2013
- const offset = (pageNumber - 1) * pageSize;
2014
- const searchPattern = `%${query}%`;
2015
- const countResult = this.db.prepare("SELECT COUNT(*) as count FROM card WHERE CAST(content AS TEXT) LIKE ?").get(searchPattern);
2016
- const totalItems = countResult.count;
2017
- const rows = this.db.prepare("SELECT hash, content, g_time FROM card WHERE CAST(content AS TEXT) LIKE ? LIMIT ? OFFSET ?").all(searchPattern, pageSize, offset);
2018
- const items = rows.map((row) => _SqliteNodeEngine.rowToCard(row));
2019
- return createPage(items, totalItems, pageNumber, pageSize);
2020
- }
2021
- async getAll() {
2022
- const rows = this.db.prepare("SELECT hash, content, g_time FROM card").all();
2023
- return rows.map((row) => _SqliteNodeEngine.rowToCard(row));
2305
+ return row.cnt;
2024
2306
  }
2025
- async clear() {
2026
- this.clearSync();
2027
- }
2028
- /**
2029
- * Clear all data synchronously
2030
- * Delete in FK-safe order: children first, then parents
2031
- */
2032
2307
  clearSync() {
2033
2308
  this.db.exec("DELETE FROM handle_history");
2034
2309
  this.db.exec("DELETE FROM handle_registry");
2035
2310
  this.db.exec("DELETE FROM card");
2036
2311
  }
2037
- // =========== Search Operations ===========
2038
- /**
2039
- * Search cards by string in content, hash, or g_time
2040
- */
2312
+ // =========== Additional sync search operations ===========
2041
2313
  searchByString(searchString, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
2042
2314
  if (pageNumber < 1) throw new Error("Page number must be >= 1");
2043
2315
  if (pageSize < 1) throw new Error("Page size must be >= 1");
2044
2316
  const pattern = `%${searchString}%`;
2045
2317
  const offset = (pageNumber - 1) * pageSize;
2046
2318
  const countStmt = this.db.prepare(`
2047
- SELECT COUNT(*) as count FROM card
2319
+ SELECT COUNT(*) as cnt FROM card
2048
2320
  WHERE hash LIKE ? OR g_time LIKE ? OR CAST(content AS TEXT) LIKE ?
2049
2321
  `);
2050
2322
  const countRow = countStmt.get(pattern, pattern, pattern);
2051
- const totalItems = countRow.count;
2323
+ const totalItems = countRow.cnt;
2052
2324
  const stmt = this.db.prepare(`
2053
- SELECT hash, content, g_time FROM card
2325
+ SELECT hash, content, g_time FROM card
2054
2326
  WHERE hash LIKE ? OR g_time LIKE ? OR CAST(content AS TEXT) LIKE ?
2055
2327
  ORDER BY g_time DESC LIMIT ? OFFSET ?
2056
2328
  `);
2057
2329
  const rows = stmt.all(pattern, pattern, pattern, pageSize, offset);
2058
- const items = rows.map((row) => _SqliteNodeEngine.rowToCard(row));
2330
+ const items = rows.map((row) => this.rowToCard(row));
2059
2331
  return createPage(items, totalItems, pageNumber, pageSize);
2060
2332
  }
2061
- /**
2062
- * Search cards by content pattern (binary-safe)
2063
- */
2064
2333
  searchByContent(searchPattern, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
2065
2334
  if (pageNumber < 1) throw new Error("Page number must be >= 1");
2066
2335
  if (pageSize < 1) throw new Error("Page size must be >= 1");
@@ -2069,172 +2338,28 @@ var SqliteNodeEngine = class _SqliteNodeEngine {
2069
2338
  }
2070
2339
  const searchBytes = typeof searchPattern === "string" ? Buffer.from(searchPattern, "utf-8") : Buffer.from(searchPattern);
2071
2340
  const offset = (pageNumber - 1) * pageSize;
2072
- const countStmt = this.db.prepare("SELECT COUNT(*) as count FROM card WHERE INSTR(content, ?) > 0");
2341
+ const countStmt = this.db.prepare("SELECT COUNT(*) as cnt FROM card WHERE INSTR(content, ?) > 0");
2073
2342
  const countRow = countStmt.get(searchBytes);
2074
- const totalItems = countRow.count;
2343
+ const totalItems = countRow.cnt;
2075
2344
  const stmt = this.db.prepare(`
2076
- SELECT hash, content, g_time FROM card
2345
+ SELECT hash, content, g_time FROM card
2077
2346
  WHERE INSTR(content, ?) > 0
2078
2347
  ORDER BY g_time DESC LIMIT ? OFFSET ?
2079
2348
  `);
2080
2349
  const rows = stmt.all(searchBytes, pageSize, offset);
2081
- const items = rows.map((row) => _SqliteNodeEngine.rowToCard(row));
2350
+ const items = rows.map((row) => this.rowToCard(row));
2082
2351
  return createPage(items, totalItems, pageNumber, pageSize);
2083
2352
  }
2084
- /**
2085
- * Get all cards (single page with all items)
2086
- */
2087
2353
  getAllCards() {
2088
2354
  const stmt = this.db.prepare("SELECT hash, content, g_time FROM card ORDER BY g_time DESC");
2089
2355
  const rows = stmt.all();
2090
- const items = rows.map((row) => _SqliteNodeEngine.rowToCard(row));
2356
+ const items = rows.map((row) => this.rowToCard(row));
2091
2357
  return createPage(items, items.length, 1, items.length || 1);
2092
2358
  }
2093
- // =========== Handle Operations ===========
2094
- async registerHandle(handle, hash) {
2095
- this.registerHandleSync(handle, hash);
2096
- }
2097
- /**
2098
- * Register a handle synchronously
2099
- */
2100
- registerHandleSync(handle, hash) {
2101
- const normalized = validateHandle(handle);
2102
- const now = (/* @__PURE__ */ new Date()).toISOString();
2103
- const checkStmt = this.db.prepare("SELECT handle FROM handle_registry WHERE handle = ?");
2104
- const existing = checkStmt.get(normalized);
2105
- if (existing) {
2106
- throw new Error(`Handle '${handle}' already exists.`);
2107
- }
2108
- const stmt = this.db.prepare(
2109
- "INSERT INTO handle_registry (handle, current_hash, created_at, updated_at) VALUES (?, ?, ?, ?)"
2110
- );
2111
- stmt.run(normalized, hash, now, now);
2112
- }
2113
- async resolveHandle(handle) {
2114
- return this.resolveHandleSync(handle);
2115
- }
2116
- /**
2117
- * Resolve a handle synchronously
2118
- */
2119
- resolveHandleSync(handle) {
2120
- const normalized = validateHandle(handle);
2121
- const stmt = this.db.prepare("SELECT current_hash FROM handle_registry WHERE handle = ?");
2122
- const row = stmt.get(normalized);
2123
- return row?.current_hash || null;
2124
- }
2125
- async getByHandle(handle) {
2126
- return this.getByHandleSync(handle);
2127
- }
2128
- /**
2129
- * Get card by handle synchronously
2130
- */
2131
- getByHandleSync(handle) {
2132
- const hash = this.resolveHandleSync(handle);
2133
- if (!hash) return null;
2134
- return this.getSync(hash);
2135
- }
2136
- async updateHandle(handle, newHash) {
2137
- return this.updateHandleSync(handle, newHash);
2138
- }
2139
- /**
2140
- * Update a handle synchronously
2141
- */
2142
- updateHandleSync(handle, newHash) {
2143
- const normalized = validateHandle(handle);
2144
- const now = (/* @__PURE__ */ new Date()).toISOString();
2145
- const getStmt = this.db.prepare("SELECT current_hash FROM handle_registry WHERE handle = ?");
2146
- const row = getStmt.get(normalized);
2147
- if (!row) {
2148
- throw new Error(`Handle '${handle}' not found.`);
2149
- }
2150
- const previousHash = row.current_hash;
2151
- const historyStmt = this.db.prepare(
2152
- "INSERT INTO handle_history (handle, previous_hash, changed_at) VALUES (?, ?, ?)"
2153
- );
2154
- historyStmt.run(normalized, previousHash, now);
2155
- const updateStmt = this.db.prepare(
2156
- "UPDATE handle_registry SET current_hash = ?, updated_at = ? WHERE handle = ?"
2157
- );
2158
- updateStmt.run(newHash, now, normalized);
2159
- return previousHash;
2160
- }
2161
- async getHandleHistory(handle) {
2162
- return this.getHandleHistorySync(handle);
2163
- }
2164
- /**
2165
- * Get handle history synchronously
2166
- */
2167
- getHandleHistorySync(handle) {
2168
- const normalized = validateHandle(handle);
2169
- const stmt = this.db.prepare(
2170
- "SELECT previous_hash, changed_at FROM handle_history WHERE handle = ? ORDER BY id DESC"
2171
- );
2172
- const rows = stmt.all(normalized);
2173
- return rows.map((row) => ({
2174
- previousHash: row.previous_hash,
2175
- changedAt: row.changed_at
2176
- }));
2177
- }
2178
- async pruneHandleHistory(handle, options = {}) {
2179
- return this.pruneHandleHistorySync(handle, options);
2180
- }
2181
- /**
2182
- * Prune handle history synchronously
2183
- */
2184
- pruneHandleHistorySync(handle, options = {}) {
2185
- const normalized = validateHandle(handle);
2186
- let stmt;
2187
- if (options.deleteAll) {
2188
- stmt = this.db.prepare("DELETE FROM handle_history WHERE handle = ?");
2189
- const result = stmt.run(normalized);
2190
- return result.changes;
2191
- } else if (options.olderThan) {
2192
- stmt = this.db.prepare("DELETE FROM handle_history WHERE handle = ? AND changed_at < ?");
2193
- const result = stmt.run(normalized, options.olderThan);
2194
- return result.changes;
2195
- }
2196
- return 0;
2197
- }
2198
- // =========== Handle Management Operations ===========
2199
- async getAllHandles() {
2200
- return this.getAllHandlesSync();
2201
- }
2202
- getAllHandlesSync() {
2203
- const stmt = this.db.prepare("SELECT handle, current_hash FROM handle_registry");
2204
- const rows = stmt.all();
2205
- return rows.map((row) => ({ handle: row.handle, hash: row.current_hash }));
2206
- }
2207
- async removeHandle(handle) {
2208
- this.removeHandleSync(handle);
2209
- }
2210
- removeHandleSync(handle) {
2211
- const normalized = validateHandle(handle);
2212
- this.db.prepare("DELETE FROM handle_history WHERE handle = ?").run(normalized);
2213
- this.db.prepare("DELETE FROM handle_registry WHERE handle = ?").run(normalized);
2214
- }
2215
- async renameHandle(oldHandle, newHandle) {
2216
- this.renameHandleSync(oldHandle, newHandle);
2217
- }
2218
- renameHandleSync(oldHandle, newHandle) {
2219
- const normalizedOld = validateHandle(oldHandle);
2220
- const normalizedNew = validateHandle(newHandle);
2221
- if (normalizedOld === normalizedNew) return;
2222
- const existsOld = this.db.prepare("SELECT handle FROM handle_registry WHERE handle = ?").get(normalizedOld);
2223
- if (!existsOld) throw new Error(`Handle '${oldHandle}' not found.`);
2224
- const existsNew = this.db.prepare("SELECT handle FROM handle_registry WHERE handle = ?").get(normalizedNew);
2225
- if (existsNew) throw new Error(`Handle '${newHandle}' already exists.`);
2226
- const performRename = this.db.transaction(() => {
2227
- this.db.pragma("defer_foreign_keys = ON");
2228
- this.db.prepare("UPDATE handle_registry SET handle = ? WHERE handle = ?").run(normalizedNew, normalizedOld);
2229
- this.db.prepare("UPDATE handle_history SET handle = ? WHERE handle = ?").run(normalizedNew, normalizedOld);
2230
- });
2231
- performRename();
2232
- }
2233
- async deleteHistoryEntry(handle, previousHash) {
2234
- this.deleteHistoryEntrySync(handle, previousHash);
2235
- }
2359
+ // =========== Unique sync method (not in AbstractSqlEngine) ===========
2236
2360
  deleteHistoryEntrySync(handle, previousHash) {
2237
- const normalized = validateHandle(handle);
2361
+ const { validateHandle: validateHandle2 } = (init_Handle(), __toCommonJS(Handle_exports));
2362
+ const normalized = validateHandle2(handle);
2238
2363
  const performStitch = this.db.transaction(() => {
2239
2364
  const rOut = this.db.prepare(
2240
2365
  "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND previous_hash = ? ORDER BY id DESC LIMIT 1"