trellis
Version:
Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications
166 lines (163 loc) • 4.45 kB
JavaScript
import {
__esm,
__require
} from "./chunk-2ESYSVXG.js";
// src/identity/identity.ts
import {
generateKeyPairSync,
sign,
verify,
createPublicKey
} from "crypto";
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
import { join, dirname } from "path";
import { homedir } from "os";
function createIdentity(opts) {
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
const pubDer = publicKey.export({ type: "spki", format: "der" });
const privDer = privateKey.export({ type: "pkcs8", format: "der" });
const rawPub = pubDer.subarray(pubDer.length - 32);
const did = deriveDid(rawPub);
const entityId = `identity:${did}`;
return {
displayName: opts.displayName,
email: opts.email,
publicKey: pubDer.toString("base64"),
privateKey: privDer.toString("base64"),
did,
entityId,
createdAt: (/* @__PURE__ */ new Date()).toISOString()
};
}
function deriveDid(rawPublicKey) {
const multicodec = Buffer.concat([
Buffer.from([237, 1]),
Buffer.from(rawPublicKey)
]);
const encoded = base58btcEncode(multicodec);
return `did:key:z${encoded}`;
}
function signMessage(message, privateKeyBase64) {
const privDer = Buffer.from(privateKeyBase64, "base64");
const privateKey = createPrivateKeyFromDer(privDer);
const sig = sign(null, Buffer.from(message, "utf-8"), privateKey);
return sig.toString("base64");
}
function verifySignature(message, signatureBase64, publicKeyBase64) {
const pubDer = Buffer.from(publicKeyBase64, "base64");
const publicKey = createPublicKey({
key: pubDer,
format: "der",
type: "spki"
});
const sig = Buffer.from(signatureBase64, "base64");
return verify(null, Buffer.from(message, "utf-8"), publicKey, sig);
}
function saveIdentity(trellisDir, identity) {
const filePath = join(trellisDir, IDENTITY_FILE);
if (!existsSync(dirname(filePath))) {
mkdirSync(dirname(filePath), { recursive: true });
}
writeFileSync(filePath, JSON.stringify(identity, null, 2), "utf-8");
}
function loadIdentity(trellisDir) {
const filePath = join(trellisDir, IDENTITY_FILE);
if (!existsSync(filePath)) return null;
try {
return JSON.parse(readFileSync(filePath, "utf-8"));
} catch {
return null;
}
}
function hasIdentity(trellisDir) {
return existsSync(join(trellisDir, IDENTITY_FILE));
}
function toPublicIdentity(identity) {
return {
displayName: identity.displayName,
email: identity.email,
publicKey: identity.publicKey,
did: identity.did,
entityId: identity.entityId,
createdAt: identity.createdAt
};
}
function personIdentityDir() {
return join(homedir(), ".trellis");
}
function personIdentityPath() {
return join(personIdentityDir(), IDENTITY_FILE);
}
function savePersonIdentity(identity) {
saveIdentity(personIdentityDir(), identity);
}
function loadPersonIdentity() {
return loadIdentity(personIdentityDir());
}
function hasPersonIdentity() {
return existsSync(personIdentityPath());
}
function ensurePersonIdentity(opts) {
const existing = loadPersonIdentity();
if (existing) return existing;
const identity = createIdentity({
displayName: opts?.displayName ?? "Anonymous",
email: opts?.email
});
savePersonIdentity(identity);
return identity;
}
function resolveRepoIdentity(trellisDir) {
return loadIdentity(trellisDir) ?? loadPersonIdentity();
}
function createPrivateKeyFromDer(der) {
const { createPrivateKey } = __require("crypto");
return createPrivateKey({
key: der,
format: "der",
type: "pkcs8"
});
}
function base58btcEncode(buf) {
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
let num = BigInt(0);
for (const byte of buf) {
num = num * 256n + BigInt(byte);
}
let encoded = "";
while (num > 0n) {
const rem = Number(num % 58n);
num = num / 58n;
encoded = ALPHABET[rem] + encoded;
}
for (const byte of buf) {
if (byte === 0) {
encoded = "1" + encoded;
} else {
break;
}
}
return encoded || "1";
}
var IDENTITY_FILE;
var init_identity = __esm({
"src/identity/identity.ts"() {
"use strict";
IDENTITY_FILE = "identity.json";
}
});
export {
createIdentity,
signMessage,
verifySignature,
saveIdentity,
loadIdentity,
hasIdentity,
toPublicIdentity,
savePersonIdentity,
loadPersonIdentity,
hasPersonIdentity,
ensurePersonIdentity,
resolveRepoIdentity,
init_identity
};