/**
* OrbitDB identity provider backed by the persistent Ed25519 seed identity
* (lib/identity.ts). Log entries chain to the durable identity: the provider
* id IS the base64url public key peers already TOFU/verify in the roster, so
* authorship in the replicated log and live presence share one identity.
*
* Wire format (OrbitDB contract, verified against @orbitdb/core 3.x source):
* the device keystore's secp256k1 key signs each entry; the provider links it
* to the durable key by signing the string `publicKey + signatures.id`.
* With replication encryption ON, identities and signatures live inside
* ciphertext — visible to room members only (PROTOCOL.md §7b preserved).
*/
import { useIdentityProvider } from "@orbitdb/core";
import { toB64url, type Bytes } from "./crypto";
import { Identity, verifyRaw } from "./identity";
const te = new TextEncoder();
interface OrbitIdentity {
id: string;
publicKey: string;
signatures: { id: string; publicKey: string };
type: string;
}
interface ProviderInstance {
type: string;
getId(): Promise<string>;
signIdentity(data: string): Promise<string>;
}
export function SuetaIdentityProvider({ identity }: { identity: Identity }): () => Promise<ProviderInstance> {
return async () => ({
type: "sueta",
getId: async () => identity.publicKeyB64,
signIdentity: async (data: string) => toB64url(await identity.signRaw(te.encode(data) as Bytes)),
});
}
SuetaIdentityProvider.type = "sueta";
SuetaIdentityProvider.verifyIdentity = async (identity: OrbitIdentity): Promise<boolean> => {
return verifyRaw(
identity.id,
identity.signatures.publicKey,
te.encode(identity.publicKey + identity.signatures.id) as Bytes,
);
};
let registered = false;
/** Idempotent registration with OrbitDB's provider registry. */
export function registerSuetaProvider(): void {
if (registered) return;
registered = true;
useIdentityProvider(SuetaIdentityProvider as never);
}