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());
    });
};
import { AllowAllTenantGate } from './core/tenant-gate.js';
import { DidResolver } from './did/did-resolver.js';
import { EventsGetHandler } from './handlers/events-get.js';
import { messageReplyFromError } from './core/message-reply.js';
import { MessagesGetHandler } from './handlers/messages-get.js';
import { PermissionsGrantHandler } from './handlers/permissions-grant.js';
import { PermissionsRequestHandler } from './handlers/permissions-request.js';
import { PermissionsRevokeHandler } from './handlers/permissions-revoke.js';
import { ProtocolsConfigureHandler } from './handlers/protocols-configure.js';
import { ProtocolsQueryHandler } from './handlers/protocols-query.js';
import { RecordsDeleteHandler } from './handlers/records-delete.js';
import { RecordsQueryHandler } from './handlers/records-query.js';
import { RecordsReadHandler } from './handlers/records-read.js';
import { RecordsWriteHandler } from './handlers/records-write.js';
import { DwnInterfaceName, DwnMethodName, Message } from './core/message.js';
import { DataStoreLevel } from './store/data-store-level.js';
import { EventLogLevel } from './event-log/event-log-level.js';
import { MessageStoreLevel } from './store/message-store-level.js';
export class Dwn {
    constructor(config) {
        this.didResolver = config.didResolver;
        this.tenantGate = config.tenantGate;
        this.messageStore = config.messageStore;
        this.dataStore = config.dataStore;
        this.eventLog = config.eventLog;
        this.methodHandlers = {
            [DwnInterfaceName.Events + DwnMethodName.Get]: new EventsGetHandler(this.didResolver, this.eventLog),
            [DwnInterfaceName.Messages + DwnMethodName.Get]: new MessagesGetHandler(this.didResolver, this.messageStore, this.dataStore),
            [DwnInterfaceName.Permissions + DwnMethodName.Grant]: new PermissionsGrantHandler(this.didResolver, this.messageStore, this.eventLog),
            [DwnInterfaceName.Permissions + DwnMethodName.Request]: new PermissionsRequestHandler(this.didResolver, this.messageStore, this.eventLog),
            [DwnInterfaceName.Permissions + DwnMethodName.Revoke]: new PermissionsRevokeHandler(this.didResolver, this.messageStore, this.eventLog),
            [DwnInterfaceName.Protocols + DwnMethodName.Configure]: new ProtocolsConfigureHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog),
            [DwnInterfaceName.Protocols + DwnMethodName.Query]: new ProtocolsQueryHandler(this.didResolver, this.messageStore, this.dataStore),
            [DwnInterfaceName.Records + DwnMethodName.Delete]: new RecordsDeleteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog),
            [DwnInterfaceName.Records + DwnMethodName.Query]: new RecordsQueryHandler(this.didResolver, this.messageStore, this.dataStore),
            [DwnInterfaceName.Records + DwnMethodName.Read]: new RecordsReadHandler(this.didResolver, this.messageStore, this.dataStore),
            [DwnInterfaceName.Records + DwnMethodName.Write]: new RecordsWriteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog),
        };
    }
    /**
     * Creates an instance of the DWN.
     */
    static create(config) {
        var _a, _b, _c, _d, _e;
        return __awaiter(this, void 0, void 0, function* () {
            // config.didResolver ??= new DidResolver();
            // config.tenantGate ??= new AllowAllTenantGate();
            config !== null && config !== void 0 ? config : (config = {});
            (_a = config.didResolver) !== null && _a !== void 0 ? _a : (config.didResolver = new DidResolver());
            (_b = config.tenantGate) !== null && _b !== void 0 ? _b : (config.tenantGate = new AllowAllTenantGate());
            (_c = config.messageStore) !== null && _c !== void 0 ? _c : (config.messageStore = new MessageStoreLevel());
            (_d = config.dataStore) !== null && _d !== void 0 ? _d : (config.dataStore = new DataStoreLevel());
            (_e = config.eventLog) !== null && _e !== void 0 ? _e : (config.eventLog = new EventLogLevel());
            const dwn = new Dwn(config);
            yield dwn.open();
            return dwn;
        });
    }
    open() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.messageStore.open();
            yield this.dataStore.open();
            yield this.eventLog.open();
        });
    }
    close() {
        return __awaiter(this, void 0, void 0, function* () {
            this.messageStore.close();
            this.dataStore.close();
            this.eventLog.close();
        });
    }
    /**
     * Processes the given DWN message and returns with a reply.
     * @param tenant The tenant DID to route the given message to.
     */
    processMessage(tenant, rawMessage, dataStream) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const errorMessageReply = (_a = yield this.validateTenant(tenant)) !== null && _a !== void 0 ? _a : yield this.validateMessageIntegrity(rawMessage);
            if (errorMessageReply !== undefined) {
                return errorMessageReply;
            }
            const handlerKey = rawMessage.descriptor.interface + rawMessage.descriptor.method;
            const methodHandlerReply = yield this.methodHandlers[handlerKey].handle({
                tenant,
                message: rawMessage,
                dataStream
            });
            return methodHandlerReply;
        });
    }
    /**
     * Handles a `RecordsQuery` message.
     */
    handleRecordsQuery(tenant, message) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const errorMessageReply = (_a = yield this.validateTenant(tenant)) !== null && _a !== void 0 ? _a : yield this.validateMessageIntegrity(message, DwnInterfaceName.Records, DwnMethodName.Query);
            if (errorMessageReply !== undefined) {
                return errorMessageReply;
            }
            const handler = new RecordsQueryHandler(this.didResolver, this.messageStore, this.dataStore);
            return handler.handle({ tenant, message });
        });
    }
    /**
     * Handles a `RecordsRead` message.
     */
    handleRecordsRead(tenant, message) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const errorMessageReply = (_a = yield this.validateTenant(tenant)) !== null && _a !== void 0 ? _a : yield this.validateMessageIntegrity(message, DwnInterfaceName.Records, DwnMethodName.Read);
            if (errorMessageReply !== undefined) {
                return errorMessageReply;
            }
            const handler = new RecordsReadHandler(this.didResolver, this.messageStore, this.dataStore);
            return handler.handle({ tenant, message });
        });
    }
    /**
     * Handles a `MessagesGet` message.
     */
    handleMessagesGet(tenant, message) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const errorMessageReply = (_a = yield this.validateTenant(tenant)) !== null && _a !== void 0 ? _a : yield this.validateMessageIntegrity(message, DwnInterfaceName.Messages, DwnMethodName.Get);
            if (errorMessageReply !== undefined) {
                return errorMessageReply;
            }
            const handler = new MessagesGetHandler(this.didResolver, this.messageStore, this.dataStore);
            return handler.handle({ tenant, message });
        });
    }
    /**
     * Privileged method for writing a pruned initial `RecordsWrite` to a DWN without needing to supply associated data.
     */
    synchronizePrunedInitialRecordsWrite(tenant, message) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const errorMessageReply = (_a = yield this.validateTenant(tenant)) !== null && _a !== void 0 ? _a : yield this.validateMessageIntegrity(message, DwnInterfaceName.Records, DwnMethodName.Write);
            if (errorMessageReply !== undefined) {
                return errorMessageReply;
            }
            const options = {
                skipDataStorage: true,
            };
            const handler = new RecordsWriteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog);
            const methodHandlerReply = yield handler.handle({ tenant, message, options });
            return methodHandlerReply;
        });
    }
    /**
     * Checks tenant gate to see if tenant is allowed.
     * @param tenant The tenant DID to route the given message to.
     * @returns GenericMessageReply if the message has an integrity error, otherwise undefined.
     */
    validateTenant(tenant) {
        return __awaiter(this, void 0, void 0, function* () {
            const isTenant = yield this.tenantGate.isTenant(tenant);
            if (!isTenant) {
                return {
                    status: { code: 401, detail: `${tenant} is not a tenant` }
                };
            }
        });
    }
    /**
     * Validates structure of DWN message
     * @param tenant The tenant DID to route the given message to.
     * @param dwnMessageInterface The interface of DWN message.
     * @param dwnMessageMethod The interface of DWN message.
  
     * @returns GenericMessageReply if the message has an integrity error, otherwise undefined.
     */
    validateMessageIntegrity(rawMessage, expectedInterface, expectedMethod) {
        var _a, _b;
        return __awaiter(this, void 0, void 0, function* () {
            // Verify interface and method
            const dwnInterface = (_a = rawMessage === null || rawMessage === void 0 ? void 0 : rawMessage.descriptor) === null || _a === void 0 ? void 0 : _a.interface;
            const dwnMethod = (_b = rawMessage === null || rawMessage === void 0 ? void 0 : rawMessage.descriptor) === null || _b === void 0 ? void 0 : _b.method;
            if (dwnInterface === undefined || dwnMethod === undefined) {
                return {
                    status: { code: 400, detail: `Both interface and method must be present, interface: ${dwnInterface}, method: ${dwnMethod}` }
                };
            }
            if (expectedInterface !== undefined && expectedInterface !== dwnInterface) {
                return {
                    status: { code: 400, detail: `Expected interface ${expectedInterface}, received ${dwnInterface}` }
                };
            }
            if (expectedMethod !== undefined && expectedMethod !== dwnMethod) {
                return {
                    status: { code: 400, detail: `Expected method ${expectedInterface}${expectedMethod}, received ${dwnInterface}${dwnMethod}` }
                };
            }
            // validate message structure
            try {
                // consider to push this down to individual handlers
                Message.validateJsonSchema(rawMessage);
            }
            catch (error) {
                return messageReplyFromError(error, 400);
            }
        });
    }
}
;
//# sourceMappingURL=dwn.js.map