UNPKG

@chittyos/core

Version:

ChittyOS Core - Essential package with ID, auth, verification, beacon tracking, and brand components for all ChittyOS applications

342 lines (341 loc) 10.2 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/canon/index.ts var canon_exports = {}; __export(canon_exports, { clearCanonCache: () => clearCanonCache, configure: () => configure, createCanonical: () => createCanonical, default: () => canon_default, getCanonStats: () => getCanonStats, getCanonical: () => getCanonical, getCanonicalHistory: () => getCanonicalHistory, mergeCanonical: () => mergeCanonical, queryCanonical: () => queryCanonical, signCanonical: () => signCanonical, updateCanonical: () => updateCanonical, validateCanonical: () => validateCanonical, verifyCanonicalSignature: () => verifyCanonicalSignature }); module.exports = __toCommonJS(canon_exports); var import_nanoid = require("nanoid"); var crypto = __toESM(require("crypto")); var DEFAULT_CONFIG = { endpoint: process.env.CHITTY_CANON_ENDPOINT || "https://canon.chitty.cc", enableChain: true, enableSignatures: true }; var config = { ...DEFAULT_CONFIG }; var canonCache = /* @__PURE__ */ new Map(); var chainIndex = /* @__PURE__ */ new Map(); function configure(customConfig) { config = { ...config, ...customConfig }; } function createCanonical(data, chittyId, metadata) { const canonId = `CANON_${(0, import_nanoid.nanoid)(21)}`; const timestamp = (/* @__PURE__ */ new Date()).toISOString(); const hash = crypto.createHash("sha256").update(JSON.stringify({ data, chittyId, timestamp })).digest("hex"); const record = { id: (0, import_nanoid.nanoid)(), canonId, version: 1, data, hash, chittyId, timestamp, metadata: { source: metadata?.source || "chittyos-core", tags: metadata?.tags || [], ttl: metadata?.ttl, immutable: metadata?.immutable || false } }; canonCache.set(canonId, record); if (config.enableChain) { chainIndex.set(canonId, [record]); } return record; } function updateCanonical(canonId, data, chittyId) { const existing = canonCache.get(canonId); if (!existing) { return null; } if (existing.metadata?.immutable) { throw new Error("Cannot update immutable canonical record"); } const timestamp = (/* @__PURE__ */ new Date()).toISOString(); const previousHash = existing.hash; const hash = crypto.createHash("sha256").update(JSON.stringify({ data, chittyId, timestamp, previousHash })).digest("hex"); const record = { ...existing, id: (0, import_nanoid.nanoid)(), version: existing.version + 1, data, hash, previousHash, chittyId, timestamp }; canonCache.set(canonId, record); if (config.enableChain) { const chain = chainIndex.get(canonId) || []; chain.push(record); chainIndex.set(canonId, chain); } return record; } async function getCanonical(canonId) { if (canonCache.has(canonId)) { return canonCache.get(canonId); } if (config.storageAdapter) { const record = await config.storageAdapter.get(canonId); if (record) { canonCache.set(canonId, record); return record; } } if (config.endpoint) { try { const response = await fetch(`${config.endpoint}/canon/${canonId}`); if (response.ok) { const record = await response.json(); canonCache.set(canonId, record); return record; } } catch (error) { console.error("[Canon] Failed to fetch from endpoint:", error); } } return null; } function getCanonicalHistory(canonId) { return chainIndex.get(canonId) || []; } function validateCanonical(record) { const errors = []; const warnings = []; if (!record.canonId || !record.canonId.startsWith("CANON_")) { errors.push("Invalid canon ID format"); } if (!record.hash) { errors.push("Missing hash"); } if (!record.chittyId) { errors.push("Missing ChittyID"); } const expectedHash = crypto.createHash("sha256").update(JSON.stringify({ data: record.data, chittyId: record.chittyId, timestamp: record.timestamp, ...record.previousHash && { previousHash: record.previousHash } })).digest("hex"); if (record.hash !== expectedHash) { errors.push("Hash mismatch - data integrity compromised"); } if (record.previousHash && record.version > 1) { const history = getCanonicalHistory(record.canonId); const previousRecord = history[record.version - 2]; if (previousRecord && previousRecord.hash !== record.previousHash) { errors.push("Chain integrity violation - previous hash mismatch"); } } if (record.metadata?.ttl) { const age = Date.now() - new Date(record.timestamp).getTime(); const ttlMs = record.metadata.ttl * 1e3; if (age > ttlMs) { warnings.push("Record has exceeded TTL"); } } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : void 0, warnings: warnings.length > 0 ? warnings : void 0 }; } function signCanonical(record, privateKey) { if (!config.enableSignatures) { return record; } const sign = crypto.createSign("SHA256"); sign.update(record.hash); const signature = sign.sign(privateKey, "base64"); return { ...record, signature }; } function verifyCanonicalSignature(record, publicKey) { if (!record.signature) { return false; } try { const verify = crypto.createVerify("SHA256"); verify.update(record.hash); return verify.verify(publicKey, record.signature, "base64"); } catch (error) { return false; } } function mergeCanonical(records, strategy = "latest", customMerge) { if (records.length === 0) { throw new Error("No records to merge"); } if (records.length === 1) { return records[0]; } let winner; switch (strategy) { case "latest": winner = records.reduce( (latest, record) => new Date(record.timestamp) > new Date(latest.timestamp) ? record : latest ); break; case "highest-version": winner = records.reduce( (highest, record) => record.version > highest.version ? record : highest ); break; case "custom": if (!customMerge) { throw new Error("Custom merge function required"); } const mergedData = customMerge(records); winner = createCanonical( mergedData, records[0].chittyId, { source: "merge", tags: ["merged"] } ); break; default: winner = records[0]; } return { ...winner, metadata: { ...winner.metadata, source: "merge", tags: [...winner.metadata?.tags || [], "merged", `from-${records.length}-records`] } }; } async function queryCanonical(filter) { let results = []; for (const record of canonCache.values()) { let matches = true; if (filter.chittyId && record.chittyId !== filter.chittyId) { matches = false; } if (filter.tags && filter.tags.length > 0) { const recordTags = record.metadata?.tags || []; if (!filter.tags.every((tag) => recordTags.includes(tag))) { matches = false; } } if (filter.source && record.metadata?.source !== filter.source) { matches = false; } if (filter.afterTimestamp && record.timestamp <= filter.afterTimestamp) { matches = false; } if (filter.beforeTimestamp && record.timestamp >= filter.beforeTimestamp) { matches = false; } if (matches) { results.push(record); } } if (config.storageAdapter) { const storedRecords = await config.storageAdapter.list(filter); results = [...results, ...storedRecords]; } const seen = /* @__PURE__ */ new Set(); results = results.filter((record) => { if (seen.has(record.canonId)) { return false; } seen.add(record.canonId); return true; }); return results; } function clearCanonCache() { canonCache.clear(); chainIndex.clear(); } function getCanonStats() { let oldest; let newest; for (const record of canonCache.values()) { if (!oldest || record.timestamp < oldest) { oldest = record.timestamp; } if (!newest || record.timestamp > newest) { newest = record.timestamp; } } return { totalRecords: canonCache.size, totalChains: chainIndex.size, cacheSize: JSON.stringify([...canonCache.values()]).length, oldestRecord: oldest, newestRecord: newest }; } var canon_default = { configure, createCanonical, updateCanonical, getCanonical, getCanonicalHistory, validateCanonical, signCanonical, verifyCanonicalSignature, mergeCanonical, queryCanonical, clearCanonCache, getCanonStats }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { clearCanonCache, configure, createCanonical, getCanonStats, getCanonical, getCanonicalHistory, mergeCanonical, queryCanonical, signCanonical, updateCanonical, validateCanonical, verifyCanonicalSignature }); //# sourceMappingURL=index.js.map