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
@@ -0,0 +1,907 @@
1
+ import {
2
+ createPage
3
+ } from "./chunk-3EIBJPNF.js";
4
+ import {
5
+ init_Handle,
6
+ validateHandle
7
+ } from "./chunk-ADV52544.js";
8
+ import {
9
+ DEFAULT_PAGE_SIZE
10
+ } from "./chunk-3MMMJ7NH.js";
11
+
12
+ // src/storage/schema_constants.ts
13
+ var MCARD_SCHEMA_SQL = `-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
14
+ -- MCard Unified Database Schema (Monadic Core)
15
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
16
+ --
17
+ -- STABILITY WARNING: This schema is the invariant "seeding meta-language" for all
18
+ -- Domain Specific Languages (DSLs). It must remain as stable as possible.
19
+ --
20
+ -- THE UNIFICATION THESIS:
21
+ -- This design unites three distinct namespaces into a single relational network
22
+ -- by leveraging the power of cryptographic hash functions:
23
+ -- 1. CONTENT SPACE (Intrinsic Identity): Content-Addressable Storage (CAS).
24
+ -- 2. HANDLE SPACE (Reserved Words): Mapping human logic to content hashes.
25
+ -- 3. VERSION SPACE (Temporal Evolution): Tracking state transitions via hash history.
26
+ --
27
+ -- TURING MACHINE ANALOGY (The Infinitely Long Tape):
28
+ -- The \`card\` table stores content blobs with unique identities, emulating the
29
+ -- "Infinitely Long Tape" of the Turing Machine formalism. By using relational
30
+ -- queries, this tape can be dynamically constructed and traversed for different
31
+ -- DSLs, providing a flexible substrate for practically all computable languages.
32
+ --
33
+ -- By using hash values as the universal primitives across content, handles, and
34
+ -- time, we create a "Wordless Book" \u2014 a minimal substrate capable of seeding any
35
+ -- domain-specific knowledge system without requiring schema changes.
36
+ --
37
+ -- Monadic Mapping (See: Monadic Justification for Schema Design.md):
38
+ -- 1. Card = Monad (Perception/State/Exponent) - Intrinsic Identity
39
+ -- 2. Handle = Registry (Appetition/Reader/Sum) - Mutable Reference
40
+ -- 3. Version = History (Harmony/Writer/Product) - Coordinated Evolution
41
+ --
42
+ -- Version: 3.0.2 (Turing Tape Refinement)
43
+ -- Last Updated: 2025-12-20
44
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
45
+
46
+
47
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
48
+ -- LAYER 1: CORE CONTENT-ADDRESSABLE STORAGE (The Monad / Exponent)
49
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
50
+ -- The fundamental MCard storage: content-addressed by cryptographic hash.
51
+ -- "Each Monad ... mirrors the universe"
52
+
53
+ -- @table card
54
+ -- @description Core content-addressable storage table (Monad/State)
55
+ -- @column hash - SHA-256 hash of content (primary key)
56
+ -- @column content - The actual content (BLOB for binary safety)
57
+ -- @column g_time - Generation timestamp (ISO 8601)
58
+ CREATE TABLE IF NOT EXISTS card (
59
+ hash TEXT PRIMARY KEY,
60
+ content BLOB NOT NULL,
61
+ g_time TEXT NOT NULL
62
+ );
63
+
64
+
65
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
66
+ -- LAYER 2: HANDLE SYSTEM (Appetition / Sum)
67
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
68
+ -- The mutable pointer that "desires" to reference new content.
69
+ -- "Appetition: the tendency to move to new states"
70
+
71
+ -- @table handle_registry (Monadic Role: Handle)
72
+ -- @description Maps human-readable handles to current content hashes
73
+ -- @column handle - UTF-8 handle name (primary key)
74
+ -- @column current_hash - FK to card.hash of current version
75
+ -- @column created_at - When handle was first created
76
+ -- @column updated_at - When handle was last updated
77
+ CREATE TABLE IF NOT EXISTS handle_registry (
78
+ handle TEXT PRIMARY KEY,
79
+ current_hash TEXT NOT NULL,
80
+ created_at TEXT NOT NULL,
81
+ updated_at TEXT NOT NULL,
82
+ FOREIGN KEY (current_hash) REFERENCES card(hash)
83
+ );
84
+
85
+ -- @index idx_handle_current_hash
86
+ -- @description Efficient reverse lookup from hash to handles
87
+ CREATE INDEX IF NOT EXISTS idx_handle_current_hash
88
+ ON handle_registry(current_hash);
89
+
90
+ -- @table handle_history (Monadic Role: Version / Product)
91
+ -- @description Audit trail for handle pointer changes (Pre-Established Harmony)
92
+ -- @column id - Auto-increment primary key
93
+ -- @column handle - The handle that was updated
94
+ -- @column previous_hash - Hash it pointed to before update
95
+ -- @column changed_at - When the change occurred
96
+ CREATE TABLE IF NOT EXISTS handle_history (
97
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
98
+ handle TEXT NOT NULL,
99
+ previous_hash TEXT NOT NULL,
100
+ changed_at TEXT NOT NULL,
101
+ FOREIGN KEY (handle) REFERENCES handle_registry(handle),
102
+ FOREIGN KEY (previous_hash) REFERENCES card(hash)
103
+ );
104
+
105
+ -- @index idx_handle_history_handle
106
+ -- @description Efficient lookup of history by handle
107
+ CREATE INDEX IF NOT EXISTS idx_handle_history_handle
108
+ ON handle_history(handle);
109
+
110
+
111
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
112
+ -- LEGACY SUPPORT: FTS5 Documents Table
113
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
114
+ -- KEPT FOR BACKWARD COMPATIBILITY with existing codebase.
115
+ -- New implementations should use mcard_vector_schema.sql -> mcard_fts
116
+
117
+ -- @virtual_table documents
118
+ -- @description Legacy FTS table for backward compatibility
119
+ -- @note Synced with card table via triggers
120
+ CREATE VIRTUAL TABLE IF NOT EXISTS documents USING fts5(content);
121
+
122
+
123
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
124
+ -- SCHEMA METADATA
125
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
126
+
127
+ -- @table schema_version
128
+ -- @description Tracks schema version for migrations
129
+ CREATE TABLE IF NOT EXISTS schema_version (
130
+ version TEXT PRIMARY KEY,
131
+ applied_at TEXT NOT NULL,
132
+ description TEXT
133
+ );
134
+
135
+ -- Insert current schema version
136
+ INSERT OR IGNORE INTO schema_version (version, applied_at, description)
137
+ VALUES ('3.0.0', datetime('now'), 'Monadic Core Schema (split vectors to mcard_vector_schema.sql)');
138
+ `;
139
+ var MCARD_VECTOR_SCHEMA_SQL = `-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
140
+ -- MCard Vector Database Schema (mcard_vectors.db)
141
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
142
+ --
143
+ -- This schema defines the structure for "Secondary Qualities" (Extrinsic Embeddings).
144
+ -- It is separated from the core mcard.db (Monadic Intrinsic Properties) to ensure:
145
+ -- 1. Separation of Concerns (Intrinsic vs Extrinsic)
146
+ -- 2. Linearity (Vectors are observer-dependent and large)
147
+ -- 3. Upgradability (Embedding models change frequently)
148
+ --
149
+ -- See: Monadic Justification for Schema Design.md
150
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
151
+
152
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
153
+ -- LAYER 3: VECTOR STORAGE (Semantic Embeddings)
154
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
155
+ -- Storage for vector embeddings enabling semantic search.
156
+ -- Links to content via hash for content-addressing.
157
+
158
+ -- @table mcard_vector_metadata
159
+ -- @description Metadata for stored embeddings
160
+ -- @column id - Auto-increment primary key
161
+ -- @column hash - FK to card.hash
162
+ -- @column model_name - Embedding model used (e.g., "nomic-embed-text")
163
+ -- @column dimensions - Vector dimensions
164
+ -- @column chunk_index - Index for chunked documents (0 = first/whole)
165
+ -- @column chunk_total - Total chunks for this document
166
+ -- @column chunk_text - Preview text for this chunk
167
+ -- @column created_at - When embedding was created
168
+ CREATE TABLE IF NOT EXISTS mcard_vector_metadata (
169
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
170
+ hash TEXT NOT NULL,
171
+ model_name TEXT NOT NULL,
172
+ dimensions INTEGER NOT NULL,
173
+ chunk_index INTEGER DEFAULT 0,
174
+ chunk_total INTEGER DEFAULT 1,
175
+ chunk_text TEXT,
176
+ created_at TEXT NOT NULL,
177
+ UNIQUE(hash, chunk_index)
178
+ );
179
+
180
+ -- @index idx_vector_metadata_hash
181
+ -- @description Efficient lookup of embeddings by content hash
182
+ CREATE INDEX IF NOT EXISTS idx_vector_metadata_hash
183
+ ON mcard_vector_metadata(hash);
184
+
185
+ -- @table mcard_embeddings
186
+ -- @description Fallback embedding storage when sqlite-vec is unavailable
187
+ -- @column id - Auto-increment primary key
188
+ -- @column metadata_id - FK to mcard_vector_metadata.id
189
+ -- @column embedding - Serialized float32 vector as BLOB
190
+ CREATE TABLE IF NOT EXISTS mcard_embeddings (
191
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
192
+ metadata_id INTEGER NOT NULL,
193
+ embedding BLOB NOT NULL,
194
+ UNIQUE(metadata_id),
195
+ FOREIGN KEY (metadata_id) REFERENCES mcard_vector_metadata(id)
196
+ );
197
+
198
+ -- @virtual_table mcard_fts
199
+ -- @description Full-text search for hybrid retrieval
200
+ -- @note Uses Porter stemming with Unicode support
201
+ CREATE VIRTUAL TABLE IF NOT EXISTS mcard_fts USING fts5(
202
+ hash,
203
+ content,
204
+ tokenize='porter unicode61'
205
+ );
206
+
207
+ -- Note: sqlite-vec virtual table is created dynamically with dimensions:
208
+ -- CREATE VIRTUAL TABLE IF NOT EXISTS mcard_vec USING vec0(
209
+ -- metadata_id INTEGER PRIMARY KEY,
210
+ -- embedding float[\${dimensions}]
211
+ -- );
212
+
213
+
214
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
215
+ -- LAYER 4: SEMANTIC VERSIONING (Handle-Vector Bridge)
216
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
217
+ -- Bridges handles to vector embeddings for semantic version comparison.
218
+ -- Enables measuring semantic drift between document versions.
219
+
220
+ -- @table handle_version_vectors
221
+ -- @description Links handle versions to their semantic embeddings
222
+ -- @column id - Auto-increment primary key
223
+ -- @column handle - FK to handle_registry.handle
224
+ -- @column hash - FK to card.hash (this version)
225
+ -- @column parent_hash - FK to card.hash (previous version)
226
+ -- @column version_order - 0 = current, 1 = previous, etc.
227
+ -- @column is_current - TRUE if this is the current version
228
+ -- @column embedding_id - FK to mcard_vector_metadata.id
229
+ -- @column semantic_delta_from_parent - Cosine similarity to parent [-1, 1]
230
+ -- @column upgrade_type - Classification: 'trivial' | 'minor' | 'major' | 'breaking'
231
+ -- @column created_at - When this version was linked
232
+ CREATE TABLE IF NOT EXISTS handle_version_vectors (
233
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
234
+ handle TEXT NOT NULL,
235
+ hash TEXT NOT NULL,
236
+ parent_hash TEXT,
237
+ version_order INTEGER NOT NULL,
238
+ is_current BOOLEAN DEFAULT FALSE,
239
+ embedding_id INTEGER,
240
+ semantic_delta_from_parent REAL,
241
+ upgrade_type TEXT,
242
+ created_at TEXT NOT NULL,
243
+ UNIQUE(handle, hash),
244
+ FOREIGN KEY (embedding_id) REFERENCES mcard_vector_metadata(id)
245
+ );
246
+
247
+ -- @index idx_hvv_handle
248
+ -- @description Efficient lookup of versions by handle
249
+ CREATE INDEX IF NOT EXISTS idx_hvv_handle
250
+ ON handle_version_vectors(handle);
251
+
252
+ -- @index idx_hvv_hash
253
+ -- @description Efficient lookup of versions by hash
254
+ CREATE INDEX IF NOT EXISTS idx_hvv_hash
255
+ ON handle_version_vectors(hash);
256
+
257
+ -- @index idx_hvv_current
258
+ -- @description Efficient lookup of current versions
259
+ CREATE INDEX IF NOT EXISTS idx_hvv_current
260
+ ON handle_version_vectors(is_current);
261
+
262
+ -- @index idx_hvv_parent
263
+ -- @description Efficient lookup by parent hash
264
+ CREATE INDEX IF NOT EXISTS idx_hvv_parent
265
+ ON handle_version_vectors(parent_hash);
266
+
267
+ -- @table version_similarity_cache
268
+ -- @description Precomputed pairwise similarities for performance
269
+ -- @column id - Auto-increment primary key
270
+ -- @column handle - Handle these versions belong to
271
+ -- @column hash_a - First version hash
272
+ -- @column hash_b - Second version hash
273
+ -- @column similarity_score - Cosine similarity [-1, 1]
274
+ -- @column distance_euclidean - L2 distance [0, \u221E)
275
+ -- @column computed_at - When similarity was computed
276
+ CREATE TABLE IF NOT EXISTS version_similarity_cache (
277
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
278
+ handle TEXT NOT NULL,
279
+ hash_a TEXT NOT NULL,
280
+ hash_b TEXT NOT NULL,
281
+ similarity_score REAL NOT NULL,
282
+ distance_euclidean REAL,
283
+ computed_at TEXT NOT NULL,
284
+ UNIQUE(handle, hash_a, hash_b)
285
+ );
286
+
287
+ -- @index idx_vsc_handle
288
+ -- @description Efficient lookup of cached similarities by handle
289
+ CREATE INDEX IF NOT EXISTS idx_vsc_handle
290
+ ON version_similarity_cache(handle);
291
+
292
+
293
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
294
+ -- LAYER 5: KNOWLEDGE GRAPH (GraphRAG)
295
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
296
+ -- Storage for extracted knowledge graph entities and relationships.
297
+
298
+ -- @table graph_entities
299
+ -- @description Nodes in the knowledge graph
300
+ -- @column id - Auto-increment primary key
301
+ -- @column name - Entity name
302
+ -- @column type - Entity type (e.g., "Person", "Organization")
303
+ -- @column description - Optional description
304
+ -- @column source_hash - FK to card.hash where entity was extracted
305
+ -- @column embedding - Optional entity embedding
306
+ -- @column created_at - When entity was created
307
+ CREATE TABLE IF NOT EXISTS graph_entities (
308
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
309
+ name TEXT NOT NULL,
310
+ type TEXT NOT NULL,
311
+ description TEXT,
312
+ source_hash TEXT NOT NULL,
313
+ embedding BLOB,
314
+ created_at TEXT NOT NULL,
315
+ UNIQUE(name, type, source_hash)
316
+ );
317
+
318
+ -- @index idx_entity_name
319
+ -- @description Efficient entity lookup by name
320
+ CREATE INDEX IF NOT EXISTS idx_entity_name
321
+ ON graph_entities(name);
322
+
323
+ -- @index idx_entity_type
324
+ -- @description Efficient entity lookup by type
325
+ CREATE INDEX IF NOT EXISTS idx_entity_type
326
+ ON graph_entities(type);
327
+
328
+ -- @index idx_entity_source
329
+ -- @description Efficient entity lookup by source document
330
+ CREATE INDEX IF NOT EXISTS idx_entity_source
331
+ ON graph_entities(source_hash);
332
+
333
+ -- @table graph_relationships
334
+ -- @description Edges in the knowledge graph
335
+ -- @column id - Auto-increment primary key
336
+ -- @column source_entity_id - FK to graph_entities.id (from)
337
+ -- @column target_entity_id - FK to graph_entities.id (to)
338
+ -- @column relationship - Relationship type/label
339
+ -- @column description - Optional description
340
+ -- @column weight - Relationship strength
341
+ -- @column source_hash - FK to card.hash where relationship was extracted
342
+ -- @column created_at - When relationship was created
343
+ CREATE TABLE IF NOT EXISTS graph_relationships (
344
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
345
+ source_entity_id INTEGER NOT NULL,
346
+ target_entity_id INTEGER NOT NULL,
347
+ relationship TEXT NOT NULL,
348
+ description TEXT,
349
+ weight REAL DEFAULT 1.0,
350
+ source_hash TEXT NOT NULL,
351
+ created_at TEXT NOT NULL,
352
+ UNIQUE(source_entity_id, target_entity_id, relationship, source_hash),
353
+ FOREIGN KEY (source_entity_id) REFERENCES graph_entities(id),
354
+ FOREIGN KEY (target_entity_id) REFERENCES graph_entities(id)
355
+ );
356
+
357
+ -- @index idx_rel_source
358
+ -- @description Efficient lookup of relationships by source entity
359
+ CREATE INDEX IF NOT EXISTS idx_rel_source
360
+ ON graph_relationships(source_entity_id);
361
+
362
+ -- @index idx_rel_target
363
+ -- @description Efficient lookup of relationships by target entity
364
+ CREATE INDEX IF NOT EXISTS idx_rel_target
365
+ ON graph_relationships(target_entity_id);
366
+
367
+ -- @table graph_communities
368
+ -- @description Hierarchical community summaries (GraphRAG)
369
+ -- @column id - Auto-increment primary key
370
+ -- @column level - Hierarchy level (0 = leaf)
371
+ -- @column title - Community title
372
+ -- @column summary - AI-generated summary
373
+ -- @column embedding - Community embedding
374
+ -- @column member_entity_ids - JSON array of entity IDs
375
+ -- @column parent_community_id - FK to parent community
376
+ -- @column created_at - When community was created
377
+ CREATE TABLE IF NOT EXISTS graph_communities (
378
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
379
+ level INTEGER NOT NULL DEFAULT 0,
380
+ title TEXT,
381
+ summary TEXT NOT NULL,
382
+ embedding BLOB,
383
+ member_entity_ids TEXT,
384
+ parent_community_id INTEGER,
385
+ created_at TEXT NOT NULL,
386
+ FOREIGN KEY (parent_community_id) REFERENCES graph_communities(id)
387
+ );
388
+
389
+ -- @index idx_community_level
390
+ -- @description Efficient lookup of communities by level
391
+ CREATE INDEX IF NOT EXISTS idx_community_level
392
+ ON graph_communities(level);
393
+
394
+ -- @table graph_extractions
395
+ -- @description Tracks which documents have been processed for entity extraction
396
+ -- @column hash - FK to card.hash (primary key)
397
+ -- @column entity_count - Number of entities extracted
398
+ -- @column relationship_count - Number of relationships extracted
399
+ -- @column extracted_at - When extraction was performed
400
+ CREATE TABLE IF NOT EXISTS graph_extractions (
401
+ hash TEXT PRIMARY KEY,
402
+ entity_count INTEGER DEFAULT 0,
403
+ relationship_count INTEGER DEFAULT 0,
404
+ extracted_at TEXT NOT NULL
405
+ );
406
+
407
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
408
+ -- SCHEMA METADATA (Vector DB)
409
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
410
+
411
+ -- @table schema_version
412
+ -- @description Tracks schema version for migrations
413
+ CREATE TABLE IF NOT EXISTS vector_schema_version (
414
+ version TEXT PRIMARY KEY,
415
+ applied_at TEXT NOT NULL,
416
+ description TEXT
417
+ );
418
+
419
+ -- Insert current schema version
420
+ INSERT OR IGNORE INTO vector_schema_version (version, applied_at, description)
421
+ VALUES ('1.0.0', datetime('now'), 'Initial MCard Vector Schema');
422
+ `;
423
+
424
+ // src/storage/schema.ts
425
+ var TABLE_LAYERS = {
426
+ // Layer 1: Core
427
+ "card": "core",
428
+ // Layer 2: Handle System
429
+ "handle_registry": "handle",
430
+ "handle_history": "handle",
431
+ // Layer 3: Vector Storage
432
+ "mcard_vector_metadata": "vector",
433
+ "mcard_embeddings": "vector",
434
+ "mcard_fts": "vector",
435
+ // Layer 4: Semantic Versioning
436
+ "handle_version_vectors": "semantic",
437
+ "version_similarity_cache": "semantic",
438
+ // Layer 5: Knowledge Graph
439
+ "graph_entities": "graph",
440
+ "graph_relationships": "graph",
441
+ "graph_communities": "graph",
442
+ "graph_extractions": "graph",
443
+ // Metadata
444
+ "schema_version": "metadata"
445
+ };
446
+ var MCardSchema = class _MCardSchema {
447
+ static instance = null;
448
+ schemaPath = "";
449
+ rawSql = "";
450
+ statements = [];
451
+ tables = /* @__PURE__ */ new Map();
452
+ indexes = /* @__PURE__ */ new Map();
453
+ loaded = false;
454
+ constructor() {
455
+ }
456
+ /**
457
+ * Get the singleton instance.
458
+ */
459
+ static getInstance() {
460
+ if (!_MCardSchema.instance) {
461
+ _MCardSchema.instance = new _MCardSchema();
462
+ _MCardSchema.instance.load();
463
+ }
464
+ return _MCardSchema.instance;
465
+ }
466
+ /**
467
+ * Reset the singleton (for testing).
468
+ */
469
+ static resetInstance() {
470
+ _MCardSchema.instance = null;
471
+ }
472
+ load() {
473
+ if (this.loaded) return;
474
+ this.schemaPath = "IN_MEMORY_CONSTANTS";
475
+ this.rawSql = MCARD_SCHEMA_SQL;
476
+ if (MCARD_VECTOR_SCHEMA_SQL) {
477
+ this.rawSql += "\n\n" + MCARD_VECTOR_SCHEMA_SQL;
478
+ }
479
+ this.statements = this.parseStatements(this.rawSql);
480
+ for (const stmt of this.statements) {
481
+ const name = this.extractName(stmt);
482
+ if (name) {
483
+ const upper = stmt.toUpperCase();
484
+ if (upper.includes("CREATE TABLE") || upper.includes("CREATE VIRTUAL TABLE")) {
485
+ this.tables.set(name.toLowerCase(), stmt);
486
+ } else if (upper.includes("CREATE INDEX")) {
487
+ this.indexes.set(name.toLowerCase(), stmt);
488
+ }
489
+ }
490
+ }
491
+ this.loaded = true;
492
+ }
493
+ parseStatements(sql) {
494
+ sql = sql.replace(/\/\*[\s\S]*?\*\//g, "");
495
+ const statements = [];
496
+ let current = [];
497
+ for (const line of sql.split("\n")) {
498
+ const stripped = line.split("--")[0].trim();
499
+ if (!stripped) continue;
500
+ current.push(stripped);
501
+ if (stripped.endsWith(";")) {
502
+ const statement = current.join(" ");
503
+ if (!statement.trim().toUpperCase().startsWith("INSERT")) {
504
+ statements.push(statement);
505
+ }
506
+ current = [];
507
+ }
508
+ }
509
+ return statements.filter((s) => s.trim());
510
+ }
511
+ extractName(statement) {
512
+ let match = statement.match(/CREATE\s+(?:VIRTUAL\s+)?TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)/i);
513
+ if (match) return match[1];
514
+ match = statement.match(/CREATE\s+INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)/i);
515
+ if (match) return match[1];
516
+ return null;
517
+ }
518
+ // ─────────────────────────────────────────────────────────────────────────
519
+ // Schema Access
520
+ // ─────────────────────────────────────────────────────────────────────────
521
+ getSchemaPath() {
522
+ return this.schemaPath;
523
+ }
524
+ getTable(tableName) {
525
+ return this.tables.get(tableName.toLowerCase());
526
+ }
527
+ getIndex(indexName) {
528
+ return this.indexes.get(indexName.toLowerCase());
529
+ }
530
+ getAllTables() {
531
+ return new Map(this.tables);
532
+ }
533
+ getAllIndexes() {
534
+ return new Map(this.indexes);
535
+ }
536
+ getAllStatements() {
537
+ return [...this.statements];
538
+ }
539
+ getTablesByLayer(layer) {
540
+ return Object.entries(TABLE_LAYERS).filter(([_, l]) => l === layer).map(([name, _]) => name);
541
+ }
542
+ getLayerStatements(layer) {
543
+ const statements = [];
544
+ const tables = this.getTablesByLayer(layer);
545
+ for (const table of tables) {
546
+ const stmt = this.getTable(table);
547
+ if (stmt) statements.push(stmt);
548
+ }
549
+ for (const [_, stmt] of this.indexes) {
550
+ const match = stmt.match(/ON\s+(\w+)/i);
551
+ if (match && tables.includes(match[1].toLowerCase())) {
552
+ statements.push(stmt);
553
+ }
554
+ }
555
+ return statements;
556
+ }
557
+ // ─────────────────────────────────────────────────────────────────────────
558
+ // Database Initialization
559
+ // ─────────────────────────────────────────────────────────────────────────
560
+ execStatements(db, statements) {
561
+ for (const stmt of statements) {
562
+ db.exec(stmt);
563
+ }
564
+ return statements.length;
565
+ }
566
+ initLayer(db, layer) {
567
+ return this.execStatements(db, this.getLayerStatements(layer));
568
+ }
569
+ initCoreTables(db) {
570
+ return this.initLayer(db, "core");
571
+ }
572
+ initHandleTables(db) {
573
+ return this.initLayer(db, "handle");
574
+ }
575
+ initVectorTables(db, enableFts = true) {
576
+ const statements = this.getLayerStatements("vector").filter((s) => enableFts || !s.toLowerCase().includes("fts"));
577
+ return this.execStatements(db, statements);
578
+ }
579
+ initSemanticTables(db) {
580
+ return this.initLayer(db, "semantic");
581
+ }
582
+ initGraphTables(db) {
583
+ return this.initLayer(db, "graph");
584
+ }
585
+ initAllTables(db, options = {}) {
586
+ const { enableFts = true, enableGraph = true, enableSemantic = true } = options;
587
+ let count = 0;
588
+ count += this.initCoreTables(db);
589
+ count += this.initHandleTables(db);
590
+ count += this.initVectorTables(db, enableFts);
591
+ if (enableSemantic) {
592
+ count += this.initSemanticTables(db);
593
+ }
594
+ if (enableGraph) {
595
+ count += this.initGraphTables(db);
596
+ }
597
+ return count;
598
+ }
599
+ initVec0Table(db, dimensions) {
600
+ db.exec(`
601
+ CREATE VIRTUAL TABLE IF NOT EXISTS mcard_vec USING vec0(
602
+ metadata_id INTEGER PRIMARY KEY,
603
+ embedding float[${dimensions}]
604
+ )
605
+ `);
606
+ }
607
+ };
608
+ function getSchemaInstance() {
609
+ return MCardSchema.getInstance();
610
+ }
611
+ var CARD_TABLE_SCHEMA = getSchemaInstance().getTable("card") || "";
612
+ var HANDLE_REGISTRY_SCHEMA = getSchemaInstance().getTable("handle_registry") || "";
613
+ var HANDLE_HISTORY_SCHEMA = getSchemaInstance().getTable("handle_history") || "";
614
+ var HANDLE_INDEX_SCHEMA = getSchemaInstance().getIndex("idx_handle_current_hash") || "";
615
+ var VECTOR_METADATA_SCHEMA = getSchemaInstance().getTable("mcard_vector_metadata") || "";
616
+ var VECTOR_METADATA_INDEX = getSchemaInstance().getIndex("idx_vector_metadata_hash") || "";
617
+ var VECTOR_EMBEDDINGS_SCHEMA = getSchemaInstance().getTable("mcard_embeddings") || "";
618
+ var VECTOR_FTS_SCHEMA = getSchemaInstance().getTable("mcard_fts") || "";
619
+ var HANDLE_VERSION_VECTORS_SCHEMA = getSchemaInstance().getTable("handle_version_vectors") || "";
620
+ var HANDLE_VERSION_VECTORS_INDEXES = [
621
+ getSchemaInstance().getIndex("idx_hvv_handle"),
622
+ getSchemaInstance().getIndex("idx_hvv_hash"),
623
+ getSchemaInstance().getIndex("idx_hvv_current"),
624
+ getSchemaInstance().getIndex("idx_hvv_parent")
625
+ ].filter(Boolean).join("; ");
626
+ var VERSION_SIMILARITY_CACHE_SCHEMA = getSchemaInstance().getTable("version_similarity_cache") || "";
627
+ var VERSION_SIMILARITY_CACHE_INDEX = getSchemaInstance().getIndex("idx_vsc_handle") || "";
628
+ var GRAPH_ENTITY_SCHEMA = getSchemaInstance().getTable("graph_entities") || "";
629
+ var GRAPH_ENTITY_INDEX_NAME = getSchemaInstance().getIndex("idx_entity_name") || "";
630
+ var GRAPH_ENTITY_INDEX_TYPE = getSchemaInstance().getIndex("idx_entity_type") || "";
631
+ var GRAPH_ENTITY_INDEX_SOURCE = getSchemaInstance().getIndex("idx_entity_source") || "";
632
+ var GRAPH_RELATIONSHIP_SCHEMA = getSchemaInstance().getTable("graph_relationships") || "";
633
+ var GRAPH_RELATIONSHIP_INDEX_SOURCE = getSchemaInstance().getIndex("idx_rel_source") || "";
634
+ var GRAPH_RELATIONSHIP_INDEX_TARGET = getSchemaInstance().getIndex("idx_rel_target") || "";
635
+ var GRAPH_COMMUNITY_SCHEMA = getSchemaInstance().getTable("graph_communities") || "";
636
+ var GRAPH_COMMUNITY_INDEX_LEVEL = getSchemaInstance().getIndex("idx_community_level") || "";
637
+ var GRAPH_EXTRACTION_SCHEMA = getSchemaInstance().getTable("graph_extractions") || "";
638
+ var CORE_SCHEMAS = {
639
+ card: CARD_TABLE_SCHEMA,
640
+ handleRegistry: HANDLE_REGISTRY_SCHEMA,
641
+ handleHistory: HANDLE_HISTORY_SCHEMA,
642
+ handleIndex: HANDLE_INDEX_SCHEMA
643
+ };
644
+ function initCoreSchemas(db) {
645
+ const schema = MCardSchema.getInstance();
646
+ schema.initCoreTables(db);
647
+ schema.initHandleTables(db);
648
+ }
649
+
650
+ // src/storage/engines/AbstractSqlEngine.ts
651
+ init_Handle();
652
+ var AbstractSqlEngine = class {
653
+ /**
654
+ * SQL expression for casting content to text in search queries.
655
+ * Override in subclasses: SQLite uses 'TEXT', DuckDB uses 'VARCHAR'.
656
+ */
657
+ get castContentAs() {
658
+ return "TEXT";
659
+ }
660
+ // ======================================================================
661
+ // Concrete: Card Operations (shared across all SQL engines)
662
+ // ======================================================================
663
+ /**
664
+ * Add a card. Default uses INSERT OR REPLACE (SQLite).
665
+ * DuckDB overrides with DELETE + INSERT.
666
+ */
667
+ async add(card) {
668
+ const contentBytes = card.content instanceof Uint8Array ? card.content : new TextEncoder().encode(String(card.content));
669
+ await this.execSql(
670
+ "INSERT OR REPLACE INTO card (hash, content, g_time) VALUES (?, ?, ?)",
671
+ card.hash,
672
+ contentBytes,
673
+ card.g_time
674
+ );
675
+ return card.hash;
676
+ }
677
+ async get(hash) {
678
+ const rows = await this.queryRows(
679
+ "SELECT hash, content, g_time FROM card WHERE hash = ?",
680
+ hash
681
+ );
682
+ if (rows.length === 0) return null;
683
+ return this.rowToCard(rows[0]);
684
+ }
685
+ async delete(hash) {
686
+ await this.execSql("DELETE FROM card WHERE hash = ?", hash);
687
+ }
688
+ async getPage(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
689
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
690
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
691
+ const totalItems = await this.count();
692
+ const offset = (pageNumber - 1) * pageSize;
693
+ const rows = await this.queryRows(
694
+ "SELECT hash, content, g_time FROM card ORDER BY g_time DESC LIMIT ? OFFSET ?",
695
+ pageSize,
696
+ offset
697
+ );
698
+ const items = rows.map((r) => this.rowToCard(r));
699
+ return createPage(items, totalItems, pageNumber, pageSize);
700
+ }
701
+ async count() {
702
+ const rows = await this.queryRows("SELECT COUNT(*) as cnt FROM card");
703
+ return Number(rows[0]?.cnt ?? 0);
704
+ }
705
+ async searchByHash(hashPrefix) {
706
+ const rows = await this.queryRows(
707
+ "SELECT hash, content, g_time FROM card WHERE hash LIKE ?",
708
+ `${hashPrefix}%`
709
+ );
710
+ return rows.map((r) => this.rowToCard(r));
711
+ }
712
+ async search(queryStr, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
713
+ if (pageNumber < 1) throw new Error("Page number must be >= 1");
714
+ if (pageSize < 1) throw new Error("Page size must be >= 1");
715
+ const offset = (pageNumber - 1) * pageSize;
716
+ const pattern = `%${queryStr}%`;
717
+ const cast = this.castContentAs;
718
+ const countRows = await this.queryRows(
719
+ `SELECT COUNT(*) as cnt FROM card WHERE CAST(content AS ${cast}) LIKE ?`,
720
+ pattern
721
+ );
722
+ const totalItems = Number(countRows[0]?.cnt ?? 0);
723
+ const rows = await this.queryRows(
724
+ `SELECT hash, content, g_time FROM card WHERE CAST(content AS ${cast}) LIKE ? ORDER BY g_time DESC LIMIT ? OFFSET ?`,
725
+ pattern,
726
+ pageSize,
727
+ offset
728
+ );
729
+ const items = rows.map((r) => this.rowToCard(r));
730
+ return createPage(items, totalItems, pageNumber, pageSize);
731
+ }
732
+ async getAll() {
733
+ const rows = await this.queryRows("SELECT hash, content, g_time FROM card ORDER BY g_time DESC");
734
+ return rows.map((r) => this.rowToCard(r));
735
+ }
736
+ // ======================================================================
737
+ // Concrete: clear (FK-safe delete order)
738
+ // ======================================================================
739
+ async clear() {
740
+ await this.execSql("DELETE FROM handle_history");
741
+ await this.execSql("DELETE FROM handle_registry");
742
+ await this.execSql("DELETE FROM card");
743
+ }
744
+ // ======================================================================
745
+ // Concrete: Handle Operations
746
+ // ======================================================================
747
+ async registerHandle(handle, hash) {
748
+ const normalized = validateHandle(handle);
749
+ const now = (/* @__PURE__ */ new Date()).toISOString();
750
+ const existing = await this.queryRows(
751
+ "SELECT handle FROM handle_registry WHERE handle = ?",
752
+ normalized
753
+ );
754
+ if (existing.length > 0) {
755
+ throw new Error(`Handle '${handle}' already exists.`);
756
+ }
757
+ await this.execSql(
758
+ "INSERT INTO handle_registry (handle, current_hash, created_at, updated_at) VALUES (?, ?, ?, ?)",
759
+ normalized,
760
+ hash,
761
+ now,
762
+ now
763
+ );
764
+ }
765
+ async resolveHandle(handle) {
766
+ const normalized = validateHandle(handle);
767
+ const rows = await this.queryRows(
768
+ "SELECT current_hash FROM handle_registry WHERE handle = ?",
769
+ normalized
770
+ );
771
+ if (rows.length === 0) return null;
772
+ return String(rows[0].current_hash);
773
+ }
774
+ async getByHandle(handle) {
775
+ const hash = await this.resolveHandle(handle);
776
+ if (!hash) return null;
777
+ return this.get(hash);
778
+ }
779
+ async updateHandle(handle, newHash) {
780
+ const normalized = validateHandle(handle);
781
+ const now = (/* @__PURE__ */ new Date()).toISOString();
782
+ const rows = await this.queryRows(
783
+ "SELECT current_hash FROM handle_registry WHERE handle = ?",
784
+ normalized
785
+ );
786
+ if (rows.length === 0) {
787
+ throw new Error(`Handle '${handle}' not found.`);
788
+ }
789
+ const previousHash = String(rows[0].current_hash);
790
+ await this.execSql(
791
+ "INSERT INTO handle_history (handle, previous_hash, changed_at) VALUES (?, ?, ?)",
792
+ normalized,
793
+ previousHash,
794
+ now
795
+ );
796
+ await this.execSql(
797
+ "UPDATE handle_registry SET current_hash = ?, updated_at = ? WHERE handle = ?",
798
+ newHash,
799
+ now,
800
+ normalized
801
+ );
802
+ return previousHash;
803
+ }
804
+ async getHandleHistory(handle) {
805
+ const normalized = validateHandle(handle);
806
+ const rows = await this.queryRows(
807
+ "SELECT previous_hash, changed_at FROM handle_history WHERE handle = ? ORDER BY id DESC",
808
+ normalized
809
+ );
810
+ return rows.map((r) => ({
811
+ previousHash: String(r.previous_hash),
812
+ changedAt: String(r.changed_at)
813
+ }));
814
+ }
815
+ async pruneHandleHistory(handle, options = {}) {
816
+ const normalized = validateHandle(handle);
817
+ if (options.deleteAll) {
818
+ return this.execSql("DELETE FROM handle_history WHERE handle = ?", normalized);
819
+ } else if (options.olderThan) {
820
+ return this.execSql(
821
+ "DELETE FROM handle_history WHERE handle = ? AND changed_at < ?",
822
+ normalized,
823
+ options.olderThan
824
+ );
825
+ }
826
+ return 0;
827
+ }
828
+ // ======================================================================
829
+ // Concrete: Handle Management Operations
830
+ // ======================================================================
831
+ async getAllHandles() {
832
+ const rows = await this.queryRows("SELECT handle, current_hash FROM handle_registry");
833
+ return rows.map((r) => ({
834
+ handle: String(r.handle),
835
+ hash: String(r.current_hash)
836
+ }));
837
+ }
838
+ async removeHandle(handle) {
839
+ const normalized = validateHandle(handle);
840
+ await this.execSql("DELETE FROM handle_history WHERE handle = ?", normalized);
841
+ await this.execSql("DELETE FROM handle_registry WHERE handle = ?", normalized);
842
+ }
843
+ async renameHandle(oldHandle, newHandle) {
844
+ const normalizedOld = validateHandle(oldHandle);
845
+ const normalizedNew = validateHandle(newHandle);
846
+ if (normalizedOld === normalizedNew) return;
847
+ const existsOld = await this.queryRows(
848
+ "SELECT handle FROM handle_registry WHERE handle = ?",
849
+ normalizedOld
850
+ );
851
+ if (existsOld.length === 0) throw new Error(`Handle '${oldHandle}' not found.`);
852
+ const existsNew = await this.queryRows(
853
+ "SELECT handle FROM handle_registry WHERE handle = ?",
854
+ normalizedNew
855
+ );
856
+ if (existsNew.length > 0) throw new Error(`Handle '${newHandle}' already exists.`);
857
+ const oldRow = await this.queryRows(
858
+ "SELECT current_hash, created_at, updated_at FROM handle_registry WHERE handle = ?",
859
+ normalizedOld
860
+ );
861
+ await this.execSql(
862
+ "INSERT INTO handle_registry (handle, current_hash, created_at, updated_at) VALUES (?, ?, ?, ?)",
863
+ normalizedNew,
864
+ String(oldRow[0].current_hash),
865
+ String(oldRow[0].created_at),
866
+ String(oldRow[0].updated_at)
867
+ );
868
+ await this.execSql(
869
+ "UPDATE handle_history SET handle = ? WHERE handle = ?",
870
+ normalizedNew,
871
+ normalizedOld
872
+ );
873
+ await this.execSql(
874
+ "DELETE FROM handle_registry WHERE handle = ?",
875
+ normalizedOld
876
+ );
877
+ }
878
+ async deleteHistoryEntry(handle, previousHash) {
879
+ const normalized = validateHandle(handle);
880
+ const rOutRows = await this.queryRows(
881
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND previous_hash = ? ORDER BY id DESC LIMIT 1",
882
+ normalized,
883
+ previousHash
884
+ );
885
+ if (rOutRows.length === 0) return;
886
+ const rOutId = Number(rOutRows[0].id);
887
+ const rInRows = await this.queryRows(
888
+ "SELECT id, previous_hash FROM handle_history WHERE handle = ? AND id < ? ORDER BY id DESC LIMIT 1",
889
+ normalized,
890
+ rOutId
891
+ );
892
+ if (rInRows.length > 0) {
893
+ const rInId = Number(rInRows[0].id);
894
+ const rInPrevHash = String(rInRows[0].previous_hash);
895
+ await this.execSql("UPDATE handle_history SET previous_hash = ? WHERE id = ?", rInPrevHash, rOutId);
896
+ await this.execSql("DELETE FROM handle_history WHERE id = ?", rInId);
897
+ } else {
898
+ await this.execSql("DELETE FROM handle_history WHERE id = ?", rOutId);
899
+ }
900
+ }
901
+ };
902
+
903
+ export {
904
+ CORE_SCHEMAS,
905
+ initCoreSchemas,
906
+ AbstractSqlEngine
907
+ };