refactor(enclave): remove IPFS integration

This commit is contained in:
2026-01-07 21:05:27 -05:00
parent f3a372123f
commit 2decc7a154
4 changed files with 7 additions and 193 deletions

View File

@@ -1,8 +1,6 @@
import { createEnclave } from '../dist/enclave.js';
let enclave = null;
let helia = null;
let lastCID = null;
let lastDatabase = null;
const LogLevel = { INFO: 'info', OK: 'ok', ERR: 'err', DATA: 'data' };
@@ -35,19 +33,6 @@ function setStatus(id, ok, message) {
}
}
function setCID(cid) {
const el = document.getElementById('cid-display');
const input = document.getElementById('cid-input');
if (el && cid) {
el.textContent = `CID: ${cid}`;
el.classList.add('visible');
}
if (input && cid) {
input.value = cid;
}
lastCID = cid;
}
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binary = '';
@@ -100,37 +85,14 @@ async function createWebAuthnCredential() {
};
}
async function initHelia() {
try {
setStatus('ipfs-status', null, 'IPFS...');
log('generate', LogLevel.INFO, 'Initializing IPFS (Helia)...');
const { createHelia } = await import('helia');
helia = await createHelia();
setStatus('ipfs-status', true, 'IPFS Ready');
log('generate', LogLevel.OK, 'IPFS initialized');
return helia;
} catch (err) {
setStatus('ipfs-status', false, 'IPFS Failed');
log('generate', LogLevel.ERR, `IPFS init failed: ${err?.message || String(err)}`);
return null;
}
}
async function init() {
try {
log('generate', LogLevel.INFO, 'Loading enclave.wasm...');
await initHelia();
enclave = await createEnclave('./enclave.wasm', {
debug: true,
ipfs: helia
});
enclave = await createEnclave('./enclave.wasm', { debug: true });
setStatus('status', true, 'Ready');
log('generate', LogLevel.OK, `Plugin loaded (IPFS: ${enclave.ipfsEnabled ? 'enabled' : 'disabled'})`);
log('generate', LogLevel.OK, 'Plugin loaded');
} catch (err) {
setStatus('status', false, 'Failed');
log('generate', LogLevel.ERR, `Load failed: ${err?.message || String(err)}`);
@@ -178,12 +140,6 @@ window.testGenerate = async function() {
const result = await enclave.generate(credentialBase64);
const logData = { did: result.did, dbSize: result.database?.length };
if (result.cid) {
logData.cid = result.cid;
setCID(result.cid);
log('generate', LogLevel.OK, `Stored to IPFS: ${result.cid}`);
}
log('generate', LogLevel.OK, `DID created: ${result.did}`, logData);
if (result.database) {
@@ -219,12 +175,6 @@ window.testGenerateMock = async function() {
const result = await enclave.generate(mockCredential);
const logData = { did: result.did, dbSize: result.database?.length };
if (result.cid) {
logData.cid = result.cid;
setCID(result.cid);
log('generate', LogLevel.OK, `Stored to IPFS: ${result.cid}`);
}
log('generate', LogLevel.OK, `DID created: ${result.did}`, logData);
if (result.database) {
@@ -237,34 +187,6 @@ window.testGenerateMock = async function() {
}
};
window.testLoadFromCID = async function() {
if (!enclave) return log('load', LogLevel.ERR, 'Plugin not loaded');
const cid = document.getElementById('cid-input').value;
if (!cid) return log('load', LogLevel.ERR, 'No CID - run generate first');
if (!cid.startsWith('bafy')) {
log('load', LogLevel.ERR, 'Invalid CID format (should start with bafy...)');
return;
}
log('load', LogLevel.INFO, `Loading from IPFS: ${cid}`);
try {
const result = await enclave.load(cid);
if (result.success) {
log('load', LogLevel.OK, `Loaded DID: ${result.did}`, result);
} else {
log('load', LogLevel.ERR, result.error, result);
}
return result;
} catch (err) {
log('load', LogLevel.ERR, err?.message || String(err));
throw err;
}
};
window.testLoadFromBytes = async function() {
if (!enclave) return log('load', LogLevel.ERR, 'Plugin not loaded');
@@ -346,7 +268,7 @@ window.runAllTests = async function() {
try {
await testPing();
await testGenerateMock();
await testLoadFromCID();
await testLoadFromBytes();
await testExec();
await testQuery();
log('query', LogLevel.OK, '=== All tests passed ===');

View File

@@ -15,7 +15,7 @@
"dist"
],
"scripts": {
"build": "bun build ./src/index.ts --outdir ./dist --format esm --target browser --sourcemap=external --external @extism/extism --external @helia/unixfs --external multiformats/cid --external helia --entry-naming enclave.js && bun run tsc --emitDeclarationOnly --declaration -p src/tsconfig.json --outDir dist",
"build": "bun build ./src/index.ts --outdir ./dist --format esm --target browser --sourcemap=external --external @extism/extism --entry-naming enclave.js && bun run tsc --emitDeclarationOnly --declaration -p src/tsconfig.json --outDir dist",
"typecheck": "tsc --noEmit -p src/tsconfig.json",
"clean": "rm -rf dist"
},
@@ -28,10 +28,5 @@
},
"peerDependencies": {
"@extism/extism": "^2.0.0-rc13"
},
"optionalDependencies": {
"@helia/unixfs": "^4.0.0",
"helia": "^5.0.0",
"multiformats": "^13.0.0"
}
}

View File

@@ -6,26 +6,17 @@ import type {
ExecOutput,
QueryOutput,
Resource,
HeliaInstance,
} from './types';
type UnixFS = {
addBytes(bytes: Uint8Array): Promise<{ toString(): string }>;
cat(cid: { toString(): string }): AsyncIterable<Uint8Array>;
};
export class Enclave {
private plugin: Plugin;
private logger: EnclaveOptions['logger'];
private debug: boolean;
private helia: HeliaInstance | null;
private unixfs: UnixFS | null = null;
private constructor(plugin: Plugin, options: EnclaveOptions = {}) {
this.plugin = plugin;
this.logger = options.logger ?? console;
this.debug = options.debug ?? false;
this.helia = options.ipfs ?? null;
}
static async create(
@@ -43,21 +34,7 @@ export class Enclave {
logger: options.debug ? (options.logger as Console) : undefined,
});
const enclave = new Enclave(plugin, options);
if (options.ipfs) {
await enclave.initIPFS();
}
return enclave;
}
private async initIPFS(): Promise<void> {
if (!this.helia) return;
const { unixfs } = await import('@helia/unixfs');
this.unixfs = unixfs(this.helia as Parameters<typeof unixfs>[0]);
this.log('IPFS initialized');
return new Enclave(plugin, options);
}
async generate(credential: string): Promise<GenerateOutput> {
@@ -68,47 +45,16 @@ export class Enclave {
if (!result) throw new Error('generate: plugin returned no output');
const output = result.json() as GenerateOutput;
if (this.unixfs && output.database) {
const bytes = new Uint8Array(output.database);
const cid = await this.unixfs.addBytes(bytes);
output.cid = cid.toString();
this.log(`generate: stored to IPFS ${output.cid}`);
}
this.log(`generate: created DID ${output.did}`);
return output;
}
async load(source: string | Uint8Array | number[]): Promise<LoadOutput> {
async load(source: Uint8Array | number[]): Promise<LoadOutput> {
this.log('load: loading database');
let database: number[];
if (typeof source === 'string' && source.startsWith('bafy')) {
if (!this.unixfs) {
throw new Error('load: IPFS not configured, cannot resolve CID');
}
this.log(`load: fetching from IPFS ${source}`);
const { CID } = await import('multiformats/cid');
const cid = CID.parse(source);
const chunks: Uint8Array[] = [];
for await (const chunk of this.unixfs.cat(cid)) {
chunks.push(chunk);
}
const totalLength = chunks.reduce((acc, c) => acc + c.length, 0);
const bytes = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
bytes.set(chunk, offset);
offset += chunk.length;
}
database = Array.from(bytes);
this.log(`load: fetched ${database.length} bytes from IPFS`);
} else if (source instanceof Uint8Array) {
if (source instanceof Uint8Array) {
database = Array.from(source);
} else if (Array.isArray(source)) {
database = source;
@@ -130,41 +76,6 @@ export class Enclave {
return output;
}
async storeToIPFS(data: Uint8Array): Promise<string> {
if (!this.unixfs) {
throw new Error('storeToIPFS: IPFS not configured');
}
const cid = await this.unixfs.addBytes(data);
this.log(`storeToIPFS: stored ${data.length} bytes as ${cid.toString()}`);
return cid.toString();
}
async fetchFromIPFS(cidString: string): Promise<Uint8Array> {
if (!this.unixfs) {
throw new Error('fetchFromIPFS: IPFS not configured');
}
const { CID } = await import('multiformats/cid');
const cid = CID.parse(cidString);
const chunks: Uint8Array[] = [];
for await (const chunk of this.unixfs.cat(cid)) {
chunks.push(chunk);
}
const totalLength = chunks.reduce((acc, c) => acc + c.length, 0);
const bytes = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
bytes.set(chunk, offset);
offset += chunk.length;
}
this.log(`fetchFromIPFS: fetched ${bytes.length} bytes from ${cidString}`);
return bytes;
}
async exec(filter: string, token?: string): Promise<ExecOutput> {
this.log(`exec: executing filter "${filter}"`);
@@ -228,10 +139,6 @@ export class Enclave {
await this.plugin.close();
}
get ipfsEnabled(): boolean {
return this.unixfs !== null;
}
private log(message: string, level: 'log' | 'error' | 'warn' | 'info' | 'debug' = 'debug'): void {
if (this.debug && this.logger) {
this.logger[level](`[Enclave] ${message}`);

View File

@@ -17,8 +17,6 @@ export interface GenerateOutput {
did: string;
/** Serialized database buffer for storage */
database: number[];
/** IPFS CID of stored database (if IPFS enabled) */
cid?: string;
}
// ============================================================================
@@ -109,14 +107,6 @@ export interface Credential {
export interface EnclaveOptions {
logger?: Pick<Console, 'log' | 'error' | 'warn' | 'info' | 'debug'>;
debug?: boolean;
ipfs?: HeliaInstance;
}
export interface HeliaInstance {
blockstore: unknown;
datastore: unknown;
start(): Promise<void>;
stop(): Promise<void>;
}
// ============================================================================