// @generated - post-processed by build.rs

import * as bare from "@rivetkit/bare-ts";

const DEFAULT_CONFIG = /* @__PURE__ */ bare.Config({});

export type i64 = bigint;
export type u16 = number;
export type u32 = number;
export type u64 = bigint;

export type Id = string;

export function readId(bc: bare.ByteCursor): Id {
	return bare.readString(bc);
}

export function writeId(bc: bare.ByteCursor, x: Id): void {
	bare.writeString(bc, x);
}

export type Json = string;

export function readJson(bc: bare.ByteCursor): Json {
	return bare.readString(bc);
}

export function writeJson(bc: bare.ByteCursor, x: Json): void {
	bare.writeString(bc, x);
}

export type GatewayId = ArrayBuffer;

export function readGatewayId(bc: bare.ByteCursor): GatewayId {
	return bare.readFixedData(bc, 4);
}

export function writeGatewayId(bc: bare.ByteCursor, x: GatewayId): void {
	assert(x.byteLength === 4);
	bare.writeFixedData(bc, x);
}

export type RequestId = ArrayBuffer;

export function readRequestId(bc: bare.ByteCursor): RequestId {
	return bare.readFixedData(bc, 4);
}

export function writeRequestId(bc: bare.ByteCursor, x: RequestId): void {
	assert(x.byteLength === 4);
	bare.writeFixedData(bc, x);
}

export type MessageIndex = u16;

export function readMessageIndex(bc: bare.ByteCursor): MessageIndex {
	return bare.readU16(bc);
}

export function writeMessageIndex(bc: bare.ByteCursor, x: MessageIndex): void {
	bare.writeU16(bc, x);
}

/**
 * Basic types
 */
export type KvKey = ArrayBuffer;

export function readKvKey(bc: bare.ByteCursor): KvKey {
	return bare.readData(bc);
}

export function writeKvKey(bc: bare.ByteCursor, x: KvKey): void {
	bare.writeData(bc, x);
}

export type KvValue = ArrayBuffer;

export function readKvValue(bc: bare.ByteCursor): KvValue {
	return bare.readData(bc);
}

export function writeKvValue(bc: bare.ByteCursor, x: KvValue): void {
	bare.writeData(bc, x);
}

export type KvMetadata = {
	readonly version: ArrayBuffer;
	readonly updateTs: i64;
};

export function readKvMetadata(bc: bare.ByteCursor): KvMetadata {
	return {
		version: bare.readData(bc),
		updateTs: bare.readI64(bc),
	};
}

export function writeKvMetadata(bc: bare.ByteCursor, x: KvMetadata): void {
	bare.writeData(bc, x.version);
	bare.writeI64(bc, x.updateTs);
}

/**
 * Query types
 */
export type KvListAllQuery = null;

export type KvListRangeQuery = {
	readonly start: KvKey;
	readonly end: KvKey;
	readonly exclusive: boolean;
};

export function readKvListRangeQuery(bc: bare.ByteCursor): KvListRangeQuery {
	return {
		start: readKvKey(bc),
		end: readKvKey(bc),
		exclusive: bare.readBool(bc),
	};
}

export function writeKvListRangeQuery(
	bc: bare.ByteCursor,
	x: KvListRangeQuery,
): void {
	writeKvKey(bc, x.start);
	writeKvKey(bc, x.end);
	bare.writeBool(bc, x.exclusive);
}

export type KvListPrefixQuery = {
	readonly key: KvKey;
};

export function readKvListPrefixQuery(bc: bare.ByteCursor): KvListPrefixQuery {
	return {
		key: readKvKey(bc),
	};
}

export function writeKvListPrefixQuery(
	bc: bare.ByteCursor,
	x: KvListPrefixQuery,
): void {
	writeKvKey(bc, x.key);
}

export type KvListQuery =
	| { readonly tag: "KvListAllQuery"; readonly val: KvListAllQuery }
	| { readonly tag: "KvListRangeQuery"; readonly val: KvListRangeQuery }
	| { readonly tag: "KvListPrefixQuery"; readonly val: KvListPrefixQuery };

export function readKvListQuery(bc: bare.ByteCursor): KvListQuery {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "KvListAllQuery", val: null };
		case 1:
			return { tag: "KvListRangeQuery", val: readKvListRangeQuery(bc) };
		case 2:
			return { tag: "KvListPrefixQuery", val: readKvListPrefixQuery(bc) };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeKvListQuery(bc: bare.ByteCursor, x: KvListQuery): void {
	switch (x.tag) {
		case "KvListAllQuery": {
			bare.writeU8(bc, 0);
			break;
		}
		case "KvListRangeQuery": {
			bare.writeU8(bc, 1);
			writeKvListRangeQuery(bc, x.val);
			break;
		}
		case "KvListPrefixQuery": {
			bare.writeU8(bc, 2);
			writeKvListPrefixQuery(bc, x.val);
			break;
		}
	}
}

function read0(bc: bare.ByteCursor): readonly KvKey[] {
	const len = bare.readUintSafe(bc);
	if (len === 0) {
		return [];
	}
	const result = [readKvKey(bc)];
	for (let i = 1; i < len; i++) {
		result[i] = readKvKey(bc);
	}
	return result;
}

function write0(bc: bare.ByteCursor, x: readonly KvKey[]): void {
	bare.writeUintSafe(bc, x.length);
	for (let i = 0; i < x.length; i++) {
		writeKvKey(bc, x[i]);
	}
}

/**
 * Request types
 */
export type KvGetRequest = {
	readonly keys: readonly KvKey[];
};

export function readKvGetRequest(bc: bare.ByteCursor): KvGetRequest {
	return {
		keys: read0(bc),
	};
}

export function writeKvGetRequest(bc: bare.ByteCursor, x: KvGetRequest): void {
	write0(bc, x.keys);
}

function read1(bc: bare.ByteCursor): boolean | null {
	return bare.readBool(bc) ? bare.readBool(bc) : null;
}

function write1(bc: bare.ByteCursor, x: boolean | null): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		bare.writeBool(bc, x);
	}
}

function read2(bc: bare.ByteCursor): u64 | null {
	return bare.readBool(bc) ? bare.readU64(bc) : null;
}

function write2(bc: bare.ByteCursor, x: u64 | null): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		bare.writeU64(bc, x);
	}
}

export type KvListRequest = {
	readonly query: KvListQuery;
	readonly reverse: boolean | null;
	readonly limit: u64 | null;
};

export function readKvListRequest(bc: bare.ByteCursor): KvListRequest {
	return {
		query: readKvListQuery(bc),
		reverse: read1(bc),
		limit: read2(bc),
	};
}

export function writeKvListRequest(
	bc: bare.ByteCursor,
	x: KvListRequest,
): void {
	writeKvListQuery(bc, x.query);
	write1(bc, x.reverse);
	write2(bc, x.limit);
}

function read3(bc: bare.ByteCursor): readonly KvValue[] {
	const len = bare.readUintSafe(bc);
	if (len === 0) {
		return [];
	}
	const result = [readKvValue(bc)];
	for (let i = 1; i < len; i++) {
		result[i] = readKvValue(bc);
	}
	return result;
}

function write3(bc: bare.ByteCursor, x: readonly KvValue[]): void {
	bare.writeUintSafe(bc, x.length);
	for (let i = 0; i < x.length; i++) {
		writeKvValue(bc, x[i]);
	}
}

export type KvPutRequest = {
	readonly keys: readonly KvKey[];
	readonly values: readonly KvValue[];
};

export function readKvPutRequest(bc: bare.ByteCursor): KvPutRequest {
	return {
		keys: read0(bc),
		values: read3(bc),
	};
}

export function writeKvPutRequest(bc: bare.ByteCursor, x: KvPutRequest): void {
	write0(bc, x.keys);
	write3(bc, x.values);
}

export type KvDeleteRequest = {
	readonly keys: readonly KvKey[];
};

export function readKvDeleteRequest(bc: bare.ByteCursor): KvDeleteRequest {
	return {
		keys: read0(bc),
	};
}

export function writeKvDeleteRequest(
	bc: bare.ByteCursor,
	x: KvDeleteRequest,
): void {
	write0(bc, x.keys);
}

export type KvDeleteRangeRequest = {
	readonly start: KvKey;
	readonly end: KvKey;
};

export function readKvDeleteRangeRequest(
	bc: bare.ByteCursor,
): KvDeleteRangeRequest {
	return {
		start: readKvKey(bc),
		end: readKvKey(bc),
	};
}

export function writeKvDeleteRangeRequest(
	bc: bare.ByteCursor,
	x: KvDeleteRangeRequest,
): void {
	writeKvKey(bc, x.start);
	writeKvKey(bc, x.end);
}

export type KvDropRequest = null;

/**
 * Response types
 */
export type KvErrorResponse = {
	readonly message: string;
};

export function readKvErrorResponse(bc: bare.ByteCursor): KvErrorResponse {
	return {
		message: bare.readString(bc),
	};
}

export function writeKvErrorResponse(
	bc: bare.ByteCursor,
	x: KvErrorResponse,
): void {
	bare.writeString(bc, x.message);
}

function read4(bc: bare.ByteCursor): readonly KvMetadata[] {
	const len = bare.readUintSafe(bc);
	if (len === 0) {
		return [];
	}
	const result = [readKvMetadata(bc)];
	for (let i = 1; i < len; i++) {
		result[i] = readKvMetadata(bc);
	}
	return result;
}

function write4(bc: bare.ByteCursor, x: readonly KvMetadata[]): void {
	bare.writeUintSafe(bc, x.length);
	for (let i = 0; i < x.length; i++) {
		writeKvMetadata(bc, x[i]);
	}
}

export type KvGetResponse = {
	readonly keys: readonly KvKey[];
	readonly values: readonly KvValue[];
	readonly metadata: readonly KvMetadata[];
};

export function readKvGetResponse(bc: bare.ByteCursor): KvGetResponse {
	return {
		keys: read0(bc),
		values: read3(bc),
		metadata: read4(bc),
	};
}

export function writeKvGetResponse(
	bc: bare.ByteCursor,
	x: KvGetResponse,
): void {
	write0(bc, x.keys);
	write3(bc, x.values);
	write4(bc, x.metadata);
}

export type KvListResponse = {
	readonly keys: readonly KvKey[];
	readonly values: readonly KvValue[];
	readonly metadata: readonly KvMetadata[];
};

export function readKvListResponse(bc: bare.ByteCursor): KvListResponse {
	return {
		keys: read0(bc),
		values: read3(bc),
		metadata: read4(bc),
	};
}

export function writeKvListResponse(
	bc: bare.ByteCursor,
	x: KvListResponse,
): void {
	write0(bc, x.keys);
	write3(bc, x.values);
	write4(bc, x.metadata);
}

export type KvPutResponse = null;

export type KvDeleteResponse = null;

export type KvDropResponse = null;

/**
 * Request/Response unions
 */
export type KvRequestData =
	| { readonly tag: "KvGetRequest"; readonly val: KvGetRequest }
	| { readonly tag: "KvListRequest"; readonly val: KvListRequest }
	| { readonly tag: "KvPutRequest"; readonly val: KvPutRequest }
	| { readonly tag: "KvDeleteRequest"; readonly val: KvDeleteRequest }
	| {
			readonly tag: "KvDeleteRangeRequest";
			readonly val: KvDeleteRangeRequest;
	  }
	| { readonly tag: "KvDropRequest"; readonly val: KvDropRequest };

export function readKvRequestData(bc: bare.ByteCursor): KvRequestData {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "KvGetRequest", val: readKvGetRequest(bc) };
		case 1:
			return { tag: "KvListRequest", val: readKvListRequest(bc) };
		case 2:
			return { tag: "KvPutRequest", val: readKvPutRequest(bc) };
		case 3:
			return { tag: "KvDeleteRequest", val: readKvDeleteRequest(bc) };
		case 4:
			return {
				tag: "KvDeleteRangeRequest",
				val: readKvDeleteRangeRequest(bc),
			};
		case 5:
			return { tag: "KvDropRequest", val: null };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeKvRequestData(
	bc: bare.ByteCursor,
	x: KvRequestData,
): void {
	switch (x.tag) {
		case "KvGetRequest": {
			bare.writeU8(bc, 0);
			writeKvGetRequest(bc, x.val);
			break;
		}
		case "KvListRequest": {
			bare.writeU8(bc, 1);
			writeKvListRequest(bc, x.val);
			break;
		}
		case "KvPutRequest": {
			bare.writeU8(bc, 2);
			writeKvPutRequest(bc, x.val);
			break;
		}
		case "KvDeleteRequest": {
			bare.writeU8(bc, 3);
			writeKvDeleteRequest(bc, x.val);
			break;
		}
		case "KvDeleteRangeRequest": {
			bare.writeU8(bc, 4);
			writeKvDeleteRangeRequest(bc, x.val);
			break;
		}
		case "KvDropRequest": {
			bare.writeU8(bc, 5);
			break;
		}
	}
}

export type KvResponseData =
	| { readonly tag: "KvErrorResponse"; readonly val: KvErrorResponse }
	| { readonly tag: "KvGetResponse"; readonly val: KvGetResponse }
	| { readonly tag: "KvListResponse"; readonly val: KvListResponse }
	| { readonly tag: "KvPutResponse"; readonly val: KvPutResponse }
	| { readonly tag: "KvDeleteResponse"; readonly val: KvDeleteResponse }
	| { readonly tag: "KvDropResponse"; readonly val: KvDropResponse };

export function readKvResponseData(bc: bare.ByteCursor): KvResponseData {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "KvErrorResponse", val: readKvErrorResponse(bc) };
		case 1:
			return { tag: "KvGetResponse", val: readKvGetResponse(bc) };
		case 2:
			return { tag: "KvListResponse", val: readKvListResponse(bc) };
		case 3:
			return { tag: "KvPutResponse", val: null };
		case 4:
			return { tag: "KvDeleteResponse", val: null };
		case 5:
			return { tag: "KvDropResponse", val: null };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeKvResponseData(
	bc: bare.ByteCursor,
	x: KvResponseData,
): void {
	switch (x.tag) {
		case "KvErrorResponse": {
			bare.writeU8(bc, 0);
			writeKvErrorResponse(bc, x.val);
			break;
		}
		case "KvGetResponse": {
			bare.writeU8(bc, 1);
			writeKvGetResponse(bc, x.val);
			break;
		}
		case "KvListResponse": {
			bare.writeU8(bc, 2);
			writeKvListResponse(bc, x.val);
			break;
		}
		case "KvPutResponse": {
			bare.writeU8(bc, 3);
			break;
		}
		case "KvDeleteResponse": {
			bare.writeU8(bc, 4);
			break;
		}
		case "KvDropResponse": {
			bare.writeU8(bc, 5);
			break;
		}
	}
}

/**
 * Core
 */
export enum StopCode {
	Ok = "Ok",
	Error = "Error",
}

export function readStopCode(bc: bare.ByteCursor): StopCode {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return StopCode.Ok;
		case 1:
			return StopCode.Error;
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeStopCode(bc: bare.ByteCursor, x: StopCode): void {
	switch (x) {
		case StopCode.Ok: {
			bare.writeU8(bc, 0);
			break;
		}
		case StopCode.Error: {
			bare.writeU8(bc, 1);
			break;
		}
	}
}

export type ActorName = {
	readonly metadata: Json;
};

export function readActorName(bc: bare.ByteCursor): ActorName {
	return {
		metadata: readJson(bc),
	};
}

export function writeActorName(bc: bare.ByteCursor, x: ActorName): void {
	writeJson(bc, x.metadata);
}

function read5(bc: bare.ByteCursor): string | null {
	return bare.readBool(bc) ? bare.readString(bc) : null;
}

function write5(bc: bare.ByteCursor, x: string | null): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		bare.writeString(bc, x);
	}
}

function read6(bc: bare.ByteCursor): ArrayBuffer | null {
	return bare.readBool(bc) ? bare.readData(bc) : null;
}

function write6(bc: bare.ByteCursor, x: ArrayBuffer | null): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		bare.writeData(bc, x);
	}
}

export type ActorConfig = {
	readonly name: string;
	readonly key: string | null;
	readonly createTs: i64;
	readonly input: ArrayBuffer | null;
};

export function readActorConfig(bc: bare.ByteCursor): ActorConfig {
	return {
		name: bare.readString(bc),
		key: read5(bc),
		createTs: bare.readI64(bc),
		input: read6(bc),
	};
}

export function writeActorConfig(bc: bare.ByteCursor, x: ActorConfig): void {
	bare.writeString(bc, x.name);
	write5(bc, x.key);
	bare.writeI64(bc, x.createTs);
	write6(bc, x.input);
}

export type ActorCheckpoint = {
	readonly actorId: Id;
	readonly generation: u32;
	readonly index: i64;
};

export function readActorCheckpoint(bc: bare.ByteCursor): ActorCheckpoint {
	return {
		actorId: readId(bc),
		generation: bare.readU32(bc),
		index: bare.readI64(bc),
	};
}

export function writeActorCheckpoint(
	bc: bare.ByteCursor,
	x: ActorCheckpoint,
): void {
	writeId(bc, x.actorId);
	bare.writeU32(bc, x.generation);
	bare.writeI64(bc, x.index);
}

/**
 * Intent
 */
export type ActorIntentSleep = null;

export type ActorIntentStop = null;

export type ActorIntent =
	| { readonly tag: "ActorIntentSleep"; readonly val: ActorIntentSleep }
	| { readonly tag: "ActorIntentStop"; readonly val: ActorIntentStop };

export function readActorIntent(bc: bare.ByteCursor): ActorIntent {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "ActorIntentSleep", val: null };
		case 1:
			return { tag: "ActorIntentStop", val: null };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeActorIntent(bc: bare.ByteCursor, x: ActorIntent): void {
	switch (x.tag) {
		case "ActorIntentSleep": {
			bare.writeU8(bc, 0);
			break;
		}
		case "ActorIntentStop": {
			bare.writeU8(bc, 1);
			break;
		}
	}
}

/**
 * State
 */
export type ActorStateRunning = null;

export type ActorStateStopped = {
	readonly code: StopCode;
	readonly message: string | null;
};

export function readActorStateStopped(bc: bare.ByteCursor): ActorStateStopped {
	return {
		code: readStopCode(bc),
		message: read5(bc),
	};
}

export function writeActorStateStopped(
	bc: bare.ByteCursor,
	x: ActorStateStopped,
): void {
	writeStopCode(bc, x.code);
	write5(bc, x.message);
}

export type ActorState =
	| { readonly tag: "ActorStateRunning"; readonly val: ActorStateRunning }
	| { readonly tag: "ActorStateStopped"; readonly val: ActorStateStopped };

export function readActorState(bc: bare.ByteCursor): ActorState {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "ActorStateRunning", val: null };
		case 1:
			return { tag: "ActorStateStopped", val: readActorStateStopped(bc) };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeActorState(bc: bare.ByteCursor, x: ActorState): void {
	switch (x.tag) {
		case "ActorStateRunning": {
			bare.writeU8(bc, 0);
			break;
		}
		case "ActorStateStopped": {
			bare.writeU8(bc, 1);
			writeActorStateStopped(bc, x.val);
			break;
		}
	}
}

/**
 * MARK: Events
 */
export type EventActorIntent = {
	readonly intent: ActorIntent;
};

export function readEventActorIntent(bc: bare.ByteCursor): EventActorIntent {
	return {
		intent: readActorIntent(bc),
	};
}

export function writeEventActorIntent(
	bc: bare.ByteCursor,
	x: EventActorIntent,
): void {
	writeActorIntent(bc, x.intent);
}

export type EventActorStateUpdate = {
	readonly state: ActorState;
};

export function readEventActorStateUpdate(
	bc: bare.ByteCursor,
): EventActorStateUpdate {
	return {
		state: readActorState(bc),
	};
}

export function writeEventActorStateUpdate(
	bc: bare.ByteCursor,
	x: EventActorStateUpdate,
): void {
	writeActorState(bc, x.state);
}

function read7(bc: bare.ByteCursor): i64 | null {
	return bare.readBool(bc) ? bare.readI64(bc) : null;
}

function write7(bc: bare.ByteCursor, x: i64 | null): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		bare.writeI64(bc, x);
	}
}

export type EventActorSetAlarm = {
	readonly alarmTs: i64 | null;
};

export function readEventActorSetAlarm(
	bc: bare.ByteCursor,
): EventActorSetAlarm {
	return {
		alarmTs: read7(bc),
	};
}

export function writeEventActorSetAlarm(
	bc: bare.ByteCursor,
	x: EventActorSetAlarm,
): void {
	write7(bc, x.alarmTs);
}

export type Event =
	| { readonly tag: "EventActorIntent"; readonly val: EventActorIntent }
	| {
			readonly tag: "EventActorStateUpdate";
			readonly val: EventActorStateUpdate;
	  }
	| { readonly tag: "EventActorSetAlarm"; readonly val: EventActorSetAlarm };

export function readEvent(bc: bare.ByteCursor): Event {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "EventActorIntent", val: readEventActorIntent(bc) };
		case 1:
			return {
				tag: "EventActorStateUpdate",
				val: readEventActorStateUpdate(bc),
			};
		case 2:
			return {
				tag: "EventActorSetAlarm",
				val: readEventActorSetAlarm(bc),
			};
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeEvent(bc: bare.ByteCursor, x: Event): void {
	switch (x.tag) {
		case "EventActorIntent": {
			bare.writeU8(bc, 0);
			writeEventActorIntent(bc, x.val);
			break;
		}
		case "EventActorStateUpdate": {
			bare.writeU8(bc, 1);
			writeEventActorStateUpdate(bc, x.val);
			break;
		}
		case "EventActorSetAlarm": {
			bare.writeU8(bc, 2);
			writeEventActorSetAlarm(bc, x.val);
			break;
		}
	}
}

export type EventWrapper = {
	readonly checkpoint: ActorCheckpoint;
	readonly inner: Event;
};

export function readEventWrapper(bc: bare.ByteCursor): EventWrapper {
	return {
		checkpoint: readActorCheckpoint(bc),
		inner: readEvent(bc),
	};
}

export function writeEventWrapper(bc: bare.ByteCursor, x: EventWrapper): void {
	writeActorCheckpoint(bc, x.checkpoint);
	writeEvent(bc, x.inner);
}

export type HibernatingRequest = {
	readonly gatewayId: GatewayId;
	readonly requestId: RequestId;
};

export function readHibernatingRequest(
	bc: bare.ByteCursor,
): HibernatingRequest {
	return {
		gatewayId: readGatewayId(bc),
		requestId: readRequestId(bc),
	};
}

export function writeHibernatingRequest(
	bc: bare.ByteCursor,
	x: HibernatingRequest,
): void {
	writeGatewayId(bc, x.gatewayId);
	writeRequestId(bc, x.requestId);
}

function read8(bc: bare.ByteCursor): readonly HibernatingRequest[] {
	const len = bare.readUintSafe(bc);
	if (len === 0) {
		return [];
	}
	const result = [readHibernatingRequest(bc)];
	for (let i = 1; i < len; i++) {
		result[i] = readHibernatingRequest(bc);
	}
	return result;
}

function write8(bc: bare.ByteCursor, x: readonly HibernatingRequest[]): void {
	bare.writeUintSafe(bc, x.length);
	for (let i = 0; i < x.length; i++) {
		writeHibernatingRequest(bc, x[i]);
	}
}

export type CommandStartActor = {
	readonly config: ActorConfig;
	readonly hibernatingRequests: readonly HibernatingRequest[];
};

export function readCommandStartActor(bc: bare.ByteCursor): CommandStartActor {
	return {
		config: readActorConfig(bc),
		hibernatingRequests: read8(bc),
	};
}

export function writeCommandStartActor(
	bc: bare.ByteCursor,
	x: CommandStartActor,
): void {
	writeActorConfig(bc, x.config);
	write8(bc, x.hibernatingRequests);
}

export type CommandStopActor = null;

export type Command =
	| { readonly tag: "CommandStartActor"; readonly val: CommandStartActor }
	| { readonly tag: "CommandStopActor"; readonly val: CommandStopActor };

export function readCommand(bc: bare.ByteCursor): Command {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "CommandStartActor", val: readCommandStartActor(bc) };
		case 1:
			return { tag: "CommandStopActor", val: null };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeCommand(bc: bare.ByteCursor, x: Command): void {
	switch (x.tag) {
		case "CommandStartActor": {
			bare.writeU8(bc, 0);
			writeCommandStartActor(bc, x.val);
			break;
		}
		case "CommandStopActor": {
			bare.writeU8(bc, 1);
			break;
		}
	}
}

export type CommandWrapper = {
	readonly checkpoint: ActorCheckpoint;
	readonly inner: Command;
};

export function readCommandWrapper(bc: bare.ByteCursor): CommandWrapper {
	return {
		checkpoint: readActorCheckpoint(bc),
		inner: readCommand(bc),
	};
}

export function writeCommandWrapper(
	bc: bare.ByteCursor,
	x: CommandWrapper,
): void {
	writeActorCheckpoint(bc, x.checkpoint);
	writeCommand(bc, x.inner);
}

/**
 * We redeclare this so its top level
 */
export type ActorCommandKeyData =
	| { readonly tag: "CommandStartActor"; readonly val: CommandStartActor }
	| { readonly tag: "CommandStopActor"; readonly val: CommandStopActor };

export function readActorCommandKeyData(
	bc: bare.ByteCursor,
): ActorCommandKeyData {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "CommandStartActor", val: readCommandStartActor(bc) };
		case 1:
			return { tag: "CommandStopActor", val: null };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeActorCommandKeyData(
	bc: bare.ByteCursor,
	x: ActorCommandKeyData,
): void {
	switch (x.tag) {
		case "CommandStartActor": {
			bare.writeU8(bc, 0);
			writeCommandStartActor(bc, x.val);
			break;
		}
		case "CommandStopActor": {
			bare.writeU8(bc, 1);
			break;
		}
	}
}

export function encodeActorCommandKeyData(
	x: ActorCommandKeyData,
	config?: Partial<bare.Config>,
): Uint8Array {
	const fullConfig = config != null ? bare.Config(config) : DEFAULT_CONFIG;
	const bc = new bare.ByteCursor(
		new Uint8Array(fullConfig.initialBufferLength),
		fullConfig,
	);
	writeActorCommandKeyData(bc, x);
	return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
}

export function decodeActorCommandKeyData(
	bytes: Uint8Array,
): ActorCommandKeyData {
	const bc = new bare.ByteCursor(bytes, DEFAULT_CONFIG);
	const result = readActorCommandKeyData(bc);
	if (bc.offset < bc.view.byteLength) {
		throw new bare.BareError(bc.offset, "remaining bytes");
	}
	return result;
}

export type MessageId = {
	/**
	 * Globally unique ID
	 */
	readonly gatewayId: GatewayId;
	/**
	 * Unique ID to the gateway
	 */
	readonly requestId: RequestId;
	/**
	 * Unique ID to the request
	 */
	readonly messageIndex: MessageIndex;
};

export function readMessageId(bc: bare.ByteCursor): MessageId {
	return {
		gatewayId: readGatewayId(bc),
		requestId: readRequestId(bc),
		messageIndex: readMessageIndex(bc),
	};
}

export function writeMessageId(bc: bare.ByteCursor, x: MessageId): void {
	writeGatewayId(bc, x.gatewayId);
	writeRequestId(bc, x.requestId);
	writeMessageIndex(bc, x.messageIndex);
}

function read9(bc: bare.ByteCursor): ReadonlyMap<string, string> {
	const len = bare.readUintSafe(bc);
	const result = new Map<string, string>();
	for (let i = 0; i < len; i++) {
		const offset = bc.offset;
		const key = bare.readString(bc);
		if (result.has(key)) {
			bc.offset = offset;
			throw new bare.BareError(offset, "duplicated key");
		}
		result.set(key, bare.readString(bc));
	}
	return result;
}

function write9(bc: bare.ByteCursor, x: ReadonlyMap<string, string>): void {
	bare.writeUintSafe(bc, x.size);
	for (const kv of x) {
		bare.writeString(bc, kv[0]);
		bare.writeString(bc, kv[1]);
	}
}

/**
 * HTTP
 */
export type ToClientRequestStart = {
	readonly actorId: Id;
	readonly method: string;
	readonly path: string;
	readonly headers: ReadonlyMap<string, string>;
	readonly body: ArrayBuffer | null;
	readonly stream: boolean;
};

export function readToClientRequestStart(
	bc: bare.ByteCursor,
): ToClientRequestStart {
	return {
		actorId: readId(bc),
		method: bare.readString(bc),
		path: bare.readString(bc),
		headers: read9(bc),
		body: read6(bc),
		stream: bare.readBool(bc),
	};
}

export function writeToClientRequestStart(
	bc: bare.ByteCursor,
	x: ToClientRequestStart,
): void {
	writeId(bc, x.actorId);
	bare.writeString(bc, x.method);
	bare.writeString(bc, x.path);
	write9(bc, x.headers);
	write6(bc, x.body);
	bare.writeBool(bc, x.stream);
}

export type ToClientRequestChunk = {
	readonly body: ArrayBuffer;
	readonly finish: boolean;
};

export function readToClientRequestChunk(
	bc: bare.ByteCursor,
): ToClientRequestChunk {
	return {
		body: bare.readData(bc),
		finish: bare.readBool(bc),
	};
}

export function writeToClientRequestChunk(
	bc: bare.ByteCursor,
	x: ToClientRequestChunk,
): void {
	bare.writeData(bc, x.body);
	bare.writeBool(bc, x.finish);
}

export type ToClientRequestAbort = null;

export type ToServerResponseStart = {
	readonly status: u16;
	readonly headers: ReadonlyMap<string, string>;
	readonly body: ArrayBuffer | null;
	readonly stream: boolean;
};

export function readToServerResponseStart(
	bc: bare.ByteCursor,
): ToServerResponseStart {
	return {
		status: bare.readU16(bc),
		headers: read9(bc),
		body: read6(bc),
		stream: bare.readBool(bc),
	};
}

export function writeToServerResponseStart(
	bc: bare.ByteCursor,
	x: ToServerResponseStart,
): void {
	bare.writeU16(bc, x.status);
	write9(bc, x.headers);
	write6(bc, x.body);
	bare.writeBool(bc, x.stream);
}

export type ToServerResponseChunk = {
	readonly body: ArrayBuffer;
	readonly finish: boolean;
};

export function readToServerResponseChunk(
	bc: bare.ByteCursor,
): ToServerResponseChunk {
	return {
		body: bare.readData(bc),
		finish: bare.readBool(bc),
	};
}

export function writeToServerResponseChunk(
	bc: bare.ByteCursor,
	x: ToServerResponseChunk,
): void {
	bare.writeData(bc, x.body);
	bare.writeBool(bc, x.finish);
}

export type ToServerResponseAbort = null;

/**
 * WebSocket
 */
export type ToClientWebSocketOpen = {
	readonly actorId: Id;
	readonly path: string;
	readonly headers: ReadonlyMap<string, string>;
};

export function readToClientWebSocketOpen(
	bc: bare.ByteCursor,
): ToClientWebSocketOpen {
	return {
		actorId: readId(bc),
		path: bare.readString(bc),
		headers: read9(bc),
	};
}

export function writeToClientWebSocketOpen(
	bc: bare.ByteCursor,
	x: ToClientWebSocketOpen,
): void {
	writeId(bc, x.actorId);
	bare.writeString(bc, x.path);
	write9(bc, x.headers);
}

export type ToClientWebSocketMessage = {
	readonly data: ArrayBuffer;
	readonly binary: boolean;
};

export function readToClientWebSocketMessage(
	bc: bare.ByteCursor,
): ToClientWebSocketMessage {
	return {
		data: bare.readData(bc),
		binary: bare.readBool(bc),
	};
}

export function writeToClientWebSocketMessage(
	bc: bare.ByteCursor,
	x: ToClientWebSocketMessage,
): void {
	bare.writeData(bc, x.data);
	bare.writeBool(bc, x.binary);
}

function read10(bc: bare.ByteCursor): u16 | null {
	return bare.readBool(bc) ? bare.readU16(bc) : null;
}

function write10(bc: bare.ByteCursor, x: u16 | null): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		bare.writeU16(bc, x);
	}
}

export type ToClientWebSocketClose = {
	readonly code: u16 | null;
	readonly reason: string | null;
};

export function readToClientWebSocketClose(
	bc: bare.ByteCursor,
): ToClientWebSocketClose {
	return {
		code: read10(bc),
		reason: read5(bc),
	};
}

export function writeToClientWebSocketClose(
	bc: bare.ByteCursor,
	x: ToClientWebSocketClose,
): void {
	write10(bc, x.code);
	write5(bc, x.reason);
}

export type ToServerWebSocketOpen = {
	readonly canHibernate: boolean;
};

export function readToServerWebSocketOpen(
	bc: bare.ByteCursor,
): ToServerWebSocketOpen {
	return {
		canHibernate: bare.readBool(bc),
	};
}

export function writeToServerWebSocketOpen(
	bc: bare.ByteCursor,
	x: ToServerWebSocketOpen,
): void {
	bare.writeBool(bc, x.canHibernate);
}

export type ToServerWebSocketMessage = {
	readonly data: ArrayBuffer;
	readonly binary: boolean;
};

export function readToServerWebSocketMessage(
	bc: bare.ByteCursor,
): ToServerWebSocketMessage {
	return {
		data: bare.readData(bc),
		binary: bare.readBool(bc),
	};
}

export function writeToServerWebSocketMessage(
	bc: bare.ByteCursor,
	x: ToServerWebSocketMessage,
): void {
	bare.writeData(bc, x.data);
	bare.writeBool(bc, x.binary);
}

export type ToServerWebSocketMessageAck = {
	readonly index: MessageIndex;
};

export function readToServerWebSocketMessageAck(
	bc: bare.ByteCursor,
): ToServerWebSocketMessageAck {
	return {
		index: readMessageIndex(bc),
	};
}

export function writeToServerWebSocketMessageAck(
	bc: bare.ByteCursor,
	x: ToServerWebSocketMessageAck,
): void {
	writeMessageIndex(bc, x.index);
}

export type ToServerWebSocketClose = {
	readonly code: u16 | null;
	readonly reason: string | null;
	readonly hibernate: boolean;
};

export function readToServerWebSocketClose(
	bc: bare.ByteCursor,
): ToServerWebSocketClose {
	return {
		code: read10(bc),
		reason: read5(bc),
		hibernate: bare.readBool(bc),
	};
}

export function writeToServerWebSocketClose(
	bc: bare.ByteCursor,
	x: ToServerWebSocketClose,
): void {
	write10(bc, x.code);
	write5(bc, x.reason);
	bare.writeBool(bc, x.hibernate);
}

/**
 * To Server
 */
export type ToServerTunnelMessageKind =
	/**
	 * HTTP
	 */
	| {
			readonly tag: "ToServerResponseStart";
			readonly val: ToServerResponseStart;
	  }
	| {
			readonly tag: "ToServerResponseChunk";
			readonly val: ToServerResponseChunk;
	  }
	| {
			readonly tag: "ToServerResponseAbort";
			readonly val: ToServerResponseAbort;
	  }
	/**
	 * WebSocket
	 */
	| {
			readonly tag: "ToServerWebSocketOpen";
			readonly val: ToServerWebSocketOpen;
	  }
	| {
			readonly tag: "ToServerWebSocketMessage";
			readonly val: ToServerWebSocketMessage;
	  }
	| {
			readonly tag: "ToServerWebSocketMessageAck";
			readonly val: ToServerWebSocketMessageAck;
	  }
	| {
			readonly tag: "ToServerWebSocketClose";
			readonly val: ToServerWebSocketClose;
	  };

export function readToServerTunnelMessageKind(
	bc: bare.ByteCursor,
): ToServerTunnelMessageKind {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return {
				tag: "ToServerResponseStart",
				val: readToServerResponseStart(bc),
			};
		case 1:
			return {
				tag: "ToServerResponseChunk",
				val: readToServerResponseChunk(bc),
			};
		case 2:
			return { tag: "ToServerResponseAbort", val: null };
		case 3:
			return {
				tag: "ToServerWebSocketOpen",
				val: readToServerWebSocketOpen(bc),
			};
		case 4:
			return {
				tag: "ToServerWebSocketMessage",
				val: readToServerWebSocketMessage(bc),
			};
		case 5:
			return {
				tag: "ToServerWebSocketMessageAck",
				val: readToServerWebSocketMessageAck(bc),
			};
		case 6:
			return {
				tag: "ToServerWebSocketClose",
				val: readToServerWebSocketClose(bc),
			};
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeToServerTunnelMessageKind(
	bc: bare.ByteCursor,
	x: ToServerTunnelMessageKind,
): void {
	switch (x.tag) {
		case "ToServerResponseStart": {
			bare.writeU8(bc, 0);
			writeToServerResponseStart(bc, x.val);
			break;
		}
		case "ToServerResponseChunk": {
			bare.writeU8(bc, 1);
			writeToServerResponseChunk(bc, x.val);
			break;
		}
		case "ToServerResponseAbort": {
			bare.writeU8(bc, 2);
			break;
		}
		case "ToServerWebSocketOpen": {
			bare.writeU8(bc, 3);
			writeToServerWebSocketOpen(bc, x.val);
			break;
		}
		case "ToServerWebSocketMessage": {
			bare.writeU8(bc, 4);
			writeToServerWebSocketMessage(bc, x.val);
			break;
		}
		case "ToServerWebSocketMessageAck": {
			bare.writeU8(bc, 5);
			writeToServerWebSocketMessageAck(bc, x.val);
			break;
		}
		case "ToServerWebSocketClose": {
			bare.writeU8(bc, 6);
			writeToServerWebSocketClose(bc, x.val);
			break;
		}
	}
}

export type ToServerTunnelMessage = {
	readonly messageId: MessageId;
	readonly messageKind: ToServerTunnelMessageKind;
};

export function readToServerTunnelMessage(
	bc: bare.ByteCursor,
): ToServerTunnelMessage {
	return {
		messageId: readMessageId(bc),
		messageKind: readToServerTunnelMessageKind(bc),
	};
}

export function writeToServerTunnelMessage(
	bc: bare.ByteCursor,
	x: ToServerTunnelMessage,
): void {
	writeMessageId(bc, x.messageId);
	writeToServerTunnelMessageKind(bc, x.messageKind);
}

/**
 * To Client
 */
export type ToClientTunnelMessageKind =
	/**
	 * HTTP
	 */
	| {
			readonly tag: "ToClientRequestStart";
			readonly val: ToClientRequestStart;
	  }
	| {
			readonly tag: "ToClientRequestChunk";
			readonly val: ToClientRequestChunk;
	  }
	| {
			readonly tag: "ToClientRequestAbort";
			readonly val: ToClientRequestAbort;
	  }
	/**
	 * WebSocket
	 */
	| {
			readonly tag: "ToClientWebSocketOpen";
			readonly val: ToClientWebSocketOpen;
	  }
	| {
			readonly tag: "ToClientWebSocketMessage";
			readonly val: ToClientWebSocketMessage;
	  }
	| {
			readonly tag: "ToClientWebSocketClose";
			readonly val: ToClientWebSocketClose;
	  };

export function readToClientTunnelMessageKind(
	bc: bare.ByteCursor,
): ToClientTunnelMessageKind {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return {
				tag: "ToClientRequestStart",
				val: readToClientRequestStart(bc),
			};
		case 1:
			return {
				tag: "ToClientRequestChunk",
				val: readToClientRequestChunk(bc),
			};
		case 2:
			return { tag: "ToClientRequestAbort", val: null };
		case 3:
			return {
				tag: "ToClientWebSocketOpen",
				val: readToClientWebSocketOpen(bc),
			};
		case 4:
			return {
				tag: "ToClientWebSocketMessage",
				val: readToClientWebSocketMessage(bc),
			};
		case 5:
			return {
				tag: "ToClientWebSocketClose",
				val: readToClientWebSocketClose(bc),
			};
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeToClientTunnelMessageKind(
	bc: bare.ByteCursor,
	x: ToClientTunnelMessageKind,
): void {
	switch (x.tag) {
		case "ToClientRequestStart": {
			bare.writeU8(bc, 0);
			writeToClientRequestStart(bc, x.val);
			break;
		}
		case "ToClientRequestChunk": {
			bare.writeU8(bc, 1);
			writeToClientRequestChunk(bc, x.val);
			break;
		}
		case "ToClientRequestAbort": {
			bare.writeU8(bc, 2);
			break;
		}
		case "ToClientWebSocketOpen": {
			bare.writeU8(bc, 3);
			writeToClientWebSocketOpen(bc, x.val);
			break;
		}
		case "ToClientWebSocketMessage": {
			bare.writeU8(bc, 4);
			writeToClientWebSocketMessage(bc, x.val);
			break;
		}
		case "ToClientWebSocketClose": {
			bare.writeU8(bc, 5);
			writeToClientWebSocketClose(bc, x.val);
			break;
		}
	}
}

export type ToClientTunnelMessage = {
	readonly messageId: MessageId;
	readonly messageKind: ToClientTunnelMessageKind;
};

export function readToClientTunnelMessage(
	bc: bare.ByteCursor,
): ToClientTunnelMessage {
	return {
		messageId: readMessageId(bc),
		messageKind: readToClientTunnelMessageKind(bc),
	};
}

export function writeToClientTunnelMessage(
	bc: bare.ByteCursor,
	x: ToClientTunnelMessage,
): void {
	writeMessageId(bc, x.messageId);
	writeToClientTunnelMessageKind(bc, x.messageKind);
}

export type ToClientPing = {
	readonly ts: i64;
};

export function readToClientPing(bc: bare.ByteCursor): ToClientPing {
	return {
		ts: bare.readI64(bc),
	};
}

export function writeToClientPing(bc: bare.ByteCursor, x: ToClientPing): void {
	bare.writeI64(bc, x.ts);
}

function read11(bc: bare.ByteCursor): ReadonlyMap<string, ActorName> {
	const len = bare.readUintSafe(bc);
	const result = new Map<string, ActorName>();
	for (let i = 0; i < len; i++) {
		const offset = bc.offset;
		const key = bare.readString(bc);
		if (result.has(key)) {
			bc.offset = offset;
			throw new bare.BareError(offset, "duplicated key");
		}
		result.set(key, readActorName(bc));
	}
	return result;
}

function write11(bc: bare.ByteCursor, x: ReadonlyMap<string, ActorName>): void {
	bare.writeUintSafe(bc, x.size);
	for (const kv of x) {
		bare.writeString(bc, kv[0]);
		writeActorName(bc, kv[1]);
	}
}

function read12(bc: bare.ByteCursor): ReadonlyMap<string, ActorName> | null {
	return bare.readBool(bc) ? read11(bc) : null;
}

function write12(
	bc: bare.ByteCursor,
	x: ReadonlyMap<string, ActorName> | null,
): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		write11(bc, x);
	}
}

function read13(bc: bare.ByteCursor): Json | null {
	return bare.readBool(bc) ? readJson(bc) : null;
}

function write13(bc: bare.ByteCursor, x: Json | null): void {
	bare.writeBool(bc, x != null);
	if (x != null) {
		writeJson(bc, x);
	}
}

/**
 * MARK: To Server
 */
export type ToServerInit = {
	readonly name: string;
	readonly version: u32;
	readonly totalSlots: u32;
	readonly prepopulateActorNames: ReadonlyMap<string, ActorName> | null;
	readonly metadata: Json | null;
};

export function readToServerInit(bc: bare.ByteCursor): ToServerInit {
	return {
		name: bare.readString(bc),
		version: bare.readU32(bc),
		totalSlots: bare.readU32(bc),
		prepopulateActorNames: read12(bc),
		metadata: read13(bc),
	};
}

export function writeToServerInit(bc: bare.ByteCursor, x: ToServerInit): void {
	bare.writeString(bc, x.name);
	bare.writeU32(bc, x.version);
	bare.writeU32(bc, x.totalSlots);
	write12(bc, x.prepopulateActorNames);
	write13(bc, x.metadata);
}

export type ToServerEvents = readonly EventWrapper[];

export function readToServerEvents(bc: bare.ByteCursor): ToServerEvents {
	const len = bare.readUintSafe(bc);
	if (len === 0) {
		return [];
	}
	const result = [readEventWrapper(bc)];
	for (let i = 1; i < len; i++) {
		result[i] = readEventWrapper(bc);
	}
	return result;
}

export function writeToServerEvents(
	bc: bare.ByteCursor,
	x: ToServerEvents,
): void {
	bare.writeUintSafe(bc, x.length);
	for (let i = 0; i < x.length; i++) {
		writeEventWrapper(bc, x[i]);
	}
}

function read14(bc: bare.ByteCursor): readonly ActorCheckpoint[] {
	const len = bare.readUintSafe(bc);
	if (len === 0) {
		return [];
	}
	const result = [readActorCheckpoint(bc)];
	for (let i = 1; i < len; i++) {
		result[i] = readActorCheckpoint(bc);
	}
	return result;
}

function write14(bc: bare.ByteCursor, x: readonly ActorCheckpoint[]): void {
	bare.writeUintSafe(bc, x.length);
	for (let i = 0; i < x.length; i++) {
		writeActorCheckpoint(bc, x[i]);
	}
}

export type ToServerAckCommands = {
	readonly lastCommandCheckpoints: readonly ActorCheckpoint[];
};

export function readToServerAckCommands(
	bc: bare.ByteCursor,
): ToServerAckCommands {
	return {
		lastCommandCheckpoints: read14(bc),
	};
}

export function writeToServerAckCommands(
	bc: bare.ByteCursor,
	x: ToServerAckCommands,
): void {
	write14(bc, x.lastCommandCheckpoints);
}

export type ToServerStopping = null;

export type ToServerPong = {
	readonly ts: i64;
};

export function readToServerPong(bc: bare.ByteCursor): ToServerPong {
	return {
		ts: bare.readI64(bc),
	};
}

export function writeToServerPong(bc: bare.ByteCursor, x: ToServerPong): void {
	bare.writeI64(bc, x.ts);
}

export type ToServerKvRequest = {
	readonly actorId: Id;
	readonly requestId: u32;
	readonly data: KvRequestData;
};

export function readToServerKvRequest(bc: bare.ByteCursor): ToServerKvRequest {
	return {
		actorId: readId(bc),
		requestId: bare.readU32(bc),
		data: readKvRequestData(bc),
	};
}

export function writeToServerKvRequest(
	bc: bare.ByteCursor,
	x: ToServerKvRequest,
): void {
	writeId(bc, x.actorId);
	bare.writeU32(bc, x.requestId);
	writeKvRequestData(bc, x.data);
}

export type ToServer =
	| { readonly tag: "ToServerInit"; readonly val: ToServerInit }
	| { readonly tag: "ToServerEvents"; readonly val: ToServerEvents }
	| { readonly tag: "ToServerAckCommands"; readonly val: ToServerAckCommands }
	| { readonly tag: "ToServerStopping"; readonly val: ToServerStopping }
	| { readonly tag: "ToServerPong"; readonly val: ToServerPong }
	| { readonly tag: "ToServerKvRequest"; readonly val: ToServerKvRequest }
	| {
			readonly tag: "ToServerTunnelMessage";
			readonly val: ToServerTunnelMessage;
	  };

export function readToServer(bc: bare.ByteCursor): ToServer {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "ToServerInit", val: readToServerInit(bc) };
		case 1:
			return { tag: "ToServerEvents", val: readToServerEvents(bc) };
		case 2:
			return {
				tag: "ToServerAckCommands",
				val: readToServerAckCommands(bc),
			};
		case 3:
			return { tag: "ToServerStopping", val: null };
		case 4:
			return { tag: "ToServerPong", val: readToServerPong(bc) };
		case 5:
			return { tag: "ToServerKvRequest", val: readToServerKvRequest(bc) };
		case 6:
			return {
				tag: "ToServerTunnelMessage",
				val: readToServerTunnelMessage(bc),
			};
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeToServer(bc: bare.ByteCursor, x: ToServer): void {
	switch (x.tag) {
		case "ToServerInit": {
			bare.writeU8(bc, 0);
			writeToServerInit(bc, x.val);
			break;
		}
		case "ToServerEvents": {
			bare.writeU8(bc, 1);
			writeToServerEvents(bc, x.val);
			break;
		}
		case "ToServerAckCommands": {
			bare.writeU8(bc, 2);
			writeToServerAckCommands(bc, x.val);
			break;
		}
		case "ToServerStopping": {
			bare.writeU8(bc, 3);
			break;
		}
		case "ToServerPong": {
			bare.writeU8(bc, 4);
			writeToServerPong(bc, x.val);
			break;
		}
		case "ToServerKvRequest": {
			bare.writeU8(bc, 5);
			writeToServerKvRequest(bc, x.val);
			break;
		}
		case "ToServerTunnelMessage": {
			bare.writeU8(bc, 6);
			writeToServerTunnelMessage(bc, x.val);
			break;
		}
	}
}

export function encodeToServer(
	x: ToServer,
	config?: Partial<bare.Config>,
): Uint8Array {
	const fullConfig = config != null ? bare.Config(config) : DEFAULT_CONFIG;
	const bc = new bare.ByteCursor(
		new Uint8Array(fullConfig.initialBufferLength),
		fullConfig,
	);
	writeToServer(bc, x);
	return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
}

export function decodeToServer(bytes: Uint8Array): ToServer {
	const bc = new bare.ByteCursor(bytes, DEFAULT_CONFIG);
	const result = readToServer(bc);
	if (bc.offset < bc.view.byteLength) {
		throw new bare.BareError(bc.offset, "remaining bytes");
	}
	return result;
}

/**
 * MARK: To Client
 */
export type ProtocolMetadata = {
	readonly runnerLostThreshold: i64;
	readonly actorStopThreshold: i64;
	readonly serverlessDrainGracePeriod: i64 | null;
};

export function readProtocolMetadata(bc: bare.ByteCursor): ProtocolMetadata {
	return {
		runnerLostThreshold: bare.readI64(bc),
		actorStopThreshold: bare.readI64(bc),
		serverlessDrainGracePeriod: read7(bc),
	};
}

export function writeProtocolMetadata(
	bc: bare.ByteCursor,
	x: ProtocolMetadata,
): void {
	bare.writeI64(bc, x.runnerLostThreshold);
	bare.writeI64(bc, x.actorStopThreshold);
	write7(bc, x.serverlessDrainGracePeriod);
}

export type ToClientInit = {
	readonly runnerId: Id;
	readonly metadata: ProtocolMetadata;
};

export function readToClientInit(bc: bare.ByteCursor): ToClientInit {
	return {
		runnerId: readId(bc),
		metadata: readProtocolMetadata(bc),
	};
}

export function writeToClientInit(bc: bare.ByteCursor, x: ToClientInit): void {
	writeId(bc, x.runnerId);
	writeProtocolMetadata(bc, x.metadata);
}

export type ToClientCommands = readonly CommandWrapper[];

export function readToClientCommands(bc: bare.ByteCursor): ToClientCommands {
	const len = bare.readUintSafe(bc);
	if (len === 0) {
		return [];
	}
	const result = [readCommandWrapper(bc)];
	for (let i = 1; i < len; i++) {
		result[i] = readCommandWrapper(bc);
	}
	return result;
}

export function writeToClientCommands(
	bc: bare.ByteCursor,
	x: ToClientCommands,
): void {
	bare.writeUintSafe(bc, x.length);
	for (let i = 0; i < x.length; i++) {
		writeCommandWrapper(bc, x[i]);
	}
}

export type ToClientAckEvents = {
	readonly lastEventCheckpoints: readonly ActorCheckpoint[];
};

export function readToClientAckEvents(bc: bare.ByteCursor): ToClientAckEvents {
	return {
		lastEventCheckpoints: read14(bc),
	};
}

export function writeToClientAckEvents(
	bc: bare.ByteCursor,
	x: ToClientAckEvents,
): void {
	write14(bc, x.lastEventCheckpoints);
}

export type ToClientKvResponse = {
	readonly requestId: u32;
	readonly data: KvResponseData;
};

export function readToClientKvResponse(
	bc: bare.ByteCursor,
): ToClientKvResponse {
	return {
		requestId: bare.readU32(bc),
		data: readKvResponseData(bc),
	};
}

export function writeToClientKvResponse(
	bc: bare.ByteCursor,
	x: ToClientKvResponse,
): void {
	bare.writeU32(bc, x.requestId);
	writeKvResponseData(bc, x.data);
}

export type ToClient =
	| { readonly tag: "ToClientInit"; readonly val: ToClientInit }
	| { readonly tag: "ToClientCommands"; readonly val: ToClientCommands }
	| { readonly tag: "ToClientAckEvents"; readonly val: ToClientAckEvents }
	| { readonly tag: "ToClientKvResponse"; readonly val: ToClientKvResponse }
	| {
			readonly tag: "ToClientTunnelMessage";
			readonly val: ToClientTunnelMessage;
	  }
	| { readonly tag: "ToClientPing"; readonly val: ToClientPing };

export function readToClient(bc: bare.ByteCursor): ToClient {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "ToClientInit", val: readToClientInit(bc) };
		case 1:
			return { tag: "ToClientCommands", val: readToClientCommands(bc) };
		case 2:
			return { tag: "ToClientAckEvents", val: readToClientAckEvents(bc) };
		case 3:
			return {
				tag: "ToClientKvResponse",
				val: readToClientKvResponse(bc),
			};
		case 4:
			return {
				tag: "ToClientTunnelMessage",
				val: readToClientTunnelMessage(bc),
			};
		case 5:
			return { tag: "ToClientPing", val: readToClientPing(bc) };
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeToClient(bc: bare.ByteCursor, x: ToClient): void {
	switch (x.tag) {
		case "ToClientInit": {
			bare.writeU8(bc, 0);
			writeToClientInit(bc, x.val);
			break;
		}
		case "ToClientCommands": {
			bare.writeU8(bc, 1);
			writeToClientCommands(bc, x.val);
			break;
		}
		case "ToClientAckEvents": {
			bare.writeU8(bc, 2);
			writeToClientAckEvents(bc, x.val);
			break;
		}
		case "ToClientKvResponse": {
			bare.writeU8(bc, 3);
			writeToClientKvResponse(bc, x.val);
			break;
		}
		case "ToClientTunnelMessage": {
			bare.writeU8(bc, 4);
			writeToClientTunnelMessage(bc, x.val);
			break;
		}
		case "ToClientPing": {
			bare.writeU8(bc, 5);
			writeToClientPing(bc, x.val);
			break;
		}
	}
}

export function encodeToClient(
	x: ToClient,
	config?: Partial<bare.Config>,
): Uint8Array {
	const fullConfig = config != null ? bare.Config(config) : DEFAULT_CONFIG;
	const bc = new bare.ByteCursor(
		new Uint8Array(fullConfig.initialBufferLength),
		fullConfig,
	);
	writeToClient(bc, x);
	return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
}

export function decodeToClient(bytes: Uint8Array): ToClient {
	const bc = new bare.ByteCursor(bytes, DEFAULT_CONFIG);
	const result = readToClient(bc);
	if (bc.offset < bc.view.byteLength) {
		throw new bare.BareError(bc.offset, "remaining bytes");
	}
	return result;
}

/**
 * MARK: To Runner
 */
export type ToRunnerPing = {
	readonly gatewayId: GatewayId;
	readonly requestId: RequestId;
	readonly ts: i64;
};

export function readToRunnerPing(bc: bare.ByteCursor): ToRunnerPing {
	return {
		gatewayId: readGatewayId(bc),
		requestId: readRequestId(bc),
		ts: bare.readI64(bc),
	};
}

export function writeToRunnerPing(bc: bare.ByteCursor, x: ToRunnerPing): void {
	writeGatewayId(bc, x.gatewayId);
	writeRequestId(bc, x.requestId);
	bare.writeI64(bc, x.ts);
}

export type ToRunnerClose = null;

/**
 * We have to re-declare the entire union since BARE will not generate the
 * ser/de for ToClient if it's not a top-level type
 */
export type ToRunner =
	| { readonly tag: "ToRunnerPing"; readonly val: ToRunnerPing }
	| { readonly tag: "ToRunnerClose"; readonly val: ToRunnerClose }
	| { readonly tag: "ToClientCommands"; readonly val: ToClientCommands }
	| { readonly tag: "ToClientAckEvents"; readonly val: ToClientAckEvents }
	| {
			readonly tag: "ToClientTunnelMessage";
			readonly val: ToClientTunnelMessage;
	  };

export function readToRunner(bc: bare.ByteCursor): ToRunner {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "ToRunnerPing", val: readToRunnerPing(bc) };
		case 1:
			return { tag: "ToRunnerClose", val: null };
		case 2:
			return { tag: "ToClientCommands", val: readToClientCommands(bc) };
		case 3:
			return { tag: "ToClientAckEvents", val: readToClientAckEvents(bc) };
		case 4:
			return {
				tag: "ToClientTunnelMessage",
				val: readToClientTunnelMessage(bc),
			};
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeToRunner(bc: bare.ByteCursor, x: ToRunner): void {
	switch (x.tag) {
		case "ToRunnerPing": {
			bare.writeU8(bc, 0);
			writeToRunnerPing(bc, x.val);
			break;
		}
		case "ToRunnerClose": {
			bare.writeU8(bc, 1);
			break;
		}
		case "ToClientCommands": {
			bare.writeU8(bc, 2);
			writeToClientCommands(bc, x.val);
			break;
		}
		case "ToClientAckEvents": {
			bare.writeU8(bc, 3);
			writeToClientAckEvents(bc, x.val);
			break;
		}
		case "ToClientTunnelMessage": {
			bare.writeU8(bc, 4);
			writeToClientTunnelMessage(bc, x.val);
			break;
		}
	}
}

export function encodeToRunner(
	x: ToRunner,
	config?: Partial<bare.Config>,
): Uint8Array {
	const fullConfig = config != null ? bare.Config(config) : DEFAULT_CONFIG;
	const bc = new bare.ByteCursor(
		new Uint8Array(fullConfig.initialBufferLength),
		fullConfig,
	);
	writeToRunner(bc, x);
	return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
}

export function decodeToRunner(bytes: Uint8Array): ToRunner {
	const bc = new bare.ByteCursor(bytes, DEFAULT_CONFIG);
	const result = readToRunner(bc);
	if (bc.offset < bc.view.byteLength) {
		throw new bare.BareError(bc.offset, "remaining bytes");
	}
	return result;
}

/**
 * MARK: To Gateway
 */
export type ToGatewayPong = {
	readonly requestId: RequestId;
	readonly ts: i64;
};

export function readToGatewayPong(bc: bare.ByteCursor): ToGatewayPong {
	return {
		requestId: readRequestId(bc),
		ts: bare.readI64(bc),
	};
}

export function writeToGatewayPong(
	bc: bare.ByteCursor,
	x: ToGatewayPong,
): void {
	writeRequestId(bc, x.requestId);
	bare.writeI64(bc, x.ts);
}

export type ToGateway =
	| { readonly tag: "ToGatewayPong"; readonly val: ToGatewayPong }
	| {
			readonly tag: "ToServerTunnelMessage";
			readonly val: ToServerTunnelMessage;
	  };

export function readToGateway(bc: bare.ByteCursor): ToGateway {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return { tag: "ToGatewayPong", val: readToGatewayPong(bc) };
		case 1:
			return {
				tag: "ToServerTunnelMessage",
				val: readToServerTunnelMessage(bc),
			};
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeToGateway(bc: bare.ByteCursor, x: ToGateway): void {
	switch (x.tag) {
		case "ToGatewayPong": {
			bare.writeU8(bc, 0);
			writeToGatewayPong(bc, x.val);
			break;
		}
		case "ToServerTunnelMessage": {
			bare.writeU8(bc, 1);
			writeToServerTunnelMessage(bc, x.val);
			break;
		}
	}
}

export function encodeToGateway(
	x: ToGateway,
	config?: Partial<bare.Config>,
): Uint8Array {
	const fullConfig = config != null ? bare.Config(config) : DEFAULT_CONFIG;
	const bc = new bare.ByteCursor(
		new Uint8Array(fullConfig.initialBufferLength),
		fullConfig,
	);
	writeToGateway(bc, x);
	return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
}

export function decodeToGateway(bytes: Uint8Array): ToGateway {
	const bc = new bare.ByteCursor(bytes, DEFAULT_CONFIG);
	const result = readToGateway(bc);
	if (bc.offset < bc.view.byteLength) {
		throw new bare.BareError(bc.offset, "remaining bytes");
	}
	return result;
}

/**
 * MARK: Serverless
 */
export type ToServerlessServerInit = {
	readonly runnerId: Id;
	readonly runnerProtocolVersion: u16;
};

export function readToServerlessServerInit(
	bc: bare.ByteCursor,
): ToServerlessServerInit {
	return {
		runnerId: readId(bc),
		runnerProtocolVersion: bare.readU16(bc),
	};
}

export function writeToServerlessServerInit(
	bc: bare.ByteCursor,
	x: ToServerlessServerInit,
): void {
	writeId(bc, x.runnerId);
	bare.writeU16(bc, x.runnerProtocolVersion);
}

export type ToServerlessServer = {
	readonly tag: "ToServerlessServerInit";
	readonly val: ToServerlessServerInit;
};

export function readToServerlessServer(
	bc: bare.ByteCursor,
): ToServerlessServer {
	const offset = bc.offset;
	const tag = bare.readU8(bc);
	switch (tag) {
		case 0:
			return {
				tag: "ToServerlessServerInit",
				val: readToServerlessServerInit(bc),
			};
		default: {
			bc.offset = offset;
			throw new bare.BareError(offset, "invalid tag");
		}
	}
}

export function writeToServerlessServer(
	bc: bare.ByteCursor,
	x: ToServerlessServer,
): void {
	switch (x.tag) {
		case "ToServerlessServerInit": {
			bare.writeU8(bc, 0);
			writeToServerlessServerInit(bc, x.val);
			break;
		}
	}
}

export function encodeToServerlessServer(
	x: ToServerlessServer,
	config?: Partial<bare.Config>,
): Uint8Array {
	const fullConfig = config != null ? bare.Config(config) : DEFAULT_CONFIG;
	const bc = new bare.ByteCursor(
		new Uint8Array(fullConfig.initialBufferLength),
		fullConfig,
	);
	writeToServerlessServer(bc, x);
	return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
}

export function decodeToServerlessServer(
	bytes: Uint8Array,
): ToServerlessServer {
	const bc = new bare.ByteCursor(bytes, DEFAULT_CONFIG);
	const result = readToServerlessServer(bc);
	if (bc.offset < bc.view.byteLength) {
		throw new bare.BareError(bc.offset, "remaining bytes");
	}
	return result;
}

function assert(condition: boolean, message?: string): asserts condition {
	if (!condition) throw new Error(message ?? "Assertion failed");
}
