{"version":3,"file":"index.cjs","names":["ReconnectingWebSocket"],"sources":["../src/index.ts"],"sourcesContent":["import ReconnectingWebSocket from \"./ws\";\n\nimport type * as RWS from \"./ws\";\nimport type { ProtocolsProvider } from \"./ws\";\n\ntype Maybe<T> = T | null | undefined;\ntype Params = Record<string, Maybe<string>>;\nconst valueIsNotNil = <T>(\n  keyValuePair: [string, Maybe<T>]\n): keyValuePair is [string, T] =>\n  keyValuePair[1] !== null && keyValuePair[1] !== undefined;\n\nexport type PartySocketOptions = Omit<RWS.Options, \"constructor\"> & {\n  id?: string; // the id of the client\n  host: string; // base url for the party\n  room?: string; // the room to connect to\n  party?: string; // the party to connect to (defaults to main)\n  basePath?: string; // the base path to use for the party\n  prefix?: string; // the prefix to use for the party\n  protocol?: \"ws\" | \"wss\";\n  protocols?: ProtocolsProvider;\n  path?: string; // the path to connect to\n  query?: Params | (() => Params | Promise<Params>);\n  disableNameValidation?: boolean; // disable validation of party/room names\n  // headers\n};\n\nexport type PartyFetchOptions = {\n  host: string; // base url for the party\n  room: string; // the room to connect to\n  party?: string; // the party to fetch from (defaults to main)\n  basePath?: string; // the base path to use for the party\n  prefix?: string; // the prefix to use for the party\n  path?: string; // the path to fetch from\n  protocol?: \"http\" | \"https\";\n  query?: Params | (() => Params | Promise<Params>);\n  fetch?: typeof fetch;\n};\n\nfunction generateUUID(): string {\n  // Public Domain/MIT\n  if (crypto?.randomUUID) {\n    return crypto.randomUUID();\n  }\n  let d = Date.now(); //Timestamp\n  let d2 = (performance?.now && performance.now() * 1000) || 0; //Time in microseconds since page-load or 0 if unsupported\n  // oxlint-disable-next-line func-style\n  return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n    let r = Math.random() * 16; //random number between 0 and 16\n    if (d > 0) {\n      //Use timestamp until depleted\n      r = ((d + r) % 16) | 0;\n      d = Math.floor(d / 16);\n    } else {\n      //Use microseconds since page-load if supported\n      r = ((d2 + r) % 16) | 0;\n      d2 = Math.floor(d2 / 16);\n    }\n    return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n  });\n}\n\nfunction getPartyInfo(\n  partySocketOptions: PartySocketOptions | PartyFetchOptions,\n  defaultProtocol: \"http\" | \"ws\",\n  defaultParams: Record<string, string> = {}\n) {\n  const {\n    host: rawHost,\n    path: rawPath,\n    protocol: rawProtocol,\n    room,\n    party,\n    basePath,\n    prefix,\n    query\n  } = partySocketOptions;\n\n  // strip the protocol from the beginning of `host` if any\n  let host = rawHost.replace(/^(http|https|ws|wss):\\/\\//, \"\");\n  // if user provided a trailing slash, remove it\n  if (host.endsWith(\"/\")) {\n    host = host.slice(0, -1);\n  }\n\n  if (rawPath?.startsWith(\"/\")) {\n    throw new Error(\"path must not start with a slash\");\n  }\n\n  const name = party ?? \"main\";\n  const path = rawPath ? `/${rawPath}` : \"\";\n  const protocol =\n    rawProtocol ||\n    (host.startsWith(\"localhost:\") ||\n    host.startsWith(\"127.0.0.1:\") ||\n    host.startsWith(\"192.168.\") ||\n    host.startsWith(\"10.\") ||\n    (host.startsWith(\"172.\") &&\n      host.split(\".\")[1] >= \"16\" &&\n      host.split(\".\")[1] <= \"31\") ||\n    host.startsWith(\"[::ffff:7f00:1]:\")\n      ? // http / ws\n        defaultProtocol\n      : // https / wss\n        `${defaultProtocol}s`);\n\n  const baseUrl = `${protocol}://${host}/${basePath || `${prefix || \"parties\"}/${name}/${room}`}${path}`;\n\n  const makeUrl = (query: Params = {}) =>\n    `${baseUrl}?${new URLSearchParams([\n      ...Object.entries(defaultParams),\n      ...Object.entries(query).filter(valueIsNotNil)\n    ])}`;\n\n  // allow urls to be defined as functions\n  const urlProvider =\n    typeof query === \"function\"\n      ? async () => makeUrl(await query())\n      : makeUrl(query);\n\n  return {\n    host,\n    path,\n    room,\n    name,\n    protocol,\n    partyUrl: baseUrl,\n    urlProvider\n  };\n}\n\n// things that nathanboktae/robust-websocket claims are better:\n// doesn't do anything in offline mode (?)\n// \"natively aware of error codes\"\n// can do custom reconnect strategies\n\n// TODO: incorporate the above notes\nexport default class PartySocket extends ReconnectingWebSocket {\n  _pk!: string;\n  _pkurl!: string;\n  name!: string;\n  room?: string;\n  host!: string;\n  path!: string;\n  basePath?: string;\n\n  constructor(readonly partySocketOptions: PartySocketOptions) {\n    const wsOptions = getWSOptions(partySocketOptions);\n\n    super(wsOptions.urlProvider, wsOptions.protocols, wsOptions.socketOptions);\n\n    this.setWSProperties(wsOptions);\n\n    if (!partySocketOptions.startClosed && !this.room && !this.basePath) {\n      this.close();\n      throw new Error(\n        \"Either room or basePath must be provided to connect. Use startClosed: true to create a socket and set them via updateProperties before calling reconnect().\"\n      );\n    }\n\n    if (!partySocketOptions.disableNameValidation) {\n      if (partySocketOptions.party?.includes(\"/\")) {\n        console.warn(\n          `PartySocket: party name \"${partySocketOptions.party}\" contains forward slash which may cause routing issues. Consider using a name without forward slashes or set disableNameValidation: true to bypass this warning.`\n        );\n      }\n      if (partySocketOptions.room?.includes(\"/\")) {\n        console.warn(\n          `PartySocket: room name \"${partySocketOptions.room}\" contains forward slash which may cause routing issues. Consider using a name without forward slashes or set disableNameValidation: true to bypass this warning.`\n        );\n      }\n    }\n  }\n\n  public updateProperties(partySocketOptions: Partial<PartySocketOptions>) {\n    const wsOptions = getWSOptions({\n      ...this.partySocketOptions,\n      ...partySocketOptions,\n      host: partySocketOptions.host ?? this.host,\n      room: partySocketOptions.room ?? this.room,\n      path: partySocketOptions.path ?? this.path,\n      basePath: partySocketOptions.basePath ?? this.basePath\n    });\n\n    this._url = wsOptions.urlProvider;\n    this._protocols = wsOptions.protocols;\n    this._options = wsOptions.socketOptions;\n\n    this.setWSProperties(wsOptions);\n  }\n\n  private setWSProperties(wsOptions: ReturnType<typeof getWSOptions>) {\n    const { _pk, _pkurl, name, room, host, path, basePath } = wsOptions;\n\n    this._pk = _pk;\n    this._pkurl = _pkurl;\n    this.name = name;\n    this.room = room;\n    this.host = host;\n    this.path = path;\n    this.basePath = basePath;\n  }\n\n  public reconnect(\n    code?: number | undefined,\n    reason?: string | undefined\n  ): void {\n    if (!this.host) {\n      throw new Error(\n        \"The host must be set before connecting, use `updateProperties` method to set it or pass it to the constructor.\"\n      );\n    }\n    if (!this.room && !this.basePath) {\n      throw new Error(\n        \"The room (or basePath) must be set before connecting, use `updateProperties` method to set it or pass it to the constructor.\"\n      );\n    }\n    super.reconnect(code, reason);\n  }\n\n  get id() {\n    return this._pk;\n  }\n\n  /**\n   * Exposes the static PartyKit room URL without applying query parameters.\n   * To access the currently connected WebSocket url, use PartySocket#url.\n   */\n  get roomUrl(): string {\n    return this._pkurl;\n  }\n\n  // a `fetch` method that uses (almost) the same options as `PartySocket`\n  static async fetch(\n    options: PartyFetchOptions,\n    init?: RequestInit\n  ): Promise<Response> {\n    const party = getPartyInfo(options, \"http\");\n    const url =\n      typeof party.urlProvider === \"string\"\n        ? party.urlProvider\n        : await party.urlProvider();\n    const doFetch = options.fetch ?? fetch;\n    return doFetch(url, init);\n  }\n}\n\nexport { PartySocket };\n\nexport { ReconnectingWebSocket as WebSocket };\n\nfunction getWSOptions(partySocketOptions: PartySocketOptions) {\n  const {\n    id,\n    host: _host,\n    path: _path,\n    party: _party,\n    room: _room,\n    protocol: _protocol,\n    query: _query,\n    protocols,\n    ...socketOptions\n  } = partySocketOptions;\n\n  const _pk = id || generateUUID();\n  const party = getPartyInfo(partySocketOptions, \"ws\", { _pk });\n\n  return {\n    _pk: _pk,\n    _pkurl: party.partyUrl,\n    name: party.name,\n    room: party.room,\n    host: party.host,\n    path: party.path,\n    basePath: partySocketOptions.basePath,\n    protocols: protocols,\n    socketOptions: socketOptions,\n    urlProvider: party.urlProvider\n  };\n}\n"],"mappings":"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"}