var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var g = generator.apply(thisArg, _arguments || []), i, q = [];
    return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
    function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
    function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
    function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
    function fulfill(value) { resume("next", value); }
    function reject(value) { resume("throw", value); }
    function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
import { createHelia } from 'helia';
import { IDBBlockstore } from 'blockstore-idb';
import { IDBDatastore } from 'datastore-idb';
import { createLibp2p } from 'libp2p';
import { noise } from '@chainsafe/libp2p-noise';
import { yamux } from '@chainsafe/libp2p-yamux';
import { circuitRelayTransport } from 'libp2p/circuit-relay';
import { unixfs } from '@helia/unixfs';
import { bootstrap } from '@libp2p/bootstrap';
import { webRTC, webRTCDirect } from '@libp2p/webrtc';
import { webSockets } from '@libp2p/websockets';
import { webTransport } from '@libp2p/webtransport';
import { identifyService } from 'libp2p/identify';
import { multiaddr, protocols } from '@multiformats/multiaddr';
import { stringToCid } from '../../utils/cid';
import { CYBER_GATEWAY_URL } from '../../config';
const libp2pFactory = (datastore, bootstrapList = []) => __awaiter(void 0, void 0, void 0, function* () {
    const libp2p = yield createLibp2p({
        datastore,
        transports: [
            webSockets(),
            webTransport(),
            webRTC({
                rtcConfiguration: {
                    iceServers: [
                        {
                            urls: [
                                'stun:stun.l.google.com:19302',
                                'stun:global.stun.twilio.com:3478',
                                'STUN:freestun.net:3479',
                                'STUN:stun.bernardoprovenzano.net:3478',
                                'STUN:stun.aa.net.uk:3478',
                            ],
                        },
                        {
                            credential: 'free',
                            username: 'free',
                            urls: ['TURN:freestun.net:3479', 'TURNS:freestun.net:5350'],
                        },
                    ],
                },
            }),
            webRTCDirect(),
            circuitRelayTransport({
                discoverRelays: 1,
            }),
        ],
        connectionEncryption: [noise()],
        streamMuxers: [yamux()],
        connectionGater: {
            denyDialMultiaddr: () => {
                return false;
            },
        },
        peerDiscovery: [
            bootstrap({
                list: bootstrapList,
            }),
        ],
        services: {
            identify: identifyService(),
        },
    });
    return libp2p;
});
const addOptionsV0 = {
    cidVersion: 0,
    rawLeaves: false,
};
class HeliaNode {
    constructor() {
        this.nodeType = 'helia';
        this._isStarted = false;
    }
    get config() {
        return { gatewayUrl: CYBER_GATEWAY_URL };
    }
    get isStarted() {
        return this._isStarted;
    }
    init() {
        return __awaiter(this, void 0, void 0, function* () {
            const blockstore = new IDBBlockstore('helia-bs');
            yield blockstore.open();
            const datastore = new IDBDatastore('helia-ds');
            yield datastore.open();
            const bootstrapList = [
                '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
                '/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
                '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
                '/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt',
                '/dns4/swarm.io.cybernode.ai/tcp/443/wss/p2p/QmUgmRxoLtGERot7Y6G7UyF6fwvnusQZfGR15PuE6pY3aB',
            ];
            const libp2p = yield libp2pFactory(datastore, bootstrapList);
            this.node = yield createHelia({ blockstore, datastore, libp2p });
            this.fs = unixfs(this.node);
            if (typeof window !== 'undefined') {
                window.libp2p = libp2p;
                window.node = this.node;
                window.fs = this.fs;
                window.toCid = stringToCid;
            }
            libp2p.addEventListener('peer:connect', (evt) => {
                const peerId = evt.detail.toString();
                const conn = libp2p.getConnections(peerId) || [];
                const transportsByAddr = Object.fromEntries(conn.map((c) => [
                    c.remoteAddr.toString(),
                    c.remoteAddr.protoCodes().map((v) => { var _a; return (_a = protocols(v)) === null || _a === void 0 ? void 0 : _a.name; }),
                ]));
                console.debug(`Connected to ${peerId}`, transportsByAddr);
            });
            libp2p.addEventListener('peer:disconnect', (evt) => {
                console.debug(`Disconnected from ${evt.detail.toString()}`);
            });
            console.log('IPFS - Helia addrs', libp2p.getMultiaddrs().map((a) => a.toString()));
            this._isStarted = true;
        });
    }
    stat(cid, options = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.fs.stat(stringToCid(cid), options).then((result) => {
                const { type, fileSize, localFileSize, blocks, dagSize, mtime } = result;
                return {
                    type,
                    size: fileSize || -1,
                    sizeLocal: localFileSize || -1,
                    blocks,
                };
            });
        });
    }
    cat(cid, options = {}) {
        return this.fs.cat(stringToCid(cid), options);
    }
    add(content, options = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            const optionsV0 = Object.assign(Object.assign({}, options), addOptionsV0);
            let cid;
            if (content instanceof File) {
                const fileName = content.name;
                const arrayBuffer = yield content.arrayBuffer();
                const data = new Uint8Array(arrayBuffer);
                cid = yield this.fs.addFile({ path: fileName, content: data }, optionsV0);
            }
            else {
                const data = new TextEncoder().encode(content);
                cid = yield this.fs.addBytes(data, optionsV0);
            }
            console.log('----added to helia', cid.toString());
            this.pin(cid.toString(), options);
            return cid.toString();
        });
    }
    pin(cid, options = {}) {
        var _a, _b, _c;
        return __awaiter(this, void 0, void 0, function* () {
            const cid_ = stringToCid(cid);
            const isPinned = yield ((_a = this.node) === null || _a === void 0 ? void 0 : _a.pins.isPinned(cid_, options));
            if (!isPinned) {
                const pinResult = (_c = (yield ((_b = this.node) === null || _b === void 0 ? void 0 : _b.pins.add(cid_, options)))) === null || _c === void 0 ? void 0 : _c.cid.toString();
            }
            return undefined;
        });
    }
    getPeers() {
        return __awaiter(this, void 0, void 0, function* () {
            return this.node.libp2p.getConnections().map((c) => c.remotePeer.toString());
        });
    }
    stop() {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            yield ((_a = this.node) === null || _a === void 0 ? void 0 : _a.stop());
        });
    }
    start() {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            yield ((_a = this.node) === null || _a === void 0 ? void 0 : _a.start());
        });
    }
    connectPeer(address) {
        return __awaiter(this, void 0, void 0, function* () {
            const conn = yield this.node.libp2p.dial(multiaddr(address));
            return true;
        });
    }
    mapToLsResult(iterable) {
        return __asyncGenerator(this, arguments, function* mapToLsResult_1() {
            var _a, e_1, _b, _c;
            try {
                for (var _d = true, iterable_1 = __asyncValues(iterable), iterable_1_1; iterable_1_1 = yield __await(iterable_1.next()), _a = iterable_1_1.done, !_a;) {
                    _c = iterable_1_1.value;
                    _d = false;
                    try {
                        const item = _c;
                        const { cid, metadata } = item;
                        yield yield __await({ cid: cid.toV0(), metadata, type: 'recursive' });
                    }
                    finally {
                        _d = true;
                    }
                }
            }
            catch (e_1_1) { e_1 = { error: e_1_1 }; }
            finally {
                try {
                    if (!_d && !_a && (_b = iterable_1.return)) yield __await(_b.call(iterable_1));
                }
                finally { if (e_1) throw e_1.error; }
            }
        });
    }
    ls() {
        const result = this.mapToLsResult(this.node.pins.ls());
        return result;
    }
    info() {
        return __awaiter(this, void 0, void 0, function* () {
            const id = this.node.libp2p.peerId.toString();
            const agentVersion = this.node.libp2p.services.identify.host
                .agentVersion;
            return { id, agentVersion, repoSize: -1 };
        });
    }
}
export default HeliaNode;
//# sourceMappingURL=helia.js.map