UNPKG

mcard-js

Version:

MCard - Content-addressable storage with cryptographic hashing, handle resolution, and vector search for Node.js and browsers

1,237 lines (1,205 loc) 83.3 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/storage/SqliteNodeEngine.ts var SqliteNodeEngine_exports = {}; __export(SqliteNodeEngine_exports, { SqliteNodeEngine: () => SqliteNodeEngine }); module.exports = __toCommonJS(SqliteNodeEngine_exports); // src/model/hash/HashValidator.ts var HashValidator = class { /** * Compute hash of content using specified algorithm */ static async computeHash(content, algorithm = "sha256") { const data = typeof content === "string" ? new TextEncoder().encode(content) : content; let algoName = "SHA-256"; switch (algorithm.toLowerCase()) { case "sha1": algoName = "SHA-1"; break; case "sha-1": algoName = "SHA-1"; break; case "sha256": algoName = "SHA-256"; break; case "sha-256": algoName = "SHA-256"; break; case "sha384": algoName = "SHA-384"; break; case "sha-384": algoName = "SHA-384"; break; case "sha512": algoName = "SHA-512"; break; case "sha-512": algoName = "SHA-512"; break; default: console.warn(`Algorithm ${algorithm} not natively supported or mapped, defaulting to SHA-256`); algoName = "SHA-256"; } const buffer = new Uint8Array(data).buffer; const hashBuffer = await crypto.subtle.digest(algoName, buffer); return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join(""); } /** * Validate that content matches expected hash */ static async validate(content, expectedHash) { const computedHash = await this.computeHash(content); return computedHash === expectedHash; } }; // src/model/GTime.ts var VALID_HASH_ALGORITHMS = ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]; var GTime = class { static DEFAULT_ALGORITHM = "sha256"; /** * Generate a GTime stamp for the current moment * Format: HASH_ALGO|TIMESTAMP|REGION_CODE */ static stampNow(hashAlgorithm = this.DEFAULT_ALGORITHM) { const algo = hashAlgorithm.toLowerCase(); const timestamp = (/* @__PURE__ */ new Date()).toISOString(); const region = "UTC"; return `${algo}|${timestamp}|${region}`; } /** * Parse a GTime string */ static parse(gtime) { const parts = gtime.split("|"); if (parts.length !== 3) { throw new Error(`Invalid GTime format: ${gtime}`); } return { algorithm: parts[0], timestamp: new Date(parts[1]), region: parts[2] }; } /** * Get the hash algorithm from a GTime string */ static getHashAlgorithm(gtime) { return this.parse(gtime).algorithm; } /** * Get the timestamp from a GTime string */ static getTimestamp(gtime) { return this.parse(gtime).timestamp; } /** * Get the region code from a GTime string */ static getRegionCode(gtime) { return this.parse(gtime).region; } /** * Check if the provided hash function is valid. * Matches Python's GTime.is_valid_hash_function() */ static isValidHashFunction(hashFunction) { if (!hashFunction || typeof hashFunction !== "string") { return false; } return VALID_HASH_ALGORITHMS.includes(hashFunction.toLowerCase()); } /** * Check if the provided region code is valid. * Matches Python's GTime.is_valid_region_code() */ static isValidRegionCode(regionCode) { return Boolean(regionCode && regionCode === regionCode.toUpperCase()); } /** * Check if the provided timestamp is in ISO format. * Matches Python's GTime.is_iso_format() */ static isIsoFormat(timestamp) { if (!timestamp || typeof timestamp !== "string") { return false; } try { const date = new Date(timestamp); if (isNaN(date.getTime())) { return false; } const isoPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/; return isoPattern.test(timestamp); } catch { return false; } } }; // src/model/detectors/BinaryDetector.ts var BinarySignatureDetector = class _BinarySignatureDetector { contentTypeName = "binary"; // Signatures map: [Signature Bytes, Mime Type] static SIGNATURES = [ [new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]), "image/png"], [new Uint8Array([255, 216, 255]), "image/jpeg"], [new Uint8Array([71, 73, 70, 56, 55, 97]), "image/gif"], // GIF87a [new Uint8Array([71, 73, 70, 56, 57, 97]), "image/gif"], // GIF89a [new Uint8Array([66, 77]), "image/bmp"], // BM [new Uint8Array([0, 0, 1, 0]), "image/x-icon"], [new Uint8Array([0, 0, 2, 0]), "image/x-icon"], [new Uint8Array([37, 80, 68, 70]), "application/pdf"], // %PDF [new Uint8Array([80, 75, 3, 4]), "application/zip"], // PK.. [new Uint8Array([31, 139, 8]), "application/gzip"], [new Uint8Array([82, 97, 114, 33, 26, 7, 0]), "application/x-rar-compressed"], [new Uint8Array([55, 122, 188, 175, 39, 28]), "application/x-7z-compressed"], [new Uint8Array([83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0]), "application/x-sqlite3"] ]; // Extension-to-MIME mapping for binary types (used when byte detection fails) static EXT_TO_MIME = { // Video ".mp4": "video/mp4", ".webm": "video/webm", ".avi": "video/x-msvideo", ".mov": "video/quicktime", ".mkv": "video/x-matroska", ".wmv": "video/x-ms-wmv", ".flv": "video/x-flv", ".m4v": "video/x-m4v", // Audio ".mp3": "audio/mpeg", ".ogg": "audio/ogg", ".flac": "audio/flac", ".aac": "audio/aac", ".m4a": "audio/mp4", ".wma": "audio/x-ms-wma", // Images (backup for when signature detection fails) ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".ico": "image/x-icon", ".webp": "image/webp", ".svg": "image/svg+xml", // Documents ".pdf": "application/pdf", // Archives ".zip": "application/zip", ".gz": "application/gzip", ".rar": "application/x-rar-compressed", ".7z": "application/x-7z-compressed", ".tar": "application/x-tar", // Database ".db": "application/x-sqlite3", ".sqlite": "application/x-sqlite3", ".sqlite3": "application/x-sqlite3", // Fonts ".woff": "font/woff", ".woff2": "font/woff2", ".ttf": "font/ttf", ".otf": "font/otf", ".eot": "application/vnd.ms-fontobject" }; detect(contentSample, lines, firstLine, fileExtension) { const mime = this.getMimeType(contentSample, lines, firstLine, fileExtension); return mime && mime !== "application/octet-stream" ? 0.95 : 0; } getMimeType(contentSample, lines, firstLine, fileExtension) { const bytes = this.toBytes(contentSample); const detected = this.detectFromBytes(bytes); if (detected !== "application/octet-stream") { return detected; } if (fileExtension) { let ext = fileExtension.toLowerCase(); const lastDotIndex = ext.lastIndexOf("."); if (lastDotIndex > -1) { ext = ext.substring(lastDotIndex); } else if (!ext.startsWith(".")) { if (ext.includes("/") || ext.includes("\\")) { return "application/octet-stream"; } ext = "." + ext; } const extMime = _BinarySignatureDetector.EXT_TO_MIME[ext]; if (extMime) { return extMime; } } return "application/octet-stream"; } /** * Detect MIME type directly from bytes. */ detectFromBytes(bytes) { if (this.startsWith(bytes, new Uint8Array([82, 73, 70, 70]))) { return this.detectRiffFormat(bytes); } for (const [sig, mime] of _BinarySignatureDetector.SIGNATURES) { if (this.startsWith(bytes, sig)) { if (mime === "application/zip") { return this.detectZipType(bytes); } return mime; } } return "application/octet-stream"; } toBytes(content) { if (content instanceof Uint8Array) return content; return new TextEncoder().encode(content); } startsWith(data, prefix) { if (data.length < prefix.length) return false; for (let i = 0; i < prefix.length; i++) { if (data[i] !== prefix[i]) return false; } return true; } detectRiffFormat(bytes) { if (bytes.length < 12) return "application/octet-stream"; const format = new TextDecoder().decode(bytes.slice(8, 12)); if (format === "WAVE") return "audio/wav"; if (format === "WEBP") return "image/webp"; return "application/octet-stream"; } detectZipType(bytes) { const header = new TextDecoder().decode(bytes.slice(0, 2048)); if (header.includes("[Content_Types].xml") && header.includes("_rels/.rels")) { if (header.includes("word/")) return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; if (header.includes("xl/")) return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; if (header.includes("ppt/")) return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; } return "application/zip"; } }; // src/model/detectors/LanguageDetector.ts var ProgrammingLanguageDetector = class { contentTypeName = "code"; detect(contentSample, lines, firstLine, fileExtension) { const mime = this.getMimeType(contentSample, lines, firstLine, fileExtension); return mime && mime !== "text/plain" ? 0.95 : 0; } getMimeType(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); if (this.isPython(firstLine, text, lines)) { return "text/x-python"; } const cType = this.detectCFamily(text); if (cType) return cType; const jsType = this.detectJsType(text); if (jsType) return jsType; if (this.isTypescript(text)) { return "text/typescript"; } return "text/plain"; } isPython(firstLine, text, lines) { if (/^\s*import\s+(\w+|\w+\.\w+)/m.test(text) || /^\s*from\s+(\w+|\w+\.\w+)\s+import\s+/m.test(text)) { const stdLibs = ["os", "sys", "re", "json", "math", "random", "datetime"]; if (stdLibs.some((lib) => text.includes(`import ${lib}`) || text.includes(`from ${lib}`))) { return true; } } if (firstLine.startsWith("#!") && firstLine.toLowerCase().includes("python")) return true; if (text.includes("if __name__ ==") && text.includes("__main__")) return true; if (/^\s*def\s+\w+\s*\(/.test(text) && !text.includes("function")) return true; if (/^\s*class\s+\w+\s*[\(:]/m.test(text)) return true; if (/^\s*@\w+/m.test(text)) return true; let count = 0; const patterns = [ /\bif\b.*?:/, /\belif\b.*?:/, /\belse\s*:/, /\bfor\b.*?\bin\b.*?:/, /\bwhile\b.*?:/, /\btry\s*:/, /\bexcept\b.*?:/, /\bfinally\s*:/, /\bNone\b/, /\bTrue\b/, /\bFalse\b/, /f["'].*?\{.*?\}["']/, // f-string /\bdef\b/, /\bclass\b/, /\bimport\b/, /\bfrom\b/, /\blambda\b.*?:/ ]; for (const p of patterns) { if (p.test(text)) count++; } const nonEmptyLines = lines.filter((l) => l.trim().length > 0).length; if (nonEmptyLines <= 5 && count >= 1) { return true; } return count >= 3; } detectCFamily(text) { const cPatterns = [ /#include\s*<.*?>/, /#include\s*".*?"/, /\b(int|void|char|float|double)\s+main\s*\(.*\)\s*\{/, /\bstruct\s+\w+\s*\{/, /#define\s+\w+/, /printf\(.*?\);/, /scanf\(.*?\);/ ]; const cppPatterns = [ /\bclass\s+\w+\s*\{/, /\bnamespace\s+\w+\s*\{/, /\btemplate\s*<.*?>/, /::/, /\bstd::/, /\bcout\s*<</, /\bcin\s*>>/, /\bnew\s+\w+/, /\bdelete\s+\w+/, /#include\s*<iostream>/ ]; let cCount = 0; let cppCount = 0; cPatterns.forEach((p) => { if (p.test(text)) cCount++; }); cppPatterns.forEach((p) => { if (p.test(text)) cppCount++; }); if (cppCount >= 2 || cppCount >= 1 && text.includes("std::")) return "text/x-c++"; if (cCount >= 2) return "text/x-c"; return null; } detectJsType(text) { const jsPatterns = [ /function\s+\w+\s*\(/.test(text), // function foo( /\bconst\s+\w+\s*=/.test(text), /\blet\s+\w+\s*=/.test(text), /\bvar\s+\w+\s*=/.test(text), /\bimport\s+.*\s+from/.test(text), /\bexport\s+/.test(text), /\=\>\s*\{/.test(text), // Arrow func /console\.log\(/.test(text) ]; const jsxPatterns = [ /<\w+(>|\s+.*?>)[\s\S]*?<\/\w+>/m.test(text), /<\w+\s+\/>/m.test(text), /className=/.test(text), /React\.createElement/.test(text) ]; const jsCount = jsPatterns.filter(Boolean).length; const jsxCount = jsxPatterns.filter(Boolean).length; if (jsxCount > 0 && (text.includes("import React") || text.includes('from "react"'))) return "text/jsx"; if (jsxCount >= 2) return "text/jsx"; if (jsCount >= 2) { const stripped = text.trim(); if (stripped.startsWith("{") && stripped.endsWith("}") || stripped.startsWith("[") && stripped.endsWith("]")) { try { JSON.parse(text); if (jsCount < 2) return null; } catch { } } return "text/javascript"; } return null; } isTypescript(text) { const tsPatterns = [ /:\s*(string|number|boolean|any|void|null|undefined)\b/, /\binterface\s+\w+\s*\{/, /\bclass\s+\w+\s+implements\s+\w+/, /\btype\s+\w+\s*=/, /\b(public|private|protected)\s+/, /\bnamespace\s+\w+\s*\{/, /<\w+>/ // Generics (simple check) ]; let count = 0; tsPatterns.forEach((p) => { if (p.test(text)) count++; }); return count >= 2; } }; // src/model/detectors/MarkupDetectors.ts var XMLDetector = class _XMLDetector { contentTypeName = "xml"; static XML_DECLARATION = /^\s*<\?xml/i; static BASIC_TAG_PAIR = /<(\w+)[^>]*>.*?<\/\1>/s; detect(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); let confidence = 0; if (fileExtension && fileExtension.toLowerCase() === ".xml") { confidence = Math.max(confidence, 0.95); } if (_XMLDetector.XML_DECLARATION.test(firstLine) || text.trim().startsWith("<?xml")) { confidence = Math.max(confidence, 0.95); } if (text.includes("<") && text.includes(">") && text.includes("</")) { confidence = Math.max(confidence, 0.5); if (_XMLDetector.BASIC_TAG_PAIR.test(text)) { confidence = Math.max(confidence, 0.7); } } if (text.toLowerCase().includes("<!doctype html")) { if (confidence > 0.3) confidence -= 0.4; } return Math.min(Math.max(confidence, 0), 1); } getMimeType(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); if (fileExtension === ".xml") return "application/xml"; if (text.toLowerCase().includes("<svg")) return "image/svg+xml"; if (text.toLowerCase().includes("<html") || text.toLowerCase().includes("<!doctype html")) return "text/html"; if (this.detect(contentSample, lines, firstLine, fileExtension) > 0.5) return "application/xml"; return "text/plain"; } }; var MarkdownDetector = class _MarkdownDetector { contentTypeName = "markdown"; static MD_PATTERNS = [ /^#{1,6}\s+\S+/, // ATX Headers /^\s*[\*\+\-]\s+\S+/, // List items /^\s*\d+\.\s+\S+/, // Ordered list items /`{1,3}[^`]+`{1,3}/, // Inline code /\[[^\]]+\]\([^\)]+\)/, // Links /!\[[^\]]+\]\([^\)]+\)/, // Images /^\s*>.*/ // Blockquotes ]; static SETEXT_HEADER = /^.*\n(?:={3,}|-{3,})\s*$/m; detect(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); let confidence = 0; if (fileExtension && [".md", ".markdown"].includes(fileExtension.toLowerCase())) { confidence = Math.max(confidence, 0.95); } let mdFeatures = 0; if (_MarkdownDetector.SETEXT_HEADER.test(text)) mdFeatures += 2; for (const line of lines.slice(0, 20)) { if (_MarkdownDetector.MD_PATTERNS.some((p) => p.test(line))) { mdFeatures++; } } const hasCodeFence = text.includes("```"); if (hasCodeFence) mdFeatures++; if (mdFeatures > 1 && hasCodeFence) confidence = Math.max(confidence, 0.85); if (mdFeatures > 3 && hasCodeFence) confidence = Math.max(confidence, 0.95); else if (mdFeatures > 1) confidence = Math.max(confidence, 0.6); else if (mdFeatures > 3) confidence = Math.max(confidence, 0.8); else if (mdFeatures > 5) confidence = Math.max(confidence, 0.9); const stripped = text.trim(); if (stripped.startsWith("{") && stripped.endsWith("}") || stripped.startsWith("[") && stripped.endsWith("]")) { try { JSON.parse(text); if (confidence > 0.3) confidence -= 0.4; } catch { } } if (stripped.startsWith("<") && text.includes("<?xml")) { if (confidence > 0.3) confidence -= 0.4; } return Math.min(Math.max(confidence, 0), 1); } getMimeType(contentSample, lines, firstLine, fileExtension) { return this.detect(contentSample, lines, firstLine, fileExtension) > 0.5 ? "text/markdown" : "text/plain"; } }; var PlainTextDetector = class _PlainTextDetector { contentTypeName = "text"; static IMAGE_EXTS = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg", ".webp"]; detect(contentSample, lines, firstLine, fileExtension) { if (!contentSample && lines.length === 0) return 0.1; if (fileExtension) { const ext = fileExtension.toLowerCase(); if (_PlainTextDetector.IMAGE_EXTS.includes(ext) || ext === ".pdf") return 0; } const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); if (text.includes(",") && lines.length < 5) { const commaLines = lines.filter((l) => l.includes(",")).length; if (commaLines > 0 && commaLines === lines.length) { return 0.8; } } return 0.15; } getMimeType(contentSample, lines, firstLine, fileExtension) { return "text/plain"; } }; // src/model/detectors/DataFormatDetectors.ts var SQLDetector = class _SQLDetector { contentTypeName = "sql"; // Keywords (case insensitive checking handled in method) static KEYWORDS = [ "SELECT ", "INSERT ", "UPDATE ", "DELETE ", "CREATE ", "DROP ", "ALTER ", "FROM ", "WHERE ", "JOIN ", "TABLE ", "INTO ", "VALUES ", "SET ", "PRIMARY KEY" ]; detect(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); let confidence = 0; if (fileExtension && fileExtension.toLowerCase() === ".sql") { confidence = Math.max(confidence, 0.95); } let hits = 0; const upperText = text.toUpperCase(); for (const line of lines.slice(0, 10)) { const upperLine = line.toUpperCase(); for (const kw of _SQLDetector.KEYWORDS) { if (upperLine.includes(kw)) { hits++; } } } if (hits >= 2) confidence = Math.max(confidence, 0.85); else if (hits === 1) confidence = Math.max(confidence, 0.6); return Math.min(confidence, 1); } getMimeType(contentSample, lines, firstLine, fileExtension) { return this.detect(contentSample, lines, firstLine, fileExtension) > 0.5 ? "text/x-sql" : "text/plain"; } }; var JSONDetector = class { contentTypeName = "json"; detect(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); if (fileExtension && fileExtension.toLowerCase() === ".json") { return this.verifyJsonStructure(text) ? 0.95 : 0.6; } const stripped = text.trim(); if (!(stripped.startsWith("{") && stripped.endsWith("}") || stripped.startsWith("[") && stripped.endsWith("]"))) { return 0; } for (const line of lines.slice(0, 5)) { const l = line.trim(); if (l.startsWith("//") || l.startsWith("/*")) return 0; } try { JSON.parse(text); return 0.9; } catch (e) { return 0; } } getMimeType(contentSample, lines, firstLine, fileExtension) { return this.detect(contentSample, lines, firstLine, fileExtension) > 0.5 ? "application/json" : "text/plain"; } verifyJsonStructure(text) { try { JSON.parse(text); return true; } catch { return false; } } }; var YAMLDetector = class _YAMLDetector { contentTypeName = "yaml"; static YAML_START_PATTERNS = [/^---\s*$/, /^%YAML/]; static KEY_VALUE_PATTERN = /^\s*[\w.-]+:\s+(?![=\{\[])/; static LIST_ITEM_PATTERN = /^\s*-\s+[\w\'\"]/; detect(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); let confidence = 0; if (fileExtension && [".yaml", ".yml"].includes(fileExtension.toLowerCase())) { confidence = Math.max(confidence, 0.95); } if (_YAMLDetector.YAML_START_PATTERNS.some((p) => p.test(firstLine))) { confidence = Math.max(confidence, 0.9); } let yamlFeatures = 0; if (_YAMLDetector.YAML_START_PATTERNS.some((p) => new RegExp(p.source, "m").test(text))) { yamlFeatures += 2; } for (const line of lines.slice(0, 20)) { const stripped = line.trim(); if (_YAMLDetector.KEY_VALUE_PATTERN.test(stripped)) yamlFeatures++; else if (_YAMLDetector.LIST_ITEM_PATTERN.test(stripped)) yamlFeatures++; } const firstNonEmpty = lines.find((l) => l.trim().length > 0) || ""; if (firstNonEmpty.trim() === "---") { if (yamlFeatures > 1) confidence = Math.max(confidence, 0.5); if (yamlFeatures > 3) confidence = Math.max(confidence, 0.75); if (yamlFeatures > 5) confidence = Math.max(confidence, 0.9); } else { if (fileExtension && [".yaml", ".yml"].includes(fileExtension.toLowerCase())) { } } return Math.min(Math.max(confidence, 0), 1); } getMimeType(contentSample, lines, firstLine, fileExtension) { const conf = this.detect(contentSample, lines, firstLine, fileExtension); return conf > 0.5 ? "application/x-yaml" : "text/plain"; } }; var CSVDetector = class { contentTypeName = "csv"; detect(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); if (fileExtension && fileExtension.toLowerCase() === ".csv") { return this.verifyCsvStructure(lines) ? 0.95 : 0.6; } return this.analyzeCsvContent(lines); } getMimeType(contentSample, lines, firstLine, fileExtension) { return this.detect(contentSample, lines, firstLine, fileExtension) > 0.5 ? "text/csv" : "text/plain"; } verifyCsvStructure(lines) { const sampleLines = lines.slice(0, 10).filter((l) => l.trim().length > 0); if (sampleLines.length === 0) return false; if (!sampleLines.every((l) => l.includes(","))) return false; const counts = sampleLines.map((l) => (l.match(/,/g) || []).length); const uniqueCounts = [...new Set(counts)]; if (uniqueCounts.length === 1 && uniqueCounts[0] > 0) return true; if (sampleLines.length > 1) { const dataCounts = counts.slice(1); const uniqueData = [...new Set(dataCounts)]; if (uniqueData.length === 1 && uniqueData[0] > 0) return true; } return false; } analyzeCsvContent(lines) { if (!lines || lines.length === 0) return 0; const sampleLines = lines.slice(0, 10).filter((l) => l.trim().length > 0); if (sampleLines.length === 0 || !sampleLines.every((l) => l.includes(","))) return 0; const counts = sampleLines.map((l) => (l.match(/,/g) || []).length); const uniqueCounts = [...new Set(counts)]; if (uniqueCounts.length === 1 && uniqueCounts[0] > 0) return 0.9; if (sampleLines.length > 1) { const dataCounts = counts.slice(1); const uniqueData = [...new Set(dataCounts)]; if (uniqueData.length === 1 && uniqueData[0] > 0) return 0.8; } if (counts.every((c) => c > 0)) return 0.5; return 0; } }; // src/model/detectors/OBJDetector.ts var OBJDetector = class _OBJDetector { contentTypeName = "obj"; // Check for 'v ' (vertex), 'f ' (face), 'vn ', 'vt ' static COMMANDS = ["v ", "vt ", "vn ", "f ", "g ", "o ", "s ", "mtllib ", "usemtl "]; detect(contentSample, lines, firstLine, fileExtension) { const text = typeof contentSample === "string" ? contentSample : new TextDecoder().decode(contentSample); let confidence = 0; if (fileExtension && fileExtension.toLowerCase() === ".obj") { confidence = Math.max(confidence, 0.95); } const validLines = lines.filter((l) => l.trim().length > 0 && !l.trim().startsWith("#")); let commandCount = 0; for (const line of validLines.slice(0, 20)) { const trimmed = line.trim(); for (const cmd of _OBJDetector.COMMANDS) { if (trimmed.startsWith(cmd)) { commandCount++; break; } } } if (commandCount >= 2) { if (commandCount > 10) confidence = Math.max(confidence, 0.9); else if (commandCount > 5) confidence = Math.max(confidence, 0.8); else confidence = Math.max(confidence, 0.7); } const codeKeywords = ["def ", "class ", "import ", "function ", "var ", "let ", "const "]; if (codeKeywords.some((k) => text.includes(k))) { return 0; } return Math.min(confidence, 1); } getMimeType(contentSample, lines, firstLine, fileExtension) { return this.detect(contentSample, lines, firstLine, fileExtension) > 0.5 ? "application/3d-obj" : "text/plain"; } }; // src/model/detectors/registry.ts var DetectorRegistry = class { detectors; constructor() { this.detectors = [ new BinarySignatureDetector(), // Programming languages new ProgrammingLanguageDetector(), // Structured data new XMLDetector(), new JSONDetector(), new OBJDetector(), // Markup new MarkdownDetector(), // Data formats (lower priority) new SQLDetector(), new CSVDetector(), new YAMLDetector(), // Fallback new PlainTextDetector() ]; } /** * Detect content type and return the most likely MIME type. */ detect(contentSample, lines, firstLine, fileExtension) { const hasComma = lines.some((l) => l.includes(",")); if (hasComma) { if (lines.length < 3) { const commaLines = lines.filter((l) => l.includes(",")).length; if (commaLines > 0 && commaLines === lines.length) { const delimCounts = lines.filter((l) => l.trim()).map((l) => (l.match(/,/g) || []).length); if (delimCounts.length > 0 && delimCounts.every((c) => c <= 2)) { return "text/plain"; } } } } let bestConfidence = 0; let bestMime = "text/plain"; for (const detector of this.detectors) { const confidence = detector.detect(contentSample, lines, firstLine, fileExtension); if (confidence > bestConfidence) { const mime = detector.getMimeType(contentSample, lines, firstLine, fileExtension); if (mime) { bestConfidence = confidence; bestMime = mime; if (confidence >= 0.99) break; } } } return bestMime; } }; var registry = new DetectorRegistry(); // src/model/ContentTypeInterpreter.ts var ContentTypeInterpreter = class { static MIME_TO_EXT = { "text/plain": ".txt", "application/json": ".json", "text/csv": ".csv", "text/x-python": ".py", "text/javascript": ".js", "text/jsx": ".jsx", "text/typescript": ".ts", "text/x-c": ".c", "text/x-c++": ".cpp", "application/xml": ".xml", "text/html": ".html", "application/x-yaml": ".yaml", "text/markdown": ".md", "text/x-sql": ".sql", "image/png": ".png", "image/jpeg": ".jpg", "image/gif": ".gif", "image/bmp": ".bmp", "image/x-icon": ".ico", "image/webp": ".webp", "image/svg+xml": ".svg", "application/pdf": ".pdf", "application/zip": ".zip", "application/gzip": ".gz", "application/x-rar-compressed": ".rar", "application/x-7z-compressed": ".7z", "application/x-sqlite3": ".db", "audio/wav": ".wav" // Add more as needed }; /** * Convenience method to detect MIME type only. * Matches the API expected by MCard/PCard/VCard. */ static detect(content) { return this.detectContentType(content).mimeType; } /** * Detect content type and suggest extension. * * @param content Content string or binary buffer * @param fileExtension Optional file extension hint * @returns Object containing detected mimeType and suggested extension */ static detectContentType(content, fileExtension) { let lines = []; let firstLine = ""; let textSample = ""; if (typeof content === "string") { textSample = content.slice(0, 8192); } else { textSample = new TextDecoder("utf-8", { fatal: false }).decode(content.slice(0, 8192)); } lines = textSample.split("\n").slice(0, 20); firstLine = lines[0] || ""; const mimeType = registry.detect(content, lines, firstLine, fileExtension); let extension = this.getExtension(mimeType); if (fileExtension && extension) { if (fileExtension.toLowerCase() === extension || fileExtension.toLowerCase() === `.${extension}`) { extension = fileExtension; } } if (!extension && fileExtension) { extension = fileExtension; } if (!extension) { extension = ".txt"; } return { mimeType, extension }; } static getExtension(mimeType) { return this.MIME_TO_EXT[mimeType] || ""; } /** * Check if content should be treated as binary. */ static isBinaryContent(content, mimeType) { if (mimeType) { if (mimeType.startsWith("text/") || mimeType.includes("json") || mimeType.includes("xml") || mimeType.includes("javascript") || mimeType.includes("ecmascript")) { return false; } return true; } if (typeof content === "string") return false; const detection = this.detectContentType(content); return !detection.mimeType.startsWith("text/") && !detection.mimeType.includes("json") && !detection.mimeType.includes("xml"); } static isKnownLongLineExtension(extension) { if (!extension) return false; const ext = extension.toLowerCase(); return [".min.js", ".min.css", ".map", ".svg", ".json", ".geojson"].some((e) => ext.endsWith(e)); } static isUnstructuredBinary(sample) { if (sample.length < 512) return false; let nullCount = 0; let controlCount = 0; const len = Math.min(sample.length, 32 * 1024); for (let i = 0; i < len; i++) { const byte = sample[i]; if (byte === 0) { nullCount++; } if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) { controlCount++; } } const nullRatio = nullCount / len; const controlRatio = controlCount / len; return nullRatio > 0.1 || controlRatio > 0.2; } static hasPathologicalLines(sample, isKnownType) { if (isKnownType || sample.length < 32768) return false; for (let i = 0; i < sample.length; i++) { if (sample[i] === 10 || sample[i] === 13) return false; } return true; } }; // src/types/dots.ts function createMCardDOTSMetadata(tightRefs = [], looseRefs = []) { return { role: "Carrier" /* CARRIER */, eosRole: "InvariantContent" /* INVARIANT_CONTENT */, plane: "Data" /* DATA */, tightRefs, looseRefs }; } // src/model/MCard.ts var MCard = class _MCard { content; hash; g_time; contentType; // Defaulting to specific string or null hashFunction; constructor(content, hash, g_time, contentType, hashFunction) { this.content = content; this.hash = hash; this.g_time = g_time; this.contentType = contentType; this.hashFunction = hashFunction; } /** * Create a new MCard from content */ static async create(content, hashAlgorithm = "sha256") { if (content === null || content === void 0) { throw new Error("Content cannot be null or undefined"); } const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content; if (bytes.length === 0) { throw new Error("Content cannot be empty"); } const hash = await HashValidator.computeHash(bytes, hashAlgorithm); const g_time = GTime.stampNow(hashAlgorithm); const contentType = ContentTypeInterpreter.detect(bytes); return new _MCard(bytes, hash, g_time, contentType, hashAlgorithm); } /** * Create an MCard from existing data (e.g., from database) */ static fromData(content, hash, g_time) { const alg = GTime.getHashAlgorithm(g_time); const contentType = ContentTypeInterpreter.detect(content); return new _MCard(content, hash, g_time, contentType, alg); } /** * Get content as text (UTF-8 decoded) */ getContentAsText() { return new TextDecoder().decode(this.content); } /** * Get content as raw bytes */ getContent() { return this.content; } /** * Convert to plain object */ toObject() { return { hash: this.hash, content: this.getContentAsText(), g_time: this.g_time, contentType: this.contentType, hashFunction: this.hashFunction }; } /** * Get DOTS vocabulary metadata for this MCard * * Returns the DOTS role information that positions this MCard * in the Double Operadic Theory of Systems framework. * * MCard is always a CARRIER object in the Data Plane. * * @param tightRefs - Optional array of prerequisite MCard hashes (vertical composition) * @param looseRefs - Optional array of alternative MCard hashes (horizontal composition) * @returns DOTSMetadata describing this card's role in the compositional system * * @example * ```typescript * const card = await MCard.create('Hello World'); * const meta = card.getDOTSMetadata(); * console.log(meta.role); // 'Carrier' * console.log(meta.plane); // 'Data' * ``` */ getDOTSMetadata(tightRefs = [], looseRefs = []) { return createMCardDOTSMetadata(tightRefs, looseRefs); } }; // src/model/Handle.ts var MAX_HANDLE_LENGTH = 255; function isValidStartChar(char) { return /^\p{L}$/u.test(char); } function isValidBodyChar(char) { return /^[\p{L}\p{N}_./ -]$/u.test(char); } var HandleValidationError = class extends Error { constructor(message) { super(message); this.name = "HandleValidationError"; } }; function validateHandle(handle) { if (!handle) { throw new HandleValidationError("Handle cannot be empty."); } const normalized = handle.trim().normalize("NFC").toLowerCase(); if (normalized.length === 0) { throw new HandleValidationError("Handle cannot be empty after normalization."); } if (normalized.length > MAX_HANDLE_LENGTH) { throw new HandleValidationError( `Handle '${handle}' is too long (${normalized.length} chars). Maximum is ${MAX_HANDLE_LENGTH}.` ); } if (!isValidStartChar(normalized[0])) { throw new HandleValidationError( `Invalid handle '${handle}'. Must start with a letter (any language).` ); } for (let i = 1; i < normalized.length; i++) { if (!isValidBodyChar(normalized[i])) { throw new HandleValidationError( `Invalid character '${normalized[i]}' at position ${i} in handle '${handle}'.` ); } } return normalized; } // src/storage/schema_constants.ts 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 -- MCard Unified Database Schema (Monadic Core) -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- -- STABILITY WARNING: This schema is the invariant "seeding meta-language" for all -- Domain Specific Languages (DSLs). It must remain as stable as possible. -- -- THE UNIFICATION THESIS: -- This design unites three distinct namespaces into a single relational network -- by leveraging the power of cryptographic hash functions: -- 1. CONTENT SPACE (Intrinsic Identity): Content-Addressable Storage (CAS). -- 2. HANDLE SPACE (Reserved Words): Mapping human logic to content hashes. -- 3. VERSION SPACE (Temporal Evolution): Tracking state transitions via hash history. -- -- TURING MACHINE ANALOGY (The Infinitely Long Tape): -- The \`card\` table stores content blobs with unique identities, emulating the -- "Infinitely Long Tape" of the Turing Machine formalism. By using relational -- queries, this tape can be dynamically constructed and traversed for different -- DSLs, providing a flexible substrate for practically all computable languages. -- -- By using hash values as the universal primitives across content, handles, and -- time, we create a "Wordless Book" \u2014 a minimal substrate capable of seeding any -- domain-specific knowledge system without requiring schema changes. -- -- Monadic Mapping (See: Monadic Justification for Schema Design.md): -- 1. Card = Monad (Perception/State/Exponent) - Intrinsic Identity -- 2. Handle = Registry (Appetition/Reader/Sum) - Mutable Reference -- 3. Version = History (Harmony/Writer/Product) - Coordinated Evolution -- -- Version: 3.0.2 (Turing Tape Refinement) -- Last Updated: 2025-12-20 -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- LAYER 1: CORE CONTENT-ADDRESSABLE STORAGE (The Monad / Exponent) -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- The fundamental MCard storage: content-addressed by cryptographic hash. -- "Each Monad ... mirrors the universe" -- @table card -- @description Core content-addressable storage table (Monad/State) -- @column hash - SHA-256 hash of content (primary key) -- @column content - The actual content (BLOB for binary safety) -- @column g_time - Generation timestamp (ISO 8601) CREATE TABLE IF NOT EXISTS card ( hash TEXT PRIMARY KEY, content BLOB NOT NULL, g_time TEXT NOT NULL ); -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- LAYER 2: HANDLE SYSTEM (Appetition / Sum) -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- The mutable pointer that "desires" to reference new content. -- "Appetition: the tendency to move to new states" -- @table handle_registry (Monadic Role: Handle) -- @description Maps human-readable handles to current content hashes -- @column handle - UTF-8 handle name (primary key) -- @column current_hash - FK to card.hash of current version -- @column created_at - When handle was first created -- @column updated_at - When handle was last updated CREATE TABLE IF NOT EXISTS handle_registry ( handle TEXT PRIMARY KEY, current_hash TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (current_hash) REFERENCES card(hash) ); -- @index idx_handle_current_hash -- @description Efficient reverse lookup from hash to handles CREATE INDEX IF NOT EXISTS idx_handle_current_hash ON handle_registry(current_hash); -- @table handle_history (Monadic Role: Version / Product) -- @description Audit trail for handle pointer changes (Pre-Established Harmony) -- @column id - Auto-increment primary key -- @column handle - The handle that was updated -- @column previous_hash - Hash it pointed to before update -- @column changed_at - When the change occurred CREATE TABLE IF NOT EXISTS handle_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, handle TEXT NOT NULL, previous_hash TEXT NOT NULL, changed_at TEXT NOT NULL, FOREIGN KEY (handle) REFERENCES handle_registry(handle), FOREIGN KEY (previous_hash) REFERENCES card(hash) ); -- @index idx_handle_history_handle -- @description Efficient lookup of history by handle CREATE INDEX IF NOT EXISTS idx_handle_history_handle ON handle_history(handle); -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- LEGACY SUPPORT: FTS5 Documents Table -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- KEPT FOR BACKWARD COMPATIBILITY with existing codebase. -- New implementations should use mcard_vector_schema.sql -> mcard_fts -- @virtual_table documents -- @description Legacy FTS table for backward compatibility -- @note Synced with card table via triggers CREATE VIRTUAL TABLE IF NOT EXISTS documents USING fts5(content); -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- SCHEMA METADATA -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- @table schema_version -- @description Tracks schema version for migrations CREATE TABLE IF NOT EXISTS schema_version ( version TEXT PRIMARY KEY, applied_at TEXT NOT NULL, description TEXT ); -- Insert current schema version INSERT OR IGNORE INTO schema_version (version, applied_at, description) VALUES ('3.0.0', datetime('now'), 'Monadic Core Schema (split vectors to mcard_vector_schema.sql)'); `; 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 -- MCard Vector Database Schema (mcard_vectors.db) -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- -- This schema defines the structure for "Secondary Qualities" (Extrinsic Embeddings). -- It is separated from the core mcard.db (Monadic Intrinsic Properties) to ensure: -- 1. Separation of Concerns (Intrinsic vs Extrinsic) -- 2. Linearity (Vectors are observer-dependent and large) -- 3. Upgradability (Embedding models change frequently) -- -- See: Monadic Justification for Schema Design.md -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- LAYER 3: VECTOR STORAGE (Semantic Embeddings) -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -- Storage for vector embeddings enabling semantic search. -- Links to content via hash for content-addressing. -- @table mcard_vector_metadata -- @description Metadata for stored embeddings -- @column id - Auto-increment primary key -- @co