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'; import { createEnclave } from '../dist/enclave.js';
let enclave = null; let enclave = null;
let helia = null;
let lastCID = null;
let lastDatabase = null; let lastDatabase = null;
const LogLevel = { INFO: 'info', OK: 'ok', ERR: 'err', DATA: 'data' }; 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) { function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer); const bytes = new Uint8Array(buffer);
let binary = ''; 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() { async function init() {
try { try {
log('generate', LogLevel.INFO, 'Loading enclave.wasm...'); log('generate', LogLevel.INFO, 'Loading enclave.wasm...');
await initHelia(); enclave = await createEnclave('./enclave.wasm', { debug: true });
enclave = await createEnclave('./enclave.wasm', {
debug: true,
ipfs: helia
});
setStatus('status', true, 'Ready'); setStatus('status', true, 'Ready');
log('generate', LogLevel.OK, `Plugin loaded (IPFS: ${enclave.ipfsEnabled ? 'enabled' : 'disabled'})`); log('generate', LogLevel.OK, 'Plugin loaded');
} catch (err) { } catch (err) {
setStatus('status', false, 'Failed'); setStatus('status', false, 'Failed');
log('generate', LogLevel.ERR, `Load failed: ${err?.message || String(err)}`); 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 result = await enclave.generate(credentialBase64);
const logData = { did: result.did, dbSize: result.database?.length }; 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); log('generate', LogLevel.OK, `DID created: ${result.did}`, logData);
if (result.database) { if (result.database) {
@@ -219,12 +175,6 @@ window.testGenerateMock = async function() {
const result = await enclave.generate(mockCredential); const result = await enclave.generate(mockCredential);
const logData = { did: result.did, dbSize: result.database?.length }; 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); log('generate', LogLevel.OK, `DID created: ${result.did}`, logData);
if (result.database) { 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() { window.testLoadFromBytes = async function() {
if (!enclave) return log('load', LogLevel.ERR, 'Plugin not loaded'); if (!enclave) return log('load', LogLevel.ERR, 'Plugin not loaded');
@@ -346,7 +268,7 @@ window.runAllTests = async function() {
try { try {
await testPing(); await testPing();
await testGenerateMock(); await testGenerateMock();
await testLoadFromCID(); await testLoadFromBytes();
await testExec(); await testExec();
await testQuery(); await testQuery();
log('query', LogLevel.OK, '=== All tests passed ==='); log('query', LogLevel.OK, '=== All tests passed ===');

View File

@@ -15,7 +15,7 @@
"dist" "dist"
], ],
"scripts": { "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", "typecheck": "tsc --noEmit -p src/tsconfig.json",
"clean": "rm -rf dist" "clean": "rm -rf dist"
}, },
@@ -28,10 +28,5 @@
}, },
"peerDependencies": { "peerDependencies": {
"@extism/extism": "^2.0.0-rc13" "@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, ExecOutput,
QueryOutput, QueryOutput,
Resource, Resource,
HeliaInstance,
} from './types'; } from './types';
type UnixFS = {
addBytes(bytes: Uint8Array): Promise<{ toString(): string }>;
cat(cid: { toString(): string }): AsyncIterable<Uint8Array>;
};
export class Enclave { export class Enclave {
private plugin: Plugin; private plugin: Plugin;
private logger: EnclaveOptions['logger']; private logger: EnclaveOptions['logger'];
private debug: boolean; private debug: boolean;
private helia: HeliaInstance | null;
private unixfs: UnixFS | null = null;
private constructor(plugin: Plugin, options: EnclaveOptions = {}) { private constructor(plugin: Plugin, options: EnclaveOptions = {}) {
this.plugin = plugin; this.plugin = plugin;
this.logger = options.logger ?? console; this.logger = options.logger ?? console;
this.debug = options.debug ?? false; this.debug = options.debug ?? false;
this.helia = options.ipfs ?? null;
} }
static async create( static async create(
@@ -43,21 +34,7 @@ export class Enclave {
logger: options.debug ? (options.logger as Console) : undefined, logger: options.debug ? (options.logger as Console) : undefined,
}); });
const enclave = new Enclave(plugin, options); return 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');
} }
async generate(credential: string): Promise<GenerateOutput> { async generate(credential: string): Promise<GenerateOutput> {
@@ -68,47 +45,16 @@ export class Enclave {
if (!result) throw new Error('generate: plugin returned no output'); if (!result) throw new Error('generate: plugin returned no output');
const output = result.json() as GenerateOutput; 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}`); this.log(`generate: created DID ${output.did}`);
return output; return output;
} }
async load(source: string | Uint8Array | number[]): Promise<LoadOutput> { async load(source: Uint8Array | number[]): Promise<LoadOutput> {
this.log('load: loading database'); this.log('load: loading database');
let database: number[]; let database: number[];
if (typeof source === 'string' && source.startsWith('bafy')) { if (source instanceof Uint8Array) {
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) {
database = Array.from(source); database = Array.from(source);
} else if (Array.isArray(source)) { } else if (Array.isArray(source)) {
database = source; database = source;
@@ -130,41 +76,6 @@ export class Enclave {
return output; 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> { async exec(filter: string, token?: string): Promise<ExecOutput> {
this.log(`exec: executing filter "${filter}"`); this.log(`exec: executing filter "${filter}"`);
@@ -228,10 +139,6 @@ export class Enclave {
await this.plugin.close(); await this.plugin.close();
} }
get ipfsEnabled(): boolean {
return this.unixfs !== null;
}
private log(message: string, level: 'log' | 'error' | 'warn' | 'info' | 'debug' = 'debug'): void { private log(message: string, level: 'log' | 'error' | 'warn' | 'info' | 'debug' = 'debug'): void {
if (this.debug && this.logger) { if (this.debug && this.logger) {
this.logger[level](`[Enclave] ${message}`); this.logger[level](`[Enclave] ${message}`);

View File

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