const require_rolldown_runtime = require('../../../../../../_virtual/rolldown_runtime.js');
const require_decorateMetadata = require('../../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateMetadata.js');
const require_decorate = require('../../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js');
const require_Ed25119Sig2018 = require('../models/did/publicKey/Ed25119Sig2018.js');
const require_ReferencedAuthentication = require('../models/did/authentication/ReferencedAuthentication.js');
const require_index = require('../models/did/authentication/index.js');
const require_DidDoc = require('../models/did/DidDoc.js');
const require_DidCommConnection = require('../models/DidCommConnection.js');
const require_DidCommDidExchangeState = require('../models/DidCommDidExchangeState.js');
const require_DidCommDidExchangeRole = require('../models/DidCommDidExchangeRole.js');
const require_DidCommHandshakeProtocol = require('../models/DidCommHandshakeProtocol.js');
require('../models/index.js');
const require_DidCommConnectionRequestMessage = require('../messages/DidCommConnectionRequestMessage.js');
const require_DidCommConnectionResponseMessage = require('../messages/DidCommConnectionResponseMessage.js');
const require_DidCommTrustPingMessage = require('../messages/DidCommTrustPingMessage.js');
require('../messages/index.js');
const require_ConnectionProblemReportError = require('../errors/ConnectionProblemReportError.js');
const require_ConnectionProblemReportReason = require('../errors/ConnectionProblemReportReason.js');
require('../errors/index.js');
const require_index$4 = require('../../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/cjs/index.js');
const require_DidCommOutOfBandState = require('../../oob/domain/DidCommOutOfBandState.js');
const require_DidCommConnectionRecord = require('../repository/DidCommConnectionRecord.js');
const require_decorateParam = require('../../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateParam.js');
const require_DidCommConnectionRepository = require('../repository/DidCommConnectionRepository.js');
require('../repository/index.js');
const require_index$6 = require('../../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/cjs/operators/index.js');
const require_SignatureDecoratorUtils = require('../../../decorators/signature/SignatureDecoratorUtils.js');
const require_helpers = require('./helpers.js');
const require_DidCommOutOfBandRole = require('../../oob/domain/DidCommOutOfBandRole.js');
const require_DidCommOutOfBandInvitation = require('../../oob/messages/DidCommOutOfBandInvitation.js');
require('../../oob/messages/index.js');
const require_DidCommOutOfBandRepository = require('../../oob/repository/DidCommOutOfBandRepository.js');
require('../../oob/repository/index.js');
const require_DidCommOutOfBandService = require('../../oob/DidCommOutOfBandService.js');
const require_outOfBandRecordMetadataTypes = require('../../oob/repository/outOfBandRecordMetadataTypes.js');
const require_DidCommConnectionEvents = require('../DidCommConnectionEvents.js');
let __credo_ts_core = require("@credo-ts/core");
__credo_ts_core = require_rolldown_runtime.__toESM(__credo_ts_core);

//#region ../didcomm/src/modules/connections/services/DidCommConnectionService.ts
var import_cjs = /* @__PURE__ */ require_rolldown_runtime.__toESM(require_index$4.require_cjs());
var import_operators = /* @__PURE__ */ require_rolldown_runtime.__toESM(require_index$6.require_operators());
var _ref, _ref2, _ref3;
let DidCommConnectionService = class DidCommConnectionService$1 {
	constructor(logger, connectionRepository, didRepository, eventEmitter) {
		this.connectionRepository = connectionRepository;
		this.didRepository = didRepository;
		this.eventEmitter = eventEmitter;
		this.logger = logger;
	}
	/**
	* Create a connection request message for a given out-of-band.
	*
	* @param outOfBandRecord out-of-band record for which to create a connection request
	* @param config config for creation of connection request
	* @returns outbound message containing connection request
	*/
	async createRequest(agentContext, outOfBandRecord, config) {
		this.logger.debug(`Create message ${require_DidCommConnectionRequestMessage.DidCommConnectionRequestMessage.type.messageTypeUri} start`, outOfBandRecord);
		outOfBandRecord.assertRole(require_DidCommOutOfBandRole.DidCommOutOfBandRole.Receiver);
		outOfBandRecord.assertState(require_DidCommOutOfBandState.DidCommOutOfBandState.PrepareResponse);
		const { outOfBandInvitation } = outOfBandRecord;
		const { mediatorId } = config.routing;
		const { didDoc, keys } = this.createDidDoc(config.routing);
		const [invitationDid] = outOfBandInvitation.invitationDids;
		const { did: peerDid } = await this.createDid(agentContext, {
			role: __credo_ts_core.DidDocumentRole.Created,
			didDoc,
			keys
		});
		const { label, imageUrl } = config;
		const connectionRequest = new require_DidCommConnectionRequestMessage.DidCommConnectionRequestMessage({
			label,
			did: didDoc.id,
			didDoc,
			imageUrl
		});
		connectionRequest.setThread({
			threadId: connectionRequest.threadId,
			parentThreadId: outOfBandRecord.outOfBandInvitation.id
		});
		const connectionRecord = await this.createConnection(agentContext, {
			protocol: require_DidCommHandshakeProtocol.DidCommHandshakeProtocol.Connections,
			role: require_DidCommDidExchangeRole.DidCommDidExchangeRole.Requester,
			state: require_DidCommDidExchangeState.DidCommDidExchangeState.InvitationReceived,
			theirLabel: outOfBandInvitation.label,
			alias: config?.alias,
			did: peerDid,
			mediatorId,
			autoAcceptConnection: config?.autoAcceptConnection,
			outOfBandId: outOfBandRecord.id,
			invitationDid,
			imageUrl: outOfBandInvitation.imageUrl,
			threadId: connectionRequest.threadId
		});
		await this.updateState(agentContext, connectionRecord, require_DidCommDidExchangeState.DidCommDidExchangeState.RequestSent);
		return {
			connectionRecord,
			message: connectionRequest
		};
	}
	async processRequest(messageContext, outOfBandRecord) {
		this.logger.debug(`Process message ${require_DidCommConnectionRequestMessage.DidCommConnectionRequestMessage.type.messageTypeUri} start`, { message: messageContext.message });
		outOfBandRecord.assertRole(require_DidCommOutOfBandRole.DidCommOutOfBandRole.Sender);
		outOfBandRecord.assertState(require_DidCommOutOfBandState.DidCommOutOfBandState.AwaitResponse);
		const { message } = messageContext;
		if (!message.connection.didDoc) throw new require_ConnectionProblemReportError.ConnectionProblemReportError("Public DIDs are not supported yet", { problemCode: require_ConnectionProblemReportReason.ConnectionProblemReportReason.RequestNotAccepted });
		const { did: peerDid } = await this.createDid(messageContext.agentContext, {
			role: __credo_ts_core.DidDocumentRole.Received,
			didDoc: message.connection.didDoc
		});
		const connectionRecord = await this.createConnection(messageContext.agentContext, {
			protocol: require_DidCommHandshakeProtocol.DidCommHandshakeProtocol.Connections,
			role: require_DidCommDidExchangeRole.DidCommDidExchangeRole.Responder,
			state: require_DidCommDidExchangeState.DidCommDidExchangeState.RequestReceived,
			alias: outOfBandRecord.alias,
			theirLabel: message.label,
			imageUrl: message.imageUrl,
			outOfBandId: outOfBandRecord.id,
			theirDid: peerDid,
			threadId: message.threadId,
			mediatorId: outOfBandRecord.mediatorId,
			autoAcceptConnection: outOfBandRecord.autoAcceptConnection
		});
		await this.connectionRepository.update(messageContext.agentContext, connectionRecord);
		this.emitStateChangedEvent(messageContext.agentContext, connectionRecord, null);
		this.logger.debug(`Process message ${require_DidCommConnectionRequestMessage.DidCommConnectionRequestMessage.type.messageTypeUri} end`, connectionRecord);
		return connectionRecord;
	}
	/**
	* Create a connection response message for the connection with the specified connection id.
	*
	* @param connectionRecord the connection for which to create a connection response
	* @returns outbound message containing connection response
	*/
	async createResponse(agentContext, connectionRecord, outOfBandRecord, routing) {
		this.logger.debug(`Create message ${require_DidCommConnectionResponseMessage.DidCommConnectionResponseMessage.type.messageTypeUri} start`, connectionRecord);
		connectionRecord.assertState(require_DidCommDidExchangeState.DidCommDidExchangeState.RequestReceived);
		connectionRecord.assertRole(require_DidCommDidExchangeRole.DidCommDidExchangeRole.Responder);
		let didDoc;
		let keys;
		if (routing) {
			const result = this.createDidDoc(routing);
			didDoc = result.didDoc;
			keys = result.keys;
		} else if (outOfBandRecord.outOfBandInvitation.getInlineServices().length > 0) {
			const result = this.createDidDocFromOutOfBandDidCommServices(outOfBandRecord);
			didDoc = result.didDoc;
			keys = result.keys;
		} else throw new __credo_ts_core.CredoError("No routing provided, and no inline services found in out of band invitation. When using did services in out of band invitation, make sure to provide routing information for rotation.");
		const { did: peerDid } = await this.createDid(agentContext, {
			role: __credo_ts_core.DidDocumentRole.Created,
			didDoc,
			keys
		});
		const connection = new require_DidCommConnection.DidCommConnection({
			did: didDoc.id,
			didDoc
		});
		const connectionJson = __credo_ts_core.JsonTransformer.toJSON(connection);
		if (!connectionRecord.threadId) throw new __credo_ts_core.CredoError(`Connection record with id ${connectionRecord.id} does not have a thread id`);
		let signingKey;
		const firstService = outOfBandRecord.outOfBandInvitation.getServices()[0];
		if (typeof firstService === "string") {
			const resolved = await agentContext.resolve(__credo_ts_core.DidsApi).resolveCreatedDidDocumentWithKeys((0, __credo_ts_core.parseDid)(firstService).did);
			const recipientKeys = resolved.didDocument.getRecipientKeysWithVerificationMethod({ mapX25519ToEd25519: true });
			if (recipientKeys.length === 0) throw new __credo_ts_core.CredoError(`Unable to extract signing key for connection response from did '${firstService}'`);
			signingKey = recipientKeys[0].publicJwk;
			signingKey.keyId = resolved.keys?.find(({ didDocumentRelativeKeyId }) => recipientKeys[0].verificationMethod.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ?? signingKey.legacyKeyId;
		} else signingKey = require_helpers.getResolvedDidcommServiceWithSigningKeyId(firstService, outOfBandRecord.invitationInlineServiceKeys).recipientKeys[0];
		const connectionResponse = new require_DidCommConnectionResponseMessage.DidCommConnectionResponseMessage({
			threadId: connectionRecord.threadId,
			connectionSig: await require_SignatureDecoratorUtils.signData(agentContext, connectionJson, signingKey)
		});
		connectionRecord.did = peerDid;
		await this.updateState(agentContext, connectionRecord, require_DidCommDidExchangeState.DidCommDidExchangeState.ResponseSent);
		this.logger.debug(`Create message ${require_DidCommConnectionResponseMessage.DidCommConnectionResponseMessage.type.messageTypeUri} end`, {
			connectionRecord,
			message: connectionResponse
		});
		return {
			connectionRecord,
			message: connectionResponse
		};
	}
	/**
	* Process a received connection response message. This will not accept the connection request
	* or send a connection acknowledgement message. It will only update the existing connection record
	* with all the new information from the connection response message. Use {@link DidCommConnectionService.createTrustPing}
	* after calling this function to create a trust ping message.
	*
	* @param messageContext the message context containing a connection response message
	* @returns updated connection record
	*/
	async processResponse(messageContext, outOfBandRecord) {
		this.logger.debug(`Process message ${require_DidCommConnectionResponseMessage.DidCommConnectionResponseMessage.type.messageTypeUri} start`, { message: messageContext.message });
		const { connection: connectionRecord, message, recipientKey, senderKey } = messageContext;
		if (!recipientKey || !senderKey) throw new __credo_ts_core.CredoError("Unable to process connection request without senderKey or recipientKey");
		if (!connectionRecord) throw new __credo_ts_core.CredoError("No connection record in message context.");
		connectionRecord.assertState(require_DidCommDidExchangeState.DidCommDidExchangeState.RequestSent);
		connectionRecord.assertRole(require_DidCommDidExchangeRole.DidCommDidExchangeRole.Requester);
		let connectionJson = null;
		try {
			connectionJson = await require_SignatureDecoratorUtils.unpackAndVerifySignatureDecorator(messageContext.agentContext, message.connectionSig);
		} catch (error) {
			if (error instanceof __credo_ts_core.CredoError) throw new require_ConnectionProblemReportError.ConnectionProblemReportError(error.message, { problemCode: require_ConnectionProblemReportReason.ConnectionProblemReportReason.ResponseProcessingError });
			throw error;
		}
		const connection = __credo_ts_core.JsonTransformer.fromJSON(connectionJson, require_DidCommConnection.DidCommConnection);
		const signerVerkey = message.connectionSig.signer;
		const invitationKey = __credo_ts_core.Kms.PublicJwk.fromFingerprint(outOfBandRecord.getTags().recipientKeyFingerprints[0]);
		if (!invitationKey.is(__credo_ts_core.Kms.Ed25519PublicJwk)) throw new require_ConnectionProblemReportError.ConnectionProblemReportError(`Expected invitation key to be an Ed25519 key, found ${invitationKey.jwkTypehumanDescription}`, { problemCode: require_ConnectionProblemReportReason.ConnectionProblemReportReason.ResponseNotAccepted });
		if (signerVerkey !== __credo_ts_core.TypedArrayEncoder.toBase58(invitationKey.publicKey.publicKey)) throw new require_ConnectionProblemReportError.ConnectionProblemReportError(`Connection object in connection response message is not signed with same key as recipient key in invitation expected='${invitationKey}' received='${signerVerkey}'`, { problemCode: require_ConnectionProblemReportReason.ConnectionProblemReportReason.ResponseNotAccepted });
		if (!connection.didDoc) throw new __credo_ts_core.CredoError("DID Document is missing.");
		const { did: peerDid } = await this.createDid(messageContext.agentContext, {
			role: __credo_ts_core.DidDocumentRole.Received,
			didDoc: connection.didDoc
		});
		connectionRecord.theirDid = peerDid;
		connectionRecord.threadId = message.threadId;
		await this.updateState(messageContext.agentContext, connectionRecord, require_DidCommDidExchangeState.DidCommDidExchangeState.ResponseReceived);
		return connectionRecord;
	}
	/**
	* Create a trust ping message for the connection with the specified connection id.
	*
	* By default a trust ping message should elicit a response. If this is not desired the
	* `config.responseRequested` property can be set to `false`.
	*
	* @param connectionRecord the connection for which to create a trust ping message
	* @param config the config for the trust ping message
	* @returns outbound message containing trust ping message
	*/
	async createTrustPing(agentContext, connectionRecord, config = {}) {
		connectionRecord.assertState([require_DidCommDidExchangeState.DidCommDidExchangeState.ResponseReceived, require_DidCommDidExchangeState.DidCommDidExchangeState.Completed]);
		const trustPing = new require_DidCommTrustPingMessage.DidCommTrustPingMessage(config);
		if (connectionRecord.state !== require_DidCommDidExchangeState.DidCommDidExchangeState.Completed) await this.updateState(agentContext, connectionRecord, require_DidCommDidExchangeState.DidCommDidExchangeState.Completed);
		return {
			connectionRecord,
			message: trustPing
		};
	}
	/**
	* Process a received ack message. This will update the state of the connection
	* to Completed if this is not already the case.
	*
	* @param messageContext the message context containing an ack message
	* @returns updated connection record
	*/
	async processAck(messageContext) {
		const { connection, recipientKey } = messageContext;
		if (!connection) throw new __credo_ts_core.CredoError(`Unable to process connection ack: connection for recipient key ${recipientKey?.fingerprint} not found`);
		if (connection.state === require_DidCommDidExchangeState.DidCommDidExchangeState.ResponseSent && connection.role === require_DidCommDidExchangeRole.DidCommDidExchangeRole.Responder) await this.updateState(messageContext.agentContext, connection, require_DidCommDidExchangeState.DidCommDidExchangeState.Completed);
		return connection;
	}
	/**
	* Process a received {@link DidCommProblemReportMessage}.
	*
	* @param messageContext The message context containing a connection problem report message
	* @returns connection record associated with the connection problem report message
	*
	*/
	async processProblemReport(messageContext) {
		const { message: connectionProblemReportMessage, recipientKey, senderKey } = messageContext;
		this.logger.debug(`Processing connection problem report for verkey ${recipientKey?.fingerprint}`);
		if (!recipientKey) throw new __credo_ts_core.CredoError("Unable to process connection problem report without recipientKey");
		const ourDidRecord = await this.didRepository.findCreatedDidByRecipientKey(messageContext.agentContext, recipientKey);
		if (!ourDidRecord) throw new __credo_ts_core.CredoError(`Unable to process connection problem report: created did record for recipient key ${recipientKey.fingerprint} not found`);
		const connectionRecord = await this.findByOurDid(messageContext.agentContext, ourDidRecord.did);
		if (!connectionRecord) throw new __credo_ts_core.CredoError(`Unable to process connection problem report: connection for recipient key ${recipientKey.fingerprint} not found`);
		const theirDidRecord = connectionRecord.theirDid && await this.didRepository.findReceivedDid(messageContext.agentContext, connectionRecord.theirDid);
		if (!theirDidRecord) throw new __credo_ts_core.CredoError(`Received did record for did ${connectionRecord.theirDid} not found.`);
		if (senderKey) {
			if (!theirDidRecord?.getTags().recipientKeyFingerprints?.includes(senderKey.fingerprint)) throw new __credo_ts_core.CredoError("Sender key doesn't match key of connection record");
		}
		connectionRecord.errorMessage = `${connectionProblemReportMessage.description.code} : ${connectionProblemReportMessage.description.en}`;
		await this.update(messageContext.agentContext, connectionRecord);
		await this.updateState(messageContext.agentContext, connectionRecord, require_DidCommDidExchangeState.DidCommDidExchangeState.Abandoned);
		return connectionRecord;
	}
	/**
	* Assert that an inbound message either has a connection associated with it,
	* or has everything correctly set up for connection-less exchange (optionally with out of band)
	*
	* @param messageContext - the inbound message context
	*/
	async assertConnectionOrOutOfBandExchange(messageContext, { lastSentMessage, lastReceivedMessage, expectedConnectionId } = {}) {
		const { connection, message } = messageContext;
		if (expectedConnectionId && !connection) throw new __credo_ts_core.CredoError(`Expected incoming message to be from connection ${expectedConnectionId} but no connection found.`);
		if (expectedConnectionId && connection?.id !== expectedConnectionId) throw new __credo_ts_core.CredoError(`Expected incoming message to be from connection ${expectedConnectionId} but connection is ${connection?.id}.`);
		if (connection) {
			connection.assertReady();
			this.logger.debug(`Processing message with id ${message.id} and connection id ${connection.id}`, { type: message.type });
		} else {
			this.logger.debug(`Processing connection-less message with id ${message.id}`, { type: message.type });
			const recipientKey = messageContext.recipientKey;
			const senderKey = messageContext.senderKey;
			let theirService = messageContext.message?.service?.resolvedDidCommService ?? lastReceivedMessage?.service?.resolvedDidCommService;
			let ourService = lastSentMessage?.service?.resolvedDidCommService;
			const outOfBandRepository = messageContext.agentContext.dependencyManager.resolve(require_DidCommOutOfBandRepository.DidCommOutOfBandRepository);
			const outOfBandService = messageContext.agentContext.dependencyManager.resolve(require_DidCommOutOfBandService.DidCommOutOfBandService);
			const outOfBandRecord = await outOfBandRepository.findSingleByQuery(messageContext.agentContext, { invitationRequestsThreadIds: [message.threadId] });
			if (outOfBandRecord?.role === require_DidCommOutOfBandRole.DidCommOutOfBandRole.Sender) ourService = await outOfBandService.getResolvedServiceForOutOfBandServices(messageContext.agentContext, outOfBandRecord.outOfBandInvitation.getServices(), outOfBandRecord.invitationInlineServiceKeys);
			else if (outOfBandRecord?.role === require_DidCommOutOfBandRole.DidCommOutOfBandRole.Receiver) theirService = await outOfBandService.getResolvedServiceForOutOfBandServices(messageContext.agentContext, outOfBandRecord.outOfBandInvitation.getServices());
			if (!theirService && !outOfBandRecord) throw new __credo_ts_core.CredoError("No service for incoming connection-less message and no associated out of band record found.");
			if (!ourService && (lastReceivedMessage || lastSentMessage)) throw new __credo_ts_core.CredoError("No keys on our side to use for encrypting messages, and previous messages found (in which case our keys MUST also be present).");
			if ((!senderKey || !recipientKey) && (lastSentMessage || lastReceivedMessage)) throw new __credo_ts_core.CredoError("Incoming message must have recipientKey and senderKey (so cannot be AuthCrypt or unpacked) if there are lastSentMessage or lastReceivedMessage.");
			if (recipientKey && ourService) {
				if (!ourService.recipientKeys.some((key) => recipientKey.equals(key))) throw new __credo_ts_core.CredoError(`Recipient key ${recipientKey.fingerprint} not found in our service`);
			}
			if (senderKey && theirService) {
				if (!theirService.recipientKeys.some((key) => senderKey.equals(key))) throw new __credo_ts_core.CredoError(`Sender key ${senderKey.fingerprint} not found in their service.`);
			}
		}
	}
	/**
	* If knownConnectionId is passed, it will compare the incoming connection id with the knownConnectionId, and skip the other validation.
	*
	* If no known connection id is passed, it asserts that the incoming message is in response to an attached request message to an out of band invitation.
	* If is the case, and the state of the out of band record is still await response, the state will be updated to done
	*
	*/
	async matchIncomingMessageToRequestMessageInOutOfBandExchange(messageContext, { expectedConnectionId }) {
		if (expectedConnectionId && messageContext.connection?.id !== expectedConnectionId) throw new __credo_ts_core.CredoError(`Expecting incoming message to have connection ${expectedConnectionId}, but incoming connection is ${messageContext.connection?.id ?? "undefined"}`);
		const outOfBandRepository = messageContext.agentContext.dependencyManager.resolve(require_DidCommOutOfBandRepository.DidCommOutOfBandRepository);
		const outOfBandInvitationId = messageContext.message.thread?.parentThreadId;
		const outOfBandRecord = await outOfBandRepository.findSingleByQuery(messageContext.agentContext, {
			invitationId: outOfBandInvitationId,
			role: require_DidCommOutOfBandRole.DidCommOutOfBandRole.Sender,
			invitationRequestsThreadIds: [messageContext.message.threadId]
		});
		if (!outOfBandRecord) throw new __credo_ts_core.CredoError(`No out of band record found for credential request message with thread ${messageContext.message.threadId}, out of band invitation id ${outOfBandInvitationId} and role ${require_DidCommOutOfBandRole.DidCommOutOfBandRole.Sender}`);
		if (outOfBandRecord.metadata.get(require_outOfBandRecordMetadataTypes.DidCommOutOfBandRecordMetadataKeys.LegacyInvitation)?.legacyInvitationType !== require_DidCommOutOfBandInvitation.DidCommInvitationType.Connectionless && outOfBandRecord.outOfBandInvitation.id !== outOfBandInvitationId) throw new __credo_ts_core.CredoError("Response messages to out of band invitation requests MUST have a parent thread id that matches the out of band invitation id.");
		if (outOfBandRecord.reusable) throw new __credo_ts_core.CredoError("Receiving messages in response to reusable out of band invitations is not supported.");
		if (outOfBandRecord.state === require_DidCommOutOfBandState.DidCommOutOfBandState.Done) {
			if (!messageContext.connection) throw new __credo_ts_core.CredoError("Can't find connection associated with incoming message, while out of band state is done. State must be await response if no connection has been created");
			if (messageContext.connection.outOfBandId !== outOfBandRecord.id) throw new __credo_ts_core.CredoError("Connection associated with incoming message is not associated with the out of band invitation containing the attached message.");
		} else if (outOfBandRecord.state === require_DidCommOutOfBandState.DidCommOutOfBandState.AwaitResponse) {
			outOfBandRecord.state = require_DidCommOutOfBandState.DidCommOutOfBandState.Done;
			await outOfBandRepository.update(messageContext.agentContext, outOfBandRecord);
		} else throw new __credo_ts_core.CredoError(`Out of band record is in incorrect state ${outOfBandRecord.state}`);
	}
	async updateState(agentContext, connectionRecord, newState) {
		const previousState = connectionRecord.state;
		connectionRecord.state = newState;
		await this.connectionRepository.update(agentContext, connectionRecord);
		this.emitStateChangedEvent(agentContext, connectionRecord, previousState);
	}
	emitStateChangedEvent(agentContext, connectionRecord, previousState) {
		this.eventEmitter.emit(agentContext, {
			type: require_DidCommConnectionEvents.DidCommConnectionEventTypes.DidCommConnectionStateChanged,
			payload: {
				connectionRecord: connectionRecord.clone(),
				previousState
			}
		});
	}
	update(agentContext, connectionRecord) {
		return this.connectionRepository.update(agentContext, connectionRecord);
	}
	/**
	* Retrieve all connections records
	*
	* @returns List containing all connection records
	*/
	getAll(agentContext) {
		return this.connectionRepository.getAll(agentContext);
	}
	/**
	* Retrieve a connection record by id
	*
	* @param connectionId The connection record id
	* @throws {RecordNotFoundError} If no record is found
	* @return The connection record
	*
	*/
	getById(agentContext, connectionId) {
		return this.connectionRepository.getById(agentContext, connectionId);
	}
	/**
	* Find a connection record by id
	*
	* @param connectionId the connection record id
	* @returns The connection record or null if not found
	*/
	findById(agentContext, connectionId) {
		return this.connectionRepository.findById(agentContext, connectionId);
	}
	/**
	* Delete a connection record by id
	*
	* @param connectionId the connection record id
	*/
	async deleteById(agentContext, connectionId) {
		const connectionRecord = await this.getById(agentContext, connectionId);
		return this.connectionRepository.delete(agentContext, connectionRecord);
	}
	async findByDids(agentContext, query) {
		return this.connectionRepository.findByDids(agentContext, query);
	}
	/**
	* Retrieve a connection record by thread id
	*
	* @param threadId The thread id
	* @throws {RecordNotFoundError} If no record is found
	* @throws {RecordDuplicateError} If multiple records are found
	* @returns The connection record
	*/
	async getByThreadId(agentContext, threadId) {
		return this.connectionRepository.getByThreadId(agentContext, threadId);
	}
	async getByRoleAndThreadId(agentContext, role, threadId) {
		return this.connectionRepository.getByRoleAndThreadId(agentContext, role, threadId);
	}
	async findByTheirDid(agentContext, theirDid) {
		return this.connectionRepository.findSingleByQuery(agentContext, { theirDid });
	}
	async findByOurDid(agentContext, ourDid) {
		return this.connectionRepository.findSingleByQuery(agentContext, { did: ourDid });
	}
	async findAllByOutOfBandId(agentContext, outOfBandId) {
		return this.connectionRepository.findByQuery(agentContext, { outOfBandId });
	}
	async findAllByConnectionTypes(agentContext, connectionTypes) {
		return this.connectionRepository.findByQuery(agentContext, { connectionTypes });
	}
	async findByInvitationDid(agentContext, invitationDid) {
		return this.connectionRepository.findByQuery(agentContext, { invitationDid });
	}
	async findByKeys(agentContext, { senderKey, recipientKey }) {
		const theirDidRecord = await this.didRepository.findReceivedDidByRecipientKey(agentContext, senderKey);
		if (theirDidRecord) {
			const ourDidRecord = await this.didRepository.findCreatedDidByRecipientKey(agentContext, recipientKey);
			if (ourDidRecord) {
				const connectionRecord = await this.findByDids(agentContext, {
					ourDid: ourDidRecord.did,
					theirDid: theirDidRecord.did
				});
				if (connectionRecord?.isReady) return connectionRecord;
			}
		}
		this.logger.debug(`No connection record found for encrypted message with recipient key ${recipientKey.fingerprint} and sender key ${senderKey.fingerprint}`);
		return null;
	}
	async findAllByQuery(agentContext, query, queryOptions) {
		return this.connectionRepository.findByQuery(agentContext, query, queryOptions);
	}
	async createConnection(agentContext, options) {
		const connectionRecord = new require_DidCommConnectionRecord.DidCommConnectionRecord(options);
		await this.connectionRepository.save(agentContext, connectionRecord);
		return connectionRecord;
	}
	async addConnectionType(agentContext, connectionRecord, type) {
		connectionRecord.connectionTypes = [type, ...connectionRecord.connectionTypes || []];
		await this.update(agentContext, connectionRecord);
	}
	async removeConnectionType(agentContext, connectionRecord, type) {
		connectionRecord.connectionTypes = connectionRecord.connectionTypes.filter((value) => value !== type);
		await this.update(agentContext, connectionRecord);
	}
	async getConnectionTypes(connectionRecord) {
		return connectionRecord.connectionTypes || [];
	}
	async createDid(agentContext, { role, didDoc, keys }) {
		if (keys && role !== __credo_ts_core.DidDocumentRole.Created) throw new __credo_ts_core.CredoError(`keys can only be provided for did documents when the role is '${__credo_ts_core.DidDocumentRole.Created}'`);
		const { didDocument, keys: updatedKeys } = require_helpers.convertToNewDidDocument(didDoc, keys);
		if (role === __credo_ts_core.DidDocumentRole.Created) await require_helpers.assertNoCreatedDidExistsForKeys(agentContext, didDocument.recipientKeys);
		const peerDid = (0, __credo_ts_core.didDocumentJsonToNumAlgo1Did)(didDocument.toJSON());
		didDocument.id = peerDid;
		const didRecord = new __credo_ts_core.DidRecord({
			did: peerDid,
			role,
			didDocument,
			keys: updatedKeys
		});
		didRecord.metadata.set(__credo_ts_core.DidRecordMetadataKeys.LegacyDid, {
			unqualifiedDid: didDoc.id,
			didDocumentString: __credo_ts_core.JsonTransformer.serialize(didDoc)
		});
		this.logger.debug("Saving DID record", {
			id: didRecord.id,
			did: didRecord.did,
			role: didRecord.role,
			tags: didRecord.getTags(),
			didDocument: "omitted..."
		});
		await this.didRepository.save(agentContext, didRecord);
		this.logger.debug("Did record created.", didRecord);
		return {
			did: peerDid,
			didDocument
		};
	}
	createDidDoc(routing) {
		const recipientKeyBase58 = __credo_ts_core.TypedArrayEncoder.toBase58(routing.recipientKey.publicKey.publicKey);
		const indyDid = __credo_ts_core.utils.indyDidFromPublicKeyBase58(recipientKeyBase58);
		const keys = [{
			didDocumentRelativeKeyId: "#1",
			kmsKeyId: routing.recipientKey.keyId
		}];
		const publicKey = new require_Ed25119Sig2018.Ed25119Sig2018({
			id: `${indyDid}#1`,
			controller: indyDid,
			publicKeyBase58: recipientKeyBase58
		});
		const auth = new require_ReferencedAuthentication.ReferencedAuthentication(publicKey, require_index.authenticationTypes.Ed25519VerificationKey2018);
		const services = routing.endpoints.map((endpoint, index) => new __credo_ts_core.IndyAgentService({
			id: `${indyDid}#IndyAgentService-${index + 1}`,
			serviceEndpoint: endpoint,
			recipientKeys: [recipientKeyBase58],
			routingKeys: routing.routingKeys.map((key) => __credo_ts_core.TypedArrayEncoder.toBase58(key.publicKey.publicKey)),
			priority: index
		}));
		return {
			didDoc: new require_DidDoc.DidDoc({
				id: indyDid,
				authentication: [auth],
				service: services,
				publicKey: [publicKey]
			}),
			keys
		};
	}
	createDidDocFromOutOfBandDidCommServices(outOfBandRecord) {
		const services = outOfBandRecord.outOfBandInvitation.getInlineServices().map((service$1) => require_helpers.getResolvedDidcommServiceWithSigningKeyId(service$1, outOfBandRecord.invitationInlineServiceKeys));
		const [recipientKey] = services[0].recipientKeys;
		const recipientKeyBase58 = __credo_ts_core.TypedArrayEncoder.toBase58(recipientKey.publicKey.publicKey);
		const did = __credo_ts_core.utils.indyDidFromPublicKeyBase58(recipientKeyBase58);
		const publicKey = new require_Ed25119Sig2018.Ed25119Sig2018({
			id: `${did}#1`,
			controller: did,
			publicKeyBase58: recipientKeyBase58
		});
		const auth = new require_ReferencedAuthentication.ReferencedAuthentication(publicKey, require_index.authenticationTypes.Ed25519VerificationKey2018);
		const service = services.map((service$1, index) => new __credo_ts_core.IndyAgentService({
			id: `${did}#IndyAgentService-${index + 1}`,
			serviceEndpoint: service$1.serviceEndpoint,
			recipientKeys: [recipientKeyBase58],
			routingKeys: service$1.routingKeys?.map((publicJwk) => __credo_ts_core.TypedArrayEncoder.toBase58(publicJwk.publicKey.publicKey)),
			priority: index
		}));
		return {
			didDoc: new require_DidDoc.DidDoc({
				id: did,
				authentication: [auth],
				service,
				publicKey: [publicKey]
			}),
			keys: [{
				didDocumentRelativeKeyId: "#1",
				kmsKeyId: recipientKey.keyId
			}]
		};
	}
	async returnWhenIsConnected(agentContext, connectionId, timeoutMs = 2e4) {
		const isConnected = (connection$1) => {
			return connection$1.id === connectionId && connection$1.state === require_DidCommDidExchangeState.DidCommDidExchangeState.Completed;
		};
		const observable = this.eventEmitter.observable(require_DidCommConnectionEvents.DidCommConnectionEventTypes.DidCommConnectionStateChanged);
		const subject = new import_cjs.ReplaySubject(1);
		observable.pipe((0, __credo_ts_core.filterContextCorrelationId)(agentContext.contextCorrelationId), (0, import_operators.map)((e) => e.payload.connectionRecord), (0, import_operators.first)(isConnected), (0, import_operators.timeout)({
			first: timeoutMs,
			meta: "DidCommConnectionService.returnWhenIsConnected"
		})).subscribe(subject);
		const connection = await this.getById(agentContext, connectionId);
		if (isConnected(connection)) subject.next(connection);
		return (0, import_cjs.firstValueFrom)(subject);
	}
};
DidCommConnectionService = require_decorate.__decorate([
	(0, __credo_ts_core.injectable)(),
	require_decorateParam.__decorateParam(0, (0, __credo_ts_core.inject)(__credo_ts_core.InjectionSymbols.Logger)),
	require_decorateMetadata.__decorateMetadata("design:paramtypes", [
		Object,
		typeof (_ref = typeof require_DidCommConnectionRepository.DidCommConnectionRepository !== "undefined" && require_DidCommConnectionRepository.DidCommConnectionRepository) === "function" ? _ref : Object,
		typeof (_ref2 = typeof __credo_ts_core.DidRepository !== "undefined" && __credo_ts_core.DidRepository) === "function" ? _ref2 : Object,
		typeof (_ref3 = typeof __credo_ts_core.EventEmitter !== "undefined" && __credo_ts_core.EventEmitter) === "function" ? _ref3 : Object
	])
], DidCommConnectionService);

//#endregion
Object.defineProperty(exports, 'DidCommConnectionService', {
  enumerable: true,
  get: function () {
    return DidCommConnectionService;
  }
});