const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
const require_errors = require('./types/errors.cjs');
const require_completable_promise = require('./utils/completable_promise.cjs');
const require_promises = require('./promises.cjs');
const require_rpc = require('./types/rpc.cjs');
const require_sdk_shared_core_wasm_bindings = require('./endpoint/handlers/vm/sdk_shared_core_wasm_bindings.cjs');
const require_rand = require('./utils/rand.cjs');
const require_io = require('./io.cjs');
let __restatedev_restate_sdk_core = require("@restatedev/restate-sdk-core");
__restatedev_restate_sdk_core = require_rolldown_runtime.__toESM(__restatedev_restate_sdk_core);

//#region src/context_impl.ts
var ContextImpl = class {
	rand;
	date = {
		now: () => {
			return this.run(() => Date.now());
		},
		toJSON: () => {
			return this.run(() => (/* @__PURE__ */ new Date()).toJSON());
		}
	};
	outputPump;
	runClosuresTracker;
	promisesExecutor;
	serviceKey;
	runInterceptor;
	cancellationPromise;
	defaultSerde;
	asTerminalError;
	trackedInvocationIdPromises;
	constructor(coreVm, input, console, handlerKind, vmLogger, invocationRequest, invocationEndPromise, inputReader, outputWriter, journalValueCodec, executionOptions) {
		this.coreVm = coreVm;
		this.console = console;
		this.handlerKind = handlerKind;
		this.vmLogger = vmLogger;
		this.invocationRequest = invocationRequest;
		this.invocationEndPromise = invocationEndPromise;
		this.journalValueCodec = journalValueCodec;
		this.rand = new require_rand.RandImpl(input.random_seed, () => {});
		this.outputPump = new require_io.OutputPump(coreVm, outputWriter);
		this.runClosuresTracker = new RunClosuresTracker();
		this.promisesExecutor = new require_promises.PromisesExecutor(coreVm, new require_io.InputPump(coreVm, inputReader, this.abortAttempt.bind(this)), this.outputPump, this.runClosuresTracker, this.abortAttempt.bind(this));
		this.serviceKey = input.key;
		this.runInterceptor = (_name, runner) => runner();
		this.defaultSerde = executionOptions?.defaultSerde ?? __restatedev_restate_sdk_core.serde.json;
		this.asTerminalError = executionOptions?.asTerminalError;
		this.trackedInvocationIdPromises = executionOptions?.explicitCancellation ? [] : void 0;
	}
	setRunInterceptor(interceptor) {
		this.runInterceptor = interceptor;
	}
	isProcessing() {
		return this.coreVm.is_processing();
	}
	cancel(invocationId) {
		this._cancel(invocationId);
	}
	_cancel(invocationId) {
		this.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.CancelInvocation, () => {}, (vm) => vm.sys_cancel_invocation(invocationId));
	}
	attach(invocationId, serde$1) {
		return this.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.AttachInvocation, () => {}, (vm) => vm.sys_attach_invocation(invocationId), SuccessWithSerde(serde$1 ?? this.defaultSerde, this.journalValueCodec), Failure);
	}
	get key() {
		switch (this.handlerKind) {
			case require_rpc.HandlerKind.EXCLUSIVE:
			case require_rpc.HandlerKind.SHARED:
			case require_rpc.HandlerKind.WORKFLOW: return this.serviceKey;
			default: throw new require_errors.TerminalError("this handler type doesn't support key()");
		}
	}
	request() {
		return this.invocationRequest;
	}
	get(name, serde$1) {
		return this.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.GetState, () => {}, (vm) => vm.sys_get_state(name), VoidAsNull, SuccessWithSerde(serde$1 ?? this.defaultSerde, this.journalValueCodec));
	}
	stateKeys() {
		return this.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.GetStateKeys, () => {}, (vm) => vm.sys_get_state_keys(), StateKeys);
	}
	set(name, value, serde$1) {
		this.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.SetState, () => this.journalValueCodec.encode((serde$1 ?? this.defaultSerde).serialize(value)), (vm, bytes) => vm.sys_set_state(name, bytes));
	}
	clear(name) {
		this.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.ClearState, () => {}, (vm) => vm.sys_clear_state(name));
	}
	clearAll() {
		this.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.ClearAllState, () => {}, (vm) => vm.sys_clear_all_state());
	}
	genericCall(call) {
		const requestSerde = call.inputSerde ?? __restatedev_restate_sdk_core.serde.binary;
		const responseSerde = call.outputSerde ?? __restatedev_restate_sdk_core.serde.binary;
		let parameter;
		try {
			parameter = this.journalValueCodec.encode(requestSerde.serialize(call.parameter));
		} catch (e) {
			this.abortAttempt(e, require_sdk_shared_core_wasm_bindings.WasmCommandType.Call);
			return Object.assign(require_promises.ConstRestatePromise.pending(), { invocationId: require_promises.pendingPromise() });
		}
		try {
			const call_handles = this.coreVm.sys_call(call.service, call.method, parameter, call.key, call.headers ? Object.entries(call.headers).map(([key, value]) => new require_sdk_shared_core_wasm_bindings.WasmHeader(key, value)) : [], call.idempotencyKey, call.name);
			const commandIndex = this.coreVm.last_command_index();
			const invocationIdPromise = new require_promises.SingleRestatePromise(this, call_handles.invocation_id_completion_id, completeCommandPromiseUsing(require_sdk_shared_core_wasm_bindings.WasmCommandType.Call, commandIndex, InvocationIdCompleter));
			this.trackedInvocationIdPromises?.push(invocationIdPromise);
			return new require_promises.InvocationRestatePromise(this, call_handles.call_completion_id, completeCommandPromiseUsing(require_sdk_shared_core_wasm_bindings.WasmCommandType.Call, commandIndex, SuccessWithSerde(responseSerde, this.journalValueCodec), Failure), invocationIdPromise);
		} catch (e) {
			this.abortAttempt(e);
			return Object.assign(require_promises.ConstRestatePromise.pending(), { invocationId: require_promises.pendingPromise() });
		}
	}
	genericSend(send) {
		const requestSerde = send.inputSerde ?? __restatedev_restate_sdk_core.serde.binary;
		let parameter;
		try {
			parameter = this.journalValueCodec.encode(requestSerde.serialize(send.parameter));
		} catch (e) {
			this.abortAttempt(e, require_sdk_shared_core_wasm_bindings.WasmCommandType.OneWayCall);
			return Object.assign(require_promises.ConstRestatePromise.pending(), { invocationId: require_promises.pendingPromise() });
		}
		try {
			const delay = send.delay !== void 0 ? (0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(send.delay) : void 0;
			const handles = this.coreVm.sys_send(send.service, send.method, parameter, send.key, send.headers ? Object.entries(send.headers).map(([key, value]) => new require_sdk_shared_core_wasm_bindings.WasmHeader(key, value)) : [], delay !== void 0 && delay > 0 ? BigInt(delay) : void 0, send.idempotencyKey, send.name);
			const commandIndex = this.coreVm.last_command_index();
			return { invocationId: new require_promises.SingleRestatePromise(this, handles.invocation_id_completion_id, completeCommandPromiseUsing(require_sdk_shared_core_wasm_bindings.WasmCommandType.OneWayCall, commandIndex, InvocationIdCompleter)) };
		} catch (e) {
			this.abortAttempt(e);
			return { invocationId: require_promises.pendingPromise() };
		}
	}
	serviceClient({ name }) {
		return require_rpc.makeRpcCallProxy((call) => this.genericCall(call), this.defaultSerde, name);
	}
	objectClient({ name }, key) {
		return require_rpc.makeRpcCallProxy((call) => this.genericCall(call), this.defaultSerde, name, key);
	}
	workflowClient({ name }, key) {
		return require_rpc.makeRpcCallProxy((call) => this.genericCall(call), this.defaultSerde, name, key);
	}
	serviceSendClient({ name }) {
		return require_rpc.makeRpcSendProxy((send) => this.genericSend(send), this.defaultSerde, name, void 0);
	}
	objectSendClient({ name }, key) {
		return require_rpc.makeRpcSendProxy((send) => this.genericSend(send), this.defaultSerde, name, key);
	}
	workflowSendClient({ name }, key) {
		return require_rpc.makeRpcSendProxy((send) => this.genericSend(send), this.defaultSerde, name, key);
	}
	run(nameOrAction, actionSecondParameter, options) {
		const { name, action } = unpackRunParameters(nameOrAction, actionSecondParameter);
		const serde$1 = options?.serde ?? this.defaultSerde;
		let handle;
		try {
			handle = this.coreVm.sys_run(name ?? "");
		} catch (e) {
			this.abortAttempt(e);
			return require_promises.ConstRestatePromise.pending();
		}
		const commandIndex = this.coreVm.last_command_index();
		const doRun = async () => {
			const startTime = Date.now();
			let res;
			let err;
			try {
				await this.runInterceptor(name ?? "", async () => {
					res = await action();
				});
			} catch (e) {
				err = require_errors.ensureError(e, this.asTerminalError);
			}
			const attemptDuration = Date.now() - startTime;
			try {
				if (err !== void 0) if (err instanceof require_errors.TerminalError) this.coreVm.propose_run_completion_failure(handle, {
					code: err.code,
					message: err.message,
					metadata: Object.entries(err.metadata ?? {}).map(([key, value]) => ({
						key,
						value
					}))
				});
				else if (err instanceof require_errors.RetryableError) this.coreVm.propose_run_completion_failure_transient_with_delay_override(handle, err.message, err.stack, BigInt(attemptDuration), err.retryAfter !== void 0 ? BigInt((0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(err.retryAfter)) : void 0, options?.maxRetryAttempts, options?.maxRetryDuration !== void 0 ? BigInt((0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(options?.maxRetryDuration)) : void 0);
				else {
					this.vmLogger.warn(`Error when processing ctx.run '${name}'.\n`, err);
					let retryPolicy;
					if (options?.retryIntervalFactor !== void 0 || options?.maxRetryAttempts !== void 0 || options?.initialRetryInterval !== void 0 || options?.maxRetryDuration !== void 0 || options?.maxRetryInterval !== void 0) retryPolicy = {
						factor: options?.retryIntervalFactor ?? 2,
						initial_interval: (0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(options?.initialRetryInterval ?? 50),
						max_attempts: options?.maxRetryAttempts,
						max_duration: options?.maxRetryDuration === void 0 ? void 0 : (0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(options?.maxRetryDuration),
						max_interval: (0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(options?.maxRetryInterval ?? { seconds: 10 })
					};
					this.coreVm.propose_run_completion_failure_transient(handle, err.message, err.stack, BigInt(attemptDuration), retryPolicy);
				}
				else {
					const serializedRes = serde$1.serialize(res);
					const encodedRes = this.journalValueCodec.encode(serializedRes);
					this.coreVm.propose_run_completion_success(handle, encodedRes);
				}
			} catch (e) {
				this.abortAttempt(e);
				return require_promises.pendingPromise();
			}
			await this.outputPump.awaitNextProgress();
		};
		this.runClosuresTracker.registerRunClosure(handle, doRun);
		return new require_promises.SingleRestatePromise(this, handle, completeCommandPromiseUsing(require_sdk_shared_core_wasm_bindings.WasmCommandType.Run, commandIndex, SuccessWithSerde(serde$1, this.journalValueCodec), Failure));
	}
	sleep(duration, name) {
		return this.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.Sleep, () => {
			if (duration === void 0) throw new Error(`Duration is undefined.`);
			const millis = (0, __restatedev_restate_sdk_core.millisOrDurationToMillis)(duration);
			if (millis < 0) throw new Error(`Invalid negative sleep duration: ${millis}ms.\nIf this duration is computed from a desired wake up time, make sure to record 'now' using 'wakeUpTime - ctx.date.now()'.`);
			return BigInt(millis);
		}, (vm, millis) => vm.sys_sleep(millis, name), VoidAsUndefined);
	}
	awakeable(serde$1) {
		let awakeable;
		try {
			awakeable = this.coreVm.sys_awakeable();
		} catch (e) {
			this.abortAttempt(e);
			return {
				id: "invalid",
				promise: require_promises.ConstRestatePromise.pending()
			};
		}
		return {
			id: awakeable.id,
			promise: new require_promises.SingleRestatePromise(this, awakeable.handle, completeSignalPromiseUsing(VoidAsUndefined, SuccessWithSerde(serde$1 ?? this.defaultSerde, this.journalValueCodec), Failure))
		};
	}
	resolveAwakeable(id, payload, serde$1) {
		this.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.CompleteAwakeable, () => {
			let value;
			if (serde$1) value = payload === void 0 ? new Uint8Array() : serde$1.serialize(payload);
			else value = payload !== void 0 ? this.defaultSerde.serialize(payload) : this.defaultSerde.serialize(null);
			return this.journalValueCodec.encode(value);
		}, (vm, bytes) => vm.sys_complete_awakeable_success(id, bytes));
	}
	rejectAwakeable(id, reason) {
		this.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.CompleteAwakeable, () => {}, (vm) => {
			vm.sys_complete_awakeable_failure(id, toWasmFailure(reason));
		});
	}
	signal(name, serde$1) {
		let handle;
		try {
			handle = this.coreVm.sys_signal(name);
		} catch (e) {
			this.abortAttempt(e);
			return require_promises.ConstRestatePromise.pending();
		}
		return new require_promises.SingleRestatePromise(this, handle, completeSignalPromiseUsing(VoidAsUndefined, SuccessWithSerde(serde$1 ?? this.defaultSerde, this.journalValueCodec), Failure));
	}
	invocation(invocationId) {
		return new InvocationReferenceImpl(this, invocationId);
	}
	promise(name, serde$1) {
		return new DurablePromiseImpl(this, name, serde$1);
	}
	cancellation() {
		if (!this.cancellationPromise || this.cancellationPromise.isCompleted()) this.cancellationPromise = new require_promises.SingleRestatePromise(this, 1, completeSignalPromiseUsing(VoidAsUndefined));
		return this.cancellationPromise;
	}
	cancelPreviousCalls() {
		if (!this.trackedInvocationIdPromises) return require_promises.ConstRestatePromise.resolve([]);
		return require_promises.CombinatorRestatePromise.fromPromises((p) => Promise.allSettled(p), this.trackedInvocationIdPromises.splice(0)).map((results, failure) => {
			if (failure) throw failure;
			const cancelled = [];
			for (const result of results) if (result.status === "fulfilled") {
				this._cancel(result.value);
				cancelled.push(result.value);
			} else this.console.warn(`Error when trying to get invocation id: ${result.reason}`);
			return cancelled;
		});
	}
	processNonCompletableEntry(commandType, prepare, vmCall) {
		let input;
		try {
			input = prepare();
		} catch (e) {
			this.abortAttempt(e, commandType);
			return;
		}
		try {
			vmCall(this.coreVm, input);
		} catch (e) {
			this.abortAttempt(e);
		}
	}
	processCompletableEntry(commandType, prepare, vmCall, ...completers) {
		let input;
		try {
			input = prepare();
		} catch (e) {
			this.abortAttempt(e, commandType);
			return require_promises.ConstRestatePromise.pending();
		}
		let handle;
		try {
			handle = vmCall(this.coreVm, input);
		} catch (e) {
			this.abortAttempt(e);
			return require_promises.ConstRestatePromise.pending();
		}
		const commandIndex = this.coreVm.last_command_index();
		return new require_promises.SingleRestatePromise(this, handle, completeCommandPromiseUsing(commandType, commandIndex, ...completers));
	}
	abortAttempt(e, commandType) {
		this.invocationEndPromise.reject(commandType !== void 0 ? new CommandError(e, commandType) : require_errors.ensureError(e));
	}
};
function toWasmFailure(reason) {
	if (typeof reason === "string") return {
		code: require_errors.UNKNOWN_ERROR_CODE,
		message: reason,
		metadata: []
	};
	return {
		code: reason.code,
		message: reason.message,
		metadata: Object.entries(reason.metadata ?? {}).map(([key, value]) => ({
			key,
			value
		}))
	};
}
function unpackRunParameters(a, b) {
	if (typeof a === "string") {
		if (typeof b !== "function") throw new TypeError("");
		return {
			name: a,
			action: b
		};
	}
	if (typeof a !== "function") throw new TypeError("unexpected type at the first parameter");
	if (b) throw new TypeError("unexpected a function as a second parameter.");
	return { action: a };
}
var InvocationReferenceImpl = class {
	constructor(ctx, invocationId) {
		this.ctx = ctx;
		this.invocationId = invocationId;
	}
	signal(name, serde$1) {
		return new SignalReferenceImpl(this.ctx, this.invocationId, name, serde$1);
	}
	cancel() {
		this.ctx.cancel(this.invocationId);
	}
	attach(serde$1) {
		return this.ctx.attach(this.invocationId, serde$1);
	}
};
var SignalReferenceImpl = class {
	serde;
	constructor(ctx, invocationId, name, serde$1) {
		this.ctx = ctx;
		this.invocationId = invocationId;
		this.name = name;
		this.serde = serde$1 ?? this.ctx.defaultSerde;
	}
	resolve(payload) {
		this.ctx.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.SendSignal, () => this.ctx.journalValueCodec.encode(this.serde.serialize(payload)), (vm, bytes) => vm.sys_complete_signal_success(this.invocationId, this.name, bytes));
	}
	reject(reason) {
		this.ctx.processNonCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.SendSignal, () => {}, (vm) => {
			vm.sys_complete_signal_failure(this.invocationId, this.name, toWasmFailure(reason));
		});
	}
};
var DurablePromiseImpl = class {
	serde;
	constructor(ctx, name, serde$1) {
		this.ctx = ctx;
		this.name = name;
		this.serde = serde$1 ?? this.ctx.defaultSerde;
	}
	then(onfulfilled, onrejected) {
		return this.get().then(onfulfilled, onrejected);
	}
	catch(onrejected) {
		return this.get().catch(onrejected);
	}
	finally(onfinally) {
		return this.get().finally(onfinally);
	}
	[Symbol.toStringTag] = "DurablePromise";
	get() {
		return this.ctx.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.GetPromise, () => {}, (vm) => vm.sys_get_promise(this.name), SuccessWithSerde(this.serde, this.ctx.journalValueCodec), Failure);
	}
	peek() {
		return this.ctx.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.PeekPromise, () => {}, (vm) => vm.sys_peek_promise(this.name), VoidAsUndefined, SuccessWithSerde(this.serde, this.ctx.journalValueCodec), Failure);
	}
	resolve(value) {
		return this.ctx.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.CompletePromise, () => this.ctx.journalValueCodec.encode(this.serde.serialize(value)), (vm, bytes) => vm.sys_complete_promise_success(this.name, bytes), VoidAsUndefined, Failure);
	}
	reject(errorMsg) {
		return this.ctx.processCompletableEntry(require_sdk_shared_core_wasm_bindings.WasmCommandType.CompletePromise, () => {}, (vm) => vm.sys_complete_promise_failure(this.name, {
			code: require_errors.INTERNAL_ERROR_CODE,
			message: errorMsg,
			metadata: []
		}), VoidAsUndefined, Failure);
	}
};
var RunClosuresTracker = class {
	currentRunWaitPoint;
	runsToExecute = /* @__PURE__ */ new Map();
	executeRun(handle) {
		const runClosure = this.runsToExecute.get(handle);
		if (runClosure === void 0) throw new Error(`Handle ${handle} doesn't exist`);
		runClosure().finally(() => {
			this.unblockCurrentRunWaitPoint();
		}).catch(() => {});
	}
	registerRunClosure(handle, runClosure) {
		this.runsToExecute.set(handle, runClosure);
	}
	awaitNextCompletedRun() {
		if (this.currentRunWaitPoint === void 0) this.currentRunWaitPoint = new require_completable_promise.CompletablePromise();
		return this.currentRunWaitPoint.promise;
	}
	unblockCurrentRunWaitPoint() {
		if (this.currentRunWaitPoint !== void 0) {
			const p = this.currentRunWaitPoint;
			this.currentRunWaitPoint = void 0;
			p.resolve();
		}
	}
};
var CommandError = class extends Error {
	constructor(cause, commandType, commandIndex) {
		const msg = cause instanceof Error ? cause.message : String(cause);
		super(msg, { cause });
		this.cause = cause;
		this.commandType = commandType;
		this.commandIndex = commandIndex;
	}
	/** True when the error is for a specific command that exists in the journal. */
	get hasCommandIndex() {
		return this.commandIndex !== void 0;
	}
};
function completeCommandPromiseUsing(commandType, commandIndex, ...completers) {
	return async (value, prom) => {
		try {
			for (const completer of completers) if (await completer(value, prom)) return;
		} catch (e) {
			throw new CommandError(e, commandType, commandIndex);
		}
		throw new Error(`Unexpected variant in async result: ${JSON.stringify(value)}`);
	};
}
function completeSignalPromiseUsing(...completers) {
	return async (value, prom) => {
		for (const completer of completers) if (await completer(value, prom)) return;
		throw new Error(`Unexpected variant in async result: ${JSON.stringify(value)}`);
	};
}
const VoidAsNull = (value, prom) => {
	if (value === "Empty") {
		prom.resolve(null);
		return Promise.resolve(true);
	}
	return Promise.resolve(false);
};
const VoidAsUndefined = (value, prom) => {
	if (value === "Empty") {
		prom.resolve(void 0);
		return Promise.resolve(true);
	}
	return Promise.resolve(false);
};
function SuccessWithSerde(serde$1, journalCodec, transform) {
	return async (value, prom) => {
		if (typeof value !== "object" || !("Success" in value)) return false;
		let buffer;
		if (journalCodec !== void 0) buffer = await journalCodec.decode(value.Success);
		else buffer = value.Success;
		let val = serde$1.deserialize(buffer);
		if (transform) val = transform(val);
		prom.resolve(val);
		return true;
	};
}
const Failure = (value, prom) => {
	if (typeof value === "object" && "Failure" in value) {
		const metadata = (value.Failure.metadata ?? []).reduce((acc, { key, value: v }) => {
			acc[key] = v;
			return acc;
		}, {});
		prom.reject(new require_errors.TerminalError(value.Failure.message, {
			errorCode: value.Failure.code,
			metadata
		}));
		return Promise.resolve(true);
	}
	return Promise.resolve(false);
};
const StateKeys = (value, prom) => {
	if (typeof value === "object" && "StateKeys" in value) {
		prom.resolve(value.StateKeys);
		return Promise.resolve(true);
	}
	return Promise.resolve(false);
};
const InvocationIdCompleter = (value, prom) => {
	if (typeof value === "object" && "InvocationId" in value) {
		prom.resolve(value.InvocationId);
		return Promise.resolve(true);
	}
	return Promise.resolve(false);
};

//#endregion
exports.CommandError = CommandError;
exports.ContextImpl = ContextImpl;