@protobase/ui 0.66.5 → 0.66.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/account/blocks/password-block.js +1 -1
  2. package/dist/account/change-email-dialog.js +5 -1
  3. package/dist/account/password-change-dialog.js +4 -11
  4. package/dist/account/password-section.js +2 -2
  5. package/dist/app/error-reporting.js +8 -3
  6. package/dist/app/field-types/field-type-cells.js +2 -1
  7. package/dist/auth/email-code-form.js +8 -4
  8. package/dist/auth/sign-up-code-form.js +8 -4
  9. package/dist/auth/two-factor-form.js +2 -1
  10. package/dist/locale/en.js +5 -4
  11. package/dist/locale/nl.js +5 -4
  12. package/dist/package.js +1 -1
  13. package/dist/shell/assets/app-BZ_OcfpZ.js +8 -0
  14. package/dist/shell/assets/calls-uuSb7D6L.js +2 -0
  15. package/dist/shell/assets/cn-B1sdg8aY.js +2 -0
  16. package/dist/shell/assets/export-worker-CcXp0ZdG.js +15 -0
  17. package/dist/shell/assets/index-B2M0LDVQ.js +2 -0
  18. package/dist/shell/assets/maplibre-DfXLXH-O.js +815 -0
  19. package/dist/shell/assets/{markdown-content-DOuciTNH.js → markdown-content-L1MZShpP.js} +2 -2
  20. package/dist/shell/assets/parse-worker-CUJ2o-AL.js +35 -0
  21. package/dist/shell/assets/preload-helper-Ru-oozfe.js +2 -0
  22. package/dist/shell/assets/{prod-YZ9ZMG1O.js → prod-DSoLg5cQ.js} +3 -3
  23. package/dist/shell/assets/{react-CR5VJ85Q.js → react-CqoBMk9d.js} +2 -2
  24. package/dist/shell/assets/record-map-Cocva8wo.js +2 -0
  25. package/dist/shell/assets/records-map-B1PDo3PS.js +2 -0
  26. package/dist/shell/assets/rolldown-runtime-DXfiGoCU.js +1 -0
  27. package/dist/shell/assets/shared-protobase-ui-V8ARYzmY.js +2 -0
  28. package/dist/shell/assets/shared-react-CJlT6JLM.js +1 -0
  29. package/dist/shell/assets/shared-react-dom-untDBgp5.js +1 -0
  30. package/dist/shell/assets/shared-react-jsx-runtime-DGG2WguE.js +1 -0
  31. package/dist/shell/assets/{vendor-Kvdo8Jrw.js → vendor-qs9zUu9T.js} +2 -2
  32. package/dist/shell/index.html +8 -8
  33. package/dist/shell/protobase.shell.json +2 -2
  34. package/dist/shell/protobase.sw.js +2 -2
  35. package/dist/shell-source-maps/assets/app-BZ_OcfpZ.js.map +1 -0
  36. package/dist/shell-source-maps/assets/calls-uuSb7D6L.js.map +1 -0
  37. package/dist/shell-source-maps/assets/cn-B1sdg8aY.js.map +1 -0
  38. package/dist/shell-source-maps/assets/export-worker-CcXp0ZdG.js.map +1 -0
  39. package/dist/shell-source-maps/assets/index-B2M0LDVQ.js.map +1 -0
  40. package/dist/shell-source-maps/assets/maplibre-DfXLXH-O.js.map +1 -0
  41. package/dist/shell-source-maps/assets/{markdown-content-DOuciTNH.js.map → markdown-content-L1MZShpP.js.map} +1 -1
  42. package/dist/shell-source-maps/assets/parse-worker-CUJ2o-AL.js.map +1 -0
  43. package/dist/shell-source-maps/assets/preload-helper-Ru-oozfe.js.map +1 -0
  44. package/dist/shell-source-maps/assets/prod-DSoLg5cQ.js.map +1 -0
  45. package/dist/shell-source-maps/assets/react-CqoBMk9d.js.map +1 -0
  46. package/dist/shell-source-maps/assets/record-map-Cocva8wo.js.map +1 -0
  47. package/dist/shell-source-maps/assets/records-map-B1PDo3PS.js.map +1 -0
  48. package/dist/shell-source-maps/assets/shared-protobase-ui-V8ARYzmY.js.map +1 -0
  49. package/dist/shell-source-maps/assets/{vendor-Kvdo8Jrw.js.map → vendor-qs9zUu9T.js.map} +1 -1
  50. package/package.json +4 -4
  51. package/dist/shell/assets/app-CqYVvgWc.js +0 -8
  52. package/dist/shell/assets/calls-EtUk7HmO.js +0 -2
  53. package/dist/shell/assets/cn-Bi0ZEjD9.js +0 -2
  54. package/dist/shell/assets/export-worker-BKuC4P2E.js +0 -15
  55. package/dist/shell/assets/index-8DBJXkuQ.js +0 -2
  56. package/dist/shell/assets/maplibre-lc2A-_P4.js +0 -815
  57. package/dist/shell/assets/parse-worker-BzLD2jKf.js +0 -35
  58. package/dist/shell/assets/preload-helper-DedkISGJ.js +0 -2
  59. package/dist/shell/assets/record-map-CupIwJyD.js +0 -2
  60. package/dist/shell/assets/records-map-CzL9UaeM.js +0 -2
  61. package/dist/shell/assets/rolldown-runtime-hePW80VL.js +0 -1
  62. package/dist/shell/assets/shared-protobase-ui-CZb9eNY5.js +0 -2
  63. package/dist/shell/assets/shared-react-CuZpzdyh.js +0 -1
  64. package/dist/shell/assets/shared-react-dom-BNlY7-7i.js +0 -1
  65. package/dist/shell/assets/shared-react-jsx-runtime-Csr2Kx2w.js +0 -1
  66. package/dist/shell-source-maps/assets/app-CqYVvgWc.js.map +0 -1
  67. package/dist/shell-source-maps/assets/calls-EtUk7HmO.js.map +0 -1
  68. package/dist/shell-source-maps/assets/cn-Bi0ZEjD9.js.map +0 -1
  69. package/dist/shell-source-maps/assets/export-worker-BKuC4P2E.js.map +0 -1
  70. package/dist/shell-source-maps/assets/index-8DBJXkuQ.js.map +0 -1
  71. package/dist/shell-source-maps/assets/maplibre-lc2A-_P4.js.map +0 -1
  72. package/dist/shell-source-maps/assets/parse-worker-BzLD2jKf.js.map +0 -1
  73. package/dist/shell-source-maps/assets/preload-helper-DedkISGJ.js.map +0 -1
  74. package/dist/shell-source-maps/assets/prod-YZ9ZMG1O.js.map +0 -1
  75. package/dist/shell-source-maps/assets/react-CR5VJ85Q.js.map +0 -1
  76. package/dist/shell-source-maps/assets/record-map-CupIwJyD.js.map +0 -1
  77. package/dist/shell-source-maps/assets/records-map-CzL9UaeM.js.map +0 -1
  78. package/dist/shell-source-maps/assets/shared-protobase-ui-CZb9eNY5.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calls-uuSb7D6L.js","names":["newPeerConnection","createPeerConnection","newPeerConnection","createPeerConnection","n","a","t","guestCallsPath","GuestRefused","reason","guestRequests","pending","ask","send","message","expiresAt","request","PublishRefused","createPeerConnection","configuration","statsOf","stats","report","transport","stat","pair","lost","received","roundTrip","connectionOf","state","pc","member","midsByStreamId","mids","section","sdp","mid","stream","firefoxMade","inFirefox","politeTo","offer","peer","peerLink","createPeerConnection$2","peers","local","remote","publishing","publishes","sendOn","track","receivedTrack","sid","transceiver","emitTracks","onTracks","open","making","event","source","sending","connect","self","renew","disconnect","signal","from","description","collision","candidate","error","receive","present","publishNow","added","tracks","answered","next","sender","muted","negotiation","inFlight","again","waiting","start","settle","resolve","simulcastLayers","singleBitrate","trackRequest","layers","simulcast","layer","width","height","sendEncodings","sfuLink","createPeerConnection$1","early","offerId","offers","negotiate","key","restartIce","stopSending","i","onUnpublished","options","encodings","sids","backoff","attempt","socketUrl","resolved","url","leftCodes","failedCodes","joinCall","WebSocketOf","retryDelay","maxRetries","socket","link","participant","callId","members","ended","rejoin","opened","resumedSinceOpen","failures","chain","joined","result","requests","guest","setState","end","newLink","input","handle","before","call","resume","mode","closed","left","code","publishOptions","size","LobbyRefused","status","guestLobby","fetchOf","lobby","systemPath","response","init","bearer","token"],"sources":["../../../../client/src/calls/guest-requests.ts","../../../../client/src/calls/publish-refused.ts","../../../../client/src/calls/media-link.ts","../../../../client/src/calls/connection-stats.ts","../../../../client/src/calls/msid-tracks.ts","../../../../client/src/calls/peer-link.ts","../../../../client/src/calls/negotiation.ts","../../../../client/src/calls/sfu-link.ts","../../../../client/src/calls/join-call.ts","../../../../client/src/calls/guest-lobby.ts"],"sourcesContent":["import type { CallClientMessage, CallGuestLink, CallGuestRefusal, CallServerMessage, CallTrackSource } from '@protobase/schema/internal'\n\n/** A guest request the server did not do, with why: see `CallGuestRefusal`. */\nexport class GuestRefused extends Error {\n constructor(readonly reason: CallGuestRefusal) {\n super(`The guest request was refused: ${reason}`)\n this.name = 'GuestRefused'\n }\n}\n\n/** What a member who invites does with the call's guests. Each rejects with `GuestRefused` when the server did not. */\nexport type CallGuests = {\n /** A new link to the call that lets a guest send these sources, until `expiresAt` or the call's end; its token once. */\n link: (options: { publish: CallTrackSource[]; expiresAt?: Date }) => Promise<{ link: CallGuestLink; token: string }>\n /** Revokes a link: its guests are out of the call, and nobody else waits on it. */\n revoke: (link: string) => Promise<void>\n admit: (guest: string) => Promise<void>\n deny: (guest: string) => Promise<void>\n /** Takes a guest out of the call, for good. */\n remove: (guest: string) => Promise<void>\n}\n\ntype Pending = { resolve: (value: never) => void; reject: (error: unknown) => void }\n\n/**\n * The member's guest requests over the call's socket: the server answers each once, in order, so the answers are paired\n * with the requests in the order they were sent. A request whose socket closed before its answer rejects.\n */\nexport const guestRequests = (send: (message: CallClientMessage) => void) => {\n const pending: Pending[] = []\n const ask = <T>(message: CallClientMessage) =>\n new Promise<T>((resolve, reject) => {\n pending.push({ resolve: resolve as (value: never) => void, reject })\n send(message)\n })\n const guests: CallGuests = {\n link: ({ publish, expiresAt }) => ask({ type: 'guest-link', publish, ...(expiresAt && { expires_at: expiresAt.toISOString() }) }),\n revoke: (link) => ask({ type: 'guest-link-revoke', link }),\n admit: (guest) => ask({ type: 'guest-decide', guest, admit: true }),\n deny: (guest) => ask({ type: 'guest-decide', guest, admit: false }),\n remove: (guest) => ask({ type: 'guest-remove', guest }),\n }\n return {\n guests,\n /** Whether the message answered a request, which it then settles. */\n receive: (message: CallServerMessage) => {\n if (message.type !== 'guest-link' && message.type !== 'guest-done' && message.type !== 'guest-refused') return false\n const request = pending.shift()\n if (message.type === 'guest-refused') request?.reject(new GuestRefused(message.reason))\n else request?.resolve((message.type === 'guest-link' ? { link: message.link, token: message.token } : undefined) as never)\n return true\n },\n /** The socket closed: the requests on it are not answered. */\n lost: () => {\n for (const request of pending.splice(0)) request.reject(new Error('The link to the call was lost before the server answered'))\n },\n }\n}\n","/** The server refused tracks the member may not send, such as a camera for a member who may only listen. */\nexport class PublishRefused extends Error {\n constructor(reason: string) {\n super(reason)\n this.name = 'PublishRefused'\n }\n}\n","import type { CallConnection } from './connection-stats'\nimport type { CallClientMessage, CallRemoteTrack, CallResume, CallServerMessage, CallTrackSource } from '@protobase/schema/internal'\n\n/** A track of another member, with its media once the browser receives it. */\nexport type CallTrack = CallRemoteTrack & { track?: MediaStreamTrack }\n\n/** How a published video track is sent: with a media server, simulcast sends it in three sizes the server picks from. */\nexport type PublishOptions = { simulcast?: boolean }\n\n/** What a media link is made with: how it talks to Protobase and what it tells the page. */\nexport type MediaLinkInput = {\n iceServers: RTCIceServer[]\n send: (message: CallClientMessage) => void\n onTracks: (tracks: CallTrack[]) => void\n /** The media server stopped sending one of the member's tracks, such as after a demotion. */\n onUnpublished: (source: CallTrackSource) => void\n createPeerConnection?: (configuration: RTCConfiguration) => RTCPeerConnection\n}\n\n/**\n * One member's media in a call, over plain `RTCPeerConnection`s: to a media server (`sfuLink`) or to each other member\n * (`peerLink`). Both take the same messages and do the same things for the call; they differ in who answers an offer.\n */\nexport type MediaLink = {\n /** A message of the server; one at a time, in order. */\n receive: (message: CallServerMessage) => Promise<void>\n publish: (tracks: Partial<Record<CallTrackSource, MediaStreamTrack>>, options?: PublishOptions) => Promise<void>\n unpublish: (source: CallTrackSource) => Promise<void>\n mute: (source: CallTrackSource, muted: boolean) => void\n restartIce: () => Promise<void>\n /** What a new server session needs to resume the link; `undefined` when it cannot, and the member joins anew. */\n resumeState: (participant: string) => Promise<Omit<CallResume, 'call'> | undefined>\n /** After a resume: offers what changed while the session was lost. */\n resumed: () => Promise<void>\n /** How each of the member's connections fares now. */\n connections: () => Promise<CallConnection[]>\n /** The tracks the member sends, by source, to publish again after a rejoin. */\n sending: () => Map<CallTrackSource, { track: MediaStreamTrack; simulcast: boolean }>\n close: () => void\n}\n\nexport const createPeerConnection = (configuration: RTCConfiguration) => new RTCPeerConnection(configuration)\n","/**\n * How one of the member's connections fares: to another member (`member`), or to the media server (no `member`). Its\n * state, and once connected, the round trip of its network path and the share of the media it received that was lost.\n */\nexport type CallConnection = { member?: string; state: RTCPeerConnectionState; roundTripMs?: number; lostRatio?: number }\n\ntype Stat = { type: string; id: string; [field: string]: unknown }\n\n/** What `connectionOf` reads of a connection's stats: the selected candidate pair's round trip, and the received media's losses. */\nexport const statsOf = (report: Iterable<Stat>): Pick<CallConnection, 'roundTripMs' | 'lostRatio'> => {\n const stats = [...report]\n const transport = stats.find((stat) => stat.type === 'transport' && typeof stat.selectedCandidatePairId === 'string')\n // Firefox names no selected pair on its transport: it marks the pair itself.\n const pair = stats.find((stat) => stat.type === 'candidate-pair' && (stat.id === transport?.selectedCandidatePairId || (!transport && stat.selected === true) || (!transport && stat.nominated === true && stat.state === 'succeeded')))\n let lost = 0\n let received = 0\n for (const stat of stats) {\n if (stat.type !== 'inbound-rtp') continue\n lost += Math.max(0, Number(stat.packetsLost ?? 0))\n received += Number(stat.packetsReceived ?? 0)\n }\n const roundTrip = typeof pair?.currentRoundTripTime === 'number' ? pair.currentRoundTripTime * 1000 : undefined\n return { ...(roundTrip !== undefined && { roundTripMs: roundTrip }), ...(lost + received > 0 && { lostRatio: lost / (lost + received) }) }\n}\n\n/** How the connection fares now, as `CallConnection`. */\nexport const connectionOf = async (pc: RTCPeerConnection, member?: string): Promise<CallConnection> => {\n const state = pc.connectionState\n const report = state === 'connected' ? statsOf((await pc.getStats()).values() as Iterable<Stat>) : {}\n return { ...(member !== undefined && { member }), state, ...report }\n}\n","/**\n * The `mid` of each media section of a description by the sending browser's track id, which its `a=msid` line names: a\n * receiver's own track may have another id, when the browser reused one of its transceivers for the section.\n */\nexport const midsByTrackId = (sdp: string) => {\n const mids = new Map<string, string>()\n for (const section of sdp.split(/\\r?\\nm=/).slice(1)) {\n const mid = /^a=mid:(\\S+)/m.exec(section)?.[1]\n const track = /^a=msid:\\S+ (\\S+)/m.exec(section)?.[1]\n if (mid !== undefined && track !== undefined) mids.set(track, mid)\n }\n return mids\n}\n\n/**\n * The `mid` of each media section of a description by the id of the stream its `a=msid` line names. Unlike the track\n * id there, which Firefox makes up for each sender, both browsers write the sending page's stream id.\n */\nexport const midsByStreamId = (sdp: string) => {\n const mids = new Map<string, string>()\n for (const section of sdp.split(/\\r?\\nm=/).slice(1)) {\n const mid = /^a=mid:(\\S+)/m.exec(section)?.[1]\n const stream = /^a=msid:(\\S+) \\S+/m.exec(section)?.[1]\n if (mid !== undefined && stream !== undefined && stream !== '-') mids.set(stream, mid)\n }\n return mids\n}\n","import { PublishRefused } from './publish-refused'\nimport type { CallCandidate, CallDescription, CallRemoteTrack, CallServerMessage, CallTrackSource } from '@protobase/schema/internal'\nimport { createPeerConnection as newPeerConnection, type MediaLink, type MediaLinkInput } from './media-link'\nimport { connectionOf } from './connection-stats'\nimport { midsByStreamId } from './msid-tracks'\n\n// `makingOffer` is the local offer being set, while it is.\ntype Peer = { pc: RTCPeerConnection; polite: boolean; makingOffer?: Promise<void>; ignoreOffer: boolean; senders: Map<CallTrackSource, RTCRtpSender> }\n// Each sent track on a stream of its own, whose id names it: the receiving browser reads it in the description's msid.\ntype LocalTrack = { track: MediaStreamTrack; sid: string; stream: MediaStream }\n\n// Whether a description was made by Firefox, whose session lines name it, and whether this browser is Firefox.\nconst firefoxMade = (sdp: string) => /^o=mozilla/m.test(sdp)\nconst inFirefox = typeof navigator !== 'undefined' && /Firefox\\//.test(navigator.userAgent)\n\n/**\n * Who gives way when this side's offer crosses the other's: Firefox, when only one of the two is, since an offer\n * Chromium rolls back for Firefox's leaves their header extension ids clashing and Chromium's next offer fails;\n * otherwise the member whose id sorts first.\n */\nconst politeTo = (peer: { polite: boolean }, offer: string) => (inFirefox === firefoxMade(offer) ? peer.polite : inFirefox)\n\n/**\n * The media link without a media server: one `RTCPeerConnection` to each other member, whose browser answers, so either\n * side may offer. Protobase passes the descriptions and candidates between the two (\"perfect negotiation\": the member\n * whose id sorts first gives way when both offer at once, or Firefox to Chromium) and says who is in the call and which tracks each member\n * hears. A track goes by the id of the stream the sending browser sends it on, which the receiving browser sees too.\n */\nexport const peerLink = (self: string, { iceServers, send, onTracks, createPeerConnection = newPeerConnection }: MediaLinkInput): MediaLink => {\n const peers = new Map<string, Peer>()\n const local = new Map<CallTrackSource, LocalTrack>()\n let remote: CallRemoteTrack[] = []\n let publishing: { resolve: () => void; reject: (error: Error) => void } | undefined\n let publishes: Promise<unknown> = Promise.resolve()\n\n // Each sent track on a transceiver of its own: one the other side's offer made would keep that offer's msid, and the\n // other browser could not tell which track it carries.\n const sendOn = (pc: RTCPeerConnection, { track, stream }: LocalTrack) => pc.addTransceiver(track, { direction: 'sendonly', streams: [stream] }).sender\n\n const receivedTrack = ({ member, sid }: CallRemoteTrack) => {\n const pc = peers.get(member)?.pc\n const mid = pc?.remoteDescription && midsByStreamId(pc.remoteDescription.sdp).get(sid)\n return mid === undefined ? undefined : pc!.getTransceivers().find((transceiver) => transceiver.mid === mid)?.receiver.track\n }\n const emitTracks = () => onTracks(remote.map((track) => ({ ...track, ...(receivedTrack(track) && { track: receivedTrack(track) }) })))\n\n // The peer's connection, new, sending this member's tracks; the one before it, if any, is closed by the caller.\n const open = (member: string, peer: Peer) => {\n const pc = createPeerConnection({ iceServers })\n peer.pc = pc\n peer.senders = new Map()\n pc.onnegotiationneeded = async () => {\n const making = pc.setLocalDescription()\n peer.makingOffer = making\n try {\n await making\n if (peer.pc === pc) send({ type: 'signal', to: member, description: pc.localDescription!.toJSON() as CallDescription })\n } finally {\n if (peer.makingOffer === making) peer.makingOffer = undefined\n }\n }\n pc.onicecandidate = (event) => {\n if (event.candidate && peer.pc === pc) send({ type: 'signal', to: member, candidate: event.candidate.toJSON() as CallCandidate })\n }\n pc.oniceconnectionstatechange = () => {\n if (pc.iceConnectionState === 'failed') pc.restartIce()\n }\n pc.ontrack = () => emitTracks()\n for (const [source, sending] of local) peer.senders.set(source, sendOn(pc, sending))\n }\n const connect = (member: string) => {\n const peer = { polite: self < member, ignoreOffer: false } as Peer\n peers.set(member, peer)\n open(member, peer)\n return peer\n }\n /**\n * Chromium sometimes gathers no candidates on a connection whose first offer it rolled back, so neither side ever\n * checks: the side that gives way on a connection never negotiated starts on a new one instead, once its offer is set.\n */\n const renew = async (member: string, peer: Peer) => {\n await peer.makingOffer\n peer.pc.close()\n open(member, peer)\n }\n const disconnect = (member: string) => {\n peers.get(member)?.pc.close()\n peers.delete(member)\n }\n\n const signal = async (from: string, description?: CallDescription, candidate?: CallCandidate) => {\n // The other member may reach this browser before the list that names them does.\n const peer = peers.get(from) ?? connect(from)\n if (description) {\n const collision = description.type === 'offer' && (peer.makingOffer !== undefined || peer.pc.signalingState !== 'stable')\n peer.ignoreOffer = !politeTo(peer, description.sdp) && collision\n if (peer.ignoreOffer) return\n if (collision && !peer.pc.currentRemoteDescription) await renew(from, peer)\n }\n const { pc } = peer\n if (description) {\n await pc.setRemoteDescription(description)\n if (description.type === 'offer') {\n await pc.setLocalDescription()\n send({ type: 'signal', to: from, description: pc.localDescription!.toJSON() as CallDescription })\n }\n emitTracks()\n }\n // A candidate of an offer this side gave way on belongs to nothing here.\n if (candidate) {\n await pc.addIceCandidate(candidate).catch((error: unknown) => {\n if (!peer.ignoreOffer) throw error\n })\n }\n }\n\n const receive = async (message: CallServerMessage) => {\n switch (message.type) {\n case 'peers': {\n const present = new Set(message.members)\n for (const member of peers.keys()) if (!present.has(member)) disconnect(member)\n for (const member of present) if (!peers.has(member)) connect(member)\n return\n }\n case 'signal':\n return signal(message.from, message.description, message.candidate)\n case 'tracks':\n remote = message.tracks\n emitTracks()\n return\n case 'published':\n publishing?.resolve()\n return\n case 'publish-refused':\n publishing?.reject(new PublishRefused(message.reason))\n return\n }\n }\n\n const publishNow = async (tracks: Partial<Record<CallTrackSource, MediaStreamTrack>>) => {\n const added = Object.entries(tracks) as [CallTrackSource, MediaStreamTrack][]\n for (const [source] of added) if (local.has(source)) throw new Error(`The call already sends a ${source} track: unpublish it first`)\n if (added.length === 0) return\n const sending = added.map(([source, track]): [CallTrackSource, LocalTrack] => {\n const stream = new MediaStream([track])\n return [source, { track, sid: stream.id, stream }]\n })\n const answered = new Promise<void>((resolve, reject) => (publishing = { resolve, reject }))\n send({ type: 'publish', tracks: sending.map(([source, { track, sid }]) => ({ cid: sid, kind: track.kind as 'audio' | 'video', source })) })\n try {\n await answered\n } finally {\n publishing = undefined\n }\n for (const [source, track] of sending) {\n local.set(source, track)\n for (const peer of peers.values()) peer.senders.set(source, sendOn(peer.pc, track))\n }\n }\n\n return {\n receive,\n publish: (tracks) => {\n const next = publishes.then(() => publishNow(tracks))\n publishes = next.catch(() => {})\n return next\n },\n unpublish: async (source) => {\n const sending = local.get(source)\n if (!sending) return\n local.delete(source)\n for (const peer of peers.values()) {\n const sender = peer.senders.get(source)\n if (sender && peer.pc.signalingState !== 'closed') peer.pc.removeTrack(sender)\n peer.senders.delete(source)\n }\n send({ type: 'unpublish', sid: sending.sid })\n },\n mute: (source, muted) => {\n const sending = local.get(source)\n if (!sending) return\n sending.track.enabled = !muted\n send({ type: 'mute', sid: sending.sid, muted })\n },\n restartIce: async () => {\n for (const peer of peers.values()) peer.pc.restartIce()\n },\n // The browsers' connections outlast the server's session: a new one only needs the member's tracks.\n resumeState: async (participant) => ({\n participant,\n tracks: [...local].map(([source, { track, sid }]) => ({ cid: sid, sid, kind: track.kind as 'audio' | 'video', source })),\n }),\n resumed: async () => {},\n sending: () => new Map([...local].map(([source, { track }]) => [source, { track, simulcast: false }])),\n connections: () => Promise.all([...peers].map(([member, peer]) => connectionOf(peer.pc, member))),\n close: () => {\n publishing?.reject(new Error('The call ended'))\n for (const member of [...peers.keys()]) disconnect(member)\n },\n }\n}\n","/**\n * One offer in flight at a time: a change while an offer waits for its answer offers once more after it. `settled`\n * resolves once no offer is in flight or queued, so a caller can wait for its change to be agreed.\n */\nexport const negotiation = (offer: () => Promise<void>) => {\n let inFlight = false\n let again = false\n const waiting: (() => void)[] = []\n\n const start = async () => {\n inFlight = true\n again = false\n await offer()\n }\n const settle = () => {\n for (const resolve of waiting.splice(0)) resolve()\n }\n\n return {\n /** Offers now, or once the offer in flight is answered. */\n request: async () => {\n if (inFlight) {\n again = true\n return\n }\n await start()\n },\n /** The answer to the offer in flight arrived: offers again when a change came meanwhile. */\n answered: async () => {\n inFlight = false\n if (again) return start()\n settle()\n },\n /** The offer in flight will not be answered, such as on a lost session: it is made again by the next `request`. */\n abandon: () => {\n if (inFlight) again = true\n inFlight = false\n },\n /** Whether an offer waits to be made again after `abandon`. */\n get pending() {\n return again\n },\n settled: () => (inFlight || again ? new Promise<void>((resolve) => waiting.push(resolve)) : Promise.resolve()),\n /** Forgets every offer, for a new peer connection; whoever waited is let go. */\n reset: () => {\n inFlight = false\n again = false\n settle()\n },\n }\n}\n","import { PublishRefused } from './publish-refused'\nimport type { CallCandidate, CallRemoteTrack, CallResume, CallServerMessage, CallTrackRequest, CallTrackSource, CallVideoLayer } from '@protobase/schema/internal'\nimport { connectionOf } from './connection-stats'\nimport { createPeerConnection as newPeerConnection, type MediaLink, type MediaLinkInput, type PublishOptions } from './media-link'\nimport { negotiation } from './negotiation'\n\ntype LocalTrack = { source: CallTrackSource; track: MediaStreamTrack; transceiver: RTCRtpTransceiver; sid?: string; simulcast: boolean }\n\n// Simulcast in a quarter, half and full size: what the media server forwards to each member depends on how they show it.\nconst simulcastLayers = [\n { rid: 'q', quality: 'low', scale: 4, maxBitrate: 150_000 },\n { rid: 'h', quality: 'medium', scale: 2, maxBitrate: 500_000 },\n { rid: 'f', quality: 'high', scale: 1, maxBitrate: 1_200_000 },\n] as const\nconst singleBitrate = 1_200_000\n\nconst trackRequest = (source: CallTrackSource, track: MediaStreamTrack, simulcast: boolean): CallTrackRequest => {\n if (track.kind === 'audio') return { cid: track.id, kind: 'audio', source }\n const { width = 0, height = 0 } = track.getSettings()\n const layers: CallVideoLayer[] = simulcast\n ? simulcastLayers.map((layer) => ({ quality: layer.quality, width: Math.round(width / layer.scale), height: Math.round(height / layer.scale), bitrate: layer.maxBitrate }))\n : []\n return { cid: track.id, kind: 'video', source, width, height, ...(simulcast && { layers }) }\n}\n\nconst sendEncodings = (track: MediaStreamTrack, simulcast: boolean): RTCRtpEncodingParameters[] | undefined => {\n if (track.kind === 'audio') return undefined\n if (!simulcast) return [{ maxBitrate: singleBitrate }]\n return simulcastLayers.map((layer) => ({ rid: layer.rid, scaleResolutionDownBy: layer.scale, maxBitrate: layer.maxBitrate }))\n}\n\n/**\n * The media link to a media server, over a single `RTCPeerConnection`: the browser always offers, one offer at a time,\n * and the server's answer maps each receiving section's `mid` to the track it carries. The link holds no media library;\n * everything it says goes through `send` to Protobase, which speaks to the media server.\n */\nexport const sfuLink = ({ iceServers, send, onTracks, onUnpublished, createPeerConnection = newPeerConnection }: MediaLinkInput): MediaLink => {\n const pc = createPeerConnection({ iceServers, bundlePolicy: 'max-bundle' })\n const local = new Map<CallTrackSource, LocalTrack>()\n // Candidates that arrive before the first answer wait for it.\n const early: CallCandidate[] = []\n let mids: Record<string, string> = {}\n let remote: CallRemoteTrack[] = []\n let offerId = 0\n let publishing: { resolve: (tracks: { cid: string; sid: string }[]) => void; reject: (error: Error) => void } | undefined\n let publishes: Promise<unknown> = Promise.resolve()\n\n const offers = negotiation(async () => {\n const offer = await pc.createOffer()\n await pc.setLocalDescription(offer)\n send({ type: 'offer', sdp: offer.sdp!, id: ++offerId })\n })\n // Chrome refuses an offer with nothing in it: a member who only listens waits for the server's `sections`. Messages\n // from the server only start an offer, since its answer is a later message.\n const offer = async () => {\n if (pc.getTransceivers().length > 0) await offers.request()\n }\n const negotiate = async () => {\n await offer()\n await offers.settled()\n }\n\n const receivedTrack = (sid: string) => {\n const mid = Object.keys(mids).find((key) => mids[key] === sid)\n return mid === undefined ? undefined : pc.getTransceivers().find((transceiver) => transceiver.mid === mid)?.receiver.track\n }\n const emitTracks = () => onTracks(remote.map((track) => ({ ...track, ...(receivedTrack(track.sid) && { track: receivedTrack(track.sid) }) })))\n\n pc.onicecandidate = (event) => {\n if (event.candidate) send({ type: 'candidate', candidate: event.candidate.toJSON() as CallCandidate })\n }\n // A path that failed, such as after a network change, gets new ICE credentials.\n pc.oniceconnectionstatechange = () => {\n if (pc.iceConnectionState === 'failed') void restartIce()\n }\n pc.ontrack = () => emitTracks()\n\n const restartIce = async () => {\n pc.restartIce()\n await negotiate()\n }\n\n const stopSending = (source: CallTrackSource) => {\n const sending = local.get(source)\n if (!sending) return false\n local.delete(source)\n if (pc.signalingState !== 'closed') pc.removeTrack(sending.transceiver.sender)\n return true\n }\n\n const receive = async (message: CallServerMessage) => {\n switch (message.type) {\n case 'answer': {\n if (message.id !== offerId) return\n mids = { ...mids, ...message.mids }\n await pc.setRemoteDescription({ type: 'answer', sdp: message.sdp })\n for (const candidate of early.splice(0)) await pc.addIceCandidate(candidate)\n emitTracks()\n await offers.answered()\n return\n }\n case 'candidate':\n if (pc.remoteDescription) await pc.addIceCandidate(message.candidate)\n else early.push(message.candidate)\n return\n case 'sections':\n for (let i = 0; i < message.audio; i++) pc.addTransceiver('audio', { direction: 'recvonly' })\n for (let i = 0; i < message.video; i++) pc.addTransceiver('video', { direction: 'recvonly' })\n await offer()\n return\n case 'tracks':\n remote = message.tracks\n emitTracks()\n return\n case 'unpublished': {\n const sending = [...local.values()].find((track) => track.sid === message.sid)\n if (!sending) return\n stopSending(sending.source)\n await offer()\n onUnpublished(sending.source)\n return\n }\n case 'published':\n publishing?.resolve(message.tracks)\n return\n case 'publish-refused':\n publishing?.reject(new PublishRefused(message.reason))\n return\n }\n }\n\n const publishNow = async (tracks: Partial<Record<CallTrackSource, MediaStreamTrack>>, options: PublishOptions) => {\n const added = (Object.entries(tracks) as [CallTrackSource, MediaStreamTrack][]).map(([source, track]) => {\n if (local.has(source)) throw new Error(`The call already sends a ${source} track: unpublish it first`)\n const simulcast = track.kind === 'video' && Boolean(options.simulcast)\n const encodings = sendEncodings(track, simulcast)\n const transceiver = pc.addTransceiver(track, { direction: 'sendonly', ...(encodings && { sendEncodings: encodings }) })\n return { source, track, transceiver, simulcast } satisfies LocalTrack\n })\n if (added.length === 0) return\n const answered = new Promise<{ cid: string; sid: string }[]>((resolve, reject) => (publishing = { resolve, reject }))\n send({ type: 'publish', tracks: added.map((track) => trackRequest(track.source, track.track, track.simulcast)) })\n try {\n const sids = await answered\n for (const track of added) local.set(track.source, { ...track, sid: sids.find((sid) => sid.cid === track.track.id)!.sid })\n } catch (error) {\n for (const track of added) track.transceiver.stop()\n throw error\n } finally {\n publishing = undefined\n }\n await negotiate()\n }\n\n return {\n receive,\n /** Sends the tracks, under the sources they carry; rejects when the member may not send them. One publish at a time. */\n publish: (tracks: Partial<Record<CallTrackSource, MediaStreamTrack>>, options: PublishOptions = {}) => {\n const next = publishes.then(() => publishNow(tracks, options))\n publishes = next.catch(() => {})\n return next\n },\n /** Stops sending the source's track; the track itself goes on until the app stops it. */\n unpublish: async (source: CallTrackSource) => {\n if (stopSending(source)) await negotiate()\n },\n mute: (source: CallTrackSource, muted: boolean) => {\n const sending = local.get(source)\n if (!sending?.sid) return\n sending.track.enabled = !muted\n send({ type: 'mute', sid: sending.sid, muted })\n },\n restartIce,\n /** What a new server session needs to resume this link, after an offer still in flight is taken back. */\n resumeState: async (participant: string): Promise<Omit<CallResume, 'call'> | undefined> => {\n if (pc.signalingState === 'have-local-offer') {\n await pc.setLocalDescription({ type: 'rollback' })\n offers.abandon()\n }\n if (!pc.localDescription || !pc.remoteDescription) return undefined\n const tracks = [...local.values()].flatMap((track) => (track.sid ? [{ cid: track.track.id, sid: track.sid, kind: track.track.kind as 'audio' | 'video', source: track.source }] : []))\n return { participant, offer: pc.localDescription.sdp, answer: pc.remoteDescription.sdp, tracks }\n },\n /** After a resume: offers what changed while the session was lost. */\n resumed: async () => {\n if (offers.pending) await offer()\n },\n /** The tracks the member sends, by source, to publish again after a rejoin. */\n sending: () => new Map([...local.values()].map((track) => [track.source, { track: track.track, simulcast: track.simulcast }])),\n connections: async () => [await connectionOf(pc)],\n close: () => {\n publishing?.reject(new Error('The call ended'))\n offers.reset()\n pc.close()\n },\n }\n}\n","import type { CallClientMessage, CallGuestLink, CallLeftReason, CallLobbyGuest, CallRosterMember, CallServerMessage, CallTrackSource } from '@protobase/schema/internal'\nimport type { CallConnection } from './connection-stats'\nimport { guestRequests, type CallGuests } from './guest-requests'\nimport type { CallTrack, MediaLink, MediaLinkInput, PublishOptions } from './media-link'\nimport { peerLink } from './peer-link'\nimport { sfuLink } from './sfu-link'\n\n/** Where a call stands: `resuming` while the link to Protobase is restored, with media still flowing. */\nexport type CallState = { state: 'connecting' } | { state: 'joined' } | { state: 'resuming' } | { state: 'left'; reason: CallLeftReason; error?: unknown }\n\nexport type JoinCallOptions = {\n /**\n * The socket of the app's function that admits the member, such as `/api/functions/meeting?call=42`: a path on the\n * page's origin, or an absolute `http(s)` or `ws(s)` URL. The browser sends its session cookie with it.\n */\n url: string\n /** A guest's token from `guestLobby`, with the lobby's `socketUrl` as `url`: the guest joins as themselves, whom no cookie names. */\n guest?: string\n /** With a member who may invite: who waits in the call's lobby, and its guest links, whenever that changes. */\n onLobby?: (lobby: { guests: CallLobbyGuest[]; links: CallGuestLink[] }) => void\n /** Every track of other members the member hears, whenever one comes, goes or its media arrives. */\n onTracks?: (tracks: CallTrack[]) => void\n /** Everyone in the call, the member too, in the order they came, whenever that changes. */\n onMembers?: (members: CallRosterMember[]) => void\n /** Who speaks how loudly, from 0 to 1, for the members whose level changed. */\n onSpeakers?: (speakers: { member: string; level: number }[]) => void\n onState?: (state: CallState) => void\n /** The media server stopped one of the member's own tracks, such as after a demotion. */\n onUnpublished?: (source: CallTrackSource) => void\n /** How long to wait before the `attempt`th try to restore a lost link. */\n retryDelayMs?: (attempt: number) => number\n /** How many tries in a row to restore a lost link, or to get in while the server fails, before the call is left. Default 8. */\n maxRetries?: number\n WebSocket?: typeof WebSocket\n createPeerConnection?: (configuration: RTCConfiguration) => RTCPeerConnection\n}\n\nexport type Call = {\n /** The call, as the record's calls list it and `calls.remove` takes it. */\n readonly id: string\n /** The member's participant in the media server. */\n readonly participant: string\n /** Everyone in the call now, the member too. */\n members: () => CallRosterMember[]\n /** Sends tracks under the sources they carry, such as `{ camera, microphone }`; rejects when the member may not. */\n publish: (tracks: Partial<Record<CallTrackSource, MediaStreamTrack>>, options?: PublishOptions) => Promise<void>\n unpublish: (source: CallTrackSource) => Promise<void>\n mute: (source: CallTrackSource, muted: boolean) => void\n /** How large remote video tracks are shown, so the media server sends a layer that fits, or `hidden` for none. */\n view: (sids: string[], size: { width: number; height: number } | 'hidden') => void\n /** New ICE credentials, such as after a network change; a failed connection restarts by itself. */\n restartIce: () => Promise<void>\n leave: () => void\n /** The tracks of other members the member hears now. */\n tracks: () => CallTrack[]\n /** How each of the member's connections fares now: to each other member, or to the media server. */\n connections: () => Promise<CallConnection[]>\n /** With a member who may invite: guest links, and letting the lobby's guests in. */\n guests: CallGuests\n}\n\nconst backoff = (attempt: number) => Math.min(10_000, 500 * 2 ** attempt)\n\nconst socketUrl = (url: string) => {\n const resolved = new URL(url, globalThis.location?.href)\n resolved.protocol = resolved.protocol.replace(/^http/, 'ws')\n return resolved.href\n}\n\n/** Close codes after which the member is out of the call: left, or refused by the app. */\nconst leftCodes: Record<number, CallLeftReason> = { 1000: 'ended', 1008: 'removed' }\n/** Close codes of a server that failed, or was too busy, for now: getting in is tried again. */\nconst failedCodes = new Set([1011, 1013])\n\n/**\n * Joins a call through the app's function socket and resolves once the member is in it. Media flows over plain\n * `RTCPeerConnection`s, to the media server or straight to the other members, as the app's calls are configured;\n * Protobase relays their offers and answers and decides who is in the call and who hears whom. A lost socket, such as during a deploy, is restored with the browser's own state while\n * media keeps flowing; when the media server no longer knows the member, the call is joined again with the same tracks.\n */\nexport const joinCall = (options: JoinCallOptions): Promise<Call> => {\n const WebSocketOf = options.WebSocket ?? WebSocket\n const retryDelay = options.retryDelayMs ?? backoff\n const maxRetries = options.maxRetries ?? 8\n const url = socketUrl(options.url)\n\n let socket: WebSocket\n let link: MediaLink | undefined\n let participant = ''\n let callId = ''\n let members: CallRosterMember[] = []\n let remote: CallTrack[] = []\n let ended = false\n let rejoin = false\n // Whether the socket reached the server, and whether the server took the resume it sent.\n let opened = false\n let resumedSinceOpen = false\n let failures = 0\n let chain: Promise<void> = Promise.resolve()\n let joined: { resolve: (call: Call) => void; reject: (error: unknown) => void }\n const result = new Promise<Call>((resolve, reject) => (joined = { resolve, reject }))\n\n const send = (message: CallClientMessage) => {\n if (socket.readyState === WebSocketOf.OPEN) socket.send(JSON.stringify(message))\n }\n const requests = guestRequests(send)\n const guest = options.guest !== undefined ? { guest: options.guest } : {}\n const setState = (state: CallState) => options.onState?.(state)\n\n const end = (reason: CallLeftReason, error?: unknown) => {\n if (ended) return\n ended = true\n link?.close()\n link = undefined\n if (socket.readyState === WebSocketOf.OPEN || socket.readyState === WebSocketOf.CONNECTING) socket.close(1000)\n joined.reject(error ?? new Error(`The call was left: ${reason}`))\n setState({ state: 'left', reason, ...(error !== undefined && { error }) })\n }\n\n // The link the call's mode needs: to a media server, or to each other member.\n const newLink = (joined: Extract<CallServerMessage, { type: 'joined' }>) => {\n const input: MediaLinkInput = {\n iceServers: joined.iceServers,\n send,\n onTracks: (tracks) => {\n remote = tracks\n options.onTracks?.(tracks)\n },\n onUnpublished: (source) => options.onUnpublished?.(source),\n ...(options.createPeerConnection && { createPeerConnection: options.createPeerConnection }),\n }\n return joined.mode === 'peer' ? peerLink(joined.participant, input) : sfuLink(input)\n }\n\n const handle = async (message: CallServerMessage) => {\n switch (message.type) {\n case 'joined': {\n const before = link?.sending()\n link?.close()\n participant = message.participant\n callId = message.call\n link = newLink(message)\n failures = 0\n setState({ state: 'joined' })\n joined.resolve(call)\n // A rejoin sends the same tracks again, outside the message chain, since its answer is a later message.\n for (const [source, { track, simulcast }] of before ?? []) void call.publish({ [source]: track }, { simulcast }).catch((error: unknown) => end('ended', error))\n return\n }\n case 'resumed':\n resumedSinceOpen = true\n failures = 0\n setState({ state: 'joined' })\n await link?.resumed()\n return\n case 'speakers':\n options.onSpeakers?.(message.speakers)\n return\n case 'members':\n members = message.members\n options.onMembers?.(members)\n return\n case 'left':\n if (message.reason === 'rejoin') rejoin = true\n else end(message.reason)\n return\n case 'lobby':\n options.onLobby?.({ guests: message.guests, links: message.links })\n return\n default:\n if (requests.receive(message)) return\n await link?.receive(message)\n }\n }\n\n const connect = (mode: 'join' | 'resume') => {\n opened = false\n resumedSinceOpen = false\n socket = new WebSocketOf(url)\n socket.onopen = () => {\n opened = true\n chain = chain.then(async () => {\n const resume = mode === 'resume' && link ? await link.resumeState(participant) : undefined\n send(resume ? { type: 'resume', call: callId, ...resume, ...guest } : { type: 'join', ...guest })\n })\n }\n socket.onmessage = (event) => {\n const message = JSON.parse(String(event.data)) as CallServerMessage\n chain = chain.then(() => handle(message)).catch((error: unknown) => end('ended', error))\n }\n socket.onclose = (event) => {\n requests.lost()\n chain = chain.then(() => closed(mode, event.code))\n }\n }\n\n const closed = (mode: 'join' | 'resume', code: number) => {\n if (ended) return\n if (rejoin) {\n rejoin = false\n return connect('join')\n }\n const left = leftCodes[code]\n if (left) return end(left)\n if (!participant && !failedCodes.has(code)) return end('refused')\n failures++\n if (failures > maxRetries) return end(participant ? 'ended' : 'unavailable')\n setState(participant ? { state: 'resuming' } : { state: 'connecting' })\n // A resume the server got but did not take is not tried again: the member joins anew with the same tracks. One that\n // never reached a server, such as during a deploy, is tried again.\n const next = mode === 'resume' && opened && !resumedSinceOpen ? 'join' : 'resume'\n setTimeout(() => {\n if (!ended) connect(next)\n }, retryDelay(failures - 1))\n }\n\n const call: Call = {\n get id() {\n return callId\n },\n get participant() {\n return participant\n },\n members: () => members,\n publish: async (tracks, publishOptions) => {\n if (!link) throw new Error('The call was left')\n await link.publish(tracks, publishOptions)\n },\n unpublish: async (source) => {\n await link?.unpublish(source)\n },\n mute: (source, muted) => link?.mute(source, muted),\n view: (sids, size) => send(size === 'hidden' ? { type: 'view', sids, width: 0, height: 0, hidden: true } : { type: 'view', sids, ...size }),\n restartIce: async () => {\n await link?.restartIce()\n },\n leave: () => {\n if (ended) return\n send({ type: 'leave' })\n end('ended')\n },\n tracks: () => remote,\n connections: async () => (link ? link.connections() : []),\n guests: requests.guests,\n }\n\n setState({ state: 'connecting' })\n connect('join')\n return result\n}\n","import { guestCallsPath, type CallGuestState, type CallTrackSource } from '@protobase/schema/internal'\n\n/** A guest's wait in the lobby, as the server tells it: once let in, the call and what the guest may send. */\nexport type GuestWait = { state: CallGuestState; call?: string; publish?: CallTrackSource[] }\n\n/** Why the lobby did not answer: no live link, too many tries for now, or a name it does not take. */\nexport class LobbyRefused extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message)\n this.name = 'LobbyRefused'\n }\n}\n\nexport type GuestLobbyOptions = {\n /** The API's system path on the page's origin, `/api` by default. */\n systemPath?: string\n fetch?: typeof fetch\n}\n\n/**\n * The lobby a guest of a call waits in, with no account: `enter` with the link's token and the guest's name gives the\n * guest's own token, which `wait` and `leave` send, and which `joinCall` takes as `guest` at `socketUrl` once a member\n * let them in. No cookie is sent or kept.\n */\nexport const guestLobby = ({ systemPath = '/api', fetch: fetchOf = globalThis.fetch }: GuestLobbyOptions = {}) => {\n const lobby = guestCallsPath(systemPath, 'lobby')\n const ask = async (init: RequestInit) => {\n const response = await fetchOf(lobby, { ...init, credentials: 'omit', cache: 'no-store' })\n if (!response.ok) throw new LobbyRefused(response.status, ((await response.json().catch(() => undefined)) as { detail?: string } | undefined)?.detail ?? response.statusText)\n return response\n }\n const bearer = (token: string) => ({ authorization: `Bearer ${token}` })\n return {\n /** The guest's call socket, for `joinCall`'s `url`. */\n socketUrl: guestCallsPath(systemPath, 'socket'),\n enter: async (link: string, name: string) => (await (await ask({ method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ link, name }) })).json()) as { guest: string; token: string },\n wait: async (token: string) => (await (await ask({ method: 'GET', headers: bearer(token) })).json()) as GuestWait,\n leave: async (token: string) => {\n await ask({ method: 'DELETE', headers: bearer(token) })\n },\n }\n}\n"],"mappings":"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","debugId":"2eb926fb-0fa2-4542-b7af-915f0c3b23f6"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn-B1sdg8aY.js","names":["n","a","t","cn","parts"],"sources":["../../../src/lib/cn.ts"],"sourcesContent":["export const cn = (...parts: Array<string | false | null | undefined>) => parts.filter(Boolean).join(' ')\n"],"mappings":"CAAA,UAAA,CAAA,GAAA,CAAA,IAAA,EAAA,OAAA,WAAA,IAAA,WAAA,OAAA,OAAA,IAAA,OAAA,OAAA,OAAA,IAAA,OAAA,OAAA,KAAA,IAAA,KAAA,CAAA,EAAA,EAAA,sBAAA,EAAA,uBAAA,CAAA,EAAA,EAAA,sBAAA,IAAA,EAAA,MAAA,CAAA,CAAA,OAAA,SAAA,EAAA,CAAA,IAAA,IAAAA,EAAA,EAAAA,EAAA,UAAA,OAAA,IAAA,CAAA,IAAAC,EAAA,UAAAD,GAAA,GAAAC,GAAA,KAAA,IAAA,IAAAC,KAAAD,EAAAA,EAAA,eAAAC,CAAA,IAAA,EAAAA,GAAAD,EAAAC,GAAA,CAAA,OAAA,CAAA,EAAA,CAAA,EAAA,EAAA,sBAAA,IAAA,EAAA,MAAA,CAAA,CAAA,OAAA,CAAA,2CAAA,EAAA,CAAA,CAAA,MAAA,CAAA,CAAA,EAAA,CAAA,EAAA,IAAaC,GAAM,GAAGC,IAAoDA,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG","debugId":"75b1d83c-6984-404f-976f-f20232bf6c42"}