@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
JavaScript
;
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