@elqnt/chat 3.0.2 → 3.0.3

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.
@@ -372,8 +372,394 @@ function createSSETransport(options = {}) {
372
372
  return transport;
373
373
  }
374
374
 
375
+ // transport/sse-fetch.ts
376
+ function createFetchSSETransport(options = {}) {
377
+ const {
378
+ retryConfig = DEFAULT_RETRY_CONFIG,
379
+ debug = false,
380
+ logger = createLogger(debug),
381
+ customFetch = fetch
382
+ } = options;
383
+ let abortController;
384
+ let config;
385
+ let state = "disconnected";
386
+ let error;
387
+ let retryCount = 0;
388
+ let reconnectTimeout;
389
+ let intentionalDisconnect = false;
390
+ const metrics = {
391
+ latency: 0,
392
+ messagesSent: 0,
393
+ messagesReceived: 0,
394
+ messagesQueued: 0,
395
+ reconnectCount: 0,
396
+ transportType: "sse-fetch"
397
+ };
398
+ const globalHandlers = /* @__PURE__ */ new Set();
399
+ const typeHandlers = /* @__PURE__ */ new Map();
400
+ function emit(event) {
401
+ metrics.messagesReceived++;
402
+ metrics.lastMessageAt = Date.now();
403
+ globalHandlers.forEach((handler) => {
404
+ try {
405
+ handler(event);
406
+ } catch (err) {
407
+ logger.error("Error in message handler:", err);
408
+ }
409
+ });
410
+ const handlers = typeHandlers.get(event.type);
411
+ if (handlers) {
412
+ handlers.forEach((handler) => {
413
+ try {
414
+ handler(event);
415
+ } catch (err) {
416
+ logger.error(`Error in ${event.type} handler:`, err);
417
+ }
418
+ });
419
+ }
420
+ }
421
+ async function sendRest(endpoint, body) {
422
+ if (!config) {
423
+ throw new Error("Transport not connected");
424
+ }
425
+ const url = `${config.baseUrl}/${endpoint}`;
426
+ logger.debug(`POST ${endpoint}`, body);
427
+ const response = await customFetch(url, {
428
+ method: "POST",
429
+ headers: { "Content-Type": "application/json" },
430
+ body: JSON.stringify(body)
431
+ });
432
+ if (!response.ok) {
433
+ const errorText = await response.text();
434
+ throw new Error(`API error: ${response.status} - ${errorText}`);
435
+ }
436
+ const json = await response.json();
437
+ if (json && typeof json === "object" && "data" in json) {
438
+ return json.data;
439
+ }
440
+ return json;
441
+ }
442
+ function parseSSEChunk(chunk) {
443
+ const events = [];
444
+ const lines = chunk.split("\n");
445
+ let eventType = "message";
446
+ let data = "";
447
+ for (const line of lines) {
448
+ if (line.startsWith("event:")) {
449
+ eventType = line.slice(6).trim();
450
+ } else if (line.startsWith("data:")) {
451
+ data = line.slice(5).trim();
452
+ } else if (line === "" && data) {
453
+ try {
454
+ const parsed = JSON.parse(data);
455
+ events.push(parsed);
456
+ } catch {
457
+ logger.warn("Failed to parse SSE data:", data);
458
+ }
459
+ eventType = "message";
460
+ data = "";
461
+ }
462
+ }
463
+ return events;
464
+ }
465
+ async function startStream(cfg) {
466
+ const url = `${cfg.baseUrl}/stream?orgId=${cfg.orgId}&userId=${cfg.userId}&clientType=${cfg.clientType}${cfg.chatKey ? `&chatId=${cfg.chatKey}` : ""}`;
467
+ logger.debug("Connecting to:", url);
468
+ abortController = new AbortController();
469
+ const response = await customFetch(url, {
470
+ method: "GET",
471
+ headers: {
472
+ Accept: "text/event-stream",
473
+ "Cache-Control": "no-cache"
474
+ },
475
+ signal: abortController.signal
476
+ });
477
+ if (!response.ok) {
478
+ throw new Error(`Stream connection failed: ${response.status}`);
479
+ }
480
+ if (!response.body) {
481
+ throw new Error("Response body is null - ReadableStream not supported");
482
+ }
483
+ const reader = response.body.getReader();
484
+ const decoder = new TextDecoder();
485
+ let buffer = "";
486
+ const readStream = async () => {
487
+ try {
488
+ while (true) {
489
+ const { done, value } = await reader.read();
490
+ if (done) {
491
+ logger.info("Stream ended");
492
+ break;
493
+ }
494
+ buffer += decoder.decode(value, { stream: true });
495
+ const lastNewline = buffer.lastIndexOf("\n\n");
496
+ if (lastNewline !== -1) {
497
+ const complete = buffer.slice(0, lastNewline + 2);
498
+ buffer = buffer.slice(lastNewline + 2);
499
+ const events = parseSSEChunk(complete);
500
+ events.forEach(emit);
501
+ }
502
+ }
503
+ } catch (err) {
504
+ if (err.name === "AbortError") {
505
+ logger.debug("Stream aborted");
506
+ return;
507
+ }
508
+ logger.error("Stream error:", err);
509
+ throw err;
510
+ }
511
+ if (!intentionalDisconnect) {
512
+ state = "disconnected";
513
+ scheduleReconnect();
514
+ }
515
+ };
516
+ readStream().catch((err) => {
517
+ if (!intentionalDisconnect) {
518
+ error = {
519
+ code: "CONNECTION_FAILED",
520
+ message: err.message,
521
+ retryable: true,
522
+ timestamp: Date.now(),
523
+ originalError: err
524
+ };
525
+ metrics.lastError = error;
526
+ state = "disconnected";
527
+ scheduleReconnect();
528
+ }
529
+ });
530
+ }
531
+ function scheduleReconnect() {
532
+ if (intentionalDisconnect || !config) return;
533
+ const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;
534
+ if (retryCount >= maxRetries) {
535
+ logger.error(`Max retries (${maxRetries}) exceeded`);
536
+ error = {
537
+ code: "CONNECTION_FAILED",
538
+ message: `Max retries (${maxRetries}) exceeded`,
539
+ retryable: false,
540
+ timestamp: Date.now()
541
+ };
542
+ return;
543
+ }
544
+ const interval = calculateRetryInterval(retryCount, retryConfig);
545
+ retryCount++;
546
+ metrics.reconnectCount++;
547
+ logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);
548
+ state = "reconnecting";
549
+ reconnectTimeout = setTimeout(() => {
550
+ if (config) {
551
+ transport.connect(config).catch((err) => {
552
+ logger.error("Reconnect failed:", err);
553
+ });
554
+ }
555
+ }, interval);
556
+ }
557
+ const transport = {
558
+ async connect(cfg) {
559
+ config = cfg;
560
+ intentionalDisconnect = false;
561
+ if (abortController) {
562
+ abortController.abort();
563
+ abortController = void 0;
564
+ }
565
+ if (reconnectTimeout) {
566
+ clearTimeout(reconnectTimeout);
567
+ reconnectTimeout = void 0;
568
+ }
569
+ state = retryCount > 0 ? "reconnecting" : "connecting";
570
+ const connectionStart = Date.now();
571
+ try {
572
+ await startStream(cfg);
573
+ const connectionTime = Date.now() - connectionStart;
574
+ logger.info(`Connected in ${connectionTime}ms`);
575
+ state = "connected";
576
+ error = void 0;
577
+ retryCount = 0;
578
+ metrics.connectedAt = Date.now();
579
+ metrics.latency = connectionTime;
580
+ } catch (err) {
581
+ const connectError = {
582
+ code: "CONNECTION_FAILED",
583
+ message: err.message,
584
+ retryable: true,
585
+ timestamp: Date.now(),
586
+ originalError: err
587
+ };
588
+ error = connectError;
589
+ metrics.lastError = connectError;
590
+ state = "disconnected";
591
+ if (!intentionalDisconnect) {
592
+ scheduleReconnect();
593
+ }
594
+ throw connectError;
595
+ }
596
+ },
597
+ disconnect(intentional = true) {
598
+ logger.info("Disconnecting", { intentional });
599
+ intentionalDisconnect = intentional;
600
+ if (reconnectTimeout) {
601
+ clearTimeout(reconnectTimeout);
602
+ reconnectTimeout = void 0;
603
+ }
604
+ if (abortController) {
605
+ abortController.abort();
606
+ abortController = void 0;
607
+ }
608
+ state = "disconnected";
609
+ retryCount = 0;
610
+ },
611
+ async send(event) {
612
+ if (!config) {
613
+ throw new Error("Transport not connected");
614
+ }
615
+ switch (event.type) {
616
+ case "message":
617
+ await sendRest("send", {
618
+ orgId: event.orgId,
619
+ chatKey: event.chatKey,
620
+ userId: event.userId,
621
+ message: event.message
622
+ });
623
+ break;
624
+ case "typing":
625
+ await sendRest("typing", {
626
+ orgId: event.orgId,
627
+ chatKey: event.chatKey,
628
+ userId: event.userId,
629
+ typing: true
630
+ });
631
+ break;
632
+ case "stopped_typing":
633
+ await sendRest("typing", {
634
+ orgId: event.orgId,
635
+ chatKey: event.chatKey,
636
+ userId: event.userId,
637
+ typing: false
638
+ });
639
+ break;
640
+ case "load_chat":
641
+ await sendRest("load", {
642
+ orgId: event.orgId,
643
+ chatKey: event.chatKey,
644
+ userId: event.userId
645
+ });
646
+ break;
647
+ case "new_chat":
648
+ await sendRest("create", {
649
+ orgId: event.orgId,
650
+ userId: event.userId,
651
+ metadata: event.data
652
+ });
653
+ break;
654
+ case "end_chat":
655
+ await sendRest("end", {
656
+ orgId: event.orgId,
657
+ chatKey: event.chatKey,
658
+ userId: event.userId,
659
+ data: event.data
660
+ });
661
+ break;
662
+ default:
663
+ await sendRest("event", {
664
+ type: event.type,
665
+ orgId: event.orgId,
666
+ chatKey: event.chatKey,
667
+ userId: event.userId,
668
+ data: event.data
669
+ });
670
+ }
671
+ metrics.messagesSent++;
672
+ },
673
+ async sendMessage(message) {
674
+ if (!config) {
675
+ throw new Error("Transport not connected");
676
+ }
677
+ await sendRest("send", {
678
+ orgId: config.orgId,
679
+ chatKey: config.chatKey,
680
+ userId: config.userId,
681
+ message
682
+ });
683
+ metrics.messagesSent++;
684
+ },
685
+ async createChat(options2) {
686
+ if (!config) {
687
+ throw new Error("Transport not connected");
688
+ }
689
+ const response = await sendRest("create", {
690
+ orgId: options2.orgId,
691
+ userId: options2.userId,
692
+ metadata: options2.metadata
693
+ });
694
+ if (!response?.chatKey) {
695
+ throw new Error("Failed to create chat: no chatKey returned");
696
+ }
697
+ return { chatKey: response.chatKey };
698
+ },
699
+ async loadChatData(options2) {
700
+ if (!config) {
701
+ throw new Error("Transport not connected");
702
+ }
703
+ const response = await sendRest("load", {
704
+ orgId: options2.orgId,
705
+ chatKey: options2.chatKey,
706
+ userId: options2.userId
707
+ });
708
+ if (!response?.chat) {
709
+ throw new Error("Failed to load chat: no chat data returned");
710
+ }
711
+ return {
712
+ chat: response.chat,
713
+ agentId: response.agentId
714
+ };
715
+ },
716
+ onMessage(handler) {
717
+ globalHandlers.add(handler);
718
+ return () => globalHandlers.delete(handler);
719
+ },
720
+ on(eventType, handler) {
721
+ if (!typeHandlers.has(eventType)) {
722
+ typeHandlers.set(eventType, /* @__PURE__ */ new Set());
723
+ }
724
+ typeHandlers.get(eventType).add(handler);
725
+ return () => {
726
+ const handlers = typeHandlers.get(eventType);
727
+ if (handlers) {
728
+ handlers.delete(handler);
729
+ if (handlers.size === 0) {
730
+ typeHandlers.delete(eventType);
731
+ }
732
+ }
733
+ };
734
+ },
735
+ getState() {
736
+ return state;
737
+ },
738
+ getMetrics() {
739
+ return { ...metrics };
740
+ },
741
+ getError() {
742
+ return error;
743
+ },
744
+ clearError() {
745
+ error = void 0;
746
+ }
747
+ };
748
+ return transport;
749
+ }
750
+
375
751
  // hooks/use-chat.ts
376
752
  function getDefaultTransport(type, debug) {
753
+ if (type === "sse-fetch") {
754
+ return createFetchSSETransport({ debug });
755
+ }
756
+ if (type === "sse") {
757
+ return createSSETransport({ debug });
758
+ }
759
+ const isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
760
+ if (isReactNative || typeof EventSource === "undefined") {
761
+ return createFetchSSETransport({ debug });
762
+ }
377
763
  return createSSETransport({ debug });
378
764
  }
379
765
  function useChat(options) {
@@ -484,6 +870,7 @@ function useChat(options) {
484
870
  throw err;
485
871
  }
486
872
  setConnectionState("connecting");
873
+ onConnectionChange?.("connecting");
487
874
  try {
488
875
  const unsubscribe = transport.onMessage(handleEvent);
489
876
  await transport.connect({
@@ -502,6 +889,7 @@ function useChat(options) {
502
889
  } catch (err) {
503
890
  const transportError = err;
504
891
  setConnectionState("disconnected");
892
+ onConnectionChange?.("disconnected");
505
893
  setError(transportError);
506
894
  onErrorRef.current?.(transportError);
507
895
  throw err;
@@ -531,7 +919,7 @@ function useChat(options) {
531
919
  },
532
920
  [orgId, userId]
533
921
  );
534
- const loadChat = useCallback(
922
+ const loadChat2 = useCallback(
535
923
  async (key) => {
536
924
  const transport = transportRef.current;
537
925
  if (!transport) {
@@ -584,7 +972,7 @@ function useChat(options) {
584
972
  },
585
973
  [orgId, chatKey, userId]
586
974
  );
587
- const endChat = useCallback(
975
+ const endChat2 = useCallback(
588
976
  async (reason) => {
589
977
  const transport = transportRef.current;
590
978
  if (!transport) {
@@ -606,7 +994,7 @@ function useChat(options) {
606
994
  },
607
995
  [orgId, chatKey, userId]
608
996
  );
609
- const sendEvent = useCallback(
997
+ const sendEvent2 = useCallback(
610
998
  async (event) => {
611
999
  const transport = transportRef.current;
612
1000
  if (!transport) {
@@ -691,10 +1079,10 @@ function useChat(options) {
691
1079
  isConnected,
692
1080
  // Chat operations
693
1081
  startChat,
694
- loadChat,
1082
+ loadChat: loadChat2,
695
1083
  sendMessage,
696
- sendEvent,
697
- endChat,
1084
+ sendEvent: sendEvent2,
1085
+ endChat: endChat2,
698
1086
  // Typing
699
1087
  startTyping,
700
1088
  stopTyping,
@@ -709,7 +1097,225 @@ function useChat(options) {
709
1097
  clearError
710
1098
  };
711
1099
  }
1100
+
1101
+ // hooks/use-chat-history.ts
1102
+ import { useMemo } from "react";
1103
+
1104
+ // api/index.ts
1105
+ import { browserApiRequest } from "@elqnt/api-client/browser";
1106
+ async function getChatHistoryApi(options) {
1107
+ return browserApiRequest("/api/v1/chats", {
1108
+ method: "POST",
1109
+ body: {
1110
+ limit: options.limit || 15,
1111
+ offset: options.offset || 0,
1112
+ ...options.skipCache ? { skipCache: true } : {}
1113
+ },
1114
+ ...options
1115
+ });
1116
+ }
1117
+ async function getChatApi(chatKey, options) {
1118
+ return browserApiRequest(`/api/v1/chats/${chatKey}`, {
1119
+ method: "GET",
1120
+ ...options
1121
+ });
1122
+ }
1123
+ async function updateChatApi(chatKey, updates, options) {
1124
+ return browserApiRequest(`/api/v1/chats/${chatKey}`, {
1125
+ method: "PATCH",
1126
+ body: updates,
1127
+ ...options
1128
+ });
1129
+ }
1130
+ async function deleteChatApi(chatKey, options) {
1131
+ return browserApiRequest(`/api/v1/chats/${chatKey}`, {
1132
+ method: "DELETE",
1133
+ ...options
1134
+ });
1135
+ }
1136
+ async function getActiveChatsCountApi(options) {
1137
+ return browserApiRequest("/api/v1/chats/active/count", {
1138
+ method: "GET",
1139
+ ...options
1140
+ });
1141
+ }
1142
+ async function getActiveChatsApi(options) {
1143
+ const params = new URLSearchParams();
1144
+ if (options.pastHours) params.set("pastHours", String(options.pastHours));
1145
+ const queryString = params.toString();
1146
+ return browserApiRequest(`/api/v1/chats/active${queryString ? `?${queryString}` : ""}`, {
1147
+ method: "GET",
1148
+ ...options
1149
+ });
1150
+ }
1151
+ async function getWaitingChatsCountApi(options) {
1152
+ return browserApiRequest("/api/v1/chats/waiting/count", {
1153
+ method: "GET",
1154
+ ...options
1155
+ });
1156
+ }
1157
+ async function getChatsByUserApi(userEmail, options) {
1158
+ return browserApiRequest(`/api/v1/chats/user/${encodeURIComponent(userEmail)}`, {
1159
+ method: "GET",
1160
+ ...options
1161
+ });
1162
+ }
1163
+ async function listQueuesApi(options) {
1164
+ return browserApiRequest("/api/v1/queues", {
1165
+ method: "GET",
1166
+ ...options
1167
+ });
1168
+ }
1169
+ async function getOnlineSessionsApi(options) {
1170
+ return browserApiRequest("/api/v1/agents/sessions/online", {
1171
+ method: "GET",
1172
+ ...options
1173
+ });
1174
+ }
1175
+ async function getAgentSessionApi(agentId, options) {
1176
+ return browserApiRequest(`/api/v1/agents/sessions/${agentId}`, {
1177
+ method: "GET",
1178
+ ...options
1179
+ });
1180
+ }
1181
+
1182
+ // hooks/use-chat-history.ts
1183
+ import { useApiAsync } from "@elqnt/api-client/hooks";
1184
+
1185
+ // hooks/use-options-ref.ts
1186
+ import { useRef as useRef2, useEffect as useEffect2 } from "react";
1187
+ function useOptionsRef(options) {
1188
+ const optionsRef = useRef2(options);
1189
+ useEffect2(() => {
1190
+ optionsRef.current = options;
1191
+ }, [options]);
1192
+ return optionsRef;
1193
+ }
1194
+
1195
+ // hooks/use-chat-history.ts
1196
+ function useChatHistory(options) {
1197
+ const optionsRef = useOptionsRef(options);
1198
+ const { execute: getChatHistory, loading: listLoading, error: listError } = useApiAsync(
1199
+ (params) => getChatHistoryApi({ ...optionsRef.current, ...params }),
1200
+ (data) => ({
1201
+ chats: data.chats,
1202
+ total: data.total,
1203
+ hasMore: data.hasMore
1204
+ }),
1205
+ { chats: [], total: 0, hasMore: false }
1206
+ );
1207
+ const { execute: getChat, loading: getLoading, error: getError } = useApiAsync(
1208
+ (chatKey) => getChatApi(chatKey, optionsRef.current),
1209
+ (data) => data.chat || null,
1210
+ null
1211
+ );
1212
+ const { execute: updateChat, loading: updateLoading, error: updateError } = useApiAsync(
1213
+ (chatKey, updates) => updateChatApi(chatKey, updates, optionsRef.current),
1214
+ (data) => !!data.chatKey,
1215
+ false
1216
+ );
1217
+ const { execute: deleteChat, loading: deleteLoading, error: deleteError } = useApiAsync(
1218
+ (chatKey) => deleteChatApi(chatKey, optionsRef.current),
1219
+ (data) => data.success,
1220
+ false
1221
+ );
1222
+ const { execute: getChatsByUser, loading: userChatsLoading, error: userChatsError } = useApiAsync(
1223
+ (userEmail) => getChatsByUserApi(userEmail, optionsRef.current),
1224
+ (data) => data.chats,
1225
+ []
1226
+ );
1227
+ const loading = listLoading || getLoading || updateLoading || deleteLoading || userChatsLoading;
1228
+ const error = listError || getError || updateError || deleteError || userChatsError;
1229
+ return useMemo(
1230
+ () => ({
1231
+ loading,
1232
+ error,
1233
+ getChatHistory,
1234
+ getChat,
1235
+ updateChat,
1236
+ deleteChat,
1237
+ getChatsByUser
1238
+ }),
1239
+ [loading, error, getChatHistory, getChat, updateChat, deleteChat, getChatsByUser]
1240
+ );
1241
+ }
1242
+
1243
+ // hooks/use-chat-monitoring.ts
1244
+ import { useMemo as useMemo2 } from "react";
1245
+ import { useApiAsync as useApiAsync2 } from "@elqnt/api-client/hooks";
1246
+ function useChatMonitoring(options) {
1247
+ const optionsRef = useOptionsRef(options);
1248
+ const { execute: getActiveChats, loading: activeLoading, error: activeError } = useApiAsync2(
1249
+ (pastHours) => getActiveChatsApi({ ...optionsRef.current, pastHours }),
1250
+ (data) => data.chats,
1251
+ []
1252
+ );
1253
+ const { execute: getActiveChatsCount, loading: activeCountLoading, error: activeCountError } = useApiAsync2(
1254
+ () => getActiveChatsCountApi(optionsRef.current),
1255
+ (data) => data.count,
1256
+ 0
1257
+ );
1258
+ const { execute: getWaitingChatsCount, loading: waitingCountLoading, error: waitingCountError } = useApiAsync2(
1259
+ () => getWaitingChatsCountApi(optionsRef.current),
1260
+ (data) => data.count,
1261
+ 0
1262
+ );
1263
+ const { execute: listQueues, loading: queuesLoading, error: queuesError } = useApiAsync2(
1264
+ () => listQueuesApi(optionsRef.current),
1265
+ (data) => data.queues,
1266
+ []
1267
+ );
1268
+ const loading = activeLoading || activeCountLoading || waitingCountLoading || queuesLoading;
1269
+ const error = activeError || activeCountError || waitingCountError || queuesError;
1270
+ return useMemo2(
1271
+ () => ({
1272
+ loading,
1273
+ error,
1274
+ getActiveChats,
1275
+ getActiveChatsCount,
1276
+ getWaitingChatsCount,
1277
+ listQueues
1278
+ }),
1279
+ [loading, error, getActiveChats, getActiveChatsCount, getWaitingChatsCount, listQueues]
1280
+ );
1281
+ }
1282
+
1283
+ // hooks/use-human-agent-sessions.ts
1284
+ import { useMemo as useMemo3 } from "react";
1285
+ import { useApiAsync as useApiAsync3 } from "@elqnt/api-client/hooks";
1286
+ function useHumanAgentSessions(options) {
1287
+ const optionsRef = useOptionsRef(options);
1288
+ const { execute: getOnlineSessions, loading: onlineLoading, error: onlineError } = useApiAsync3(
1289
+ () => getOnlineSessionsApi(optionsRef.current),
1290
+ (data) => data.sessions,
1291
+ []
1292
+ );
1293
+ const { execute: getAgentSession, loading: sessionLoading, error: sessionError } = useApiAsync3(
1294
+ (agentId) => getAgentSessionApi(agentId, optionsRef.current),
1295
+ (data) => data.session || null,
1296
+ null
1297
+ );
1298
+ const loading = onlineLoading || sessionLoading;
1299
+ const error = onlineError || sessionError;
1300
+ return useMemo3(
1301
+ () => ({
1302
+ loading,
1303
+ error,
1304
+ getOnlineSessions,
1305
+ getAgentSession
1306
+ }),
1307
+ [loading, error, getOnlineSessions, getAgentSession]
1308
+ );
1309
+ }
1310
+
1311
+ // hooks/index.ts
1312
+ import { useApiAsync as useApiAsync4 } from "@elqnt/api-client/hooks";
712
1313
  export {
713
- useChat
1314
+ useApiAsync4 as useApiAsync,
1315
+ useChat,
1316
+ useChatHistory,
1317
+ useChatMonitoring,
1318
+ useHumanAgentSessions,
1319
+ useOptionsRef
714
1320
  };
715
1321
  //# sourceMappingURL=index.mjs.map