{"version":3,"file":"composable.cjs","names":["defaultRealTimeConfig: WebSocketConfig","generateUid","state: ConnectionState","reconnectState: ReconnectState","client","eventHandlers: Record<WebSocketEvents, Set<WebSocketEventHandler>>","auth","messageCallback","pong","resolve!: (value: WebSocketInterface | PromiseLike<WebSocketInterface>) => void","reject!: (reason?: any) => void","ws: WebSocketInterface","connectTimeout: ReturnType<typeof setTimeout> | undefined","event","queryToParams"],"sources":["../../src/realtime/composable.ts"],"sourcesContent":["import type { AuthenticationClient } from '../auth/types.js';\nimport type { ConsoleInterface, ExtendedQuery, WebSocketInterface } from '../index.js';\nimport type { DirectusClient } from '../types/client.js';\nimport { queryToParams } from '../utils/query-to-params.js';\nimport { auth } from './commands/auth.js';\nimport { pong } from './commands/pong.js';\nimport type {\n\tConnectionState,\n\tReconnectState,\n\tSubscribeOptions,\n\tSubscriptionEvents,\n\tSubscriptionOutput,\n\tWebSocketAuthError,\n\tWebSocketClient,\n\tWebSocketConfig,\n\tWebSocketEventHandler,\n\tWebSocketEvents,\n} from './types.js';\nimport { generateUid } from './utils/generate-uid.js';\nimport { messageCallback } from './utils/message-callback.js';\n\ntype AuthWSClient<Schema> = WebSocketClient<Schema> & AuthenticationClient<Schema>;\n\nconst defaultRealTimeConfig: WebSocketConfig = {\n\tauthMode: 'handshake',\n\theartbeat: true,\n\tdebug: false,\n\tconnect: {\n\t\ttimeout: 10000, // 10 seconds\n\t},\n\treconnect: {\n\t\tdelay: 1000, // 1 second\n\t\tretries: 10,\n\t},\n};\n\n/**\n * Creates a client to communicate with a Directus REST WebSocket.\n *\n * @param config The optional configuration.\n *\n * @returns A Directus realtime client.\n */\nexport function realtime(config: WebSocketConfig = {}) {\n\treturn <Schema>(client: DirectusClient<Schema>) => {\n\t\tconfig = { ...defaultRealTimeConfig, ...config };\n\t\tlet uid = generateUid();\n\n\t\tlet state: ConnectionState = {\n\t\t\tcode: 'closed',\n\t\t};\n\n\t\tconst reconnectState: ReconnectState = {\n\t\t\tattempts: 0,\n\t\t\tactive: false,\n\t\t};\n\n\t\t// Disable reconnection after manual disconnection\n\t\tlet wasManuallyDisconnected = false;\n\n\t\tconst subscriptions = new Set<Record<string, any>>();\n\n\t\tconst hasAuth = (client: AuthWSClient<Schema>) => 'getToken' in client;\n\n\t\tconst debug = (level: keyof ConsoleInterface, ...data: any[]) =>\n\t\t\tconfig.debug && client.globals.logger[level]('[Directus SDK]', ...data);\n\n\t\tconst withStrictAuth = async (url: URL | string, currentClient: AuthWSClient<Schema>) => {\n\t\t\tconst newUrl = new client.globals.URL(url);\n\n\t\t\tif (config.authMode === 'strict' && hasAuth(currentClient)) {\n\t\t\t\tconst token = await currentClient.getToken();\n\t\t\t\tif (token) newUrl.searchParams.set('access_token', token);\n\t\t\t}\n\n\t\t\treturn newUrl.toString();\n\t\t};\n\n\t\tconst getSocketUrl = async (currentClient: AuthWSClient<Schema>) => {\n\t\t\tif ('url' in config) return await withStrictAuth(config.url, currentClient);\n\n\t\t\t// if the main URL is a websocket URL use it directly!\n\t\t\tif (['ws:', 'wss:'].includes(client.url.protocol)) {\n\t\t\t\treturn await withStrictAuth(client.url, currentClient);\n\t\t\t}\n\n\t\t\t// try filling in the defaults based on the main URL\n\t\t\tconst newUrl = new client.globals.URL(client.url.toString());\n\t\t\tnewUrl.protocol = client.url.protocol === 'https:' ? 'wss:' : 'ws:';\n\t\t\tnewUrl.pathname = '/websocket';\n\n\t\t\treturn await withStrictAuth(newUrl, currentClient);\n\t\t};\n\n\t\tconst reconnect = (self: WebSocketClient<Schema>) => {\n\t\t\tconst reconnectPromise = new Promise<WebSocketInterface>((resolve, reject) => {\n\t\t\t\tif (!config.reconnect || wasManuallyDisconnected) return reject();\n\n\t\t\t\tdebug(\n\t\t\t\t\t'info',\n\t\t\t\t\t`reconnect #${reconnectState.attempts} ` +\n\t\t\t\t\t\t(reconnectState.attempts >= config.reconnect.retries\n\t\t\t\t\t\t\t? 'maximum retries reached'\n\t\t\t\t\t\t\t: `trying again in ${Math.max(100, config.reconnect.delay)}ms`),\n\t\t\t\t);\n\n\t\t\t\tif (reconnectState.active) return reconnectState.active;\n\n\t\t\t\tif (reconnectState.attempts >= config.reconnect.retries) {\n\t\t\t\t\treconnectState.attempts = -1;\n\t\t\t\t\treturn reject();\n\t\t\t\t}\n\n\t\t\t\tsetTimeout(\n\t\t\t\t\t() =>\n\t\t\t\t\t\tself\n\t\t\t\t\t\t\t.connect()\n\t\t\t\t\t\t\t.then((ws) => {\n\t\t\t\t\t\t\t\t// reconnect to existing subscriptions\n\t\t\t\t\t\t\t\tsubscriptions.forEach((sub) => {\n\t\t\t\t\t\t\t\t\tself.sendMessage(sub);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\treturn ws;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.then(resolve)\n\t\t\t\t\t\t\t.catch(reject),\n\t\t\t\t\tMath.max(100, config.reconnect.delay),\n\t\t\t\t);\n\t\t\t});\n\n\t\t\treconnectState.attempts += 1;\n\n\t\t\treconnectState.active = reconnectPromise\n\t\t\t\t.catch(() => {})\n\t\t\t\t.finally(() => {\n\t\t\t\t\treconnectState.active = false;\n\t\t\t\t});\n\t\t};\n\n\t\tconst eventHandlers: Record<WebSocketEvents, Set<WebSocketEventHandler>> = {\n\t\t\topen: new Set<WebSocketEventHandler>([]),\n\t\t\terror: new Set<WebSocketEventHandler>([]),\n\t\t\tclose: new Set<WebSocketEventHandler>([]),\n\t\t\tmessage: new Set<WebSocketEventHandler>([]),\n\t\t};\n\n\t\tfunction isAuthError(message: Record<string, any> | MessageEvent<string>): message is WebSocketAuthError {\n\t\t\treturn (\n\t\t\t\t'type' in message &&\n\t\t\t\t'status' in message &&\n\t\t\t\t'error' in message &&\n\t\t\t\t'code' in message['error'] &&\n\t\t\t\t'message' in message['error'] &&\n\t\t\t\tmessage['type'] === 'auth' &&\n\t\t\t\tmessage['status'] === 'error'\n\t\t\t);\n\t\t}\n\n\t\tasync function handleAuthError(message: WebSocketAuthError, currentClient: AuthWSClient<Schema>) {\n\t\t\tif (state.code !== 'open') return;\n\n\t\t\tif (message.error.code === 'TOKEN_EXPIRED') {\n\t\t\t\tdebug('warn', 'Authentication token expired!');\n\n\t\t\t\tif (hasAuth(currentClient)) {\n\t\t\t\t\tconst access_token = await currentClient.getToken();\n\n\t\t\t\t\tif (!access_token) {\n\t\t\t\t\t\tthrow Error('No token for re-authenticating the websocket');\n\t\t\t\t\t}\n\n\t\t\t\t\tstate.connection.send(auth({ access_token }));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (message.error.code === 'AUTH_TIMEOUT') {\n\t\t\t\tif (state.firstMessage && config.authMode === 'public') {\n\t\t\t\t\t// detected likely misconfigured authMode\n\t\t\t\t\tdebug('warn', 'Authentication failed! Currently the \"authMode\" is \"public\" try using \"handshake\" instead');\n\t\t\t\t\tconfig.reconnect = false;\n\t\t\t\t} else {\n\t\t\t\t\tdebug('warn', 'Authentication timed out!');\n\t\t\t\t}\n\n\t\t\t\treturn state.connection.close();\n\t\t\t}\n\n\t\t\tif (message.error.code === 'AUTH_FAILED') {\n\t\t\t\tif (state.firstMessage && config.authMode === 'public') {\n\t\t\t\t\t// detected likely misconfigured authMode\n\t\t\t\t\tdebug('warn', 'Authentication failed! Currently the \"authMode\" is \"public\" try using \"handshake\" instead');\n\t\t\t\t\tconfig.reconnect = false;\n\t\t\t\t\treturn state.connection.close();\n\t\t\t\t}\n\n\t\t\t\tdebug('warn', 'Authentication failed!');\n\t\t\t}\n\t\t}\n\n\t\tconst handleMessages = async (currentClient: AuthWSClient<Schema>) => {\n\t\t\twhile (state.code === 'open') {\n\t\t\t\tconst message = await messageCallback(state.connection).catch(() => {\n\t\t\t\t\t/* ignore invalid messages */\n\t\t\t\t});\n\n\t\t\t\tif (!message) continue;\n\n\t\t\t\tif (isAuthError(message)) {\n\t\t\t\t\tawait handleAuthError(message, currentClient);\n\t\t\t\t\tstate.firstMessage = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (config.heartbeat && message['type'] === 'ping') {\n\t\t\t\t\tstate.connection.send(pong());\n\t\t\t\t\tstate.firstMessage = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\teventHandlers['message'].forEach((handler) => {\n\t\t\t\t\tif (state.code === 'open') handler.call(state.connection, message);\n\t\t\t\t});\n\n\t\t\t\tstate.firstMessage = false;\n\t\t\t}\n\t\t};\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Checks if a websocket connection has been established.\n\t\t\t * Does not check authentication status.\n\t\t\t */\n\t\t\tasync isConnected() {\n\t\t\t\tif (state.code === 'connecting') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait state.connection;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn state.code === 'open';\n\t\t\t},\n\t\t\tasync connect() {\n\t\t\t\twasManuallyDisconnected = false;\n\n\t\t\t\tif (state.code === 'connecting') {\n\t\t\t\t\t// wait for the current connection to open\n\t\t\t\t\treturn await state.connection;\n\t\t\t\t} else if (state.code !== 'closed') {\n\t\t\t\t\t// error state\n\t\t\t\t\tthrow new Error(`Cannot connect when state is \"${state.code}\"`);\n\t\t\t\t}\n\n\t\t\t\t// Eventually update to Promise.withResolvers()\n\t\t\t\tlet resolve!: (value: WebSocketInterface | PromiseLike<WebSocketInterface>) => void;\n\t\t\t\tlet reject!: (reason?: any) => void;\n\n\t\t\t\tconst connectPromise = new Promise<WebSocketInterface>((res, rej) => {\n\t\t\t\t\tresolve = res;\n\t\t\t\t\treject = rej;\n\t\t\t\t});\n\n\t\t\t\tstate = {\n\t\t\t\t\tcode: 'connecting',\n\t\t\t\t\tconnection: connectPromise,\n\t\t\t\t};\n\n\t\t\t\t// we need to use THIS here instead of client to access overridden functions\n\t\t\t\tconst self = this as AuthWSClient<Schema>;\n\t\t\t\tlet ws: WebSocketInterface;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst url = await getSocketUrl(self);\n\t\t\t\t\tdebug('info', `Connecting to ${url}...`);\n\n\t\t\t\t\tws = new client.globals.WebSocket(url);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tstate = { code: 'closed' };\n\t\t\t\t\treject(e);\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\tlet resolved = false;\n\t\t\t\tlet connectTimeout: ReturnType<typeof setTimeout> | undefined;\n\n\t\t\t\tif (config.connect) {\n\t\t\t\t\tconnectTimeout = setTimeout(() => {\n\t\t\t\t\t\treject('Connection attempt timed out.');\n\t\t\t\t\t}, config.connect.timeout ?? 10000);\n\t\t\t\t}\n\n\t\t\t\tws.addEventListener('open', async (evt: Event) => {\n\t\t\t\t\tdebug('info', `Connection open.`);\n\n\t\t\t\t\tstate = { code: 'open', connection: ws, firstMessage: true };\n\t\t\t\t\treconnectState.attempts = 0;\n\t\t\t\t\treconnectState.active = false;\n\t\t\t\t\tclearTimeout(connectTimeout);\n\t\t\t\t\thandleMessages(self);\n\n\t\t\t\t\tif (config.authMode === 'handshake' && hasAuth(self)) {\n\t\t\t\t\t\tconst access_token = await self.getToken();\n\n\t\t\t\t\t\tif (!access_token) {\n\t\t\t\t\t\t\treturn reject(\n\t\t\t\t\t\t\t\t'No token for authenticating the websocket. Make sure to provide one or call the login() function beforehand.',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tws.send(auth({ access_token }));\n\t\t\t\t\t\tconst confirm = await messageCallback(ws);\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\tconfirm &&\n\t\t\t\t\t\t\t\t'type' in confirm &&\n\t\t\t\t\t\t\t\t'status' in confirm &&\n\t\t\t\t\t\t\t\tconfirm['type'] === 'auth' &&\n\t\t\t\t\t\t\t\tconfirm['status'] === 'ok'\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn reject('Authentication failed while opening websocket connection');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdebug('info', 'Authentication successful!');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\teventHandlers['open'].forEach((handler) => handler.call(ws, evt));\n\n\t\t\t\t\tresolved = true;\n\t\t\t\t\tresolve(ws);\n\t\t\t\t});\n\n\t\t\t\tws.addEventListener('error', (evt: Event) => {\n\t\t\t\t\tdebug('warn', `Connection errored.`);\n\t\t\t\t\teventHandlers['error'].forEach((handler) => handler.call(ws, evt));\n\t\t\t\t\tws.close();\n\t\t\t\t\tstate = { code: 'error' };\n\t\t\t\t\tif (!resolved) reject(evt);\n\t\t\t\t});\n\n\t\t\t\tws.addEventListener('close', (evt: CloseEvent) => {\n\t\t\t\t\tdebug('info', `Connection closed.`);\n\t\t\t\t\teventHandlers['close'].forEach((handler) => handler.call(ws, evt));\n\t\t\t\t\tuid = generateUid();\n\t\t\t\t\tstate = { code: 'closed' };\n\t\t\t\t\treconnect(this);\n\t\t\t\t\tif (!resolved) reject(evt);\n\t\t\t\t});\n\n\t\t\t\treturn connectPromise;\n\t\t\t},\n\t\t\tdisconnect() {\n\t\t\t\twasManuallyDisconnected = true;\n\n\t\t\t\tif (state.code === 'open') {\n\t\t\t\t\tstate.connection.close();\n\t\t\t\t}\n\t\t\t},\n\t\t\tonWebSocket(event: WebSocketEvents, callback: (this: WebSocketInterface, ev: Event | CloseEvent | any) => any) {\n\t\t\t\tif (event === 'message') {\n\t\t\t\t\t// add some message parsing\n\t\t\t\t\tconst updatedCallback = function (this: WebSocketInterface, event: MessageEvent<any>) {\n\t\t\t\t\t\tif (typeof event.data !== 'string') return callback.call(this, event);\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn callback.call(this, JSON.parse(event.data));\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn callback.call(this, event);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\teventHandlers[event].add(updatedCallback);\n\t\t\t\t\treturn () => eventHandlers[event].delete(updatedCallback);\n\t\t\t\t}\n\n\t\t\t\teventHandlers[event].add(callback);\n\t\t\t\treturn () => eventHandlers[event].delete(callback);\n\t\t\t},\n\t\t\tsendMessage(message: string | Record<string, any>) {\n\t\t\t\tif (state.code !== 'open') {\n\t\t\t\t\t// TODO use directus error\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Cannot send messages without an open connection. Make sure you are calling \"await client.connect()\".',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (typeof message === 'string') {\n\t\t\t\t\treturn state.connection.send(message);\n\t\t\t\t}\n\n\t\t\t\tif ('uid' in message === false) {\n\t\t\t\t\tmessage['uid'] = uid.next().value;\n\t\t\t\t}\n\n\t\t\t\tstate.connection.send(JSON.stringify(message));\n\t\t\t},\n\t\t\tasync subscribe<Collection extends keyof Schema, const Options extends SubscribeOptions<Schema, Collection>>(\n\t\t\t\tcollection: Collection,\n\t\t\t\toptions = {} as Options,\n\t\t\t) {\n\t\t\t\tif ('uid' in options === false) options.uid = uid.next().value;\n\n\t\t\t\tif (options.query) {\n\t\t\t\t\toptions.query = queryToParams(options.query as ExtendedQuery<Schema, Schema[Collection]>);\n\t\t\t\t}\n\n\t\t\t\tsubscriptions.add({ ...options, collection, type: 'subscribe' });\n\n\t\t\t\tif (state.code !== 'open') {\n\t\t\t\t\tdebug('info', 'No connection available for subscribing!');\n\t\t\t\t\tawait this.connect();\n\t\t\t\t}\n\n\t\t\t\tthis.sendMessage({ ...options, collection, type: 'subscribe' });\n\t\t\t\tlet subscribed = true;\n\n\t\t\t\tasync function* subscriptionGenerator(): AsyncGenerator<\n\t\t\t\t\tSubscriptionOutput<Schema, Collection, Options['query'], SubscriptionEvents>,\n\t\t\t\t\tvoid,\n\t\t\t\t\tunknown\n\t\t\t\t> {\n\t\t\t\t\twhile (subscribed && state.code === 'open') {\n\t\t\t\t\t\tconst message = await messageCallback(state.connection).catch(() => {\n\t\t\t\t\t\t\t/* let the loop continue */\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (!message) continue;\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t'type' in message &&\n\t\t\t\t\t\t\t'status' in message &&\n\t\t\t\t\t\t\tmessage['type'] === 'subscribe' &&\n\t\t\t\t\t\t\tmessage['status'] === 'error'\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tthrow message;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t'type' in message &&\n\t\t\t\t\t\t\t'uid' in message &&\n\t\t\t\t\t\t\tmessage['type'] === 'subscription' &&\n\t\t\t\t\t\t\tmessage['uid'] === options.uid\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tyield message as SubscriptionOutput<Schema, Collection, Options['query'], SubscriptionEvents>;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (config.reconnect && reconnectState.active) {\n\t\t\t\t\t\tawait reconnectState.active;\n\n\t\t\t\t\t\tif (state.code === 'open') {\n\t\t\t\t\t\t\t// re-subscribe on the new connection\n\t\t\t\t\t\t\tstate.connection.send(JSON.stringify({ ...options, collection, type: 'subscribe' }));\n\n\t\t\t\t\t\t\tyield* subscriptionGenerator();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst unsubscribe = () => {\n\t\t\t\t\tsubscriptions.delete({ ...options, collection, type: 'subscribe' });\n\t\t\t\t\tthis.sendMessage({ uid: options.uid, type: 'unsubscribe' });\n\t\t\t\t\tsubscribed = false;\n\t\t\t\t};\n\n\t\t\t\treturn {\n\t\t\t\t\tsubscription: subscriptionGenerator(),\n\t\t\t\t\tunsubscribe,\n\t\t\t\t};\n\t\t\t},\n\t\t} as WebSocketClient<Schema>;\n\t};\n}\n"],"mappings":"kMAuBMA,EAAyC,CAC9C,SAAU,YACV,UAAW,GACX,MAAO,GACP,QAAS,CACR,QAAS,IACT,CACD,UAAW,CACV,MAAO,IACP,QAAS,GACT,CACD,CASD,SAAgB,EAAS,EAA0B,EAAE,CAAE,CACtD,MAAgB,IAAmC,CAClD,EAAS,CAAE,GAAG,EAAuB,GAAG,EAAQ,CAChD,IAAI,EAAMC,EAAAA,aAAa,CAEnBC,EAAyB,CAC5B,KAAM,SACN,CAEKC,EAAiC,CACtC,SAAU,EACV,OAAQ,GACR,CAGG,EAA0B,GAExB,EAAgB,IAAI,IAEpB,EAAW,GAAiC,aAAcC,EAE1D,GAAS,EAA+B,GAAG,IAChD,EAAO,OAAS,EAAO,QAAQ,OAAO,GAAO,iBAAkB,GAAG,EAAK,CAElE,EAAiB,MAAO,EAAmB,IAAwC,CACxF,IAAM,EAAS,IAAI,EAAO,QAAQ,IAAI,EAAI,CAE1C,GAAI,EAAO,WAAa,UAAY,EAAQ,EAAc,CAAE,CAC3D,IAAM,EAAQ,MAAM,EAAc,UAAU,CACxC,GAAO,EAAO,aAAa,IAAI,eAAgB,EAAM,CAG1D,OAAO,EAAO,UAAU,EAGnB,EAAe,KAAO,IAAwC,CACnE,GAAI,QAAS,EAAQ,OAAO,MAAM,EAAe,EAAO,IAAK,EAAc,CAG3E,GAAI,CAAC,MAAO,OAAO,CAAC,SAAS,EAAO,IAAI,SAAS,CAChD,OAAO,MAAM,EAAe,EAAO,IAAK,EAAc,CAIvD,IAAM,EAAS,IAAI,EAAO,QAAQ,IAAI,EAAO,IAAI,UAAU,CAAC,CAI5D,MAHA,GAAO,SAAW,EAAO,IAAI,WAAa,SAAW,OAAS,MAC9D,EAAO,SAAW,aAEX,MAAM,EAAe,EAAQ,EAAc,EAG7C,EAAa,GAAkC,CACpD,IAAM,EAAmB,IAAI,SAA6B,EAAS,IAAW,CAC7E,GAAI,CAAC,EAAO,WAAa,EAAyB,OAAO,GAAQ,CAUjE,GARA,EACC,OACA,cAAc,EAAe,SAAS,IACpC,EAAe,UAAY,EAAO,UAAU,QAC1C,0BACA,mBAAmB,KAAK,IAAI,IAAK,EAAO,UAAU,MAAM,CAAC,KAC7D,CAEG,EAAe,OAAQ,OAAO,EAAe,OAEjD,GAAI,EAAe,UAAY,EAAO,UAAU,QAE/C,MADA,GAAe,SAAW,GACnB,GAAQ,CAGhB,eAEE,EACE,SAAS,CACT,KAAM,IAEN,EAAc,QAAS,GAAQ,CAC9B,EAAK,YAAY,EAAI,EACpB,CAEK,GACN,CACD,KAAK,EAAQ,CACb,MAAM,EAAO,CAChB,KAAK,IAAI,IAAK,EAAO,UAAU,MAAM,CACrC,EACA,CAEF,EAAe,UAAY,EAE3B,EAAe,OAAS,EACtB,UAAY,GAAG,CACf,YAAc,CACd,EAAe,OAAS,IACvB,EAGEC,EAAqE,CAC1E,KAAM,IAAI,IAA2B,EAAE,CAAC,CACxC,MAAO,IAAI,IAA2B,EAAE,CAAC,CACzC,MAAO,IAAI,IAA2B,EAAE,CAAC,CACzC,QAAS,IAAI,IAA2B,EAAE,CAAC,CAC3C,CAED,SAAS,EAAY,EAAoF,CACxG,MACC,SAAU,GACV,WAAY,GACZ,UAAW,GACX,SAAU,EAAQ,OAClB,YAAa,EAAQ,OACrB,EAAQ,OAAY,QACpB,EAAQ,SAAc,QAIxB,eAAe,EAAgB,EAA6B,EAAqC,CAC5F,KAAM,OAAS,OAEnB,IAAI,EAAQ,MAAM,OAAS,kBAC1B,EAAM,OAAQ,gCAAgC,CAE1C,EAAQ,EAAc,EAAE,CAC3B,IAAM,EAAe,MAAM,EAAc,UAAU,CAEnD,GAAI,CAAC,EACJ,MAAM,MAAM,+CAA+C,CAG5D,EAAM,WAAW,KAAKC,EAAAA,KAAK,CAAE,eAAc,CAAC,CAAC,CAI/C,GAAI,EAAQ,MAAM,OAAS,eAS1B,OARI,EAAM,cAAgB,EAAO,WAAa,UAE7C,EAAM,OAAQ,4FAA4F,CAC1G,EAAO,UAAY,IAEnB,EAAM,OAAQ,4BAA4B,CAGpC,EAAM,WAAW,OAAO,CAGhC,GAAI,EAAQ,MAAM,OAAS,cAAe,CACzC,GAAI,EAAM,cAAgB,EAAO,WAAa,SAI7C,OAFA,EAAM,OAAQ,4FAA4F,CAC1G,EAAO,UAAY,GACZ,EAAM,WAAW,OAAO,CAGhC,EAAM,OAAQ,yBAAyB,GAIzC,IAAM,EAAiB,KAAO,IAAwC,CACrE,KAAO,EAAM,OAAS,QAAQ,CAC7B,IAAM,EAAU,MAAMC,EAAAA,gBAAgB,EAAM,WAAW,CAAC,UAAY,GAElE,CAEG,KAEL,IAAI,EAAY,EAAQ,CAAE,CACzB,MAAM,EAAgB,EAAS,EAAc,CAC7C,EAAM,aAAe,GACrB,SAGD,GAAI,EAAO,WAAa,EAAQ,OAAY,OAAQ,CACnD,EAAM,WAAW,KAAKC,EAAAA,MAAM,CAAC,CAC7B,EAAM,aAAe,GACrB,SAGD,EAAc,QAAW,QAAS,GAAY,CACzC,EAAM,OAAS,QAAQ,EAAQ,KAAK,EAAM,WAAY,EAAQ,EACjE,CAEF,EAAM,aAAe,MAIvB,MAAO,CAKN,MAAM,aAAc,CACnB,GAAI,EAAM,OAAS,aAClB,GAAI,CACH,MAAM,EAAM,gBACL,CACP,MAAO,GAIT,OAAO,EAAM,OAAS,QAEvB,MAAM,SAAU,CAGf,GAFA,EAA0B,GAEtB,EAAM,OAAS,aAElB,OAAO,MAAM,EAAM,cACT,EAAM,OAAS,SAEzB,MAAU,MAAM,iCAAiC,EAAM,KAAK,GAAG,CAIhE,IAAIC,EACAC,EAEE,EAAiB,IAAI,SAA6B,EAAK,IAAQ,CACpE,EAAU,EACV,EAAS,GACR,CAEF,EAAQ,CACP,KAAM,aACN,WAAY,EACZ,CAGD,IAAM,EAAO,KACTC,EAEJ,GAAI,CACH,IAAM,EAAM,MAAM,EAAa,EAAK,CACpC,EAAM,OAAQ,iBAAiB,EAAI,KAAK,CAExC,EAAK,IAAI,EAAO,QAAQ,UAAU,EAAI,OAC9B,EAAG,CAGX,KAFA,GAAQ,CAAE,KAAM,SAAU,CAC1B,EAAO,EAAE,CACH,EAGP,IAAI,EAAW,GACXC,EAmEJ,OAjEI,EAAO,UACV,EAAiB,eAAiB,CACjC,EAAO,gCAAgC,EACrC,EAAO,QAAQ,SAAW,IAAM,EAGpC,EAAG,iBAAiB,OAAQ,KAAO,IAAe,CASjD,GARA,EAAM,OAAQ,mBAAmB,CAEjC,EAAQ,CAAE,KAAM,OAAQ,WAAY,EAAI,aAAc,GAAM,CAC5D,EAAe,SAAW,EAC1B,EAAe,OAAS,GACxB,aAAa,EAAe,CAC5B,EAAe,EAAK,CAEhB,EAAO,WAAa,aAAe,EAAQ,EAAK,CAAE,CACrD,IAAM,EAAe,MAAM,EAAK,UAAU,CAE1C,GAAI,CAAC,EACJ,OAAO,EACN,+GACA,CAGF,EAAG,KAAKN,EAAAA,KAAK,CAAE,eAAc,CAAC,CAAC,CAC/B,IAAM,EAAU,MAAMC,EAAAA,gBAAgB,EAAG,CAEzC,GAEE,GACA,SAAU,GACV,WAAY,GACZ,EAAQ,OAAY,QACpB,EAAQ,SAAc,KAKvB,EAAM,OAAQ,6BAA6B,MAF3C,OAAO,EAAO,2DAA2D,CAM3E,EAAc,KAAQ,QAAS,GAAY,EAAQ,KAAK,EAAI,EAAI,CAAC,CAEjE,EAAW,GACX,EAAQ,EAAG,EACV,CAEF,EAAG,iBAAiB,QAAU,GAAe,CAC5C,EAAM,OAAQ,sBAAsB,CACpC,EAAc,MAAS,QAAS,GAAY,EAAQ,KAAK,EAAI,EAAI,CAAC,CAClE,EAAG,OAAO,CACV,EAAQ,CAAE,KAAM,QAAS,CACpB,GAAU,EAAO,EAAI,EACzB,CAEF,EAAG,iBAAiB,QAAU,GAAoB,CACjD,EAAM,OAAQ,qBAAqB,CACnC,EAAc,MAAS,QAAS,GAAY,EAAQ,KAAK,EAAI,EAAI,CAAC,CAClE,EAAMN,EAAAA,aAAa,CACnB,EAAQ,CAAE,KAAM,SAAU,CAC1B,EAAU,KAAK,CACV,GAAU,EAAO,EAAI,EACzB,CAEK,GAER,YAAa,CACZ,EAA0B,GAEtB,EAAM,OAAS,QAClB,EAAM,WAAW,OAAO,EAG1B,YAAY,EAAwB,EAA2E,CAC9G,GAAI,IAAU,UAAW,CAExB,IAAM,EAAkB,SAAoC,EAA0B,CACrF,GAAI,OAAOY,EAAM,MAAS,SAAU,OAAO,EAAS,KAAK,KAAMA,EAAM,CAErE,GAAI,CACH,OAAO,EAAS,KAAK,KAAM,KAAK,MAAMA,EAAM,KAAK,CAAC,MAC3C,CACP,OAAO,EAAS,KAAK,KAAMA,EAAM,GAKnC,OADA,EAAc,GAAO,IAAI,EAAgB,KAC5B,EAAc,GAAO,OAAO,EAAgB,CAI1D,OADA,EAAc,GAAO,IAAI,EAAS,KACrB,EAAc,GAAO,OAAO,EAAS,EAEnD,YAAY,EAAuC,CAClD,GAAI,EAAM,OAAS,OAElB,MAAU,MACT,uGACA,CAGF,GAAI,OAAO,GAAY,SACtB,OAAO,EAAM,WAAW,KAAK,EAAQ,CAGlC,QAAS,IACZ,EAAQ,IAAS,EAAI,MAAM,CAAC,OAG7B,EAAM,WAAW,KAAK,KAAK,UAAU,EAAQ,CAAC,EAE/C,MAAM,UACL,EACA,EAAU,EAAE,CACX,CACG,QAAS,IAAmB,EAAQ,IAAM,EAAI,MAAM,CAAC,OAEzD,AACC,EAAQ,QAAQC,EAAAA,cAAc,EAAQ,MAAmD,CAG1F,EAAc,IAAI,CAAE,GAAG,EAAS,aAAY,KAAM,YAAa,CAAC,CAE5D,EAAM,OAAS,SAClB,EAAM,OAAQ,2CAA2C,CACzD,MAAM,KAAK,SAAS,EAGrB,KAAK,YAAY,CAAE,GAAG,EAAS,aAAY,KAAM,YAAa,CAAC,CAC/D,IAAI,EAAa,GAEjB,eAAgB,GAId,CACD,KAAO,GAAc,EAAM,OAAS,QAAQ,CAC3C,IAAM,EAAU,MAAMP,EAAAA,gBAAgB,EAAM,WAAW,CAAC,UAAY,GAElE,CAEG,KAEL,IACC,SAAU,GACV,WAAY,GACZ,EAAQ,OAAY,aACpB,EAAQ,SAAc,QAEtB,MAAM,EAIN,SAAU,GACV,QAAS,GACT,EAAQ,OAAY,gBACpB,EAAQ,MAAW,EAAQ,MAE3B,MAAM,IAIJ,EAAO,WAAa,EAAe,SACtC,MAAM,EAAe,OAEjB,EAAM,OAAS,SAElB,EAAM,WAAW,KAAK,KAAK,UAAU,CAAE,GAAG,EAAS,aAAY,KAAM,YAAa,CAAC,CAAC,CAEpF,MAAO,GAAuB,GAWjC,MAAO,CACN,aAAc,GAAuB,CACrC,gBARyB,CACzB,EAAc,OAAO,CAAE,GAAG,EAAS,aAAY,KAAM,YAAa,CAAC,CACnE,KAAK,YAAY,CAAE,IAAK,EAAQ,IAAK,KAAM,cAAe,CAAC,CAC3D,EAAa,IAMb,EAEF"}