"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } var _class; var _class2;


var _chunkFUBHHHK5cjs = require('./chunk-FUBHHHK5.cjs');


































var _chunkQ5CW77ITcjs = require('./chunk-Q5CW77IT.cjs');


var _chunkLNDVGTPQcjs = require('./chunk-LNDVGTPQ.cjs');


















var _chunkMMUXNMJFcjs = require('./chunk-MMUXNMJF.cjs');



var _chunkL47L3ZWJcjs = require('./chunk-L47L3ZWJ.cjs');

// src/devtools-loader/log.ts
function logger2() {
  return _chunkMMUXNMJFcjs.getLogger.call(void 0, "devtools");
}

// src/devtools-loader/index.ts
var DEFAULT_DEVTOOLS_URL = (version = _chunkMMUXNMJFcjs.VERSION) => `https://releases.rivet.dev/rivet/latest/devtools/mod.js?v=${version}`;
var scriptId = "rivetkit-devtools-script";
function injectDevtools(config) {
  if (!window) {
    logger2().warn("devtools not available outside browser environment");
    return;
  }
  if (!document.getElementById(scriptId)) {
    const script = document.createElement("script");
    script.id = scriptId;
    script.src = DEFAULT_DEVTOOLS_URL();
    script.async = true;
    document.head.appendChild(script);
  }
  window.__rivetkit = window.__rivetkit || [];
  window.__rivetkit.push(config);
}

// src/remote-manager-driver/mod.ts
var _cborx = require('cbor-x'); var cbor2 = _interopRequireWildcard(_cborx); var cbor = _interopRequireWildcard(_cborx); var cbor4 = _interopRequireWildcard(_cborx); var cbor3 = _interopRequireWildcard(_cborx); var cbor5 = _interopRequireWildcard(_cborx);
var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant);

// src/remote-manager-driver/api-utils.ts
var _v4 = require('zod/v4'); var _v42 = _interopRequireDefault(_v4);

// src/client/utils.ts



// src/client/errors.ts
var ActorClientError = class extends Error {
};
var InternalError = class extends ActorClientError {
};
var ManagerError = class extends ActorClientError {
  constructor(error, opts) {
    super(`Manager error: ${error}`, opts);
  }
};
var MalformedResponseMessage = class extends ActorClientError {
  constructor(cause) {
    super(`Malformed response message: ${cause}`, { cause });
  }
};
var ActorError = (_class = class extends ActorClientError {
  constructor(group, code, message, metadata) {
    super(message);_class.prototype.__init.call(this);;
    this.group = group;
    this.code = code;
    this.metadata = metadata;
  }
  __init() {this.__type = "ActorError"}
}, _class);
var HttpRequestError = class extends ActorClientError {
  constructor(message, opts) {
    super(`HTTP request error: ${message}`, { cause: opts == null ? void 0 : opts.cause });
  }
};
var ActorConnDisposed = class extends ActorClientError {
  constructor() {
    super("Attempting to interact with a disposed actor connection.");
  }
};
function isSchedulingError(group, code) {
  return group === "guard" && (code === "actor_ready_timeout" || code === "actor_runner_failed");
}
var ActorSchedulingError = class extends ActorError {
  
  
  constructor(group, code, actorId, details) {
    super(
      group,
      code,
      `Actor failed to start (${actorId}): ${JSON.stringify(details)}`,
      { actorId, details }
    );
    this.name = "ActorSchedulingError";
    this.actorId = actorId;
    this.details = details;
  }
};

// src/client/utils.ts
function parseWebSocketCloseReason(reason) {
  const [mainPart, rayId] = reason.split("#");
  const [group, code] = mainPart.split(".");
  if (!group || !code) {
    _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({ msg: "failed to parse close reason", reason });
    return void 0;
  }
  return {
    group,
    code,
    rayId
  };
}
function messageLength(message) {
  if (message instanceof Blob) {
    return message.size;
  }
  if (message instanceof ArrayBuffer) {
    return message.byteLength;
  }
  if (message instanceof Uint8Array) {
    return message.byteLength;
  }
  if (typeof message === "string") {
    return message.length;
  }
  _chunkMMUXNMJFcjs.assertUnreachable.call(void 0, message);
}
async function sendHttpRequest(opts) {
  _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
    msg: "sending http request",
    url: opts.url,
    encoding: opts.encoding
  });
  let contentType;
  let bodyData;
  if (opts.method === "POST" || opts.method === "PUT") {
    _invariant2.default.call(void 0, opts.body !== void 0, "missing body");
    contentType = _chunkQ5CW77ITcjs.contentTypeForEncoding.call(void 0, opts.encoding);
    bodyData = _chunkQ5CW77ITcjs.serializeWithEncoding.call(void 0, 
      opts.encoding,
      opts.body,
      opts.requestVersionedDataHandler,
      opts.requestVersion,
      opts.requestZodSchema,
      opts.requestToJson,
      opts.requestToBare
    );
  }
  let response;
  try {
    response = await (_nullishCoalesce(opts.customFetch, () => ( fetch)))(
      new globalThis.Request(opts.url, {
        method: opts.method,
        headers: {
          ...opts.headers,
          ...contentType ? {
            "Content-Type": contentType
          } : {},
          "User-Agent": _chunkMMUXNMJFcjs.httpUserAgent.call(void 0, )
        },
        body: bodyData,
        credentials: "include",
        signal: opts.signal
      })
    );
  } catch (error) {
    throw new HttpRequestError(`Request failed: ${error}`, {
      cause: error
    });
  }
  if (!response.ok) {
    const bufferResponse = await response.arrayBuffer();
    const contentType2 = response.headers.get("content-type");
    const rayId = response.headers.get("x-rivet-ray-id");
    const encoding = (contentType2 == null ? void 0 : contentType2.includes("application/json")) ? "json" : opts.encoding;
    try {
      const responseData = _chunkQ5CW77ITcjs.deserializeWithEncoding.call(void 0, 
        encoding,
        new Uint8Array(bufferResponse),
        _chunkQ5CW77ITcjs.HTTP_RESPONSE_ERROR_VERSIONED,
        _chunkQ5CW77ITcjs.HttpResponseErrorSchema,
        // JSON: metadata is already unknown
        (json) => json,
        // BARE: decode ArrayBuffer metadata to unknown
        (bare) => ({
          group: bare.group,
          code: bare.code,
          message: bare.message,
          metadata: bare.metadata ? cbor.decode(new Uint8Array(bare.metadata)) : void 0
        })
      );
      throw new ActorError(
        responseData.group,
        responseData.code,
        responseData.message,
        responseData.metadata
      );
    } catch (error) {
      if (error instanceof ActorError) {
        throw error;
      }
      const textResponse = new TextDecoder("utf-8", {
        fatal: false
      }).decode(bufferResponse);
      if (rayId) {
        throw new HttpRequestError(
          `${response.statusText} (${response.status}) (Ray ID: ${rayId}):
${textResponse}`
        );
      } else {
        throw new HttpRequestError(
          `${response.statusText} (${response.status}):
${textResponse}`
        );
      }
    }
  }
  if (opts.skipParseResponse) {
    return void 0;
  }
  try {
    const buffer = new Uint8Array(await response.arrayBuffer());
    return _chunkQ5CW77ITcjs.deserializeWithEncoding.call(void 0, 
      opts.encoding,
      buffer,
      opts.responseVersionedDataHandler,
      opts.responseZodSchema,
      opts.responseFromJson,
      opts.responseFromBare
    );
  } catch (error) {
    throw new HttpRequestError(`Failed to parse response: ${error}`, {
      cause: error
    });
  }
}

// src/remote-manager-driver/log.ts
function logger3() {
  return _chunkMMUXNMJFcjs.getLogger.call(void 0, "remote-manager-driver");
}

// src/remote-manager-driver/api-utils.ts
var EngineApiError = class extends Error {
  constructor(group, code, message) {
    super(message || `Engine API error: ${group}/${code}`);
    this.group = group;
    this.code = code;
    this.name = "EngineApiError";
  }
};
function getEndpoint(config) {
  return _nullishCoalesce(config.endpoint, () => ( "http://127.0.0.1:6420"));
}
async function apiCall(config, method, path, body) {
  const endpoint = getEndpoint(config);
  const url = _chunkMMUXNMJFcjs.combineUrlPath.call(void 0, endpoint, path, {
    namespace: config.namespace
  });
  logger3().debug({ msg: "making api call", method, url });
  const headers = {
    ...config.headers
  };
  if (config.token) {
    headers.Authorization = `Bearer ${config.token}`;
  }
  return await sendHttpRequest({
    method,
    url,
    headers,
    body,
    encoding: "json",
    skipParseResponse: false,
    requestVersionedDataHandler: void 0,
    requestVersion: void 0,
    responseVersionedDataHandler: void 0,
    responseVersion: void 0,
    requestZodSchema: _v4.z.any(),
    responseZodSchema: _v4.z.any(),
    // Identity conversions (passthrough for generic API calls)
    requestToJson: (value) => value,
    requestToBare: (value) => value,
    responseFromJson: (value) => value,
    responseFromBare: (value) => value
  });
}

// src/remote-manager-driver/actor-websocket-client.ts
function buildActorGatewayUrl(endpoint, actorId, token, path = "") {
  const tokenSegment = token !== void 0 ? `@${encodeURIComponent(token)}` : "";
  const gatewayPath = `/gateway/${encodeURIComponent(actorId)}${tokenSegment}${path}`;
  return _chunkMMUXNMJFcjs.combineUrlPath.call(void 0, endpoint, gatewayPath);
}
async function openWebSocketToActor(runConfig, path, actorId, encoding, params) {
  const WebSocket2 = await _chunkFUBHHHK5cjs.importWebSocket.call(void 0, );
  const endpoint = getEndpoint(runConfig);
  const guardUrl = buildActorGatewayUrl(
    endpoint,
    actorId,
    runConfig.token,
    path
  );
  logger3().debug({
    msg: "opening websocket to actor via guard",
    actorId,
    path,
    guardUrl
  });
  const ws = new WebSocket2(
    guardUrl,
    buildWebSocketProtocols(runConfig, encoding, params)
  );
  ws.binaryType = "arraybuffer";
  logger3().debug({ msg: "websocket connection opened", actorId });
  return ws;
}
function buildWebSocketProtocols(runConfig, encoding, params) {
  const protocols = [];
  protocols.push(_chunkQ5CW77ITcjs.WS_PROTOCOL_STANDARD);
  protocols.push(`${_chunkQ5CW77ITcjs.WS_PROTOCOL_ENCODING}${encoding}`);
  if (params) {
    protocols.push(
      `${_chunkQ5CW77ITcjs.WS_PROTOCOL_CONN_PARAMS}${encodeURIComponent(JSON.stringify(params))}`
    );
  }
  return protocols;
}

// src/remote-manager-driver/actor-http-client.ts
async function sendHttpRequestToActor(runConfig, actorId, actorRequest) {
  const url = new URL(actorRequest.url);
  const endpoint = getEndpoint(runConfig);
  const guardUrl = buildActorGatewayUrl(
    endpoint,
    actorId,
    runConfig.token,
    `${url.pathname}${url.search}`
  );
  let bodyToSend = null;
  const guardHeaders = buildGuardHeadersForHttp(
    runConfig,
    actorRequest,
    actorId
  );
  if (actorRequest.method !== "GET" && actorRequest.method !== "HEAD") {
    if (actorRequest.bodyUsed) {
      throw new Error("Request body has already been consumed");
    }
    const reqBody = await actorRequest.arrayBuffer();
    if (reqBody.byteLength !== 0) {
      bodyToSend = reqBody;
      guardHeaders.delete("transfer-encoding");
      guardHeaders.set("content-length", String(bodyToSend.byteLength));
    }
  }
  const guardRequest = new Request(guardUrl, {
    method: actorRequest.method,
    headers: guardHeaders,
    body: bodyToSend,
    signal: actorRequest.signal
  });
  return mutableResponse(await fetch(guardRequest));
}
function mutableResponse(fetchRes) {
  return new Response(fetchRes.body, fetchRes);
}
function buildGuardHeadersForHttp(runConfig, actorRequest, actorId) {
  const headers = new Headers();
  actorRequest.headers.forEach((value, key) => {
    headers.set(key, value);
  });
  for (const [key, value] of Object.entries(runConfig.headers)) {
    headers.set(key, value);
  }
  if (runConfig.token) {
    headers.set(_chunkQ5CW77ITcjs.HEADER_RIVET_TOKEN, runConfig.token);
  }
  return headers;
}

// src/remote-manager-driver/api-endpoints.ts
async function getActor(config, _, actorId) {
  return apiCall(
    config,
    "GET",
    `/actors?actor_ids=${encodeURIComponent(actorId)}`
  );
}
async function getActorByKey(config, name, key) {
  const serializedKey = _chunkQ5CW77ITcjs.serializeActorKey.call(void 0, key);
  return apiCall(
    config,
    "GET",
    `/actors?name=${encodeURIComponent(name)}&key=${encodeURIComponent(serializedKey)}`
  );
}
async function listActorsByName(config, name) {
  return apiCall(
    config,
    "GET",
    `/actors?name=${encodeURIComponent(name)}`
  );
}
async function getOrCreateActor(config, request) {
  return apiCall(
    config,
    "PUT",
    `/actors`,
    request
  );
}
async function createActor(config, request) {
  return apiCall(
    config,
    "POST",
    `/actors`,
    request
  );
}
async function destroyActor(config, actorId) {
  return apiCall(
    config,
    "DELETE",
    `/actors/${encodeURIComponent(actorId)}`
  );
}
async function getMetadata(config) {
  return apiCall(config, "GET", `/metadata`);
}
async function getDatacenters(config) {
  return apiCall(config, "GET", `/datacenters`);
}
async function updateRunnerConfig(config, runnerName, request) {
  return apiCall(
    config,
    "PUT",
    `/runner-configs/${runnerName}`,
    request
  );
}
async function kvGet(config, actorId, key) {
  return apiCall(
    config,
    "GET",
    `/actors/${encodeURIComponent(actorId)}/kv/keys/${encodeURIComponent(key)}`
  );
}

// src/remote-manager-driver/metadata.ts
var _pretry = require('p-retry'); var _pretry2 = _interopRequireDefault(_pretry);
var metadataLookupCache = /* @__PURE__ */ new Map();
async function lookupMetadataCached(config) {
  const endpoint = getEndpoint(config);
  const existingPromise = metadataLookupCache.get(endpoint);
  if (existingPromise) {
    return existingPromise;
  }
  const metadataLookupPromise = _pretry2.default.call(void 0, 
    async () => {
      logger3().debug({
        msg: "fetching metadata",
        endpoint
      });
      const metadataData = await getMetadata(config);
      logger3().debug({
        msg: "received metadata",
        endpoint,
        clientEndpoint: metadataData.clientEndpoint
      });
      return metadataData;
    },
    {
      forever: true,
      minTimeout: 500,
      maxTimeout: 15e3,
      onFailedAttempt: (error) => {
        if (error.attemptNumber > 1) {
          logger3().warn({
            msg: "failed to fetch metadata, retrying",
            endpoint,
            attempt: error.attemptNumber,
            error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, error)
          });
        }
      }
    }
  );
  metadataLookupCache.set(endpoint, metadataLookupPromise);
  return metadataLookupPromise;
}

// src/remote-manager-driver/ws-proxy.ts
async function createWebSocketProxy(c, targetUrl, protocols) {
  const WebSocket2 = await _chunkFUBHHHK5cjs.importWebSocket.call(void 0, );
  const state = {};
  return {
    onOpen: async (event, clientWs) => {
      logger3().debug({ msg: "client websocket connected", targetUrl });
      if (clientWs.readyState !== 1) {
        logger3().warn({
          msg: "client websocket not open on connection",
          targetUrl,
          readyState: clientWs.readyState
        });
        return;
      }
      const targetWs = new WebSocket2(targetUrl, protocols);
      state.targetWs = targetWs;
      state.connectPromise = new Promise((resolve, reject) => {
        targetWs.addEventListener("open", () => {
          logger3().debug({
            msg: "target websocket connected",
            targetUrl
          });
          if (clientWs.readyState !== 1) {
            logger3().warn({
              msg: "client websocket closed before target connected",
              targetUrl,
              clientReadyState: clientWs.readyState
            });
            targetWs.close(1001, "Client disconnected");
            reject(new Error("Client disconnected"));
            return;
          }
          resolve();
        });
        targetWs.addEventListener("error", (error) => {
          logger3().warn({
            msg: "target websocket error during connection",
            targetUrl
          });
          reject(error);
        });
      });
      state.targetWs.addEventListener("message", (event2) => {
        if (typeof event2.data === "string" || event2.data instanceof ArrayBuffer) {
          clientWs.send(event2.data);
        } else if (event2.data instanceof Blob) {
          event2.data.arrayBuffer().then((buffer) => {
            clientWs.send(buffer);
          });
        }
      });
      state.targetWs.addEventListener("close", (event2) => {
        logger3().debug({
          msg: "target websocket closed",
          targetUrl,
          code: event2.code,
          reason: event2.reason
        });
        closeWebSocketIfOpen(clientWs, event2.code, event2.reason);
      });
      state.targetWs.addEventListener("error", (error) => {
        logger3().error({
          msg: "target websocket error",
          targetUrl,
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, error)
        });
        closeWebSocketIfOpen(clientWs, 1011, "Target WebSocket error");
      });
    },
    onMessage: async (event, clientWs) => {
      if (!state.targetWs || !state.connectPromise) {
        logger3().error({
          msg: "websocket state not initialized",
          targetUrl
        });
        return;
      }
      try {
        await state.connectPromise;
        if (state.targetWs.readyState === WebSocket2.OPEN) {
          state.targetWs.send(event.data);
        } else {
          logger3().warn({
            msg: "target websocket not open",
            targetUrl,
            readyState: state.targetWs.readyState
          });
        }
      } catch (error) {
        logger3().error({
          msg: "failed to connect to target websocket",
          targetUrl,
          error
        });
        closeWebSocketIfOpen(
          clientWs,
          1011,
          "Failed to connect to target"
        );
      }
    },
    onClose: (event, clientWs) => {
      logger3().debug({
        msg: "client websocket closed",
        targetUrl,
        code: event.code,
        reason: event.reason,
        wasClean: event.wasClean
      });
      if (state.targetWs) {
        if (state.targetWs.readyState === WebSocket2.OPEN || state.targetWs.readyState === WebSocket2.CONNECTING) {
          state.targetWs.close(
            1e3,
            event.reason || "Client disconnected"
          );
        }
      }
    },
    onError: (event, clientWs) => {
      logger3().error({ msg: "client websocket error", targetUrl, event });
      if (state.targetWs) {
        if (state.targetWs.readyState === WebSocket2.OPEN) {
          state.targetWs.close(1011, "Client WebSocket error");
        } else if (state.targetWs.readyState === WebSocket2.CONNECTING) {
          state.targetWs.close();
        }
      }
    }
  };
}
function closeWebSocketIfOpen(ws, code, reason) {
  if (ws.readyState === 1) {
    ws.close(code, reason);
  } else if ("close" in ws && ws.readyState === WebSocket.OPEN) {
    ws.close(code, reason);
  }
}

// src/remote-manager-driver/mod.ts
var RemoteManagerDriver = class {
  #config;
  #metadataPromise;
  constructor(runConfig) {
    if (_chunkMMUXNMJFcjs.getNextPhase.call(void 0, ) === "phase-production-build") {
      logger3().info(
        "detected next.js build phase, disabling health check"
      );
      runConfig.disableMetadataLookup = true;
    }
    this.#config = { ...runConfig };
    if (!runConfig.disableMetadataLookup) {
      this.#metadataPromise = lookupMetadataCached(this.#config).then(
        (metadataData) => {
          if (metadataData.clientEndpoint) {
            this.#config.endpoint = metadataData.clientEndpoint;
            if (metadataData.clientNamespace) {
              this.#config.namespace = metadataData.clientNamespace;
            }
            if (metadataData.clientToken) {
              this.#config.token = metadataData.clientToken;
            }
            logger3().info({
              msg: "overriding client endpoint",
              endpoint: metadataData.clientEndpoint,
              namespace: metadataData.clientNamespace,
              token: metadataData.clientToken
            });
          }
          logger3().info({
            msg: "connected to rivetkit manager",
            runtime: metadataData.runtime,
            version: metadataData.version,
            runner: metadataData.runner
          });
        }
      );
    }
  }
  async getForId({
    c,
    name,
    actorId
  }) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    const response = await getActor(this.#config, name, actorId);
    const actor = response.actors[0];
    if (!actor) return void 0;
    if (actor.name !== name) {
      logger3().debug({
        msg: "actor name mismatch from api",
        actorId,
        apiName: actor.name,
        requestedName: name
      });
      return void 0;
    }
    return apiActorToOutput(actor);
  }
  async getWithKey({
    c,
    name,
    key
  }) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    logger3().debug({ msg: "getWithKey: searching for actor", name, key });
    try {
      const response = await getActorByKey(this.#config, name, key);
      const actor = response.actors[0];
      if (!actor) return void 0;
      logger3().debug({
        msg: "getWithKey: found actor via api",
        actorId: actor.actor_id,
        name,
        key
      });
      return apiActorToOutput(actor);
    } catch (error) {
      if (error instanceof EngineApiError && error.group === "actor" && error.code === "not_found") {
        return void 0;
      }
      throw error;
    }
  }
  async getOrCreateWithKey(input) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    const { c, name, key, input: actorInput, region } = input;
    logger3().info({
      msg: "getOrCreateWithKey: getting or creating actor via engine api",
      name,
      key
    });
    const { actor, created } = await getOrCreateActor(this.#config, {
      datacenter: region,
      name,
      key: _chunkQ5CW77ITcjs.serializeActorKey.call(void 0, key),
      runner_name_selector: this.#config.runnerName,
      input: actorInput ? _chunkQ5CW77ITcjs.uint8ArrayToBase64.call(void 0, cbor2.encode(actorInput)) : void 0,
      crash_policy: "sleep"
    });
    logger3().info({
      msg: "getOrCreateWithKey: actor ready",
      actorId: actor.actor_id,
      name,
      key,
      created
    });
    return apiActorToOutput(actor);
  }
  async createActor({
    c,
    name,
    key,
    input,
    region
  }) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    logger3().info({ msg: "creating actor via engine api", name, key });
    const result = await createActor(this.#config, {
      datacenter: region,
      name,
      runner_name_selector: this.#config.runnerName,
      key: _chunkQ5CW77ITcjs.serializeActorKey.call(void 0, key),
      input: input ? _chunkQ5CW77ITcjs.uint8ArrayToBase64.call(void 0, cbor2.encode(input)) : void 0,
      crash_policy: "sleep"
    });
    logger3().info({
      msg: "actor created",
      actorId: result.actor.actor_id,
      name,
      key
    });
    return apiActorToOutput(result.actor);
  }
  async listActors({ c, name }) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    logger3().debug({ msg: "listing actors via engine api", name });
    const response = await listActorsByName(this.#config, name);
    return response.actors.map(apiActorToOutput);
  }
  async destroyActor(actorId) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    logger3().info({ msg: "destroying actor via engine api", actorId });
    await destroyActor(this.#config, actorId);
    logger3().info({ msg: "actor destroyed", actorId });
  }
  async sendRequest(actorId, actorRequest) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    return await sendHttpRequestToActor(
      this.#config,
      actorId,
      actorRequest
    );
  }
  async openWebSocket(path, actorId, encoding, params) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    return await openWebSocketToActor(
      this.#config,
      path,
      actorId,
      encoding,
      params
    );
  }
  async buildGatewayUrl(actorId) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    const endpoint = getEndpoint(this.#config);
    return buildActorGatewayUrl(endpoint, actorId, this.#config.token);
  }
  async proxyRequest(_c, actorRequest, actorId) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    return await sendHttpRequestToActor(
      this.#config,
      actorId,
      actorRequest
    );
  }
  async proxyWebSocket(c, path, actorId, encoding, params) {
    var _a, _b;
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    const upgradeWebSocket = (_b = (_a = this.#config).getUpgradeWebSocket) == null ? void 0 : _b.call(_a);
    _invariant2.default.call(void 0, upgradeWebSocket, "missing getUpgradeWebSocket");
    const endpoint = getEndpoint(this.#config);
    const guardUrl = _chunkMMUXNMJFcjs.combineUrlPath.call(void 0, endpoint, path);
    const wsGuardUrl = guardUrl.replace("http://", "ws://");
    logger3().debug({
      msg: "forwarding websocket to actor via guard",
      actorId,
      path,
      guardUrl
    });
    const protocols = buildWebSocketProtocols(
      this.#config,
      encoding,
      params
    );
    const args = await createWebSocketProxy(c, wsGuardUrl, protocols);
    return await upgradeWebSocket(() => args)(c, _chunkMMUXNMJFcjs.noopNext.call(void 0, ));
  }
  async kvGet(actorId, key) {
    if (this.#metadataPromise) {
      await this.#metadataPromise;
    }
    logger3().debug({ msg: "getting kv value via engine api", key });
    const response = await kvGet(
      this.#config,
      actorId,
      new TextDecoder("utf8").decode(key)
    );
    return response.value;
  }
  displayInformation() {
    return { properties: {} };
  }
  setGetUpgradeWebSocket(getUpgradeWebSocket) {
    this.#config.getUpgradeWebSocket = getUpgradeWebSocket;
  }
};
function apiActorToOutput(actor) {
  return {
    actorId: actor.actor_id,
    name: actor.name,
    key: _chunkQ5CW77ITcjs.deserializeActorKey.call(void 0, actor.key),
    createTs: actor.create_ts,
    startTs: _nullishCoalesce(actor.start_ts, () => ( null)),
    connectableTs: _nullishCoalesce(actor.connectable_ts, () => ( null)),
    sleepTs: _nullishCoalesce(actor.sleep_ts, () => ( null)),
    destroyTs: _nullishCoalesce(actor.destroy_ts, () => ( null)),
    error: _nullishCoalesce(actor.error, () => ( void 0))
  };
}

// src/client/actor-conn.ts




// src/client/actor-query.ts
async function queryActor(c, query, managerDriver) {
  _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "querying actor", query: JSON.stringify(query) });
  let actorOutput;
  if ("getForId" in query) {
    const output = await managerDriver.getForId({
      c,
      name: query.getForId.name,
      actorId: query.getForId.actorId
    });
    if (!output) throw new (0, _chunkL47L3ZWJcjs.ActorNotFound)(query.getForId.actorId);
    actorOutput = output;
  } else if ("getForKey" in query) {
    const existingActor = await managerDriver.getWithKey({
      c,
      name: query.getForKey.name,
      key: query.getForKey.key
    });
    if (!existingActor) {
      throw new (0, _chunkL47L3ZWJcjs.ActorNotFound)(
        `${query.getForKey.name}:${JSON.stringify(query.getForKey.key)}`
      );
    }
    actorOutput = existingActor;
  } else if ("getOrCreateForKey" in query) {
    const getOrCreateOutput = await managerDriver.getOrCreateWithKey({
      c,
      name: query.getOrCreateForKey.name,
      key: query.getOrCreateForKey.key,
      input: query.getOrCreateForKey.input,
      region: query.getOrCreateForKey.region
    });
    actorOutput = {
      actorId: getOrCreateOutput.actorId
    };
  } else if ("create" in query) {
    const createOutput = await managerDriver.createActor({
      c,
      name: query.create.name,
      key: query.create.key,
      input: query.create.input,
      region: query.create.region
    });
    actorOutput = {
      actorId: createOutput.actorId
    };
  } else {
    throw new (0, _chunkL47L3ZWJcjs.InvalidRequest)("Invalid query format");
  }
  _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "actor query result", actorId: actorOutput.actorId });
  return { actorId: actorOutput.actorId };
}
function getActorNameFromQuery(query) {
  if ("getForId" in query) return query.getForId.name;
  if ("getForKey" in query) return query.getForKey.name;
  if ("getOrCreateForKey" in query) return query.getOrCreateForKey.name;
  if ("create" in query) return query.create.name;
  throw new (0, _chunkL47L3ZWJcjs.InvalidRequest)("Invalid query format");
}
async function checkForSchedulingError(group, code, actorId, query, driver) {
  const name = getActorNameFromQuery(query);
  try {
    const actor = await driver.getForId({ name, actorId });
    if (actor == null ? void 0 : actor.error) {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).info({
        msg: "found actor scheduling error",
        actorId,
        error: actor.error
      });
      return new ActorSchedulingError(group, code, actorId, actor.error);
    }
  } catch (err) {
    _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({
      msg: "failed to fetch actor details for scheduling error check",
      actorId,
      error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
    });
  }
  return null;
}

// src/client/queue.ts

function createQueueSender(senderOptions) {
  async function send(name, body, options) {
    const wait = _nullishCoalesce((options == null ? void 0 : options.wait), () => ( false));
    const timeout = options == null ? void 0 : options.timeout;
    const result = await sendHttpRequest({
      url: `http://actor/queue/${encodeURIComponent(name)}`,
      method: "POST",
      headers: {
        [_chunkQ5CW77ITcjs.HEADER_ENCODING]: senderOptions.encoding,
        ...senderOptions.params !== void 0 ? {
          [_chunkQ5CW77ITcjs.HEADER_CONN_PARAMS]: JSON.stringify(
            senderOptions.params
          )
        } : {}
      },
      body: { body, wait, timeout },
      encoding: senderOptions.encoding,
      customFetch: senderOptions.customFetch,
      signal: options == null ? void 0 : options.signal,
      requestVersion: _chunkQ5CW77ITcjs.CURRENT_VERSION,
      requestVersionedDataHandler: _chunkQ5CW77ITcjs.HTTP_QUEUE_SEND_REQUEST_VERSIONED,
      responseVersion: _chunkQ5CW77ITcjs.CURRENT_VERSION,
      responseVersionedDataHandler: _chunkQ5CW77ITcjs.HTTP_QUEUE_SEND_RESPONSE_VERSIONED,
      requestZodSchema: _chunkQ5CW77ITcjs.HttpQueueSendRequestSchema,
      responseZodSchema: _chunkQ5CW77ITcjs.HttpQueueSendResponseSchema,
      requestToJson: (value) => ({
        ...value,
        name
      }),
      requestToBare: (value) => ({
        name: _nullishCoalesce(value.name, () => ( name)),
        body: _chunkMMUXNMJFcjs.bufferToArrayBuffer.call(void 0, cbor3.encode(value.body)),
        wait: _nullishCoalesce(value.wait, () => ( false)),
        timeout: value.timeout !== void 0 ? BigInt(value.timeout) : null
      }),
      responseFromJson: (json) => {
        if (json.response === void 0) {
          return { status: json.status };
        }
        return {
          status: json.status,
          response: json.response
        };
      },
      responseFromBare: (bare) => {
        if (bare.response === null || bare.response === void 0) {
          return { status: bare.status };
        }
        return {
          status: bare.status,
          response: cbor3.decode(new Uint8Array(bare.response))
        };
      }
    });
    if (wait) {
      return result;
    }
    return;
  }
  return {
    send
  };
}

// src/client/actor-conn.ts
var CONNECT_SYMBOL = /* @__PURE__ */ Symbol("connect");
var ActorConnRaw = class {
  #disposed = false;
  /* Will be aborted on dispose. */
  #abortController = new AbortController();
  #connStatus = "idle";
  #actorId;
  #connId;
  #messageQueue = [];
  #actionsInFlight = /* @__PURE__ */ new Map();
  // biome-ignore lint/suspicious/noExplicitAny: Unknown subscription type
  #eventSubscriptions = /* @__PURE__ */ new Map();
  #errorHandlers = /* @__PURE__ */ new Set();
  #openHandlers = /* @__PURE__ */ new Set();
  #openScheduled = false;
  #closeHandlers = /* @__PURE__ */ new Set();
  #statusChangeHandlers = /* @__PURE__ */ new Set();
  #actionIdCounter = 0;
  #queueSender;
  /**
   * Interval that keeps the NodeJS process alive if this is the only thing running.
   *
   * See ttps://github.com/nodejs/node/issues/22088
   */
  #keepNodeAliveInterval;
  /** Promise used to indicate the socket has connected successfully. This will be rejected if the connection fails. */
  #onOpenPromise;
  #websocket;
  #client;
  #driver;
  #params;
  #encoding;
  #actorQuery;
  // TODO: ws message queue
  /**
   * Do not call this directly.
   *
   * Creates an instance of ActorConnRaw.
   *
   * @protected
   */
  constructor(client, driver, params, encoding, actorQuery) {
    this.#client = client;
    this.#driver = driver;
    this.#params = params;
    this.#encoding = encoding;
    this.#actorQuery = actorQuery;
    this.#queueSender = createQueueSender({
      encoding: this.#encoding,
      params: this.#params,
      customFetch: async (request) => {
        if (!this.#actorId) {
          const { actorId } = await queryActor(
            void 0,
            this.#actorQuery,
            this.#driver
          );
          this.#actorId = actorId;
        }
        return this.#driver.sendRequest(this.#actorId, request);
      }
    });
    this.#keepNodeAliveInterval = setInterval(() => 6e4);
  }
  send(name, body, options) {
    return this.#queueSender.send(name, body, options);
  }
  /**
   * Call a raw action connection. See {@link ActorConn} for type-safe action calls.
   *
   * @see {@link ActorConn}
   * @template Args - The type of arguments to pass to the action function.
   * @template Response - The type of the response returned by the action function.
   * @param {string} name - The name of the action function to call.
   * @param {...Args} args - The arguments to pass to the action function.
   * @returns {Promise<Response>} - A promise that resolves to the response of the action function.
   */
  async action(opts) {
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "action", name: opts.name, args: opts.args });
    const actionId = this.#actionIdCounter;
    this.#actionIdCounter += 1;
    const { promise, resolve, reject } = _chunkMMUXNMJFcjs.promiseWithResolvers.call(void 0, (reason) => _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({ msg: "unhandled action promise rejection", reason }));
    this.#actionsInFlight.set(actionId, {
      name: opts.name,
      resolve,
      reject
    });
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "added action to in-flight map",
      actionId,
      actionName: opts.name,
      inFlightCount: this.#actionsInFlight.size
    });
    this.#sendMessage({
      body: {
        tag: "ActionRequest",
        val: {
          id: BigInt(actionId),
          name: opts.name,
          args: opts.args
        }
      }
    });
    const { id: responseId, output } = await promise;
    if (responseId !== BigInt(actionId))
      throw new Error(
        `Request ID ${actionId} does not match response ID ${responseId}`
      );
    return output;
  }
  /**
   * Do not call this directly.
   * Establishes a connection to the server using the specified endpoint & encoding & driver.
   *
   * @protected
   */
  [CONNECT_SYMBOL]() {
    this.#connectWithRetry();
  }
  #setConnStatus(status) {
    const prevStatus = this.#connStatus;
    if (prevStatus === status) return;
    this.#connStatus = status;
    for (const handler of [...this.#statusChangeHandlers]) {
      try {
        handler(status);
      } catch (err) {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
          msg: "error in status change handler",
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
        });
      }
    }
    if (status === "connected") {
      for (const handler of [...this.#openHandlers]) {
        try {
          handler();
        } catch (err) {
          _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
            msg: "error in open handler",
            error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
          });
        }
      }
    }
    if ((status === "disconnected" || status === "idle") && prevStatus === "connected") {
      for (const handler of [...this.#closeHandlers]) {
        try {
          handler();
        } catch (err) {
          _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
            msg: "error in close handler",
            error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
          });
        }
      }
    }
  }
  #connectWithRetry() {
    this.#setConnStatus("connecting");
    _pretry2.default.call(void 0, this.#connectAndWait.bind(this), {
      forever: true,
      minTimeout: 250,
      maxTimeout: 3e4,
      onFailedAttempt: (error) => {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({
          msg: "failed to reconnect",
          attempt: error.attemptNumber,
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, error)
        });
      },
      // Cancel retry if aborted
      signal: this.#abortController.signal
    }).catch((err) => {
      if (err.name === "AbortError") {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).info({ msg: "connection retry aborted" });
      } else {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
          msg: "unexpected error in connection retry",
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
        });
      }
    });
  }
  async #connectAndWait() {
    try {
      if (this.#onOpenPromise)
        throw new Error("#onOpenPromise already defined");
      this.#onOpenPromise = _chunkMMUXNMJFcjs.promiseWithResolvers.call(void 0, (reason) => _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({ msg: "unhandled open promise rejection", reason }));
      await this.#connectWebSocket();
      await this.#onOpenPromise.promise;
    } finally {
      this.#onOpenPromise = void 0;
    }
  }
  async #connectWebSocket() {
    const { actorId } = await queryActor(
      void 0,
      this.#actorQuery,
      this.#driver
    );
    this.#actorId = actorId;
    const ws = await this.#driver.openWebSocket(
      _chunkQ5CW77ITcjs.PATH_CONNECT,
      actorId,
      this.#encoding,
      this.#params
    );
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "opened websocket",
      connId: this.#connId,
      readyState: ws.readyState,
      messageQueueLength: this.#messageQueue.length
    });
    this.#websocket = ws;
    ws.addEventListener("open", () => {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "client websocket open",
        connId: this.#connId
      });
    });
    ws.addEventListener("message", async (ev) => {
      try {
        await this.#handleOnMessage(ev.data);
      } catch (err) {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
          msg: "error in websocket message handler",
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
        });
      }
    });
    ws.addEventListener("close", async (ev) => {
      try {
        await this.#handleOnClose(ev);
      } catch (err) {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
          msg: "error in websocket close handler",
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
        });
      }
    });
    ws.addEventListener("error", (_ev) => {
      try {
        this.#handleOnError();
      } catch (err) {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
          msg: "error in websocket error handler",
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
        });
      }
    });
  }
  /** Called by the onopen event from drivers. */
  #handleOnOpen() {
    if (this.#disposed) {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "handleOnOpen called after dispose, closing websocket"
      });
      if (this.#websocket) {
        this.#websocket.close(1e3, "Disposed");
        this.#websocket = void 0;
      }
      return;
    }
    if (this.#connStatus === "connected" || this.#openScheduled) {
      return;
    }
    this.#openScheduled = true;
    queueMicrotask(() => {
      this.#openScheduled = false;
      if (this.#disposed) {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
          msg: "handleOnOpen scheduled after dispose, closing websocket"
        });
        if (this.#websocket) {
          this.#websocket.close(1e3, "Disposed");
          this.#websocket = void 0;
        }
        return;
      }
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "socket open",
        messageQueueLength: this.#messageQueue.length,
        connId: this.#connId
      });
      this.#setConnStatus("connected");
      if (this.#onOpenPromise) {
        this.#onOpenPromise.resolve(void 0);
      } else {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({ msg: "#onOpenPromise is undefined" });
      }
      for (const eventName of this.#eventSubscriptions.keys()) {
        this.#sendSubscription(eventName, true);
      }
      const queue = this.#messageQueue;
      this.#messageQueue = [];
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "flushing message queue",
        queueLength: queue.length
      });
      for (const msg of queue) {
        this.#sendMessage(msg);
      }
    });
  }
  /** Called by the onmessage event from drivers. */
  async #handleOnMessage(data) {
    _chunkFUBHHHK5cjs.logger.call(void 0, ).trace({
      msg: "received message",
      dataType: typeof data,
      isBlob: data instanceof Blob,
      isArrayBuffer: data instanceof ArrayBuffer
    });
    const response = await this.#parseMessage(data);
    _chunkFUBHHHK5cjs.logger.call(void 0, ).trace(
      _chunkMMUXNMJFcjs.getLogMessage.call(void 0, ) ? {
        msg: "parsed message",
        message: _chunkQ5CW77ITcjs.jsonStringifyCompat.call(void 0, response).substring(0, 100) + "..."
      } : { msg: "parsed message" }
    );
    if (response.body.tag === "Init") {
      this.#actorId = response.body.val.actorId;
      this.#connId = response.body.val.connectionId;
      _chunkFUBHHHK5cjs.logger.call(void 0, ).trace({
        msg: "received init message",
        actorId: this.#actorId,
        connId: this.#connId
      });
      this.#handleOnOpen();
    } else if (response.body.tag === "Error") {
      const { group, code, message, metadata, actionId } = response.body.val;
      if (actionId) {
        const inFlight = this.#takeActionInFlight(Number(actionId));
        _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({
          msg: "action error",
          actionId,
          actionName: inFlight == null ? void 0 : inFlight.name,
          group,
          code,
          message,
          metadata
        });
        inFlight.reject(
          new ActorError(group, code, message, metadata)
        );
      } else {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({
          msg: "connection error",
          group,
          code,
          message,
          metadata
        });
        let errorToThrow = new ActorError(
          group,
          code,
          message,
          metadata
        );
        if (isSchedulingError(group, code) && this.#actorId) {
          const schedulingError = await checkForSchedulingError(
            group,
            code,
            this.#actorId,
            this.#actorQuery,
            this.#driver
          );
          if (schedulingError) {
            errorToThrow = schedulingError;
          }
        }
        if (this.#onOpenPromise) {
          this.#onOpenPromise.reject(errorToThrow);
        }
        for (const [id, inFlight] of this.#actionsInFlight.entries()) {
          inFlight.reject(errorToThrow);
          this.#actionsInFlight.delete(id);
        }
        this.#dispatchActorError(errorToThrow);
      }
    } else if (response.body.tag === "ActionResponse") {
      const { id: actionId } = response.body.val;
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "received action response",
        actionId: Number(actionId),
        inFlightCount: this.#actionsInFlight.size,
        inFlightIds: Array.from(this.#actionsInFlight.keys())
      });
      const inFlight = this.#takeActionInFlight(Number(actionId));
      _chunkFUBHHHK5cjs.logger.call(void 0, ).trace({
        msg: "resolving action promise",
        actionId,
        actionName: inFlight == null ? void 0 : inFlight.name
      });
      inFlight.resolve(response.body.val);
    } else if (response.body.tag === "Event") {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).trace({
        msg: "received event",
        name: response.body.val.name
      });
      this.#dispatchEvent(response.body.val);
    } else {
      _chunkMMUXNMJFcjs.assertUnreachable.call(void 0, response.body);
    }
  }
  /** Called by the onclose event from drivers. */
  async #handleOnClose(event) {
    const closeEvent = event;
    const wasClean = closeEvent.wasClean;
    const wasConnected = this.#connStatus === "connected";
    _chunkFUBHHHK5cjs.logger.call(void 0, ).info({
      msg: "socket closed",
      code: closeEvent.code,
      reason: closeEvent.reason,
      wasClean,
      disposed: this.#disposed,
      connId: this.#connId
    });
    this.#websocket = void 0;
    if (this.#disposed) {
      this.#rejectPendingPromises(new ActorConnDisposed(), true);
    } else {
      this.#setConnStatus("disconnected");
      let error;
      const reason = closeEvent.reason || "";
      const parsed = parseWebSocketCloseReason(reason);
      if (parsed) {
        const { group, code } = parsed;
        if (isSchedulingError(group, code) && this.#actorId) {
          const schedulingError = await checkForSchedulingError(
            group,
            code,
            this.#actorId,
            this.#actorQuery,
            this.#driver
          );
          if (schedulingError) {
            error = schedulingError;
          } else {
            error = new ActorError(
              group,
              code,
              `Connection closed: ${reason}`,
              void 0
            );
          }
        } else {
          error = new ActorError(
            group,
            code,
            `Connection closed: ${reason}`,
            void 0
          );
        }
      } else {
        error = new Error(
          `${wasClean ? "Connection closed" : "Connection lost"} (code: ${closeEvent.code}, reason: ${reason})`
        );
      }
      this.#rejectPendingPromises(error, false);
      if (error instanceof ActorError) {
        this.#dispatchActorError(error);
      }
      if (wasConnected) {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
          msg: "triggering reconnect",
          connId: this.#connId
        });
        this.#connectWithRetry();
      }
    }
  }
  #rejectPendingPromises(error, suppressUnhandled) {
    if (this.#onOpenPromise) {
      if (suppressUnhandled) {
        this.#onOpenPromise.promise.catch(() => {
        });
      }
      this.#onOpenPromise.reject(error);
    }
    for (const actionInfo of this.#actionsInFlight.values()) {
      actionInfo.reject(error);
    }
    this.#actionsInFlight.clear();
  }
  /** Called by the onerror event from drivers. */
  #handleOnError() {
    if (this.#disposed) return;
    _chunkFUBHHHK5cjs.logger.call(void 0, ).warn("socket error");
  }
  #takeActionInFlight(id) {
    const inFlight = this.#actionsInFlight.get(id);
    if (!inFlight) {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
        msg: "action not found in in-flight map",
        lookupId: id,
        inFlightCount: this.#actionsInFlight.size,
        inFlightIds: Array.from(this.#actionsInFlight.keys()),
        inFlightActions: Array.from(
          this.#actionsInFlight.entries()
        ).map(([id2, action]) => ({
          id: id2,
          name: action.name
        }))
      });
      throw new InternalError(`No in flight response for ${id}`);
    }
    this.#actionsInFlight.delete(id);
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "removed action from in-flight map",
      actionId: id,
      actionName: inFlight.name,
      inFlightCount: this.#actionsInFlight.size
    });
    return inFlight;
  }
  #dispatchEvent(event) {
    const { name, args } = event;
    const listeners = this.#eventSubscriptions.get(name);
    if (!listeners) return;
    for (const listener of [...listeners]) {
      listener.callback(...args);
      if (listener.once) {
        listeners.delete(listener);
      }
    }
    if (listeners.size === 0) {
      this.#eventSubscriptions.delete(name);
    }
  }
  #dispatchActorError(error) {
    for (const handler of [...this.#errorHandlers]) {
      try {
        handler(error);
      } catch (err) {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).error({
          msg: "error in connection error handler",
          error: _chunkMMUXNMJFcjs.stringifyError.call(void 0, err)
        });
      }
    }
  }
  #addEventSubscription(eventName, callback, once) {
    const listener = {
      callback,
      once
    };
    let subscriptionSet = this.#eventSubscriptions.get(eventName);
    if (subscriptionSet === void 0) {
      subscriptionSet = /* @__PURE__ */ new Set();
      this.#eventSubscriptions.set(eventName, subscriptionSet);
      this.#sendSubscription(eventName, true);
    }
    subscriptionSet.add(listener);
    return () => {
      const listeners = this.#eventSubscriptions.get(eventName);
      if (listeners) {
        listeners.delete(listener);
        if (listeners.size === 0) {
          this.#eventSubscriptions.delete(eventName);
          this.#sendSubscription(eventName, false);
        }
      }
    };
  }
  /**
   * Subscribes to an event that will happen repeatedly.
   *
   * @template Args - The type of arguments the event callback will receive.
   * @param {string} eventName - The name of the event to subscribe to.
   * @param {(...args: Args) => void} callback - The callback function to execute when the event is triggered.
   * @returns {EventUnsubscribe} - A function to unsubscribe from the event.
   * @see {@link https://rivet.dev/docs/events|Events Documentation}
   */
  on(eventName, callback) {
    return this.#addEventSubscription(eventName, callback, false);
  }
  /**
   * Subscribes to an event that will be triggered only once.
   *
   * @template Args - The type of arguments the event callback will receive.
   * @param {string} eventName - The name of the event to subscribe to.
   * @param {(...args: Args) => void} callback - The callback function to execute when the event is triggered.
   * @returns {EventUnsubscribe} - A function to unsubscribe from the event.
   * @see {@link https://rivet.dev/docs/events|Events Documentation}
   */
  once(eventName, callback) {
    return this.#addEventSubscription(eventName, callback, true);
  }
  /**
   * Subscribes to connection errors.
   *
   * @param {ActorErrorCallback} callback - The callback function to execute when a connection error occurs.
   * @returns {() => void} - A function to unsubscribe from the error handler.
   */
  onError(callback) {
    this.#errorHandlers.add(callback);
    return () => {
      this.#errorHandlers.delete(callback);
    };
  }
  /**
   * Returns the current connection status.
   *
   * @returns {ActorConnStatus} - The current connection status.
   */
  get connStatus() {
    return this.#connStatus;
  }
  /**
   * Returns whether the connection is currently open.
   *
   * @deprecated Use `connStatus` instead.
   * @returns {boolean} - True if the connection is open, false otherwise.
   */
  get isConnected() {
    return this.#connStatus === "connected";
  }
  /**
   * Subscribes to connection open events.
   *
   * This is called when the WebSocket connection is established and the Init message is received.
   *
   * @param {ConnectionStateCallback} callback - The callback function to execute when the connection opens.
   * @returns {() => void} - A function to unsubscribe from the open handler.
   */
  onOpen(callback) {
    this.#openHandlers.add(callback);
    return () => {
      this.#openHandlers.delete(callback);
    };
  }
  /**
   * Subscribes to connection close events.
   *
   * This is called when the WebSocket connection is closed. The connection will automatically
   * attempt to reconnect unless disposed.
   *
   * @param {ConnectionStateCallback} callback - The callback function to execute when the connection closes.
   * @returns {() => void} - A function to unsubscribe from the close handler.
   */
  onClose(callback) {
    this.#closeHandlers.add(callback);
    return () => {
      this.#closeHandlers.delete(callback);
    };
  }
  /**
   * Subscribes to connection status changes.
   *
   * This is called whenever the connection status changes between Disconnected, Connecting, and Connected.
   *
   * @param {StatusChangeCallback} callback - The callback function to execute when the status changes.
   * @returns {() => void} - A function to unsubscribe from the status change handler.
   */
  onStatusChange(callback) {
    this.#statusChangeHandlers.add(callback);
    return () => {
      this.#statusChangeHandlers.delete(callback);
    };
  }
  #sendMessage(message, opts) {
    var _a, _b;
    if (this.#disposed) {
      if (opts == null ? void 0 : opts.ephemeral) {
        return;
      } else {
        throw new ActorConnDisposed();
      }
    }
    let queueMessage = false;
    if (this.#websocket) {
      const readyState = this.#websocket.readyState;
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "websocket send attempt",
        readyState,
        readyStateString: readyState === 0 ? "CONNECTING" : readyState === 1 ? "OPEN" : readyState === 2 ? "CLOSING" : "CLOSED",
        connId: this.#connId,
        messageType: message.body.tag,
        actionName: (_a = message.body.val) == null ? void 0 : _a.name
      });
      if (this.#connStatus !== "connected") {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
          msg: "websocket init pending, queueing message",
          connStatus: this.#connStatus,
          messageType: message.body.tag
        });
        queueMessage = true;
      } else if (readyState === 1) {
        try {
          const messageSerialized = _chunkQ5CW77ITcjs.serializeWithEncoding.call(void 0, 
            this.#encoding,
            message,
            _chunkQ5CW77ITcjs.TO_SERVER_VERSIONED,
            _chunkQ5CW77ITcjs.CURRENT_VERSION,
            _chunkQ5CW77ITcjs.ToServerSchema,
            // JSON: args is the raw value
            (msg) => msg,
            // BARE: args needs to be CBOR-encoded to ArrayBuffer
            (msg) => {
              if (msg.body.tag === "ActionRequest") {
                return {
                  body: {
                    tag: "ActionRequest",
                    val: {
                      id: msg.body.val.id,
                      name: msg.body.val.name,
                      args: _chunkMMUXNMJFcjs.bufferToArrayBuffer.call(void 0, 
                        cbor4.encode(msg.body.val.args)
                      )
                    }
                  }
                };
              } else {
                return msg;
              }
            }
          );
          this.#websocket.send(messageSerialized);
          _chunkFUBHHHK5cjs.logger.call(void 0, ).trace({
            msg: "sent websocket message",
            len: messageLength(messageSerialized)
          });
        } catch (error) {
          _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({
            msg: "failed to send message, added to queue",
            error,
            connId: this.#connId
          });
          queueMessage = true;
        }
      } else {
        _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
          msg: "websocket not open, queueing message",
          readyState
        });
        queueMessage = true;
      }
    } else {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "no websocket, queueing message" });
      queueMessage = true;
    }
    if (!(opts == null ? void 0 : opts.ephemeral) && queueMessage) {
      this.#messageQueue.push(message);
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "queued connection message",
        queueLength: this.#messageQueue.length,
        connId: this.#connId,
        messageType: message.body.tag,
        actionName: (_b = message.body.val) == null ? void 0 : _b.name
      });
    }
  }
  async #parseMessage(data) {
    _invariant2.default.call(void 0, this.#websocket, "websocket must be defined");
    const buffer = await _chunkQ5CW77ITcjs.inputDataToBuffer.call(void 0, data);
    return _chunkQ5CW77ITcjs.deserializeWithEncoding.call(void 0, 
      this.#encoding,
      buffer,
      _chunkQ5CW77ITcjs.TO_CLIENT_VERSIONED,
      _chunkQ5CW77ITcjs.ToClientSchema,
      // JSON: values are already the correct type
      (msg) => msg,
      // BARE: need to decode ArrayBuffer fields back to unknown
      (msg) => {
        if (msg.body.tag === "Error") {
          return {
            body: {
              tag: "Error",
              val: {
                group: msg.body.val.group,
                code: msg.body.val.code,
                message: msg.body.val.message,
                metadata: msg.body.val.metadata ? cbor4.decode(
                  new Uint8Array(
                    msg.body.val.metadata
                  )
                ) : null,
                actionId: msg.body.val.actionId
              }
            }
          };
        } else if (msg.body.tag === "ActionResponse") {
          return {
            body: {
              tag: "ActionResponse",
              val: {
                id: msg.body.val.id,
                output: cbor4.decode(
                  new Uint8Array(msg.body.val.output)
                )
              }
            }
          };
        } else if (msg.body.tag === "Event") {
          return {
            body: {
              tag: "Event",
              val: {
                name: msg.body.val.name,
                args: cbor4.decode(
                  new Uint8Array(msg.body.val.args)
                )
              }
            }
          };
        } else {
          return msg;
        }
      }
    );
  }
  /**
   * Get the actor ID (for testing purposes).
   * @internal
   */
  get actorId() {
    return this.#actorId;
  }
  /**
   * Get the connection ID (for testing purposes).
   * @internal
   */
  get connId() {
    return this.#connId;
  }
  /**
   * Get the connection ID (for testing purposes).
   * @internal
   * @deprecated Use `connId` instead.
   */
  get connectionId() {
    return this.#connId;
  }
  /**
   * Disconnects from the actor.
   *
   * @returns {Promise<void>} A promise that resolves when the socket is gracefully closed.
   */
  async dispose() {
    if (this.#disposed) {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({ msg: "connection already disconnected" });
      return;
    }
    this.#disposed = true;
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "disposing actor conn" });
    this.#setConnStatus("idle");
    clearInterval(this.#keepNodeAliveInterval);
    this.#abortController.abort();
    this.#client[ACTOR_CONNS_SYMBOL].delete(this);
    if (this.#websocket) {
      const ws = this.#websocket;
      if (ws.readyState !== 2 && ws.readyState !== 3) {
        const { promise, resolve } = _chunkMMUXNMJFcjs.promiseWithResolvers.call(void 0, (reason) => _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({ msg: "unhandled websocket close promise rejection", reason }));
        ws.addEventListener("close", () => resolve(void 0));
        ws.close(1e3, "Disposed");
        await promise;
      }
    } else {
      this.#rejectPendingPromises(new ActorConnDisposed(), true);
    }
    this.#websocket = void 0;
  }
  #sendSubscription(eventName, subscribe) {
    this.#sendMessage(
      {
        body: {
          tag: "SubscriptionRequest",
          val: {
            eventName,
            subscribe
          }
        }
      },
      { ephemeral: true }
    );
  }
};

// src/client/actor-handle.ts



// src/client/raw-utils.ts

async function rawHttpFetch(driver, actorQuery, params, input, init) {
  let path;
  let mergedInit = init || {};
  if (typeof input === "string") {
    path = input;
  } else if (input instanceof URL) {
    path = input.pathname + input.search;
  } else if (input instanceof Request) {
    const url = new URL(input.url);
    path = url.pathname + url.search;
    const requestHeaders = new Headers(input.headers);
    const initHeaders = new Headers((init == null ? void 0 : init.headers) || {});
    const mergedHeaders = new Headers(requestHeaders);
    initHeaders.forEach((value, key) => {
      mergedHeaders.set(key, value);
    });
    mergedInit = {
      method: input.method,
      body: input.body,
      mode: input.mode,
      credentials: input.credentials,
      redirect: input.redirect,
      referrer: input.referrer,
      referrerPolicy: input.referrerPolicy,
      integrity: input.integrity,
      keepalive: input.keepalive,
      signal: input.signal,
      ...mergedInit,
      // init overrides Request properties
      headers: mergedHeaders
      // headers must be set after spread to ensure proper merge
    };
    if (mergedInit.body) {
      mergedInit.duplex = "half";
    }
  } else {
    throw new TypeError("Invalid input type for fetch");
  }
  try {
    const { actorId } = await queryActor(void 0, actorQuery, driver);
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "found actor for raw http", actorId });
    _invariant2.default.call(void 0, actorId, "Missing actor ID");
    const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
    const url = new URL(`http://actor/request/${normalizedPath}`);
    const proxyRequestHeaders = new Headers(mergedInit.headers);
    if (params) {
      proxyRequestHeaders.set(_chunkQ5CW77ITcjs.HEADER_CONN_PARAMS, JSON.stringify(params));
    }
    const proxyRequest = new Request(url, {
      ...mergedInit,
      headers: proxyRequestHeaders
    });
    return driver.sendRequest(actorId, proxyRequest);
  } catch (err) {
    const { group, code, message, metadata } = _chunkMMUXNMJFcjs.deconstructError.call(void 0, 
      err,
      _chunkFUBHHHK5cjs.logger.call(void 0, ),
      {},
      true
    );
    throw new ActorError(group, code, message, metadata);
  }
}
async function rawWebSocket(driver, actorQuery, params, path, protocols) {
  const encoding = "bare";
  const { actorId } = await queryActor(void 0, actorQuery, driver);
  _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "found actor for action", actorId });
  _invariant2.default.call(void 0, actorId, "Missing actor ID");
  let pathPortion = "";
  let queryPortion = "";
  if (path) {
    const queryIndex = path.indexOf("?");
    if (queryIndex !== -1) {
      pathPortion = path.substring(0, queryIndex);
      queryPortion = path.substring(queryIndex);
    } else {
      pathPortion = path;
    }
    if (pathPortion.startsWith("/")) {
      pathPortion = pathPortion.slice(1);
    }
  }
  const fullPath = `${_chunkQ5CW77ITcjs.PATH_WEBSOCKET_PREFIX}${pathPortion}${queryPortion}`;
  _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
    msg: "opening websocket",
    actorId,
    encoding,
    path: fullPath
  });
  const ws = await driver.openWebSocket(fullPath, actorId, encoding, params);
  return ws;
}

// src/client/actor-handle.ts
var ActorHandleRaw = class {
  #client;
  #driver;
  #encoding;
  #actorQuery;
  #params;
  #queueSender;
  /**
   * Do not call this directly.
   *
   * Creates an instance of ActorHandleRaw.
   *
   * @protected
   */
  constructor(client, driver, params, encoding, actorQuery) {
    this.#client = client;
    this.#driver = driver;
    this.#encoding = encoding;
    this.#actorQuery = actorQuery;
    this.#params = params;
    this.#queueSender = createQueueSender({
      encoding: this.#encoding,
      params: this.#params,
      customFetch: async (request) => {
        const { actorId } = await queryActor(
          void 0,
          this.#actorQuery,
          this.#driver
        );
        return this.#driver.sendRequest(actorId, request);
      }
    });
  }
  send(name, body, options) {
    return this.#queueSender.send(name, body, options);
  }
  /**
   * Call a raw action. This method sends an HTTP request to invoke the named action.
   *
   * @see {@link ActorHandle}
   * @template Args - The type of arguments to pass to the action function.
   * @template Response - The type of the response returned by the action function.
   */
  async action(opts) {
    let actorId;
    try {
      const result = await queryActor(
        void 0,
        this.#actorQuery,
        this.#driver
      );
      actorId = result.actorId;
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "found actor for action", actorId });
      _invariant2.default.call(void 0, actorId, "Missing actor ID");
      _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
        msg: "handling action",
        name: opts.name,
        encoding: this.#encoding
      });
      const responseData = await sendHttpRequest({
        url: `http://actor/action/${encodeURIComponent(opts.name)}`,
        method: "POST",
        headers: {
          [_chunkQ5CW77ITcjs.HEADER_ENCODING]: this.#encoding,
          ...this.#params !== void 0 ? { [_chunkQ5CW77ITcjs.HEADER_CONN_PARAMS]: JSON.stringify(this.#params) } : {}
        },
        body: opts.args,
        encoding: this.#encoding,
        customFetch: this.#driver.sendRequest.bind(
          this.#driver,
          actorId
        ),
        signal: opts == null ? void 0 : opts.signal,
        requestVersion: _chunkQ5CW77ITcjs.CURRENT_VERSION,
        requestVersionedDataHandler: _chunkQ5CW77ITcjs.HTTP_ACTION_REQUEST_VERSIONED,
        responseVersion: _chunkQ5CW77ITcjs.CURRENT_VERSION,
        responseVersionedDataHandler: _chunkQ5CW77ITcjs.HTTP_ACTION_RESPONSE_VERSIONED,
        requestZodSchema: _chunkQ5CW77ITcjs.HttpActionRequestSchema,
        responseZodSchema: _chunkQ5CW77ITcjs.HttpActionResponseSchema,
        // JSON Request: args is the raw value
        requestToJson: (args) => ({
          args
        }),
        // BARE Request: args needs to be CBOR-encoded
        requestToBare: (args) => ({
          args: _chunkMMUXNMJFcjs.bufferToArrayBuffer.call(void 0, cbor5.encode(args))
        }),
        // JSON Response: output is the raw value
        responseFromJson: (json) => json.output,
        // BARE Response: output is ArrayBuffer that needs CBOR-decoding
        responseFromBare: (bare) => cbor5.decode(new Uint8Array(bare.output))
      });
      return responseData;
    } catch (err) {
      const { group, code, message, metadata } = _chunkMMUXNMJFcjs.deconstructError.call(void 0, 
        err,
        _chunkFUBHHHK5cjs.logger.call(void 0, ),
        {},
        true
      );
      if (actorId && isSchedulingError(group, code)) {
        const schedulingError = await checkForSchedulingError(
          group,
          code,
          actorId,
          this.#actorQuery,
          this.#driver
        );
        if (schedulingError) {
          throw schedulingError;
        }
      }
      throw new ActorError(group, code, message, metadata);
    }
  }
  /**
   * Establishes a persistent connection to the actor.
   *
   * @template AD The actor class that this connection is for.
   * @returns {ActorConn<AD>} A connection to the actor.
   */
  connect() {
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "establishing connection from handle",
      query: this.#actorQuery
    });
    const conn = new ActorConnRaw(
      this.#client,
      this.#driver,
      this.#params,
      this.#encoding,
      this.#actorQuery
    );
    return this.#client[CREATE_ACTOR_CONN_PROXY](
      conn
    );
  }
  /**
   * Fetches a resource from this actor via the /request endpoint. This is a
   * convenience wrapper around the raw HTTP API.
   */
  fetch(input, init) {
    return rawHttpFetch(
      this.#driver,
      this.#actorQuery,
      this.#params,
      input,
      init
    );
  }
  /**
   * Opens a raw WebSocket connection to this actor.
   */
  webSocket(path, protocols) {
    return rawWebSocket(
      this.#driver,
      this.#actorQuery,
      this.#params,
      path,
      protocols
    );
  }
  /**
   * Resolves the actor to get its unique actor ID.
   */
  async resolve() {
    if ("getForKey" in this.#actorQuery) {
      const name = this.#actorQuery.getForKey.name;
      const { actorId } = await queryActor(
        void 0,
        this.#actorQuery,
        this.#driver
      );
      this.#actorQuery = { getForId: { actorId, name } };
      return actorId;
    } else if ("getOrCreateForKey" in this.#actorQuery) {
      const name = this.#actorQuery.getOrCreateForKey.name;
      const { actorId } = await queryActor(
        void 0,
        this.#actorQuery,
        this.#driver
      );
      this.#actorQuery = { getForId: { actorId, name } };
      return actorId;
    } else if ("getForId" in this.#actorQuery) {
      return this.#actorQuery.getForId.actorId;
    } else if ("create" in this.#actorQuery) {
      _invariant2.default.call(void 0, false, "actorQuery cannot be create");
    } else {
      _chunkLNDVGTPQcjs.assertUnreachable.call(void 0, this.#actorQuery);
    }
  }
  /**
   * Returns the raw URL for routing traffic to the actor.
   */
  async getGatewayUrl() {
    const { actorId } = await queryActor(
      void 0,
      this.#actorQuery,
      this.#driver
    );
    return await this.#driver.buildGatewayUrl(actorId);
  }
};

// src/client/client.ts
var ACTOR_CONNS_SYMBOL = /* @__PURE__ */ Symbol("actorConns");
var CREATE_ACTOR_CONN_PROXY = /* @__PURE__ */ Symbol("createActorConnProxy");
var ClientRaw = (_class2 = class {
  #disposed = false;
  __init2() {this[ACTOR_CONNS_SYMBOL] = /* @__PURE__ */ new Set()}
  #driver;
  #encodingKind;
  /**
   * Creates an instance of Client.
   */
  constructor(driver, encoding) {;_class2.prototype.__init2.call(this);
    this.#driver = driver;
    this.#encodingKind = _nullishCoalesce(encoding, () => ( "bare"));
  }
  /**
   * Gets a stateless handle to a actor by its ID.
   *
   * @template AD The actor class that this handle is for.
   * @param {string} name - The name of the actor.
   * @param {string} actorId - The ID of the actor.
   * @param {GetWithIdOptions} [opts] - Options for getting the actor.
   * @returns {ActorHandle<AD>} - A handle to the actor.
   */
  getForId(name, actorId, opts) {
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "get handle to actor with id",
      name,
      actorId,
      params: opts == null ? void 0 : opts.params
    });
    const actorQuery = {
      getForId: {
        name,
        actorId
      }
    };
    const handle = this.#createHandle(opts == null ? void 0 : opts.params, actorQuery);
    return createActorProxy(handle);
  }
  /**
   * Gets a stateless handle to a actor by its key, but does not create the actor if it doesn't exist.
   *
   * @template AD The actor class that this handle is for.
   * @param {string} name - The name of the actor.
   * @param {string | string[]} [key=[]] - The key to identify the actor. Can be a single string or an array of strings.
   * @param {GetWithIdOptions} [opts] - Options for getting the actor.
   * @returns {ActorHandle<AD>} - A handle to the actor.
   */
  get(name, key, opts) {
    const keyArray = typeof key === "string" ? [key] : key || [];
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "get handle to actor",
      name,
      key: keyArray,
      parameters: opts == null ? void 0 : opts.params
    });
    const actorQuery = {
      getForKey: {
        name,
        key: keyArray
      }
    };
    const handle = this.#createHandle(opts == null ? void 0 : opts.params, actorQuery);
    return createActorProxy(handle);
  }
  /**
   * Gets a stateless handle to a actor by its key, creating it if necessary.
   *
   * @template AD The actor class that this handle is for.
   * @param {string} name - The name of the actor.
   * @param {string | string[]} [key=[]] - The key to identify the actor. Can be a single string or an array of strings.
   * @param {GetOptions} [opts] - Options for getting the actor.
   * @returns {ActorHandle<AD>} - A handle to the actor.
   */
  getOrCreate(name, key, opts) {
    const keyArray = typeof key === "string" ? [key] : key || [];
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "get or create handle to actor",
      name,
      key: keyArray,
      parameters: opts == null ? void 0 : opts.params,
      createInRegion: opts == null ? void 0 : opts.createInRegion
    });
    const actorQuery = {
      getOrCreateForKey: {
        name,
        key: keyArray,
        input: opts == null ? void 0 : opts.createWithInput,
        region: opts == null ? void 0 : opts.createInRegion
      }
    };
    const handle = this.#createHandle(opts == null ? void 0 : opts.params, actorQuery);
    return createActorProxy(handle);
  }
  /**
   * Creates a new actor with the provided key and returns a stateless handle to it.
   * Resolves the actor ID and returns a handle with getForId query.
   *
   * @template AD The actor class that this handle is for.
   * @param {string} name - The name of the actor.
   * @param {string | string[]} key - The key to identify the actor. Can be a single string or an array of strings.
   * @param {CreateOptions} [opts] - Options for creating the actor (excluding name and key).
   * @returns {Promise<ActorHandle<AD>>} - A promise that resolves to a handle to the actor.
   */
  async create(name, key, opts) {
    const keyArray = typeof key === "string" ? [key] : key || [];
    const createQuery = {
      create: {
        ...opts,
        // Do these last to override `opts`
        name,
        key: keyArray
      }
    };
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "create actor handle",
      name,
      key: keyArray,
      parameters: opts == null ? void 0 : opts.params,
      create: createQuery.create
    });
    const { actorId } = await queryActor(
      void 0,
      createQuery,
      this.#driver
    );
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({
      msg: "created actor with ID",
      name,
      key: keyArray,
      actorId
    });
    const getForIdQuery = {
      getForId: {
        name,
        actorId
      }
    };
    const handle = this.#createHandle(opts == null ? void 0 : opts.params, getForIdQuery);
    const proxy = createActorProxy(handle);
    return proxy;
  }
  #createHandle(params, actorQuery) {
    return new ActorHandleRaw(
      this,
      this.#driver,
      params,
      this.#encodingKind,
      actorQuery
    );
  }
  [CREATE_ACTOR_CONN_PROXY](conn) {
    this[ACTOR_CONNS_SYMBOL].add(conn);
    conn[CONNECT_SYMBOL]();
    return createActorProxy(conn);
  }
  /**
   * Disconnects from all actors.
   *
   * @returns {Promise<void>} A promise that resolves when all connections are closed.
   */
  async dispose() {
    if (this.#disposed) {
      _chunkFUBHHHK5cjs.logger.call(void 0, ).warn({ msg: "client already disconnected" });
      return;
    }
    this.#disposed = true;
    _chunkFUBHHHK5cjs.logger.call(void 0, ).debug({ msg: "disposing client" });
    const disposePromises = [];
    for (const conn of this[ACTOR_CONNS_SYMBOL].values()) {
      disposePromises.push(conn.dispose());
    }
    await Promise.all(disposePromises);
  }
}, _class2);
function createClientWithDriver(driver, config = {}) {
  const client = new ClientRaw(driver, config.encoding);
  return new Proxy(client, {
    get: (target, prop, receiver) => {
      if (typeof prop === "symbol" || prop in target) {
        const value = Reflect.get(target, prop, receiver);
        if (typeof value === "function") {
          return value.bind(target);
        }
        return value;
      }
      if (typeof prop === "string") {
        return {
          // Handle methods (stateless action)
          get: (key, opts) => {
            return target.get(prop, key, opts);
          },
          getOrCreate: (key, opts) => {
            return target.getOrCreate(prop, key, opts);
          },
          getForId: (actorId, opts) => {
            return target.getForId(prop, actorId, opts);
          },
          create: async (key, opts = {}) => {
            return await target.create(prop, key, opts);
          }
        };
      }
      return void 0;
    }
  });
}
function createActorProxy(handle) {
  const methodCache = /* @__PURE__ */ new Map();
  return new Proxy(handle, {
    get(target, prop, receiver) {
      if (typeof prop === "symbol") {
        return Reflect.get(target, prop, receiver);
      }
      if (prop === "constructor" || prop in target) {
        const value = Reflect.get(target, prop, target);
        if (typeof value === "function") {
          return value.bind(target);
        }
        return value;
      }
      if (typeof prop === "string") {
        if (prop === "then") return void 0;
        let method = methodCache.get(prop);
        if (!method) {
          method = (...args) => target.action({ name: prop, args });
          methodCache.set(prop, method);
        }
        return method;
      }
    },
    // Support for 'in' operator
    has(target, prop) {
      if (typeof prop === "string") return true;
      return Reflect.has(target, prop);
    },
    // Support instanceof checks
    getPrototypeOf(target) {
      return Reflect.getPrototypeOf(target);
    },
    // Prevent property enumeration of non-existent action methods
    ownKeys(target) {
      return Reflect.ownKeys(target);
    },
    // Support proper property descriptors
    getOwnPropertyDescriptor(target, prop) {
      const targetDescriptor = Reflect.getOwnPropertyDescriptor(
        target,
        prop
      );
      if (targetDescriptor) {
        return targetDescriptor;
      }
      if (typeof prop === "string") {
        return {
          configurable: true,
          enumerable: false,
          writable: false,
          value: (...args) => target.action({ name: prop, args })
        };
      }
      return void 0;
    }
  });
}

// src/client/config.ts

function getDefaultEndpoint() {
  var _a;
  if (typeof window !== "undefined" && ((_a = window.location) == null ? void 0 : _a.origin)) {
    return `${window.location.origin}/api/rivet`;
  }
  return "http://127.0.0.1:6420";
}
var ClientConfigSchemaBase = _v42.default.object({
  /**
   * Endpoint to connect to for Rivet Engine or RivetKit manager API.
   *
   * Supports URL auth syntax for namespace and token:
   * - `https://namespace:token@api.rivet.dev`
   * - `https://namespace@api.rivet.dev`
   *
   * Can also be set via RIVET_ENDPOINT environment variables.
   *
   * Defaults to current origin + /api/rivet in browser, or 127.0.0.1:6420 server-side.
   */
  endpoint: _v42.default.string().optional().transform(
    (val) => _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(val, () => ( _chunkMMUXNMJFcjs.getRivetEngine.call(void 0, ))), () => ( _chunkMMUXNMJFcjs.getRivetEndpoint.call(void 0, ))), () => ( getDefaultEndpoint()))
  ),
  /** Token to use to authenticate with the API. */
  token: _v42.default.string().optional().transform((val) => _nullishCoalesce(val, () => ( _chunkMMUXNMJFcjs.getRivetToken.call(void 0, )))),
  /** Namespace to connect to. */
  namespace: _v42.default.string().optional().transform((val) => _nullishCoalesce(val, () => ( _chunkMMUXNMJFcjs.getRivetNamespace.call(void 0, )))),
  /** Name of the runner. This is used to group together runners in to different pools. */
  runnerName: _v42.default.string().default(() => _nullishCoalesce(_chunkMMUXNMJFcjs.getRivetRunner.call(void 0, ), () => ( "default"))),
  encoding: _chunkQ5CW77ITcjs.EncodingSchema.default("bare"),
  headers: _v42.default.record(_v42.default.string(), _v42.default.string()).optional().default(() => ({})),
  // See RunConfig.getUpgradeWebSocket
  //
  // This is required in the client config in order to support
  // `proxyWebSocket`
  getUpgradeWebSocket: _v42.default.custom().optional(),
  /** Whether to automatically perform health checks when the client is created. */
  disableMetadataLookup: _v42.default.boolean().optional().default(false),
  /** Whether to enable RivetKit Devtools integration. */
  devtools: _v42.default.boolean().default(
    () => {
      var _a, _b;
      return typeof window !== "undefined" && (((_a = window == null ? void 0 : window.location) == null ? void 0 : _a.hostname) === "127.0.0.1" || ((_b = window.location) == null ? void 0 : _b.hostname) === "localhost");
    }
  )
});
var ClientConfigSchema = ClientConfigSchemaBase.transform(
  (config, ctx) => transformClientConfig(config, ctx)
);
function transformClientConfig(config, ctx) {
  const parsedEndpoint = _chunkQ5CW77ITcjs.tryParseEndpoint.call(void 0, ctx, {
    endpoint: config.endpoint,
    path: ["endpoint"],
    namespace: config.namespace,
    token: config.token
  });
  return {
    ...config,
    endpoint: parsedEndpoint == null ? void 0 : parsedEndpoint.endpoint,
    namespace: _nullishCoalesce(_nullishCoalesce((parsedEndpoint == null ? void 0 : parsedEndpoint.namespace), () => ( config.namespace)), () => ( "default")),
    token: _nullishCoalesce((parsedEndpoint == null ? void 0 : parsedEndpoint.token), () => ( config.token))
  };
}
function convertRegistryConfigToClientConfig(config) {
  var _a, _b;
  return {
    endpoint: config.endpoint,
    token: config.token,
    namespace: config.namespace,
    runnerName: config.runner.runnerName,
    headers: config.headers,
    encoding: "bare",
    getUpgradeWebSocket: void 0,
    // We don't need health checks for internal clients
    disableMetadataLookup: true,
    devtools: typeof window !== "undefined" && (((_a = window == null ? void 0 : window.location) == null ? void 0 : _a.hostname) === "127.0.0.1" || ((_b = window == null ? void 0 : window.location) == null ? void 0 : _b.hostname) === "localhost")
  };
}

// src/client/mod.ts
function createClient(endpointOrConfig) {
  const configInput = endpointOrConfig === void 0 ? {} : typeof endpointOrConfig === "string" ? { endpoint: endpointOrConfig } : endpointOrConfig;
  const config = ClientConfigSchema.parse(configInput);
  const driver = new RemoteManagerDriver(config);
  if (config.devtools) {
    injectDevtools(config);
  }
  return createClientWithDriver(driver, config);
}




















exports.ActorClientError = ActorClientError; exports.InternalError = InternalError; exports.ManagerError = ManagerError; exports.MalformedResponseMessage = MalformedResponseMessage; exports.ActorError = ActorError; exports.ActorConnDisposed = ActorConnDisposed; exports.ActorConnRaw = ActorConnRaw; exports.ActorHandleRaw = ActorHandleRaw; exports.createClientWithDriver = createClientWithDriver; exports.ClientConfigSchemaBase = ClientConfigSchemaBase; exports.ClientConfigSchema = ClientConfigSchema; exports.transformClientConfig = transformClientConfig; exports.convertRegistryConfigToClientConfig = convertRegistryConfigToClientConfig; exports.getEndpoint = getEndpoint; exports.getDatacenters = getDatacenters; exports.updateRunnerConfig = updateRunnerConfig; exports.RemoteManagerDriver = RemoteManagerDriver; exports.createClient = createClient;
//# sourceMappingURL=chunk-AGERRJ32.cjs.map