refactor(enclave): remove IPFS integration
This commit is contained in:
@@ -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 ===');
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
10
src/types.ts
10
src/types.ts
@@ -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>;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user